From 90105cb1480f636899ae50687ece102c2689f66a Mon Sep 17 00:00:00 2001 From: Amruth Pillai Date: Wed, 8 Jul 2026 19:07:05 +0200 Subject: [PATCH] chore: integrate improve-integration --- README.md | 2 +- apps/server/package.json | 53 +- apps/server/src/static/uploads.test.ts | 2 + apps/server/src/static/uploads.ts | 2 - apps/server/src/static/web.test.ts | 9 + apps/server/src/static/web.ts | 11 +- apps/web/locales/af-ZA.po | 55 +- apps/web/locales/am-ET.po | 55 +- apps/web/locales/ar-SA.po | 55 +- apps/web/locales/az-AZ.po | 55 +- apps/web/locales/bg-BG.po | 55 +- apps/web/locales/bn-BD.po | 55 +- apps/web/locales/ca-ES.po | 55 +- apps/web/locales/cs-CZ.po | 55 +- apps/web/locales/da-DK.po | 55 +- apps/web/locales/de-DE.po | 55 +- apps/web/locales/el-GR.po | 55 +- apps/web/locales/en-GB.po | 55 +- apps/web/locales/en-US.po | 53 +- apps/web/locales/es-ES.po | 55 +- apps/web/locales/fa-IR.po | 55 +- apps/web/locales/fi-FI.po | 55 +- apps/web/locales/fr-FR.po | 55 +- apps/web/locales/he-IL.po | 55 +- apps/web/locales/hi-IN.po | 55 +- apps/web/locales/hu-HU.po | 55 +- apps/web/locales/id-ID.po | 55 +- apps/web/locales/it-IT.po | 55 +- apps/web/locales/ja-JP.po | 55 +- apps/web/locales/km-KH.po | 55 +- apps/web/locales/kn-IN.po | 55 +- apps/web/locales/ko-KR.po | 55 +- apps/web/locales/lt-LT.po | 55 +- apps/web/locales/lv-LV.po | 55 +- apps/web/locales/ml-IN.po | 55 +- apps/web/locales/mr-IN.po | 55 +- apps/web/locales/ms-MY.po | 55 +- apps/web/locales/ne-NP.po | 55 +- apps/web/locales/nl-NL.po | 55 +- apps/web/locales/no-NO.po | 55 +- apps/web/locales/or-IN.po | 55 +- apps/web/locales/pl-PL.po | 55 +- apps/web/locales/pt-BR.po | 55 +- apps/web/locales/pt-PT.po | 55 +- apps/web/locales/ro-RO.po | 55 +- apps/web/locales/ru-RU.po | 55 +- apps/web/locales/sk-SK.po | 55 +- apps/web/locales/sl-SI.po | 55 +- apps/web/locales/sq-AL.po | 55 +- apps/web/locales/sr-SP.po | 55 +- apps/web/locales/sv-SE.po | 55 +- apps/web/locales/ta-IN.po | 55 +- apps/web/locales/te-IN.po | 55 +- apps/web/locales/th-TH.po | 55 +- apps/web/locales/tr-TR.po | 55 +- apps/web/locales/uk-UA.po | 55 +- apps/web/locales/uz-UZ.po | 55 +- apps/web/locales/vi-VN.po | 55 +- apps/web/locales/zh-CN.po | 55 +- apps/web/locales/zh-TW.po | 55 +- apps/web/locales/zu-ZA.po | 51 +- apps/web/package.json | 44 +- .../src/components/typography/combobox.tsx | 32 +- .../src/features/command-palette/index.tsx | 22 +- .../command-palette/pages/resumes.test.tsx | 99 +- .../command-palette/pages/resumes.tsx | 11 +- .../resume/export/download-dialog.tsx | 29 +- .../features/resume/export/pdf-document.tsx | 11 +- .../resume/export/use-resume-export.ts | 12 +- .../components/ai-section.test.tsx | 21 + .../integrations/components/ai-section.tsx | 67 +- .../src/libs/resume/section-actions.test.ts | 3 +- .../right/sections/layout/pages.test.tsx | 13 + .../-sidebar/right/sections/layout/pages.tsx | 52 +- .../-sidebar/right/sections/template.test.tsx | 8 + .../-sidebar/right/sections/template.tsx | 59 +- ...02-structured-style-rules-for-react-pdf.md | 5 - docs/changelog/index.mdx | 37 + .../2026-05-14-monorepo-architecture-reorg.md | 241 -- ...olith-and-split-deployment-architecture.md | 1143 ------ .../2026-05-14-monorepo-architecture-reorg.md | 277 -- .../2026-05-15-docker-nightly-release-tags.md | 214 -- .../plans/2026-05-15-manifest-only-pwa.md | 117 - .../2026-05-15-unsafe-oauth-redirect-uri.md | 222 -- .../superpowers/plans/2026-06-20-e2e-tests.md | 670 ---- ...2026-07-07-applications-rest-mcp-parity.md | 1372 ------- ...-11-react-pdf-html-prose-spacing-design.md | 55 - ...5-15-docker-nightly-release-tags-design.md | 94 - .../2026-05-15-manifest-only-pwa-design.md | 99 - ...-05-15-unsafe-oauth-redirect-uri-design.md | 95 - ...26-05-19-agent-snapshot-rollback-design.md | 29 - ...-26-custom-styles-header-targets-design.md | 129 - .../specs/2026-06-19-e2e-tests-design.md | 262 -- .../2026-07-05-applications-tracker-design.md | 94 - ...-07-applications-rest-mcp-parity-design.md | 215 -- .../2026-05-14-monorepo-architecture-reorg.md | 323 -- ...026-07-07-mcp-and-directory-submissions.md | 55 - knip.json | 9 + package.json | 26 +- packages/ai/package.json | 4 +- packages/ai/src/types.test.ts | 23 + packages/ai/src/types.ts | 18 + packages/api/package.json | 33 +- packages/api/src/dto/application.test.ts | 21 + packages/api/src/dto/application.ts | 4 +- .../api/src/features/ai-providers/inputs.ts | 17 + .../src/features/ai-providers/router.test.ts | 8 + .../api/src/features/ai-providers/router.ts | 19 +- .../src/features/ai-providers/service.test.ts | 122 + .../api/src/features/ai-providers/service.ts | 2 +- .../api/src/features/ai/service.docx.test.ts | 110 + packages/api/src/features/ai/service.test.ts | 76 +- packages/api/src/features/ai/service.ts | 162 +- .../api/src/features/resume/service.test.ts | 341 ++ packages/api/src/features/resume/service.ts | 12 +- .../src/features/resume/view-dedup.test.ts | 53 + .../api/src/features/resume/view-dedup.ts | 45 + packages/auth/package.json | 6 +- packages/db/package.json | 4 +- packages/docx/package.json | 4 +- packages/email/package.json | 8 +- packages/env/package.json | 6 +- packages/fonts/package.json | 4 +- packages/import/package.json | 4 +- packages/mcp/package.json | 8 +- packages/pdf/package.json | 6 +- packages/pdf/src/browser.tsx | 10 +- packages/pdf/src/context.tsx | 18 +- packages/pdf/src/document.tsx | 6 +- .../src/templates/shared/cover-letter.test.ts | 7 + .../pdf/src/templates/shared/cover-letter.ts | 9 +- packages/resume/package.json | 4 +- packages/schema/package.json | 4 +- packages/ui/package.json | 6 +- packages/utils/package.json | 6 +- pnpm-lock.yaml | 3283 ++++++++++------- tests/e2e/fixtures/resume.ts | 4 +- tests/e2e/specs/dashboard-lifecycle.spec.ts | 4 +- tooling/package.json | 2 +- 139 files changed, 6054 insertions(+), 7793 deletions(-) create mode 100644 apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/layout/pages.test.tsx delete mode 100644 docs/adr/0002-structured-style-rules-for-react-pdf.md delete mode 100644 docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md delete mode 100644 docs/superpowers/plans/2026-05-14-monolith-and-split-deployment-architecture.md delete mode 100644 docs/superpowers/plans/2026-05-14-monorepo-architecture-reorg.md delete mode 100644 docs/superpowers/plans/2026-05-15-docker-nightly-release-tags.md delete mode 100644 docs/superpowers/plans/2026-05-15-manifest-only-pwa.md delete mode 100644 docs/superpowers/plans/2026-05-15-unsafe-oauth-redirect-uri.md delete mode 100644 docs/superpowers/plans/2026-06-20-e2e-tests.md delete mode 100644 docs/superpowers/plans/2026-07-07-applications-rest-mcp-parity.md delete mode 100644 docs/superpowers/specs/2026-05-11-react-pdf-html-prose-spacing-design.md delete mode 100644 docs/superpowers/specs/2026-05-15-docker-nightly-release-tags-design.md delete mode 100644 docs/superpowers/specs/2026-05-15-manifest-only-pwa-design.md delete mode 100644 docs/superpowers/specs/2026-05-15-unsafe-oauth-redirect-uri-design.md delete mode 100644 docs/superpowers/specs/2026-05-19-agent-snapshot-rollback-design.md delete mode 100644 docs/superpowers/specs/2026-05-26-custom-styles-header-targets-design.md delete mode 100644 docs/superpowers/specs/2026-06-19-e2e-tests-design.md delete mode 100644 docs/superpowers/specs/2026-07-05-applications-tracker-design.md delete mode 100644 docs/superpowers/specs/2026-07-07-applications-rest-mcp-parity-design.md delete mode 100644 docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md delete mode 100644 docs/superpowers/worklogs/2026-07-07-mcp-and-directory-submissions.md create mode 100644 packages/ai/src/types.test.ts create mode 100644 packages/api/src/features/ai-providers/inputs.ts create mode 100644 packages/api/src/features/ai-providers/router.test.ts create mode 100644 packages/api/src/features/ai-providers/service.test.ts create mode 100644 packages/api/src/features/ai/service.docx.test.ts create mode 100644 packages/api/src/features/resume/service.test.ts create mode 100644 packages/api/src/features/resume/view-dedup.test.ts create mode 100644 packages/api/src/features/resume/view-dedup.ts diff --git a/README.md b/README.md index 593dd1340..f4879761f 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ If your company would like to sponsor Reactive Resume, email [hello@amruthpillai - Professionally designed templates - A4 and Letter size support - Customizable colors, fonts, and spacing -- Custom CSS for advanced styling +- Structured Style Rules for section and text styling **Privacy & Control** diff --git a/apps/server/package.json b/apps/server/package.json index cceea199e..16ba7c715 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -17,24 +17,33 @@ "#react-pdf-renderer": "@react-pdf/renderer" }, "dependencies": { - "@ai-sdk/anthropic": "^4.0.8", - "@ai-sdk/google": "^4.0.8", - "@ai-sdk/openai": "^4.0.7", - "@ai-sdk/openai-compatible": "^3.0.5", - "@aws-sdk/client-s3": "^3.1079.0", + "@ai-sdk/anthropic": "^4.0.10", + "@ai-sdk/cerebras": "^3.0.6", + "@ai-sdk/cohere": "^4.0.6", + "@ai-sdk/deepseek": "^3.0.6", + "@ai-sdk/fireworks": "^3.0.7", + "@ai-sdk/google": "^4.0.10", + "@ai-sdk/groq": "^4.0.6", + "@ai-sdk/mistral": "^4.0.7", + "@ai-sdk/openai": "^4.0.9", + "@ai-sdk/openai-compatible": "^3.0.6", + "@ai-sdk/perplexity": "^4.0.7", + "@ai-sdk/togetherai": "^3.0.7", + "@ai-sdk/xai": "^4.0.9", + "@aws-sdk/client-s3": "^3.1081.0", "@better-auth/api-key": "^1.6.23", "@better-auth/drizzle-adapter": "^1.6.23", - "@better-auth/infra": "^0.3.4", + "@better-auth/infra": "^0.3.5", "@better-auth/oauth-provider": "^1.6.23", "@better-auth/passkey": "^1.6.23", "@hono/node-server": "^2.0.8", "@modelcontextprotocol/sdk": "^1.29.0", - "@orpc/client": "^1.14.6", - "@orpc/experimental-ratelimit": "^1.14.6", - "@orpc/json-schema": "^1.14.6", - "@orpc/openapi": "^1.14.6", - "@orpc/server": "^1.14.6", - "@orpc/zod": "^1.14.6", + "@orpc/client": "^1.14.7", + "@orpc/experimental-ratelimit": "^1.14.7", + "@orpc/json-schema": "^1.14.7", + "@orpc/openapi": "^1.14.7", + "@orpc/server": "^1.14.7", + "@orpc/zod": "^1.14.7", "@react-pdf/renderer": "^4.5.1", "@reactive-resume/api": "workspace:*", "@reactive-resume/auth": "workspace:*", @@ -46,7 +55,7 @@ "@sindresorhus/slugify": "^3.0.0", "@t3-oss/env-core": "^0.13.11", "@uiw/color-convert": "^2.10.3", - "ai": "^7.0.15", + "ai": "^7.0.18", "bcrypt": "^6.0.0", "better-auth": "1.6.23", "cjk-regex": "^3.4.0", @@ -55,15 +64,15 @@ "drizzle-zod": "1.0.0-beta.14-a36c63d", "es-toolkit": "^1.49.0", "fast-json-patch": "^3.1.1", - "hono": "^4.12.27", + "hono": "^4.12.28", "jsonrepair": "^3.15.0", - "node-html-parser": "^8.0.4", + "node-html-parser": "^9.0.0", "nodemailer": "^9.0.3", - "ollama-ai-provider-v2": "^3.6.0", + "ollama-ai-provider-v2": "^4.0.1", "pg": "^8.22.0", "phosphor-icons-react-pdf": "^0.1.3", "react": "^19.2.7", - "react-email": "^6.6.6", + "react-email": "^6.6.8", "react-pdf-html": "^2.1.5", "resumable-stream": "^2.2.12", "sharp": "^0.35.3", @@ -74,13 +83,13 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@types/node": "^26.1.0", + "@types/node": "^26.1.1", "@types/pg": "^8.20.0", "@types/react": "^19.2.17", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "tsdown": "^0.22.3", + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "tsdown": "^0.22.4", "tsx": "^4.23.0", - "typescript": "^6.0.3", - "vitest": "^4.1.9" + "typescript": "^7.0.2", + "vitest": "^4.1.10" } } diff --git a/apps/server/src/static/uploads.test.ts b/apps/server/src/static/uploads.test.ts index 7d314393f..015c4d182 100644 --- a/apps/server/src/static/uploads.test.ts +++ b/apps/server/src/static/uploads.test.ts @@ -33,6 +33,8 @@ describe("handleUpload", () => { expect(response.status).toBe(200); expect(readMock).toHaveBeenCalledWith("uploads/user-1/pictures/photo.jpeg"); expect(response.headers.get("Content-Type")).toBe("image/jpeg"); + expect(response.headers.get("Cross-Origin-Resource-Policy")).toBe("same-site"); + expect(response.headers.get("Access-Control-Allow-Origin")).toBeNull(); }); it("does not serve private agent attachment keys through the public uploads route", async () => { diff --git a/apps/server/src/static/uploads.ts b/apps/server/src/static/uploads.ts index b3e37dfe6..5a22a8c33 100644 --- a/apps/server/src/static/uploads.ts +++ b/apps/server/src/static/uploads.ts @@ -1,7 +1,6 @@ import { createHash } from "node:crypto"; import { basename, extname, normalize } from "node:path"; import { getStorageService, inferContentType } from "@reactive-resume/api/features/storage"; -import { env } from "@reactive-resume/env/server"; export async function handleUpload(request: Request) { const { userId, filePath } = parseRouteParams(request.url); @@ -41,7 +40,6 @@ export async function handleUpload(request: Request) { headers.set("Referrer-Policy", "strict-origin-when-cross-origin"); headers.set("X-Frame-Options", "DENY"); headers.set("X-Download-Options", "noopen"); - headers.set("Access-Control-Allow-Origin", env.APP_URL); return new Response(toArrayBuffer(storedFile.data), { headers }); } diff --git a/apps/server/src/static/web.test.ts b/apps/server/src/static/web.test.ts index c373ac130..868370e28 100644 --- a/apps/server/src/static/web.test.ts +++ b/apps/server/src/static/web.test.ts @@ -32,6 +32,15 @@ describe("web app fallback classification", () => { expect(await response.text()).toBe("app"); }); + it.each(["/", "/alice/resume"])("sets framing and report-only CSP security headers on %s", async (pathname) => { + const response = await handleWebApp(new Request(`https://example.com${pathname}`)); + + expect(response.status).toBe(200); + expect(response.headers.get("X-Frame-Options")).toBe("DENY"); + expect(response.headers.get("X-Content-Type-Options")).toBe("nosniff"); + expect(response.headers.get("Content-Security-Policy-Report-Only")).toContain("frame-ancestors 'none'"); + }); + it.each([ "/auth/login", "/dashboard", diff --git a/apps/server/src/static/web.ts b/apps/server/src/static/web.ts index d29167b5e..a8650864b 100644 --- a/apps/server/src/static/web.ts +++ b/apps/server/src/static/web.ts @@ -52,12 +52,21 @@ function isPublicResumePath(pathname: string): boolean { return segments.length === 2 && firstSegment !== undefined && !reservedPublicResumeSegments.has(firstSegment); } +const BASE_SECURITY_HEADERS = { + "X-Frame-Options": "DENY", + "X-Content-Type-Options": "nosniff", + "Referrer-Policy": "strict-origin-when-cross-origin", + "Content-Security-Policy-Report-Only": + "default-src 'self'; img-src 'self' data: blob:; font-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; object-src 'none'", +}; + function getFallbackResponseHeaders(pathname: string) { - if (pathname === "/") return { "Content-Type": "text/html; charset=UTF-8" }; + if (pathname === "/") return { "Content-Type": "text/html; charset=UTF-8", ...BASE_SECURITY_HEADERS }; if (isNoindexShellPath(pathname) || isPublicResumePath(pathname)) { return { "Content-Type": "text/html; charset=UTF-8", "X-Robots-Tag": "noindex, follow", + ...BASE_SECURITY_HEADERS, }; } diff --git a/apps/web/locales/af-ZA.po b/apps/web/locales/af-ZA.po index 08e725c37..1db77aa0b 100644 --- a/apps/web/locales/af-ZA.po +++ b/apps/web/locales/af-ZA.po @@ -8,7 +8,7 @@ msgstr "" "Language: af\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Afrikaans\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Katalaans" msgid "Center Align" msgstr "Middelbelyn" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Serebras" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Klik hier om 'n lêer te kies om in te voer" msgid "Close AI assistant" msgstr "Maak KI-assistent toe" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Samehang" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Verklein inspringing" msgid "Decrease zoom" msgstr "Verminder zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DiepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Graad" @@ -1885,6 +1897,10 @@ msgstr "Vind swak kolpunte en herskryf hulle met sterker uitkomste, getalle, omv msgid "Finnish" msgstr "Fins" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Vuurwerke" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Pas om te sien" @@ -2072,6 +2088,10 @@ msgstr "Grieks" msgid "Grid" msgstr "Rooster" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Laat die span groei" @@ -2271,6 +2291,10 @@ msgstr "Besig om jou CV in te voer..." msgid "Importing…" msgstr "Voer tans… in" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Sluit CV-kop in" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Verhoog inspringing" @@ -2574,11 +2598,6 @@ msgstr "Lys" msgid "Lithuanian" msgstr "Litaus" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Regstreekse voorskou van jou CV in die {0} sjabloon" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Laai tans KI-verskaffers. Probeer asseblief weer oor 'n oomblik." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Werkende CV ontbreek" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral KI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama-wolk" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Periode" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Verwarring" + #: src/libs/locale.ts msgid "Persian" msgstr "Persies" @@ -3838,6 +3865,10 @@ msgstr "Wys wagwoord" msgid "Show picture" msgstr "Wys prent" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Wys dieselfde eerste-bladsy-kop op die dekbrief." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Titel" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Om jou rekening uit te vee, moet jy die bevestigingstekst invoer en die knoppie hieronder klik." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Saam.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Die moeite werd" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Ja, Reactive Resume is in verskeie tale beskikbaar. Jy kan jou voorkeurtaal kies op die instellingsbladsy, of deur die taalwisselaar regs bo te gebruik. As jy jou taal nie sien nie, of as jy die bestaande vertalings wil verbeter, kan jy <0>bydra tot die vertalings op Crowdin<1> (maak in nuwe oortjie oop)." diff --git a/apps/web/locales/am-ET.po b/apps/web/locales/am-ET.po index 5ca68ac79..643977ecf 100644 --- a/apps/web/locales/am-ET.po +++ b/apps/web/locales/am-ET.po @@ -8,7 +8,7 @@ msgstr "" "Language: am\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Amharic\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" @@ -758,6 +758,10 @@ msgstr "ካታላንኛ" msgid "Center Align" msgstr "መሀከል ማሰለፊያ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "ሴሬብራስ" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "ፋይል ለማምጣት ለመምረጥ እዚህ ጠቅ ያድርጉ" msgid "Close AI assistant" msgstr "የ AI ረዳትን ዝጋ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "ኮሄሬ" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "ገብን ቀንስ" msgid "Decrease zoom" msgstr "ማጉላትን ቀንስ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "ዲፕሴክ" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "ዲግሪ" @@ -1885,6 +1897,10 @@ msgstr "ደካማ ነጥቦችን ፈልግ እና ጠንካራ ውጤቶችን msgid "Finnish" msgstr "ፊኒሽ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "ርችቶች" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "ለእይታ ተስማሚ" @@ -2072,6 +2088,10 @@ msgstr "ግሪክኛ" msgid "Grid" msgstr "ግሪድ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "ግሮክ" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "ቡድኑን አስፋ" @@ -2271,6 +2291,10 @@ msgstr "የየታሪክዎን በመጫን ላይ…" msgid "Importing…" msgstr "በማስመጣት ላይ…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "የሪዙሜውን ራስጌ አካትት" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "ገብ ጨምር" @@ -2574,11 +2598,6 @@ msgstr "ዝርዝር" msgid "Lithuanian" msgstr "ሊቱዌንያንኛ" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "በ {0} አብነት ውስጥ የስራ ልምድዎ የቀጥታ ቅድመ እይታ" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "የAI አቅራቢዎችን በመጫን ላይ። እባክዎ ከአፍታ በኋላ እንደገና ይሞክሩ።" @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "የስራ ማጠቃለያ ይጎድላል" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "ሚስራል ኤአይ" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "ሞዴል" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "ኦዲያ" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "የኦላማ ክላውድ" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "ወቅት" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "ግራ መጋባት" + #: src/libs/locale.ts msgid "Persian" msgstr "ፐርሲያንኛ" @@ -3838,6 +3865,10 @@ msgstr "የይለፍ ቃል አሳይ" msgid "Show picture" msgstr "ስዕል አሳይ" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "በማመልከቻ ደብዳቤው ላይ ተመሳሳይ የመጀመሪያ ገጽ ራስጌ አሳይ።" + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "ርዕስ" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "መለያዎን ለመሰረዝ የማረጋገጫ ጽሑፍን ያስገቡ እና ከታች ያለውን አዝራር ይጫኑ።" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "አንድ ሙከራ የሚያረካ" msgid "X (Twitter)" msgstr "ኤክስ (ትዊተር)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI ግሮክ" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "አዎ፣ Reactive Resume በብዙ ቋንቋዎች ላይ ይገኛል። የምትመርጡትን ቋንቋ በቅንብሮች ገጽ ውስጥ ወይም በላይኛው ቀኝ ጠርዝ ያለውን የቋንቋ መቀየሪያ በመጠቀም መምረጥ ትችላላችሁ። ቋንቋዎን ካላያችሁ፣ ወይም ቀረውን ትርጉም ለማሻሻል ከፈለጉ፣ በ<0> Crowdin ላይ ትርጉሞችን በማሻሻል መዋኛ ለመያዝ ትችላላችሁ<1> (በአዲስ ታብ ይከፈታል)።" diff --git a/apps/web/locales/ar-SA.po b/apps/web/locales/ar-SA.po index af6e37025..162a8c49d 100644 --- a/apps/web/locales/ar-SA.po +++ b/apps/web/locales/ar-SA.po @@ -8,7 +8,7 @@ msgstr "" "Language: ar\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Arabic\n" "Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n" @@ -758,6 +758,10 @@ msgstr "الكتالانية" msgid "Center Align" msgstr "محاذاة في الوسط" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "الأدمغة" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "انقر هنا لتحديد ملف لاستيراده" msgid "Close AI assistant" msgstr "مساعد الذكاء الاصطناعي للإغلاق" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "التحم" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "تقليل المسافة البادئة" msgid "Decrease zoom" msgstr "تقليل التكبير" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "البحث العميق" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "الدرجة" @@ -1885,6 +1897,10 @@ msgstr "ابحث عن النقاط الضعيفة وأعد صياغتها بنت msgid "Finnish" msgstr "الفنلندية" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "ألعاب نارية" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "مناسب للعرض" @@ -2072,6 +2088,10 @@ msgstr "اليونانية" msgid "Grid" msgstr "الشبكة" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "جروك" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "توسيع الفريق" @@ -2271,6 +2291,10 @@ msgstr "جاري استيراد سيرتك الذاتية..." msgid "Importing…" msgstr "جارٍ الاستيراد…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "تضمين ترويسة السيرة الذاتية" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "زيادة المسافة البادئة" @@ -2574,11 +2598,6 @@ msgstr "قائمة" msgid "Lithuanian" msgstr "اللتوانية" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "معاينة مباشرة لسيرتك الذاتية في قالب {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "جارٍ تحميل مزودي خدمات الذكاء الاصطناعي. يرجى المحاولة مرة أخرى بعد قليل." @@ -2698,6 +2717,10 @@ msgstr "مايكروسوفت وورد" msgid "Missing working resume" msgstr "سيرة ذاتية مفقودة" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "ميسترال للذكاء الاصطناعي" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "النموذج" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "الأودية" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "أولاما" +msgid "Ollama Cloud" +msgstr "سحابة أولاما" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "الفترة" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "حيرة" + #: src/libs/locale.ts msgid "Persian" msgstr "الفارسية" @@ -3838,6 +3865,10 @@ msgstr "إظهار كلمة المرور" msgid "Show picture" msgstr "عرض الصورة" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "إظهار نفس ترويسة الصفحة الأولى في خطاب التقديم." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "العنوان" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "لحذف حسابك، تحتاج إلى إدخال نص التأكيد والنقر على الزر أدناه." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "يستحق المحاولة" msgid "X (Twitter)" msgstr "X (تويتر)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "نعم، يتوفر Reactive Resume بعدة لغات. يمكنك اختيار لغتك المفضلة في صفحة الإعدادات، أو باستخدام مبدّل اللغة في الزاوية العلوية اليمنى. إذا لم ترَ لغتك، أو كنت ترغب في تحسين الترجمات الموجودة، يمكنك <0>المساهمة في الترجمات على Crowdin<1> (يفتح في علامة تبويب جديدة)." diff --git a/apps/web/locales/az-AZ.po b/apps/web/locales/az-AZ.po index 23b9530ef..a2d4d6e44 100644 --- a/apps/web/locales/az-AZ.po +++ b/apps/web/locales/az-AZ.po @@ -8,7 +8,7 @@ msgstr "" "Language: az\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Azerbaijani\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Katalan" msgid "Center Align" msgstr "Mərkəzləndir" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Beyinciklər" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "İdxal üçün fayl seçmək üçün bura klikləyin" msgid "Close AI assistant" msgstr "Süni intellekt köməkçisini bağlayın" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Birgə" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Abzası azaldın" msgid "Decrease zoom" msgstr "Zumu azaldın" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Dərin Axtarış" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Dərəcə" @@ -1885,6 +1897,10 @@ msgstr "Zəif ifadələri tapın və onları daha güclü nəticələr, rəqəml msgid "Finnish" msgstr "Fin" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Atəşfəşanlıq" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Görüntü üçün uyğunlaşdırın" @@ -2072,6 +2088,10 @@ msgstr "Yunan" msgid "Grid" msgstr "Şəbəkə" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Qroq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Komandanı böyüdün" @@ -2271,6 +2291,10 @@ msgstr "Özgeçmişiniz idxal olunur..." msgid "Importing…" msgstr "… idxal edilir" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "CV başlığını daxil et" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Abzası artırın" @@ -2574,11 +2598,6 @@ msgstr "Siyahı" msgid "Lithuanian" msgstr "Litva" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} şablonunda CV-nizin canlı önizləməsi" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Süni intellekt provayderləri yüklənir. Zəhmət olmasa, bir az sonra yenidən cəhd edin." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "İşçi CV-si yoxdur" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral süni intellekt" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odiya" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Buludu" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Müddət" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Çaşqınlıq" + #: src/libs/locale.ts msgid "Persian" msgstr "Fars" @@ -3838,6 +3865,10 @@ msgstr "Şifrəni göstər" msgid "Show picture" msgstr "Şəkili göstər" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Müraciət məktubunda birinci səhifə başlığının eynisini göstər." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Başlıq" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Hesabınızı silmək üçün təsdiq mətnini daxil etməli və aşağıdakı düyməyə klikləməlisiniz." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Bir cəhd etməyə dəyər" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Bəli, Reactive Resume bir neçə dildə mövcuddur. Seçim etdiyiniz dili parametrlər səhifəsindən və ya sağ yuxarı küncdəki dil dəyişdiricisindən seçə bilərsiniz. Əgər dilinizi görmürsünüzsə və ya mövcud tərcümələri yaxşılaşdırmaq istəyirsinizsə, <0>Crowdin‑də tərcümələrə töhfə verə bilərsiniz<1> (yeni vərəqdə açılır)." diff --git a/apps/web/locales/bg-BG.po b/apps/web/locales/bg-BG.po index 3a73a2cf0..fb6107c86 100644 --- a/apps/web/locales/bg-BG.po +++ b/apps/web/locales/bg-BG.po @@ -8,7 +8,7 @@ msgstr "" "Language: bg\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Bulgarian\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Каталонски" msgid "Center Align" msgstr "Подравняване в центъра" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Церебрас" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Кликнете тук, за да изберете файл за имп msgid "Close AI assistant" msgstr "Затвори асистента с изкуствен интелект" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Кохерентност" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Намаляване на отстъпа" msgid "Decrease zoom" msgstr "Намаляване на мащаба" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Дълбоко търсене" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Степен" @@ -1885,6 +1897,10 @@ msgstr "Намерете слаби точки и ги пренапишете с msgid "Finnish" msgstr "Фински" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Фойерверки" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Побиране в изглед" @@ -2072,6 +2088,10 @@ msgstr "Гръцки" msgid "Grid" msgstr "Мрежа" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Грок" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Разширяване на екипа" @@ -2271,6 +2291,10 @@ msgstr "Вашата автобиография се импортира..." msgid "Importing…" msgstr "Импортиране…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Включи заглавката на автобиографията" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Увеличаване на отстъпа" @@ -2574,11 +2598,6 @@ msgstr "Списък" msgid "Lithuanian" msgstr "Литовски" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Преглед на автобиографията ви на живо в шаблона {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Зареждане на доставчици на ИИ. Моля, опитайте отново след малко." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Липсва работна автобиография" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Мистрал ИИ" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Модел" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Одия" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Облак Олама" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Период" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Озадаченост" + #: src/libs/locale.ts msgid "Persian" msgstr "Персийски" @@ -3838,6 +3865,10 @@ msgstr "Показване на паролата" msgid "Show picture" msgstr "Покажи снимка" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Показвай същата заглавка на първата страница и в мотивационното писмо." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Заглавие" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "За да изтриете профила си, трябва да въведете текста за потвърждение и да кликнете бутона по-долу." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Заедно.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Струва си да опитате" msgid "X (Twitter)" msgstr "X (Туитър)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Грок" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Да, Reactive Resume е наличен на множество езици. Можете да изберете предпочитания от вас език от страницата с настройки или чрез превключвателя за език в горния десен ъгъл. Ако не виждате вашия език или искате да подобрите съществуващите преводи, можете да <0>допринесете към преводите в Crowdin<1> (отваря се в нов раздел)." diff --git a/apps/web/locales/bn-BD.po b/apps/web/locales/bn-BD.po index fd9e2460a..12e889710 100644 --- a/apps/web/locales/bn-BD.po +++ b/apps/web/locales/bn-BD.po @@ -8,7 +8,7 @@ msgstr "" "Language: bn\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Bengali\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "কাতালান" msgid "Center Align" msgstr "মধ্যের দিকে অ্যালাইন" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "সেরেব্রাস" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "ইমপোর্ট করার জন্য এখান ক্ল msgid "Close AI assistant" msgstr "এআই সহকারী বন্ধ করুন" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "কোহেয়ার" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "ইন্ডেন্ট হ্রাস করুন" msgid "Decrease zoom" msgstr "জুম কমান" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "ডিপসিক" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "ডিগ্রি" @@ -1885,6 +1897,10 @@ msgstr "দুর্বল বুলেট পয়েন্টগুলো খ msgid "Finnish" msgstr "ফিনিশ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "আতশবাজি" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "দেখার জন্য উপযুক্ত" @@ -2072,6 +2088,10 @@ msgstr "গ্রিক" msgid "Grid" msgstr "গ্রিড" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "গ্রোক" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "টিম বড় করুন" @@ -2271,6 +2291,10 @@ msgstr "আপনার জীবনবৃত্তান্ত ইমপোর msgid "Importing…" msgstr "… আমদানি করা হচ্ছে" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "জীবনবৃত্তান্তের হেডার অন্তর্ভুক্ত করুন" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "ইন্ডেন্ট বৃদ্ধি করুন" @@ -2574,11 +2598,6 @@ msgstr "তালিকা" msgid "Lithuanian" msgstr "লিথুয়ানিয়ান" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} টেমপ্লেটে আপনার জীবনবৃত্তান্তের সরাসরি প্রিভিউ দেখুন" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "এআই প্রোভাইডার লোড করা হচ্ছে। অনুগ্রহ করে কিছুক্ষণ পর আবার চেষ্টা করুন।" @@ -2698,6 +2717,10 @@ msgstr "মাইক্রোসফট ওয়ার্ড" msgid "Missing working resume" msgstr "কাজের জীবনবৃত্তান্ত অনুপস্থিত" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "মিস্ট্রাল এআই" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "মডেল" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "ওড়িয়া" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "ওলামা" +msgid "Ollama Cloud" +msgstr "ওলামা ক্লাউড" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "পিডিএফ" msgid "Period" msgstr "সময়কাল" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "বিভ্রান্তি" + #: src/libs/locale.ts msgid "Persian" msgstr "ফার্সি" @@ -3838,6 +3865,10 @@ msgstr "পাসওয়ার্ড দেখান" msgid "Show picture" msgstr "ছবি দেখান" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "কভার লেটারে একই প্রথম পৃষ্ঠার হেডার দেখান।" + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "শিরোনাম" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "আপনার অ্যাকাউন্ট মুছে ফেলতে চাইলে নিশ্চয়তাসূচক টেক্সট লিখে নিচের বাটনে ক্লিক করতে হবে।" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "চেষ্টা করে দেখা যেতে পারে।" msgid "X (Twitter)" msgstr "এক্স (টুইটার)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI গ্রোক" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "হ্যাঁ, Reactive Resume একাধিক ভাষায় উপলভ্য। আপনি সেটিংস পেজ থেকে বা ডান দিকের উপরের কোণের ভাষা পরিবর্তনকারী ব্যবহার করে নিজের পছন্দের ভাষা বেছে নিতে পারেন। যদি আপনার ভাষা তালিকায় না থাকে, বা আপনি বিদ্যমান অনুবাদ উন্নত করতে চান, তাহলে আপনি <0>Crowdin‑এ অনুবাদে অবদান রাখতে পারেন<1> (নতুন ট্যাবে খুলবে)।" diff --git a/apps/web/locales/ca-ES.po b/apps/web/locales/ca-ES.po index c846b8036..b09e8803a 100644 --- a/apps/web/locales/ca-ES.po +++ b/apps/web/locales/ca-ES.po @@ -8,7 +8,7 @@ msgstr "" "Language: ca\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Catalan\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Català" msgid "Center Align" msgstr "Alinea al centre" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cerebres" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Fes clic aquí per seleccionar un fitxer per importar" msgid "Close AI assistant" msgstr "Tanca l'assistent d'IA" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Coherència" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Reduir la sagnia" msgid "Decrease zoom" msgstr "Redueix el zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Titulació" @@ -1885,6 +1897,10 @@ msgstr "Troba els punts febles i reescriu-los amb resultats, números, abast i v msgid "Finnish" msgstr "Finès" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Focs artificials" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Ajustar a la vista" @@ -2072,6 +2088,10 @@ msgstr "Grec" msgid "Grid" msgstr "Graella" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Fes créixer l’equip" @@ -2271,6 +2291,10 @@ msgstr "S’està important el currículum..." msgid "Importing…" msgstr "Important…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Inclou la capçalera del currículum" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Augmenta la sagnia" @@ -2574,11 +2598,6 @@ msgstr "Llista" msgid "Lithuanian" msgstr "Lituà" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Vista prèvia en directe del vostre currículum a la plantilla {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "S'estan carregant els proveïdors d'IA. Si us plau, torneu-ho a provar d'aquí a un moment." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Falta un currículum laboral" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "IA Mistral" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Núvol d'Ollama" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Període" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Perplexitat" + #: src/libs/locale.ts msgid "Persian" msgstr "Persa" @@ -3838,6 +3865,10 @@ msgstr "Mostra la contrasenya" msgid "Show picture" msgstr "Mostra la imatge" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Mostra la mateixa capçalera de la primera pàgina a la carta de presentació." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Títol" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Per suprimir el compte, has d’introduir el text de confirmació i fer clic al botó següent." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Junts.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Val la pena intentar-ho" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Sí, Reactive Resume està disponible en múltiples idiomes. Pots triar l’idioma preferit a la pàgina de configuració o utilitzant el selector d’idioma a l’angle superior dret. Si no hi veus el teu idioma o vols millorar les traduccions existents, pots <0>contribuir a les traduccions a Crowdin<1> (s’obre en una pestanya nova)." diff --git a/apps/web/locales/cs-CZ.po b/apps/web/locales/cs-CZ.po index 296c2f6b2..27e7d6bd1 100644 --- a/apps/web/locales/cs-CZ.po +++ b/apps/web/locales/cs-CZ.po @@ -8,7 +8,7 @@ msgstr "" "Language: cs\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Czech\n" "Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3;\n" @@ -758,6 +758,10 @@ msgstr "Katalánština" msgid "Center Align" msgstr "Zarovnat na střed" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Mozky" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Kliknutím zde vyberte soubor k importu" msgid "Close AI assistant" msgstr "Zavřít asistenta s umělou inteligencí" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Soudržný" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Zmenšit odsazení" msgid "Decrease zoom" msgstr "Zmenšit přiblížení" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Hluboké vyhledávání" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Titul" @@ -1885,6 +1897,10 @@ msgstr "Najděte slabé odrážky a přepište je se silnějšími výsledky, č msgid "Finnish" msgstr "Finština" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Ohňostroj" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Přizpůsobit zobrazení" @@ -2072,6 +2088,10 @@ msgstr "Řečtina" msgid "Grid" msgstr "Mřížka" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Rozšířit tým" @@ -2271,6 +2291,10 @@ msgstr "Importování životopisu…" msgid "Importing…" msgstr "Import…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Zahrnout záhlaví životopisu" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Zvětšit odsazení" @@ -2574,11 +2598,6 @@ msgstr "Seznam" msgid "Lithuanian" msgstr "Litevština" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Živý náhled vašeho životopisu v šabloně {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Načítání poskytovatelů umělé inteligence. Zkuste to prosím znovu za chvíli." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Chybí pracovní životopis" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Udijština" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Cloud" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Období" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Zmatek" + #: src/libs/locale.ts msgid "Persian" msgstr "Perština" @@ -3838,6 +3865,10 @@ msgstr "Zobrazit heslo" msgid "Show picture" msgstr "Zobrazit obrázek" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Zobrazit stejné záhlaví první stránky i v průvodním dopise." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Název" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Pro smazání účtu musíte zadat potvrzovací text a kliknout na tlačítko níže." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Stojí za to vyzkoušet" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Ano, Reactive Resume je dostupné ve více jazycích. Svůj preferovaný jazyk si můžete vybrat na stránce nastavení nebo pomocí přepínače jazyka v pravém horním rohu. Pokud svůj jazyk nevidíte nebo chcete vylepšit existující překlady, můžete <0>přispět k překladům na Crowdin<1> (otevře se na nové kartě)." diff --git a/apps/web/locales/da-DK.po b/apps/web/locales/da-DK.po index 1c019a2c9..533931793 100644 --- a/apps/web/locales/da-DK.po +++ b/apps/web/locales/da-DK.po @@ -8,7 +8,7 @@ msgstr "" "Language: da\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Danish\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Katalansk" msgid "Center Align" msgstr "Centrer justering" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cerebras" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Klik her for at vælge en fil, der skal importeres" msgid "Close AI assistant" msgstr "Luk AI-assistent" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Sammenhæng" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Formindsk indrykning" msgid "Decrease zoom" msgstr "Reducer zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Grad" @@ -1885,6 +1897,10 @@ msgstr "Find svage punktopstillinger og omskriv dem med stærkere udfald, tal, o msgid "Finnish" msgstr "Finsk" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Fyrværkeri" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Tilpas til visning" @@ -2072,6 +2088,10 @@ msgstr "Græsk" msgid "Grid" msgstr "Gitter" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Udvid teamet" @@ -2271,6 +2291,10 @@ msgstr "Importerer dit CV..." msgid "Importing…" msgstr "Importerer…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Medtag CV-header" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Øg indrykning" @@ -2574,11 +2598,6 @@ msgstr "Liste" msgid "Lithuanian" msgstr "Litauisk" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Live forhåndsvisning af dit CV i skabelonen {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Indlæser AI-udbydere. Prøv igen om et øjeblik." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Mangler arbejds-CV" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama-skyen" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Periode" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Forvirring" + #: src/libs/locale.ts msgid "Persian" msgstr "Persisk" @@ -3838,6 +3865,10 @@ msgstr "Vis adgangskode" msgid "Show picture" msgstr "Vis billede" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Vis den samme header fra første side på følgebrevet." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Titel" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "For at slette din konto skal du indtaste bekræftelsesteksten og klikke på knappen nedenfor." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Sammen.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Et forsøg værd" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Ja, Reactive Resume er tilgængelig på flere sprog. Du kan vælge dit foretrukne sprog på indstillingssiden eller ved hjælp af sprogvælgeren i øverste højre hjørne. Hvis du ikke kan se dit sprog, eller hvis du gerne vil forbedre de eksisterende oversættelser, kan du <0>bidrage til oversættelserne på Crowdin<1> (åbner i ny fane)." diff --git a/apps/web/locales/de-DE.po b/apps/web/locales/de-DE.po index 1b71a7d78..26e22f933 100644 --- a/apps/web/locales/de-DE.po +++ b/apps/web/locales/de-DE.po @@ -8,7 +8,7 @@ msgstr "" "Language: de\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: German\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Katalanisch" msgid "Center Align" msgstr "Zentriert" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Großhirn" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Hier klicken, um eine Datei zum Importieren auszuwählen" msgid "Close AI assistant" msgstr "Schließen Sie den KI-Assistenten" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Zusammenhängen" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Einzug verringern" msgid "Decrease zoom" msgstr "Zoom verringern" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Abschluss" @@ -1885,6 +1897,10 @@ msgstr "Finden Sie schwache Stichpunkte und formulieren Sie sie mit aussagekräf msgid "Finnish" msgstr "Finnisch" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Feuerwerk" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Passend zur Ansicht" @@ -2072,6 +2088,10 @@ msgstr "Griechisch" msgid "Grid" msgstr "Rasteransicht" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Team vergrößern" @@ -2271,6 +2291,10 @@ msgstr "Dein Lebenslauf wird importiert ..." msgid "Importing…" msgstr "Importieren…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Lebenslauf-Kopfzeile einfügen" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Einzug vergrößern" @@ -2574,11 +2598,6 @@ msgstr "Listenansicht" msgid "Lithuanian" msgstr "Litauisch" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Live-Vorschau Ihres Lebenslaufs in der {0} Vorlage" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "KI-Anbieter werden geladen. Bitte versuchen Sie es in einem Moment erneut." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Fehlender Arbeitslebenslauf" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral KI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modell" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama-Wolke" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Zeitraum" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Verwirrung" + #: src/libs/locale.ts msgid "Persian" msgstr "Persisch" @@ -3838,6 +3865,10 @@ msgstr "Passwort anzeigen" msgid "Show picture" msgstr "Bild anzeigen" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Zeigt denselben Header der ersten Seite auch auf dem Anschreiben an." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Titel" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Um Ihr Konto zu löschen, müssen Sie den Bestätigungstext eingeben und unten auf die Schaltfläche klicken." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Einen Versuch wert" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Ja, Reactive Resume ist in mehreren Sprachen verfügbar. Du kannst deine bevorzugte Sprache auf der Einstellungsseite oder über den Sprachumschalter in der oberen rechten Ecke auswählen. Wenn du deine Sprache nicht findest oder die bestehenden Übersetzungen verbessern möchtest, kannst du <0>auf Crowdin zu den Übersetzungen beitragen<1> (öffnet in neuem Tab)." diff --git a/apps/web/locales/el-GR.po b/apps/web/locales/el-GR.po index ebb5a430c..875b06035 100644 --- a/apps/web/locales/el-GR.po +++ b/apps/web/locales/el-GR.po @@ -8,7 +8,7 @@ msgstr "" "Language: el\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Greek\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Καταλανικά" msgid "Center Align" msgstr "Στοίχιση στο κέντρο" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Εγκεφαλίδες" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Κάντε κλικ εδώ για να επιλέξετε ένα αρχ msgid "Close AI assistant" msgstr "Κλείσιμο βοηθού τεχνητής νοημοσύνης" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Διατηρώ συνέπεια" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Μείωση εσοχής" msgid "Decrease zoom" msgstr "Μείωση ζουμ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Βαθιά Αναζήτηση" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Πτυχίο" @@ -1885,6 +1897,10 @@ msgstr "Βρείτε αδύναμες κουκκίδες και ξαναγράψ msgid "Finnish" msgstr "Φινλανδικά" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Πυροτεχνήματα" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Κατάλληλο για προβολή" @@ -2072,6 +2088,10 @@ msgstr "Ελληνικά" msgid "Grid" msgstr "Πλέγμα" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Γκροκ" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Ανάπτυξη της ομάδας" @@ -2271,6 +2291,10 @@ msgstr "Εισαγωγή του βιογραφικού σας σημειώματ msgid "Importing…" msgstr "Εισαγωγή…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Συμπερίληψη κεφαλίδας βιογραφικού" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Αύξηση εσοχής" @@ -2574,11 +2598,6 @@ msgstr "Λίστα" msgid "Lithuanian" msgstr "Λιθουανικά" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Ζωντανή προεπισκόπηση του βιογραφικού σας στο πρότυπο {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Φόρτωση παρόχων τεχνητής νοημοσύνης. Δοκιμάστε ξανά σε λίγο." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Λείπει το βιογραφικό εργασίας" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Μοντέλο" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Οντιά" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ολάμα Νέφος" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Περίοδος" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Αμηχανία" + #: src/libs/locale.ts msgid "Persian" msgstr "Περσικά" @@ -3838,6 +3865,10 @@ msgstr "Εμφάνιση κωδικού πρόσβασης" msgid "Show picture" msgstr "Εμφάνιση εικόνας" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Εμφάνιση της ίδιας κεφαλίδας πρώτης σελίδας και στη συνοδευτική επιστολή." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Τίτλος" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Για να διαγράψετε τον λογαριασμό σας, πρέπει να εισαγάγετε το κείμενο επιβεβαίωσης και να κάνετε κλικ στο παρακάτω κουμπί." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Μαζί.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Αξίζει μια προσπάθεια" msgid "X (Twitter)" msgstr "Χ (Τwitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Ναι, το Reactive Resume είναι διαθέσιμο σε πολλές γλώσσες. Μπορείτε να επιλέξετε την προτιμώμενη γλώσσα σας στη σελίδα ρυθμίσεων ή χρησιμοποιώντας τον επιλογέα γλώσσας στην επάνω δεξιά γωνία. Αν δεν βλέπετε τη γλώσσα σας ή θα θέλατε να βελτιώσετε τις υπάρχουσες μεταφράσεις, μπορείτε να <0>συμβάλετε στις μεταφράσεις στο Crowdin<1> (ανοίγει σε νέα καρτέλα)." diff --git a/apps/web/locales/en-GB.po b/apps/web/locales/en-GB.po index 65af311be..42881e34a 100644 --- a/apps/web/locales/en-GB.po +++ b/apps/web/locales/en-GB.po @@ -8,7 +8,7 @@ msgstr "" "Language: en_GB\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: English, United Kingdom\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Catalan" msgid "Center Align" msgstr "Center Align" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cerebras" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Click here to select a file to import" msgid "Close AI assistant" msgstr "Close AI assistant" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Cohere" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Decrease indent" msgid "Decrease zoom" msgstr "Decrease zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Degree" @@ -1885,6 +1897,10 @@ msgstr "Find weak bullets and rewrite them with stronger outcomes, numbers, scop msgid "Finnish" msgstr "Finnish" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Fireworks" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Fit to view" @@ -2072,6 +2088,10 @@ msgstr "Greek" msgid "Grid" msgstr "Grid" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Grow the Team" @@ -2271,6 +2291,10 @@ msgstr "Importing your resume..." msgid "Importing…" msgstr "Importing…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Include CV header" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Increase indent" @@ -2574,11 +2598,6 @@ msgstr "List" msgid "Lithuanian" msgstr "Lithuanian" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Live preview of your resume in the {0} template" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Loading AI providers. Please try again in a moment." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Missing working resume" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Cloud" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Period" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Perplexity" + #: src/libs/locale.ts msgid "Persian" msgstr "Persian" @@ -3838,6 +3865,10 @@ msgstr "Show password" msgid "Show picture" msgstr "Show picture" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Show the same first-page header on the cover letter." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Title" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "To delete your account, you need to enter the confirmation text and click the button below." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Worth a shot" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." diff --git a/apps/web/locales/en-US.po b/apps/web/locales/en-US.po index a886e1229..be58699bf 100644 --- a/apps/web/locales/en-US.po +++ b/apps/web/locales/en-US.po @@ -753,6 +753,10 @@ msgstr "Catalan" msgid "Center Align" msgstr "Center Align" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cerebras" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -849,6 +853,10 @@ msgstr "Click here to select a file to import" msgid "Close AI assistant" msgstr "Close AI assistant" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Cohere" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1277,6 +1285,10 @@ msgstr "Decrease indent" msgid "Decrease zoom" msgstr "Decrease zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Degree" @@ -1880,6 +1892,10 @@ msgstr "Find weak bullets and rewrite them with stronger outcomes, numbers, scop msgid "Finnish" msgstr "Finnish" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Fireworks" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Fit to view" @@ -2067,6 +2083,10 @@ msgstr "Greek" msgid "Grid" msgstr "Grid" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Grow the Team" @@ -2266,6 +2286,10 @@ msgstr "Importing your resume..." msgid "Importing…" msgstr "Importing…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Include resume header" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Increase indent" @@ -2569,11 +2593,6 @@ msgstr "List" msgid "Lithuanian" msgstr "Lithuanian" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Live preview of your resume in the {0} template" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Loading AI providers. Please try again in a moment." @@ -2693,6 +2712,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Missing working resume" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2866,8 +2889,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Cloud" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3086,6 +3109,10 @@ msgstr "PDF" msgid "Period" msgstr "Period" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Perplexity" + #: src/libs/locale.ts msgid "Persian" msgstr "Persian" @@ -3833,6 +3860,10 @@ msgstr "Show password" msgid "Show picture" msgstr "Show picture" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Show the same first-page header on the cover letter." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4402,6 +4433,10 @@ msgstr "Title" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "To delete your account, you need to enter the confirmation text and click the button below." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4856,6 +4891,10 @@ msgstr "Worth a shot" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." diff --git a/apps/web/locales/es-ES.po b/apps/web/locales/es-ES.po index d36b51e8c..4dd466a9a 100644 --- a/apps/web/locales/es-ES.po +++ b/apps/web/locales/es-ES.po @@ -8,7 +8,7 @@ msgstr "" "Language: es\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:48\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Spanish\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Catalán" msgid "Center Align" msgstr "Alinear al centro" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cerebros" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Haz clic aquí para seleccionar un archivo para importar" msgid "Close AI assistant" msgstr "Asistente de IA de cierre" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Adherirse" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Disminuir sangría" msgid "Decrease zoom" msgstr "Disminuir el zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Búsqueda profunda" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Título académico" @@ -1885,6 +1897,10 @@ msgstr "Identifica los puntos débiles y reescríbelos con resultados, cifras, a msgid "Finnish" msgstr "Finés" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Fuegos artificiales" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Apto para visualización" @@ -2072,6 +2088,10 @@ msgstr "Griego" msgid "Grid" msgstr "Cuadrícula" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Hacer crecer el equipo" @@ -2271,6 +2291,10 @@ msgstr "Importando tu currículum..." msgid "Importing…" msgstr "Importando…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Incluir encabezado del currículum" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Aumentar sangría" @@ -2574,11 +2598,6 @@ msgstr "Lista" msgid "Lithuanian" msgstr "Lituano" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Vista previa en vivo de tu currículum en la plantilla {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Cargando proveedores de IA. Inténtelo de nuevo en un momento." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Falta el currículum vitae laboral" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modelo" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Nube de Ollama" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Periodo" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Perplejidad" + #: src/libs/locale.ts msgid "Persian" msgstr "Persa" @@ -3838,6 +3865,10 @@ msgstr "Mostrar contraseña" msgid "Show picture" msgstr "Mostrar imagen" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Mostrar el mismo encabezado de la primera página en la carta de presentación." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Título" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Para eliminar tu cuenta, debes introducir el texto de confirmación y hacer clic en el botón de abajo." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Juntos.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Vale la pena intentarlo" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Sí, Reactive Resume está disponible en varios idiomas. Puedes elegir tu idioma preferido en la página de configuración o usando el selector de idioma en la esquina superior derecha. Si no ves tu idioma o quieres mejorar las traducciones existentes, puedes <0>contribuir a las traducciones en Crowdin<1> (abrir en una nueva pestaña)." diff --git a/apps/web/locales/fa-IR.po b/apps/web/locales/fa-IR.po index 7e82168b6..c67de4ad8 100644 --- a/apps/web/locales/fa-IR.po +++ b/apps/web/locales/fa-IR.po @@ -8,7 +8,7 @@ msgstr "" "Language: fa\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Persian\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "کاتالان" msgid "Center Align" msgstr "تراز وسط" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "مغزها" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "برای انتخاب فایل برای وارد کردن، اینجا msgid "Close AI assistant" msgstr "دستیار هوش مصنوعی را ببندید" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "کوهر" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "کاهش تورفتگی" msgid "Decrease zoom" msgstr "کاهش زوم" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "جستجوی عمیق" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "مدرک" @@ -1885,6 +1897,10 @@ msgstr "نقاط ضعف را پیدا کنید و آنها را با نتایج msgid "Finnish" msgstr "فنلاندی" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "آتش بازی" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "مناسب برای مشاهده" @@ -2072,6 +2088,10 @@ msgstr "یونانی" msgid "Grid" msgstr "جدول" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "گروک" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "گسترش تیم" @@ -2271,6 +2291,10 @@ msgstr "در حال وارد کردن رزومه شما..." msgid "Importing…" msgstr "در حال وارد کردن…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "افزودن سربرگ رزومه" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "افزایش تورفتگی" @@ -2574,11 +2598,6 @@ msgstr "لیست" msgid "Lithuanian" msgstr "لیتوانیایی" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "پیش‌نمایش زنده رزومه شما در قالب {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "در حال بارگذاری ارائه دهندگان هوش مصنوعی. لطفاً چند لحظه دیگر دوباره امتحان کنید." @@ -2698,6 +2717,10 @@ msgstr "مایکروسافت ورد" msgid "Missing working resume" msgstr "رزومه کاری موجود نیست" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "هوش مصنوعی میسترال" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "مدل" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "اودیایی" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "اولاما" +msgid "Ollama Cloud" +msgstr "ابر اولاما" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "پی‌دی‌اف" msgid "Period" msgstr "دوره" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "سرگشتگی" + #: src/libs/locale.ts msgid "Persian" msgstr "فارسی" @@ -3838,6 +3865,10 @@ msgstr "نمایش رمز عبور" msgid "Show picture" msgstr "نمایش تصویر" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "همان سربرگ صفحه اول را در نامه پوششی نیز نمایش بده." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "عنوان" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "برای حذف حساب خود، باید متن تأیید را وارد کرده و دکمهٔ زیر را کلیک کنید." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "ارزش امتحان کردن دارد" msgid "X (Twitter)" msgstr "ایکس (توییتر)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI گروک" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "بله، Reactive Resume در چندین زبان در دسترس است. می‌توانید زبان دلخواه خود را در صفحهٔ تنظیمات یا با استفاده از تعویض‌کنندهٔ زبان در گوشهٔ بالا سمت راست انتخاب کنید. اگر زبان خود را نمی‌بینید یا می‌خواهید ترجمه‌های موجود را بهبود دهید، می‌توانید <0>در ترجمه‌ها روی Crowdin مشارکت کنید<1> (در زبانهٔ جدید باز می‌شود)." diff --git a/apps/web/locales/fi-FI.po b/apps/web/locales/fi-FI.po index bd5247f86..0591e76cc 100644 --- a/apps/web/locales/fi-FI.po +++ b/apps/web/locales/fi-FI.po @@ -8,7 +8,7 @@ msgstr "" "Language: fi\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Finnish\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "katalaani" msgid "Center Align" msgstr "Keskitä" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Aivot" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Napsauta tästä valitaksesi tuotavan tiedoston" msgid "Close AI assistant" msgstr "Sulje tekoälyavustaja" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Koheroitua" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Pienennä sisennystä" msgid "Decrease zoom" msgstr "Pienennä zoomausta" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Tutkinto" @@ -1885,6 +1897,10 @@ msgstr "Etsi heikkoja luettelokohtia ja kirjoita ne uudelleen vahvemmilla tuloks msgid "Finnish" msgstr "suomi" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Ilotulitus" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Sovita näkymään" @@ -2072,6 +2088,10 @@ msgstr "kreikka" msgid "Grid" msgstr "Ruudukko" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Kasvata tiimiä" @@ -2271,6 +2291,10 @@ msgstr "Tuodaan ansioluetteloasi..." msgid "Importing…" msgstr "Tuodaan…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Sisällytä CV:n ylätunniste" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Suurenna sisennystä" @@ -2574,11 +2598,6 @@ msgstr "Lista" msgid "Lithuanian" msgstr "liettua" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Ansioluettelosi reaaliaikainen esikatselu {0} -mallissa" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Ladataan tekoälypalveluntarjoajia. Yritä uudelleen hetken kuluttua." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Puuttuva työansioluettelo" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral-tekoäly" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Malli" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Cloud" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Ajanjakso" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Hämmennys" + #: src/libs/locale.ts msgid "Persian" msgstr "persia" @@ -3838,6 +3865,10 @@ msgstr "Näytä salasana" msgid "Show picture" msgstr "Näytä kuva" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Näytä sama ensimmäisen sivun ylätunniste myös saatekirjeessä." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Otsikko" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Poistaaksesi tilisi sinun täytyy syöttää vahvistusteksti ja napsauttaa alla olevaa painiketta." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Yhdessä.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Kannattaa kokeilla" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Kyllä, Reactive Resume on saatavilla useilla kielillä. Voit valita haluamasi kielen asetussivulla tai oikean yläkulman kielivalitsimesta. Jos et näe omaa kieltäsi tai haluat parantaa olemassa olevia käännöksiä, voit <0>osallistua käännöksiin Crowdinessa<1> (avautuu uuteen välilehteen)." diff --git a/apps/web/locales/fr-FR.po b/apps/web/locales/fr-FR.po index 4c8f2a3ea..2db70dae0 100644 --- a/apps/web/locales/fr-FR.po +++ b/apps/web/locales/fr-FR.po @@ -8,7 +8,7 @@ msgstr "" "Language: fr\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: French\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" @@ -758,6 +758,10 @@ msgstr "Catalan" msgid "Center Align" msgstr "Alignement centré" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cerveaux" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Cliquez ici pour sélectionner un fichier à importer" msgid "Close AI assistant" msgstr "Assistant IA proche" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Adhérer" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Diminuer le retrait" msgid "Decrease zoom" msgstr "Diminuer le zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Diplôme" @@ -1885,6 +1897,10 @@ msgstr "Repérez les points faibles et reformulez-les avec des résultats, des c msgid "Finnish" msgstr "Finnois" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Feux d'artifice" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Ajuster à la vue" @@ -2072,6 +2088,10 @@ msgstr "Grec" msgid "Grid" msgstr "Grille" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Faire grandir l'équipe" @@ -2271,6 +2291,10 @@ msgstr "Importation de votre CV en cours..." msgid "Importing…" msgstr "Importer…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Inclure l’en-tête du CV" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Augmenter l'indentation" @@ -2574,11 +2598,6 @@ msgstr "Liste" msgid "Lithuanian" msgstr "Lithuanien" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Aperçu en direct de votre CV dans le modèle {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Chargement des fournisseurs d'IA. Veuillez réessayer dans un instant." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "CV professionnel manquant" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral IA" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modèle" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Nuage Ollama" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF (EN ANGLAIS)" msgid "Period" msgstr "Période" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Perplexité" + #: src/libs/locale.ts msgid "Persian" msgstr "Persan" @@ -3838,6 +3865,10 @@ msgstr "Afficher le mot de passe" msgid "Show picture" msgstr "Afficher l'image" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Afficher le même en-tête de première page sur la lettre de motivation." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Titre" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Pour supprimer votre compte, vous devez saisir le texte de confirmation et cliquer sur le bouton ci-dessous." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Ensemble.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Ça vaut le coup d'essayer" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Oui, Reactive Resume est disponible en plusieurs langues. Vous pouvez choisir votre langue préférée dans la page des paramètres, ou en utilisant le sélecteur de langue dans le coin supérieur droit. Si vous ne voyez pas votre langue, ou si vous souhaitez améliorer les traductions existantes, vous pouvez <0>contribuer aux traductions sur Crowdin<1> (s'ouvre dans un nouvel onglet)." diff --git a/apps/web/locales/he-IL.po b/apps/web/locales/he-IL.po index 9213b5997..747479c27 100644 --- a/apps/web/locales/he-IL.po +++ b/apps/web/locales/he-IL.po @@ -8,7 +8,7 @@ msgstr "" "Language: he\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Hebrew\n" "Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;\n" @@ -758,6 +758,10 @@ msgstr "קטלאנית" msgid "Center Align" msgstr "יישור למרכז" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "מוח" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "לחץ כאן כדי לבחור קובץ לייבוא" msgid "Close AI assistant" msgstr "סגור את עוזר הבינה המלאכותית" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "לִדבּוֹק יָחָד" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "הקטנת כניסה" msgid "Decrease zoom" msgstr "הקטנת הזום" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "דיפקייק" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "תואר" @@ -1885,6 +1897,10 @@ msgstr "מצא נקודות תבליט חלשות וכתוב אותן מחדש msgid "Finnish" msgstr "פינית" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "זיקוקים" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "התאמה לתצוגה" @@ -2072,6 +2088,10 @@ msgstr "יוונית" msgid "Grid" msgstr "רשת" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "גרוק" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "הגדלת הצוות" @@ -2271,6 +2291,10 @@ msgstr "מייבא את קורות החיים שלך..." msgid "Importing…" msgstr "ייבוא…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "כלול את כותרת קורות החיים" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "הגדלת כניסה" @@ -2574,11 +2598,6 @@ msgstr "רשימה" msgid "Lithuanian" msgstr "ליטאית" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "תצוגה מקדימה חיה של קורות החיים שלך בתבנית {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "טוען ספקי בינה מלאכותית. אנא נסה שוב בעוד רגע." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "קורות חיים חסרים" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "מיסטרל בינה מלאכותית" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "מודל" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "אודיה" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "אולמה" +msgid "Ollama Cloud" +msgstr "אולמה קלאוד" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "תקופה" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "מְבוּכָה" + #: src/libs/locale.ts msgid "Persian" msgstr "פרסית" @@ -3838,6 +3865,10 @@ msgstr "הצג סיסמה" msgid "Show picture" msgstr "הצג תמונה" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "הצג את אותה כותרת עמוד ראשון גם במכתב המקדים." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "כותרת" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "כדי למחוק את החשבון שלך, עליך להזין את טקסט האישור וללחוץ על הכפתור שלמטה." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "יחד.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "שווה ניסיון" msgid "X (Twitter)" msgstr "איקס (טוויטר)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI גרוק" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "כן, Reactive Resume זמין במספר שפות. אפשר לבחור את השפה המועדפת עליך בעמוד ההגדרות או באמצעות מחליף השפה בפינה העליונה הימנית. אם אינך רואה את השפה שלך, או אם ברצונך לשפר את התרגומים הקיימים, אפשר <0>לתמוך בתרגומים ב־Crowdin<1> (נפתח בלשונית חדשה)." diff --git a/apps/web/locales/hi-IN.po b/apps/web/locales/hi-IN.po index 2765c990e..c023936c8 100644 --- a/apps/web/locales/hi-IN.po +++ b/apps/web/locales/hi-IN.po @@ -8,7 +8,7 @@ msgstr "" "Language: hi\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Hindi\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "कातालान" msgid "Center Align" msgstr "मध्य में संरेखित करें" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "मस्तिष्क" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "इम्पोर्ट करने के लिए फ़ाइल msgid "Close AI assistant" msgstr "एआई सहायक को बंद करें" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "जुटना" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "इंडेंट घटाएँ" msgid "Decrease zoom" msgstr "ज़ूम कम करें" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "डीपसीक" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "डिग्री" @@ -1885,6 +1897,10 @@ msgstr "कमजोर बिंदुओं को पहचानें औ msgid "Finnish" msgstr "फिनिश" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "आतिशबाजी" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "देखने के लिए उपयुक्त" @@ -2072,6 +2088,10 @@ msgstr "ग्रीक" msgid "Grid" msgstr "ग्रिड" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "ग्रोक" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "टीम बढ़ाएँ" @@ -2271,6 +2291,10 @@ msgstr "आपका रेज़्यूमे आयात किया ज msgid "Importing…" msgstr "आयात करना…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "रिज़्यूमे हेडर शामिल करें" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "बढ़ते हुए अंतर में" @@ -2574,11 +2598,6 @@ msgstr "सूची" msgid "Lithuanian" msgstr "लिथुआनियाई" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} टेम्पलेट में अपने रिज्यूमे का लाइव पूर्वावलोकन देखें" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "एआई प्रदाताओं को लोड किया जा रहा है। कृपया कुछ देर बाद पुनः प्रयास करें।" @@ -2698,6 +2717,10 @@ msgstr "माइक्रोसॉफ्ट वर्ड" msgid "Missing working resume" msgstr "कार्य संबंधी रिज्यूमे गुम है" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "मिस्ट्रल एआई" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "मॉडल" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "ओड़िया" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "ओल्लामा" +msgid "Ollama Cloud" +msgstr "ओलामा क्लाउड" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "पीडीएफ" msgid "Period" msgstr "अवधि" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "विकलता" + #: src/libs/locale.ts msgid "Persian" msgstr "फ़ारसी" @@ -3838,6 +3865,10 @@ msgstr "पासवर्ड दिखाएँ" msgid "Show picture" msgstr "चित्र दर्शाएं" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "कवर लेटर पर वही पहला पेज हेडर दिखाएं।" + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "शीर्षक" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "अपना खाता हटाने के लिए, आपको पुष्टिकरण पाठ दर्ज करना होगा और नीचे दिए गए बटन पर क्लिक करना होगा।" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "कोशिश करने लायक" msgid "X (Twitter)" msgstr "एक्स (ट्विटर)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI ग्रोक" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "हाँ, Reactive Resume कई भाषाओं में उपलब्ध है। आप सेटिंग्स पेज में, या ऊपर दाएँ कोने में भाषा स्विचर का उपयोग करके अपनी पसंदीदा भाषा चुन सकते हैं। यदि आपको अपनी भाषा नहीं दिखती, या आप मौजूदा अनुवादों में सुधार करना चाहते हैं, तो आप <0>Crowdin पर अनुवादों में योगदान दे सकते हैं<1> (नए टैब में खुलता है)।" diff --git a/apps/web/locales/hu-HU.po b/apps/web/locales/hu-HU.po index 943c24752..84f0e176a 100644 --- a/apps/web/locales/hu-HU.po +++ b/apps/web/locales/hu-HU.po @@ -8,7 +8,7 @@ msgstr "" "Language: hu\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Hungarian\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "katalán" msgid "Center Align" msgstr "Középre igazítás" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Agy" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Kattints ide az importálandó fájl kiválasztásához" msgid "Close AI assistant" msgstr "Bezárás AI asszisztens" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Összefügg" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Behúzás csökkentése" msgid "Decrease zoom" msgstr "Csökkentse a nagyítást" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Fokozat" @@ -1885,6 +1897,10 @@ msgstr "Keress gyenge felsoroláspontokat, és írd át őket erősebb eredmény msgid "Finnish" msgstr "finn" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Tűzijáték" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Nézethez igazítva" @@ -2072,6 +2088,10 @@ msgstr "görög" msgid "Grid" msgstr "Rács" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "A csapat bővítése" @@ -2271,6 +2291,10 @@ msgstr "Önéletrajz importálása..." msgid "Importing…" msgstr "… importálása" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Önéletrajz fejlécének beillesztése" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Behúzás növelése" @@ -2574,11 +2598,6 @@ msgstr "Lista" msgid "Lithuanian" msgstr "litván" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Élő előnézet az önéletrajzodról a {0} sablonban" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "MI-szolgáltatók betöltése folyamatban. Kérjük, próbálja újra egy pillanat múlva." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Hiányzó munkaköri önéletrajz" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral mesterséges intelligencia" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modell" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "odija" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Cloud" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Időszak" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Zavar" + #: src/libs/locale.ts msgid "Persian" msgstr "perzsa" @@ -3838,6 +3865,10 @@ msgstr "Jelszó megjelenítése" msgid "Show picture" msgstr "Kép megjelenítése" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Ugyanazon első oldali fejléc megjelenítése a motivációs levélen is." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Cím" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "A fiókod törléséhez add meg a megerősítő szöveget, majd kattints az alábbi gombra." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Együtt.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Megér egy próbát" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Igen, a Reactive Resume több nyelven is elérhető. A beállítások oldalon választhatod ki a kívánt nyelvet, vagy a jobb felső sarokban található nyelvváltó segítségével. Ha nem látod a saját nyelvedet, vagy szeretnél javítani a meglévő fordításokon, <0>közreműködhetsz a fordításokban a Crowdin‑on<1> (új lapon nyílik meg)." diff --git a/apps/web/locales/id-ID.po b/apps/web/locales/id-ID.po index ea9bcc743..570ec3432 100644 --- a/apps/web/locales/id-ID.po +++ b/apps/web/locales/id-ID.po @@ -8,7 +8,7 @@ msgstr "" "Language: id\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Indonesian\n" "Plural-Forms: nplurals=1; plural=0;\n" @@ -758,6 +758,10 @@ msgstr "Katala" msgid "Center Align" msgstr "Rata Tengah" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Otak Besar" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Klik di sini untuk memilih file yang akan diimpor" msgid "Close AI assistant" msgstr "Tutup asisten AI" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Berpadu" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Kurangi lekukan" msgid "Decrease zoom" msgstr "Kurangi zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Gelar" @@ -1885,6 +1897,10 @@ msgstr "Temukan poin-poin yang lemah dan tulis ulang dengan hasil, angka, cakupa msgid "Finnish" msgstr "Finlandia" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Kembang api" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Sesuai untuk dilihat" @@ -2072,6 +2088,10 @@ msgstr "Yunani" msgid "Grid" msgstr "Grid" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Perbesar Tim" @@ -2271,6 +2291,10 @@ msgstr "Mengimpor resume Anda..." msgid "Importing…" msgstr "Mengimpor…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Sertakan header resume" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Perbesar lekukan" @@ -2574,11 +2598,6 @@ msgstr "List" msgid "Lithuanian" msgstr "Lituania" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Pratinjau langsung resume Anda di templat {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Sedang memuat penyedia AI. Silakan coba lagi sebentar lagi." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Riwayat pekerjaan yang hilang" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Cloud" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Periode" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Kebingungan" + #: src/libs/locale.ts msgid "Persian" msgstr "Persia" @@ -3838,6 +3865,10 @@ msgstr "Tampilkan kata sandi" msgid "Show picture" msgstr "Tampilkan gambar" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Tampilkan header halaman pertama yang sama pada surat lamaran." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Judul" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Untuk menghapus akun Anda, Anda perlu memasukkan teks konfirmasi dan klik tombol di bawah." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Layak dicoba" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Ya, Reactive Resume tersedia dalam banyak bahasa. Anda dapat memilih bahasa pilihan Anda di halaman pengaturan, atau menggunakan pengalih bahasa di sudut kanan atas. Jika Anda tidak melihat bahasa Anda, atau ingin meningkatkan terjemahan yang ada, Anda dapat <0>berkontribusi pada terjemahan di Crowdin<1> (terbuka di tab baru)." diff --git a/apps/web/locales/it-IT.po b/apps/web/locales/it-IT.po index 38fa106b3..10907acde 100644 --- a/apps/web/locales/it-IT.po +++ b/apps/web/locales/it-IT.po @@ -8,7 +8,7 @@ msgstr "" "Language: it\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Italian\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Catalano" msgid "Center Align" msgstr "Allinea al centro" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cervelli" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Fai clic qui per selezionare un file da importare" msgid "Close AI assistant" msgstr "Assistente AI ravvicinato" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Coerenza" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Diminuire la rientranza" msgid "Decrease zoom" msgstr "Diminuire lo zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Ricerca profonda" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Titolo di studio" @@ -1885,6 +1897,10 @@ msgstr "Individua i punti deboli e riscrivili con risultati più solidi, dati pi msgid "Finnish" msgstr "Finlandese" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "fuochi d'artificio" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Adatto alla visione" @@ -2072,6 +2088,10 @@ msgstr "Greco" msgid "Grid" msgstr "Griglia" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Amplia il team" @@ -2271,6 +2291,10 @@ msgstr "Importazione del tuo curriculum in corso..." msgid "Importing…" msgstr "Importazione…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Includi l'intestazione del CV" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Aumentare il rientro" @@ -2574,11 +2598,6 @@ msgstr "Lista" msgid "Lithuanian" msgstr "Lituano" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Anteprima in tempo reale del tuo curriculum nel modello {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Caricamento dei provider di intelligenza artificiale. Riprova tra un attimo." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Mancanza di curriculum vitae" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Intelligenza artificiale Mistral" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modello" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Nuvola Ollam" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Periodo" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Perplessità" + #: src/libs/locale.ts msgid "Persian" msgstr "Persiano" @@ -3838,6 +3865,10 @@ msgstr "Mostra la password" msgid "Show picture" msgstr "Mostra l'immagine" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Mostra la stessa intestazione della prima pagina anche nella lettera di presentazione." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Titolo" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Per eliminare il tuo account devi inserire il testo di conferma e fare clic sul pulsante qui sotto." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Vale un tentativo" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Sì, Reactive Resume è disponibile in più lingue. Puoi scegliere la tua lingua preferita nella pagina delle impostazioni o usando il selettore di lingua nell'angolo in alto a destra. Se non vedi la tua lingua, o se vuoi migliorare le traduzioni esistenti, puoi <0>contribuire alle traduzioni su Crowdin<1> (apre in una nuova scheda)." diff --git a/apps/web/locales/ja-JP.po b/apps/web/locales/ja-JP.po index f153939d3..71615f764 100644 --- a/apps/web/locales/ja-JP.po +++ b/apps/web/locales/ja-JP.po @@ -8,7 +8,7 @@ msgstr "" "Language: ja\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Japanese\n" "Plural-Forms: nplurals=1; plural=0;\n" @@ -758,6 +758,10 @@ msgstr "カタロニア語" msgid "Center Align" msgstr "中央揃え" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "脳" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "ここをクリックしてインポートするファイルを選択" msgid "Close AI assistant" msgstr "AIアシスタントを閉じる" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "調和する" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "インデントを減らす" msgid "Decrease zoom" msgstr "ズームを縮小する" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "ディープシーク" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "学位" @@ -1885,6 +1897,10 @@ msgstr "弱い箇条書きを見つけ出し、より力強い成果、数値、 msgid "Finnish" msgstr "フィンランド語" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "花火" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "見るのにふさわしい" @@ -2072,6 +2088,10 @@ msgstr "ギリシャ語" msgid "Grid" msgstr "グリッド表示" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "グロク" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "チームを拡大" @@ -2271,6 +2291,10 @@ msgstr "レジュメをインポートしています…" msgid "Importing…" msgstr "… をインポートしています" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "履歴書のヘッダーを含める" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "インデントを増やす" @@ -2574,11 +2598,6 @@ msgstr "一覧" msgid "Lithuanian" msgstr "リトアニア語" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} テンプレートでの履歴書のライブプレビュー" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "AIプロバイダーを読み込んでいます。しばらくしてからもう一度お試しください。" @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "レジュメが選択されていません" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "ミストラルAI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "モデル" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "オディア語" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Orlama" +msgid "Ollama Cloud" +msgstr "オラマ・クラウド" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "期間" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "困惑" + #: src/libs/locale.ts msgid "Persian" msgstr "ペルシア語" @@ -3838,6 +3865,10 @@ msgstr "パスワードを表示する" msgid "Show picture" msgstr "画像を表示" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "カバーレターにも1ページ目と同じヘッダーを表示します。" + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "タイトル" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "アカウントを削除するには、確認用のテキストを入力し、下のボタンをクリックしてください。" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "一緒に。" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "試す価値あり" msgid "X (Twitter)" msgstr "X(ツイッター)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "はい。Reactive Resume は複数の言語に対応しています。設定ページ、または右上の言語切り替えからお好みの言語を選択できます。もしご希望の言語が見つからない場合や、既存の翻訳を改善したい場合は、<0>Crowdin で翻訳に貢献<1>(新しいタブで開きます)できます。" diff --git a/apps/web/locales/km-KH.po b/apps/web/locales/km-KH.po index f15e6e720..516fef12d 100644 --- a/apps/web/locales/km-KH.po +++ b/apps/web/locales/km-KH.po @@ -8,7 +8,7 @@ msgstr "" "Language: km\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Khmer\n" "Plural-Forms: nplurals=1; plural=0;\n" @@ -758,6 +758,10 @@ msgstr "Catalan" msgid "Center Align" msgstr "តម្រង់​កណ្ដាល" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "ខួរក្បាល" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "ចុច​ទីនេះ​ដើម្បី​ជ្រើស​ឯ msgid "Close AI assistant" msgstr "បិទជំនួយការ AI" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "កូហៀរ" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "បន្ថយ​ការ​ចូល​បន្ទាត់" msgid "Decrease zoom" msgstr "បន្ថយការពង្រីក" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "សញ្ញាប័ត្រ" @@ -1885,6 +1897,10 @@ msgstr "ស្វែងរកចំណុចខ្សោយ ហើយសរស msgid "Finnish" msgstr "Finnish" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "កាំជ្រួច" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "សមនឹងមើល" @@ -2072,6 +2088,10 @@ msgstr "Greek" msgid "Grid" msgstr "ក្រឡារៀបចំ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "ហ្គ្រូក" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "ពង្រីក​ក្រុម" @@ -2271,6 +2291,10 @@ msgstr "កំពុង​នាំចូល​ប្រវត្តិរូប msgid "Importing…" msgstr "កំពុងនាំចូល…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "បញ្ចូលបឋមកថានៃប្រវត្តិរូប" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "បង្កើន​ការ​ចូល​បន្ទាត់" @@ -2574,11 +2598,6 @@ msgstr "បញ្ជី" msgid "Lithuanian" msgstr "Lithuanian" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "ការមើលជាមុនផ្ទាល់នៃប្រវត្តិរូបសង្ខេបរបស់អ្នកនៅក្នុងគំរូ {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "កំពុងផ្ទុកអ្នកផ្តល់សេវា AI។ សូមព្យាយាមម្តងទៀតក្នុងពេលឆាប់ៗនេះ។" @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "បាត់ប្រវត្តិរូបសង្ខេបការងារ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "មីស្ត្រាល អាយអាយ" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "ម៉ូដែល" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "ពពកអូឡាម៉ា" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "កំឡុងពេល" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "ភាពច្របូកច្របល់" + #: src/libs/locale.ts msgid "Persian" msgstr "Persian" @@ -3838,6 +3865,10 @@ msgstr "បង្ហាញពាក្យសម្ងាត់" msgid "Show picture" msgstr "បង្ហាញរូបភាព" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "បង្ហាញបឋមកថាទំព័រទីមួយដូចគ្នានៅលើលិខិតសម្រាប់ដាក់ពាក្យ។" + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "ចំណងជើង" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "ដើម្បី​លុប​គណនី​របស់​អ្នក អ្នក​ត្រូវ​បញ្ចូល​អក្សរ​បញ្ជាក់ ហើយ​ចុច​ប៊ូតុង​ខាងក្រោម។" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "គួរតែសាកល្បង" msgid "X (Twitter)" msgstr "X (ធ្វីតធ័រ)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "បាទ Reactive Resume អាច​ប្រើ​បាន​ជា​ភាសា​ច្រើន។ អ្នក​អាច​ជ្រើស​ភាសា​ដែល​អ្នក​ពេញចិត្ត​នៅលើ​ទំព័រ​ការកំណត់ ឬ​ដោយ​ប្រើ​កម្មវិធី​ប្ដូរ​ភាសា​នៅ​កូណឺ​ឆ្វេងលើ។ បើ​អ្នក​មិន​ឃើញ​ភាសា​របស់​អ្នក ឬ​ចង់​ធ្វើ​ឱ្យ​ការ​បកប្រែ​ដែល​មាន​ស្រាប់​ប្រសើរ​ឡើង អ្នក​អាច <0>ចូលរួម​បកប្រែនៅលើ Crowdin<1> (បើក​ក្នុង​ផ្ទាំង​ថ្មី)។" diff --git a/apps/web/locales/kn-IN.po b/apps/web/locales/kn-IN.po index fe9099691..1c7da046c 100644 --- a/apps/web/locales/kn-IN.po +++ b/apps/web/locales/kn-IN.po @@ -8,7 +8,7 @@ msgstr "" "Language: kn\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Kannada\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "ಕ್ಯಾಟಲನ್" msgid "Center Align" msgstr "ಮಧ್ಯ ಸರಿಸು" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "ಸೆರೆಬ್ರಸ್" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "ಆಮದು ಮಾಡಲು ಕಡತವನ್ನು ಆಯ್ಕೆ msgid "Close AI assistant" msgstr "AI ಸಹಾಯಕವನ್ನು ಮುಚ್ಚಿ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "ಕೊಹೆರೆ" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "ಇಂಡೆಂಟ್ ಕಡಿಮೆ ಮಾಡಿ" msgid "Decrease zoom" msgstr "ಝೂಮ್ ಕಡಿಮೆ ಮಾಡಿ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "ಡೀಪ್‌ಸೀಕ್" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "ಪದವಿ" @@ -1885,6 +1897,10 @@ msgstr "ದುರ್ಬಲ ಗುಂಡುಗಳನ್ನು ಹುಡುಕಿ msgid "Finnish" msgstr "ಫಿನ್ನಿಷ್" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "ಪಟಾಕಿಗಳು" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "ವೀಕ್ಷಿಸಲು ಹೊಂದಿಕೊಳ್ಳಿ" @@ -2072,6 +2088,10 @@ msgstr "ಗ್ರೀಕ್" msgid "Grid" msgstr "ಗ್ರಿಡ್" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "ಗ್ರೋಕ್" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "ತಂಡವನ್ನು ವಿಸ್ತರಿಸಿ" @@ -2271,6 +2291,10 @@ msgstr "ನಿಮ್ಮ ರೆಸ್ಯೂಮ್ ಅನ್ನು ಆಮದು msgid "Importing…" msgstr "… ಆಮದು ಮಾಡಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "ರೆಸ್ಯೂಮೆಯ ಹೆಡರ್ ಸೇರಿಸಿ" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "ಇಂಡೆಂಟ್ ಹೆಚ್ಚಿಸಿ" @@ -2574,11 +2598,6 @@ msgstr "ಪಟ್ಟಿ" msgid "Lithuanian" msgstr "ಲಿಥುವೇನಿಯನ್" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} ಟೆಂಪ್ಲೇಟ್‌ನಲ್ಲಿ ನಿಮ್ಮ ರೆಸ್ಯೂಮ್‌ನ ಲೈವ್ ಪೂರ್ವವೀಕ್ಷಣೆ" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "AI ಪೂರೈಕೆದಾರರನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ. ದಯವಿಟ್ಟು ಸ್ವಲ್ಪ ಸಮಯದ ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "ಕೆಲಸದ ರೆಸ್ಯೂಮ್ ಕಾಣೆಯಾಗಿದೆ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "ಮಿಸ್ಟ್ರಲ್ AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "ಮಾದರಿ" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "ಒಡಿಯಾ" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "ಒಲ್ಲಮಾ ಮೇಘ" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "ಅವಧಿ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "ಗೊಂದಲ" + #: src/libs/locale.ts msgid "Persian" msgstr "ಫಾರ್ಸಿ" @@ -3838,6 +3865,10 @@ msgstr "ಪಾಸ್‌ವರ್ಡ್ ತೋರಿಸಿ" msgid "Show picture" msgstr "ಚಿತ್ರವನ್ನು ತೋರಿಸಿ" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "ಕವರ್ ಲೆಟರ್‌ನಲ್ಲಿ ಅದೇ ಮೊದಲ ಪುಟದ ಹೆಡರ್ ಅನ್ನು ತೋರಿಸಿ." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "ಶೀರ್ಷಿಕೆ" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "ನಿಮ್ಮ ಖಾತೆಯನ್ನು ಅಳಿಸಲು, ನೀವು ದೃಢೀಕರಣ ಪಠ್ಯವನ್ನು ನಮೂದಿಸಿ ಮತ್ತು ಕೆಳಗಿನ ಬಟನ್ ಅನ್ನು ಕ್ಲಿಕ್ ಮಾಡಬೇಕು." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "ಟುಗೆದರ್.ಐ" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "ಪ್ರಯತ್ನಿಸಲು ಯೋಗ್ಯ" msgid "X (Twitter)" msgstr "ಎಕ್ಸ್ (ಟ್ವಿಟರ್)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI ಗ್ರೋಕ್" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "ಹೌದು, Reactive Resume ಅನೇಕ ಭಾಷೆಗಳಲ್ಲಿ ಲಭ್ಯವಿದೆ. ನೀವು ಸೆಟ್ಟಿಂಗ್ಸ್ ಪುಟದಲ್ಲಿ ಅಥವಾ ಮೇಲ್ಭಾಗದ ಬಲ ಮೂಲೆಯಲ್ಲಿರುವ ಭಾಷಾ ಸ್ವಿಚರ್ ಬಳಸಿ ನಿಮ್ಮ ಇಷ್ಟದ ಭಾಷೆಯನ್ನು ಆರಿಸಬಹುದು. ನಿಮ್ಮ ಭಾಷೆ ಕಾಣದಿದ್ದರೆ ಅಥವಾ ಇತ್ತೀಚಗಿನ ಅನುವಾದಗಳನ್ನು ಸುಧಾರಿಸಲು ಬಯಸಿದರೆ, ನೀವು <0>Crowdin ನಲ್ಲಿ ಅನುವಾದಗಳಿಗೆ ಕೊಡುಗೆ ನೀಡಬಹುದು<1> (ಹೊಸ ಟ್ಯಾಬ್‌ನಲ್ಲಿ ತೆರೆಯುತ್ತದೆ)." diff --git a/apps/web/locales/ko-KR.po b/apps/web/locales/ko-KR.po index cd36a3a29..ca3d5611b 100644 --- a/apps/web/locales/ko-KR.po +++ b/apps/web/locales/ko-KR.po @@ -8,7 +8,7 @@ msgstr "" "Language: ko\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Korean\n" "Plural-Forms: nplurals=1; plural=0;\n" @@ -758,6 +758,10 @@ msgstr "카탈루냐어" msgid "Center Align" msgstr "가운데 정렬" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "대뇌" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "가져올 파일을 선택하려면 여기를 클릭하세요" msgid "Close AI assistant" msgstr "AI 비서 닫기" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "응집하다" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "들여쓰기 감소" msgid "Decrease zoom" msgstr "확대/축소 크기 줄이기" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "딥시크" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "학위" @@ -1885,6 +1897,10 @@ msgstr "약한 항목들을 찾아내어 더 강력한 결과, 수치, 범위 msgid "Finnish" msgstr "핀란드어" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "불꽃" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "보기에 적합함" @@ -2072,6 +2088,10 @@ msgstr "그리스어" msgid "Grid" msgstr "그리드" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "그로크" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "팀 확장" @@ -2271,6 +2291,10 @@ msgstr "이력서를 가져오는 중입니다..." msgid "Importing…" msgstr "… 가져오기" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "이력서 헤더 포함" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "들여쓰기 증가" @@ -2574,11 +2598,6 @@ msgstr "목록" msgid "Lithuanian" msgstr "리투아니아어" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} 템플릿에서 이력서를 실시간으로 미리 보세요." - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "AI 제공업체를 불러오는 중입니다. 잠시 후 다시 시도해 주세요." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "이력서가 누락되었습니다." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "미스트랄 AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "모델" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "오디아어" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "올라마 클라우드" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "기간" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "당황" + #: src/libs/locale.ts msgid "Persian" msgstr "페르시아어" @@ -3838,6 +3865,10 @@ msgstr "비밀번호 표시" msgid "Show picture" msgstr "사진 표시" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "자기소개서에도 동일한 첫 페이지 헤더를 표시합니다." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "제목" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "계정을 삭제하려면 확인 문구를 입력한 뒤 아래 버튼을 클릭해야 합니다." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "투게더.에이" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "시도해 볼 만함" msgid "X (Twitter)" msgstr "X (트위터)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI 그록" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "네, Reactive Resume는 여러 언어로 제공됩니다. 설정 페이지나 오른쪽 상단의 언어 전환기를 사용해 원하는 언어를 선택할 수 있습니다. 원하는 언어가 없거나 기존 번역을 개선하고 싶다면, <0>Crowdin에서 번역에 기여해 보세요<1> (새 탭에서 열림)." diff --git a/apps/web/locales/lt-LT.po b/apps/web/locales/lt-LT.po index 6b380be72..5c1ea31af 100644 --- a/apps/web/locales/lt-LT.po +++ b/apps/web/locales/lt-LT.po @@ -8,7 +8,7 @@ msgstr "" "Language: lt\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Lithuanian\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && (n%100>19 || n%100<11) ? 0 : (n%10>=2 && n%10<=9) && (n%100>19 || n%100<11) ? 1 : n%1!=0 ? 2: 3);\n" @@ -758,6 +758,10 @@ msgstr "Katalonų" msgid "Center Align" msgstr "Lygiuoti centre" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Smegenys" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Spustelėkite čia, kad pasirinktumėte importuojamą failą" msgid "Close AI assistant" msgstr "Uždaryti DI asistentą" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Koheras" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Sumažinti įtrauką" msgid "Decrease zoom" msgstr "Sumažinti mastelį" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Laipsnis" @@ -1885,6 +1897,10 @@ msgstr "Raskite silpnus sąrašus ir perrašykite juos su stipresniais rezultata msgid "Finnish" msgstr "Suomių" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Fejerverkai" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Pritaikyti peržiūrai" @@ -2072,6 +2088,10 @@ msgstr "Graikų" msgid "Grid" msgstr "Tinklelis" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Plėsti komandą" @@ -2271,6 +2291,10 @@ msgstr "Importuojamas jūsų gyvenimo aprašymas..." msgid "Importing…" msgstr "Importuojama…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Įtraukti gyvenimo aprašymo antraštę" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Padidinti įtrauką" @@ -2574,11 +2598,6 @@ msgstr "Sąrašas" msgid "Lithuanian" msgstr "Lietuvių" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Tiesioginė jūsų gyvenimo aprašymo peržiūra šablone {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Įkeliami dirbtinio intelekto teikėjai. Bandykite dar kartą po akimirkos." @@ -2698,6 +2717,10 @@ msgstr "\"Microsoft Word" msgid "Missing working resume" msgstr "Trūksta darbo gyvenimo aprašymo" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modelis" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odijų" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Cloud" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Laikotarpis" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Sumišimas" + #: src/libs/locale.ts msgid "Persian" msgstr "Persų" @@ -3838,6 +3865,10 @@ msgstr "Rodyti slaptažodį" msgid "Show picture" msgstr "Rodyti paveikslėlį" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Rodyti tą pačią pirmojo puslapio antraštę ir motyvaciniame laiške." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Pavadinimas" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Norėdami ištrinti paskyrą, įveskite patvirtinimo tekstą ir spustelėkite žemiau esantį mygtuką." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Kartu.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Verta pabandyti" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grokas" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Taip, „Reactive Resume“ prieinama keliomis kalbomis. Galite pasirinkti pageidaujamą kalbą nustatymų puslapyje arba naudoti kalbos perjungiklį viršutiniame dešiniajame kampe. Jei nematote savo kalbos arba norite patobulinti esamus vertimus, galite <0>prisidėti prie vertimų „Crowdin“<1> (atidaro naujame skirtuke)." diff --git a/apps/web/locales/lv-LV.po b/apps/web/locales/lv-LV.po index 33043a67b..60f743e5f 100644 --- a/apps/web/locales/lv-LV.po +++ b/apps/web/locales/lv-LV.po @@ -8,7 +8,7 @@ msgstr "" "Language: lv\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Latvian\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n" @@ -758,6 +758,10 @@ msgstr "Katalāņu" msgid "Center Align" msgstr "Centrēt" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Smadzenes" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Noklikšķiniet šeit, lai izvēlētos importējamo failu" msgid "Close AI assistant" msgstr "Aizvērt mākslīgā intelekta palīgu" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Kohere" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Samazināt atkāpi" msgid "Decrease zoom" msgstr "Samazināt tālummaiņu" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Grāds" @@ -1885,6 +1897,10 @@ msgstr "Atrodiet vājas aizzīmes un pārrakstiet tās ar spēcīgākiem rezult msgid "Finnish" msgstr "Somu" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Uguņošana" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Piemērots skatam" @@ -2072,6 +2088,10 @@ msgstr "Grieķu" msgid "Grid" msgstr "Režģis" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Paplašināt komandu" @@ -2271,6 +2291,10 @@ msgstr "Tiek importēts jūsu CV..." msgid "Importing…" msgstr "Importē…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Iekļaut CV galveni" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Palielināt atkāpi" @@ -2574,11 +2598,6 @@ msgstr "Saraksts" msgid "Lithuanian" msgstr "Lietuviešu" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Jūsu CV tiešraides priekšskatījums veidnē {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Notiek mākslīgā intelekta pakalpojumu sniedzēju ielāde. Lūdzu, mēģiniet vēlreiz pēc brīža." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Trūkst darba CV" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modelis" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odiju" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Cloud" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Periods" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Apjukums" + #: src/libs/locale.ts msgid "Persian" msgstr "Persiešu" @@ -3838,6 +3865,10 @@ msgstr "Rādīt paroli" msgid "Show picture" msgstr "Rādīt attēlu" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Rādīt to pašu pirmās lapas galveni arī motivācijas vēstulē." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Nosaukums" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Lai dzēstu savu kontu, jums jāievada apstiprinājuma teksts un jānoklikšķina uz zemāk esošās pogas." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Kopā.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Ir vērts mēģināt" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Groks" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Jā, Reactive Resume ir pieejams vairākās valodās. Jūs varat izvēlēties vēlamo valodu iestatījumu lapā vai, izmantojot valodas pārslēdzēju augšējā labajā stūrī. Ja neredzat savu valodu vai vēlaties uzlabot esošos tulkojumus, varat <0>piedalīties tulkošanā vietnē Crowdin<1> (atveras jaunā cilnē)." diff --git a/apps/web/locales/ml-IN.po b/apps/web/locales/ml-IN.po index f436d0064..4955093e6 100644 --- a/apps/web/locales/ml-IN.po +++ b/apps/web/locales/ml-IN.po @@ -8,7 +8,7 @@ msgstr "" "Language: ml\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Malayalam\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "കറ്റലാൻ" msgid "Center Align" msgstr "സെന്റർ അലൈനിൽ ആക്കുക" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "സെറിബ്രകൾ" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "ഇംപോർട്ട് ചെയ്യാൻ ഒരു ഫയൽ msgid "Close AI assistant" msgstr "AI അസിസ്റ്റന്റ് അടയ്ക്കുക" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "കോഹെർ" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "ഇൻഡന്റ് കുറയ്ക്കുക" msgid "Decrease zoom" msgstr "സൂം കുറയ്ക്കുക" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "ഡീപ്‌സീക്ക്" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "ഡിഗ്രി" @@ -1885,6 +1897,10 @@ msgstr "ദുർബലമായ ബുള്ളറ്റുകൾ കണ്ട msgid "Finnish" msgstr "ഫിന്നിഷ്" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "വെടിക്കെട്ട്" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "കാണാൻ അനുയോജ്യം" @@ -2072,6 +2088,10 @@ msgstr "ഗ്രീക്ക്" msgid "Grid" msgstr "ഗ്രിഡ്" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "ഗ്രോക്ക്" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "ടീം വികസിപ്പിക്കുക" @@ -2271,6 +2291,10 @@ msgstr "നിങ്ങളുടെ റിസ്യൂം ഇംപോർട് msgid "Importing…" msgstr "… ഇറക്കുമതി ചെയ്യുന്നു" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "റെസ്യൂമിന്റെ ഹെഡർ ഉൾപ്പെടുത്തുക" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "ഇൻഡന്റ് വർദ്ധിപ്പിക്കുക" @@ -2574,11 +2598,6 @@ msgstr "ലിസ്റ്റ്" msgid "Lithuanian" msgstr "ലിത്വാനിയൻ" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} ടെംപ്ലേറ്റിൽ നിങ്ങളുടെ റെസ്യൂമെയുടെ തത്സമയ പ്രിവ്യൂ" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "AI ദാതാക്കളെ ലോഡ് ചെയ്യുന്നു. ദയവായി അൽപ്പസമയത്തിനുശേഷം വീണ്ടും ശ്രമിക്കുക." @@ -2698,6 +2717,10 @@ msgstr "മൈക്രോസോഫ്റ്റ് വേഡ്" msgid "Missing working resume" msgstr "വർക്കിംഗ് റെസ്യൂമെ കാണുന്നില്ല" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "മിസ്ട്രൽ AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "മോഡൽ" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "ഒഡിയ" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "ഒല്ലാമ" +msgid "Ollama Cloud" +msgstr "ഒല്ലാമ മേഘം" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "പിഡിഎഫ്" msgid "Period" msgstr "കാലയളവ്" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "ആശയക്കുഴപ്പം" + #: src/libs/locale.ts msgid "Persian" msgstr "പേഴ്‌സിയൻ" @@ -3838,6 +3865,10 @@ msgstr "പാസ്‌വേഡ് കാണിക്കുക" msgid "Show picture" msgstr "ചിത്രം കാണിക്കുക" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "കവർ ലെറ്ററിലും അതേ ആദ്യ പേജ് ഹെഡർ കാണിക്കുക." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "ടൈറ്റിൽ" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "നിങ്ങളുടെ അക്കൗണ്ട് ഡിലീറ്റ് ചെയ്യാൻ, നിങ്ങൾ സ്ഥിരീകരണ ടെക്സ്റ്റ് നൽകുകയും താഴെയുള്ള ബട്ടൺ ക്ലിക്ക് ചെയ്യുകയും വേണം." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "ടുഗെദർ.ഐ" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "ഒരു ഷോട്ട് വിലമതിക്കുന്നു" msgid "X (Twitter)" msgstr "എക്സ് (ട്വിറ്റർ)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI ഗ്രോക്ക്" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "അതെ, Reactive Resume പല ഭാഷകളിലും ലഭ്യമാണ്. സെറ്റിംഗ്സ് പേജിൽ നിന്നോ മുകളിലെ വലതു കോണിലുള്ള ഭാഷാ സ്വിച്ചർ ഉപയോഗിച്ചോ നിങ്ങൾക്ക് ഇഷ്ടമുള്ള ഭാഷ തിരഞ്ഞെടുക്കാം. നിങ്ങളുടെ ഭാഷ ലഭ്യമല്ലെങ്കിൽ, അല്ലെങ്കിൽ നിലവിലുള്ള തർജ്ജമകൾ മെച്ചപ്പെടുത്താനാഗ്രഹിക്കുന്നുവെങ്കിൽ, നിങ്ങൾക്ക് <0>Crowdin‑ൽ തർജ്ജമകൾക്ക് സംഭാവന ചെയ്യാം<1> (പുതിയ ടാബിൽ തുറക്കും)." diff --git a/apps/web/locales/mr-IN.po b/apps/web/locales/mr-IN.po index 347920632..b89970d86 100644 --- a/apps/web/locales/mr-IN.po +++ b/apps/web/locales/mr-IN.po @@ -8,7 +8,7 @@ msgstr "" "Language: mr\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Marathi\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "कॅटालन" msgid "Center Align" msgstr "मधोमध जुळवा" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "सेरेब्रास" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "इम्पोर्ट करण्यासाठी फाईल न msgid "Close AI assistant" msgstr "एआय सहाय्यक बंद करा" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "कोहेअर" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "इंडेंट कमी करा" msgid "Decrease zoom" msgstr "झूम कमी करा" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "डीपसीक" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "पदवी" @@ -1885,6 +1897,10 @@ msgstr "कमजोर मुद्दे शोधा आणि अधिक msgid "Finnish" msgstr "फिन्निश" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "फटाके" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "पाहण्यासाठी योग्य" @@ -2072,6 +2088,10 @@ msgstr "ग्रीक" msgid "Grid" msgstr "ग्रिड" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "ग्रोक" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "टीम वाढवा" @@ -2271,6 +2291,10 @@ msgstr "तुमचा रेझ्युमे इम्पोर्ट के msgid "Importing…" msgstr "… आयात करत आहे" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "रेझ्युमे हेडर समाविष्ट करा" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "इंडेंट वाढवा" @@ -2574,11 +2598,6 @@ msgstr "यादी" msgid "Lithuanian" msgstr "लिथुआनियन" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} टेम्पलेटमध्ये तुमच्या रिझ्युमेचे थेट पूर्वावलोकन" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "एआय प्रोव्हायडर्स लोड होत आहेत. कृपया थोड्या वेळाने पुन्हा प्रयत्न करा." @@ -2698,6 +2717,10 @@ msgstr "मायक्रोसॉफ्ट वर्ड" msgid "Missing working resume" msgstr "कामाचा बायोडाटा गहाळ आहे" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "मिस्ट्रल एआय" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "मॉडेल" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "ओडिया" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "ओल्लामा" +msgid "Ollama Cloud" +msgstr "ओलामा क्लाउड" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "पीडीएफ" msgid "Period" msgstr "कालावधी" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "गोंधळ" + #: src/libs/locale.ts msgid "Persian" msgstr "फारसी" @@ -3838,6 +3865,10 @@ msgstr "पासवर्ड दाखवा" msgid "Show picture" msgstr "चित्र दाखवा" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "कव्हर लेटरवर तोच पहिला पेज हेडर दाखवा." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "शीर्षक" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "तुमचे खाते हटवण्यासाठी तुम्हाला पुष्टीकरण मजकूर टाकून खालील बटणावर क्लिक करणे आवश्यक आहे." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "एक शॉट वाचतो" msgid "X (Twitter)" msgstr "एक्स (ट्विटर)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "होय, Reactive Resume अनेक भाषांमध्ये उपलब्ध आहे. तुम्ही सेटिंग्ज पेजवर किंवा उजव्या वरच्या कोपऱ्यातील भाषा स्विचर वापरून तुमची आवडती भाषा निवडू शकता. जर तुम्हाला तुमची भाषा दिसत नसेल किंवा विद्यमान भाषांतर सुधारायचे असेल, तर तुम्ही <0>Crowdin वर भाषांतरांमध्ये योगदान देऊ शकता<1> (नवीन टॅबमध्ये उघडते)." diff --git a/apps/web/locales/ms-MY.po b/apps/web/locales/ms-MY.po index ec88c5b58..17c375bd5 100644 --- a/apps/web/locales/ms-MY.po +++ b/apps/web/locales/ms-MY.po @@ -8,7 +8,7 @@ msgstr "" "Language: ms\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Malay\n" "Plural-Forms: nplurals=1; plural=0;\n" @@ -758,6 +758,10 @@ msgstr "Catalan" msgid "Center Align" msgstr "Jajaran Tengah" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Serebrum" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Klik di sini untuk memilih fail untuk diimport" msgid "Close AI assistant" msgstr "Tutup pembantu AI" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Bersatu padu" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Kurangkan inden" msgid "Decrease zoom" msgstr "Kurangkan zum" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Ijazah" @@ -1885,6 +1897,10 @@ msgstr "Cari poin yang lemah dan tulis semula dengan hasil, nombor, skop dan kat msgid "Finnish" msgstr "Finland" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Bunga api" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Sesuai untuk dilihat" @@ -2072,6 +2088,10 @@ msgstr "Greek" msgid "Grid" msgstr "Grid" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Tambahkan Ahli Pasukan" @@ -2271,6 +2291,10 @@ msgstr "Mengimport resume anda..." msgid "Importing…" msgstr "Mengimport…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Sertakan pengepala resume" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Tingkatkan inden" @@ -2574,11 +2598,6 @@ msgstr "Senarai" msgid "Lithuanian" msgstr "Lithuania" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Pratonton langsung resume anda dalam templat {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Memuatkan penyedia AI. Sila cuba lagi sebentar lagi." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Resume kerja yang hilang" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Awan Ollama" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Tempoh" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Kekeliruan" + #: src/libs/locale.ts msgid "Persian" msgstr "Parsi" @@ -3838,6 +3865,10 @@ msgstr "Tunjukkan kata laluan" msgid "Show picture" msgstr "Tunjukkan gambar" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Tunjukkan pengepala halaman pertama yang sama pada surat iringan." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Tajuk" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Untuk memadam akaun anda, anda perlu memasukkan teks pengesahan dan klik butang di bawah." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Bersama.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Berbaloi" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Ya, Reactive Resume tersedia dalam pelbagai bahasa. Anda boleh memilih bahasa pilihan anda di halaman tetapan, atau menggunakan penukar bahasa di penjuru kanan atas. Jika anda tidak melihat bahasa anda, atau anda ingin menambah baik terjemahan sedia ada, anda boleh <0>menyumbang kepada terjemahan di Crowdin<1> (dibuka dalam tab baharu)." diff --git a/apps/web/locales/ne-NP.po b/apps/web/locales/ne-NP.po index c4fcc2ce4..fb4f8eaa7 100644 --- a/apps/web/locales/ne-NP.po +++ b/apps/web/locales/ne-NP.po @@ -8,7 +8,7 @@ msgstr "" "Language: ne\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Nepali\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "क्याटालान" msgid "Center Align" msgstr "बीचतिर क्रमबद्ध (Center Align)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "सेरेब्रास" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "आयात गर्न फाइल छान्न यहाँ क msgid "Close AI assistant" msgstr "एआई सहायक बन्द गर्नुहोस्" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "कोहेर" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "इन्डेन्ट घटाउनुहोस्" msgid "Decrease zoom" msgstr "जुम घटाउनुहोस्" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "डीपसिक" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "डिग्री" @@ -1885,6 +1897,10 @@ msgstr "कमजोर बुलेटहरू फेला पार्नु msgid "Finnish" msgstr "फिनिस" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "आतिशबाजी" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "हेर्नको लागि उपयुक्त" @@ -2072,6 +2088,10 @@ msgstr "ग्रीक" msgid "Grid" msgstr "ग्रिड" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "ग्रोक" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "टिम बढाउनुहोस्" @@ -2271,6 +2291,10 @@ msgstr "तपाईंको बायोडाटा आयात हुँद msgid "Importing…" msgstr "आयात गर्दै…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "रिजुमे हेडर समावेश गर्नुहोस्" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "इन्डेन्ट बढाउनुहोस्" @@ -2574,11 +2598,6 @@ msgstr "सूची" msgid "Lithuanian" msgstr "लिथुआनियन" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} टेम्प्लेटमा तपाईंको बायोडाटाको प्रत्यक्ष पूर्वावलोकन" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "AI प्रदायकहरू लोड गर्दै। कृपया केही बेरमा फेरि प्रयास गर्नुहोस्।" @@ -2698,6 +2717,10 @@ msgstr "माइक्रोसफ्ट वर्ड" msgid "Missing working resume" msgstr "काम गर्ने बायोडाटा हराइरहेको छ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "मिस्ट्रल एआई" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "मोडेल" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "ओडिया" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "ओल्लामा" +msgid "Ollama Cloud" +msgstr "ओलामा क्लाउड" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "पीडीएफ" msgid "Period" msgstr "अवधि" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "अन्योल" + #: src/libs/locale.ts msgid "Persian" msgstr "फारसी" @@ -3838,6 +3865,10 @@ msgstr "पासवर्ड देखाउनुहोस्" msgid "Show picture" msgstr "तस्वीर देखाउनुहोस्" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "कभर लेटरमा उही पहिलो पृष्ठको हेडर देखाउनुहोस्।" + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "शीर्षक" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "तपाईंको खाता मेटाउन, तपाईंले यकिन पाठ (confirmation text) प्रविष्ट गरेर तलको बटन थिच्नुपर्छ।" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai का थप वस्तुहरू" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "एक शट लायक" msgid "X (Twitter)" msgstr "एक्स (ट्विटर)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI ग्रोक" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "हो, Reactive Resume धेरै भाषाहरूमा उपलब्ध छ। तपाईंले सेटिङ पेजबाट वा माथिको दायाँ कुनामा रहेको भाषा सुइचर प्रयोग गरेर आफ्नो मनपर्ने भाषा छान्न सक्नुहुन्छ। यदि आफ्नो भाषा नदेखिनुभयो वा विद्यमान अनुवाद सुधार गर्न चाहनुहुन्छ भने, तपाईं <0>Crowdin मा अनुवादमा योगदान गर्न सक्नुहुन्छ<1> (नयाँ ट्याबमा खुल्छ)।" diff --git a/apps/web/locales/nl-NL.po b/apps/web/locales/nl-NL.po index 083ccac7d..1770420eb 100644 --- a/apps/web/locales/nl-NL.po +++ b/apps/web/locales/nl-NL.po @@ -8,7 +8,7 @@ msgstr "" "Language: nl\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Dutch\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Catalaans" msgid "Center Align" msgstr "Centreren" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cerebras" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Klik hier om een bestand te selecteren om te importeren" msgid "Close AI assistant" msgstr "AI-assistent sluiten" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Samenhangen" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Verklein de inspringing" msgid "Decrease zoom" msgstr "Verklein de zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Diepzoeken" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Diploma" @@ -1885,6 +1897,10 @@ msgstr "Identificeer zwakke punten en herschrijf ze met sterkere resultaten, cij msgid "Finnish" msgstr "Fins" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Vuurwerk" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Geschikt om te bekijken" @@ -2072,6 +2088,10 @@ msgstr "Grieks" msgid "Grid" msgstr "Raster" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Het team uitbreiden" @@ -2271,6 +2291,10 @@ msgstr "Uw cv wordt geïmporteerd..." msgid "Importing…" msgstr "Importeren…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Cv-koptekst opnemen" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Verhoog de inkeping" @@ -2574,11 +2598,6 @@ msgstr "Lijst" msgid "Lithuanian" msgstr "Litouws" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Live voorbeeld van je cv in de {0} -sjabloon" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "AI-providers worden geladen. Probeer het over een moment opnieuw." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Ontbrekend werk-cv" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Cloud" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Periode" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Verwarring" + #: src/libs/locale.ts msgid "Persian" msgstr "Perzisch" @@ -3838,6 +3865,10 @@ msgstr "Wachtwoord tonen" msgid "Show picture" msgstr "Afbeelding weergeven" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Toon dezelfde koptekst van de eerste pagina op de motivatiebrief." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Titel" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Om uw account te verwijderen, moet u de bevestigingstekst invoeren en op de knop hieronder klikken." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Samen.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Het proberen waard" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Ja, Reactive Resume is beschikbaar in meerdere talen. U kunt uw voorkeurstaal kiezen op de instellingenpagina of met de taalwisselaar rechtsboven. Als u uw taal niet ziet, of als u de bestaande vertalingen wilt verbeteren, kunt u <0>bijdagen aan de vertalingen op Crowdin<1> (opent in nieuw tabblad)." diff --git a/apps/web/locales/no-NO.po b/apps/web/locales/no-NO.po index 5fba68bf7..5eeca6bec 100644 --- a/apps/web/locales/no-NO.po +++ b/apps/web/locales/no-NO.po @@ -8,7 +8,7 @@ msgstr "" "Language: no\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Norwegian\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Katalansk" msgid "Center Align" msgstr "Midtstill" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Hjernen" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Klikk her for å velge en fil å importere" msgid "Close AI assistant" msgstr "Lukk AI-assistenten" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Koherens" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Reduser innrykk" msgid "Decrease zoom" msgstr "Reduser zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Grad" @@ -1885,6 +1897,10 @@ msgstr "Finn svake punkter og skriv dem om med sterkere utfall, tall, omfang og msgid "Finnish" msgstr "Finsk" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Fyrverkeri" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Tilpasset til visning" @@ -2072,6 +2088,10 @@ msgstr "Gresk" msgid "Grid" msgstr "Rutenett" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Voks teamet" @@ -2271,6 +2291,10 @@ msgstr "Importerer CV-en din..." msgid "Importing…" msgstr "Importerer…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Inkluder CV-topptekst" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Øk innrykk" @@ -2574,11 +2598,6 @@ msgstr "Liste" msgid "Lithuanian" msgstr "Litauisk" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Forhåndsvisning av CV-en din i sanntid i {0} -malen" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Laster inn AI-leverandører. Prøv igjen om et øyeblikk." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Mangler arbeids-CV" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modell" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama-skyen" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Periode" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Forvirring" + #: src/libs/locale.ts msgid "Persian" msgstr "Persisk" @@ -3838,6 +3865,10 @@ msgstr "Vis passord" msgid "Show picture" msgstr "Vis bilde" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Vis den samme topptekst fra første side på følgebrevet." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Tittel" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "For å slette kontoen din må du skrive inn bekreftelsesteksten og klikke på knappen nedenfor." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Sammen.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Verdt et forsøk" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Ja, Reactive Resume er tilgjengelig på flere språk. Du kan velge foretrukket språk på innstillingssiden, eller ved å bruke språkvælgeren øverst til høyre. Hvis du ikke ser språket ditt, eller du vil forbedre eksisterende oversettelser, kan du <0>bidra til oversettelsene på Crowdin<1> (åpnes i ny fane)." diff --git a/apps/web/locales/or-IN.po b/apps/web/locales/or-IN.po index 0901543d0..3a4c5c705 100644 --- a/apps/web/locales/or-IN.po +++ b/apps/web/locales/or-IN.po @@ -8,7 +8,7 @@ msgstr "" "Language: or\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Odia\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "କାଟାଲାନ୍" msgid "Center Align" msgstr "ମଧ୍ୟରେ ସଙ୍ଗୁଯୋଗ କରନ୍ତୁ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "ସେରେବ୍ରାସ୍" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "ଆୟାତ କରିବା ପାଇଁ ଫାଇଲ୍ ଚୟନ କ msgid "Close AI assistant" msgstr "AI ଆସିଷ୍ଟାଣ୍ଟ ବନ୍ଦ କରନ୍ତୁ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "କୋହେର" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "ଇଣ୍ଡେଣ୍ଟ କମାନ୍ତୁ" msgid "Decrease zoom" msgstr "ଜୁମ୍ କମାନ୍ତୁ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "ଡିପସିକ୍" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "ଡିଗ୍ରୀ" @@ -1885,6 +1897,10 @@ msgstr "ଦୁର୍ବଳ ବୁଲେଟ୍ ଖୋଜନ୍ତୁ ଏବଂ msgid "Finnish" msgstr "ଫିନିଶ୍" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "ଆତସବାଜି" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "ଦେଖିବା ପାଇଁ ଫିଟ୍" @@ -2072,6 +2088,10 @@ msgstr "ଗ୍ରୀକ୍" msgid "Grid" msgstr "ଗ୍ରିଡ୍ (Grid)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "ଗ୍ରୋକ୍" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "ଟିମ୍‌କୁ ବଢ଼ାନ୍ତୁ" @@ -2271,6 +2291,10 @@ msgstr "ଆପଣଙ୍କ ରେଜ୍ୟୁମେ ଆୟାତ ହେଉଛି msgid "Importing…" msgstr "ଆମଦାନି କରାଯାଉଛି…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "ରେଜ୍ୟୁମେ ହେଡର୍ ଅନ୍ତର୍ଭୁକ୍ତ କରନ୍ତୁ" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "ଇଣ୍ଡେଣ୍ଟ ବୃଦ୍ଧି କରନ୍ତୁ" @@ -2574,11 +2598,6 @@ msgstr "ତାଲିକା (List)" msgid "Lithuanian" msgstr "ଲିଥୁଆନିଆନ୍" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} ଟେମ୍ପଲେଟରେ ଆପଣଙ୍କ ରିଜ୍ୟୁମର ଲାଇଭ୍ ପ୍ରିଭ୍ୟୁ" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "AI ପ୍ରଦାନକାରୀଙ୍କୁ ଲୋଡ୍ କରାଯାଉଛି। ଦୟାକରି କିଛି ସମୟ ମଧ୍ୟରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।" @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "କାର୍ଯ୍ୟକ୍ଷମ ରିଜ୍ୟୁମ୍ ଉପଲବ୍ଧ ନାହିଁ" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "ମିଷ୍ଟ୍ରାଲ୍ ଏଆଇ" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "ମଡେଲ୍" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "ଓଡ଼ିଆ" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "ଓଲାମା କ୍ଲାଉଡ୍" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "ଅବଧି" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "ଦ୍ୱନ୍ଦ୍ୱ" + #: src/libs/locale.ts msgid "Persian" msgstr "ପର୍ସିଆନ୍" @@ -3838,6 +3865,10 @@ msgstr "ପାସୱାର୍ଡ ଦେଖାନ୍ତୁ" msgid "Show picture" msgstr "ଚିତ୍ର ଦେଖାନ୍ତୁ" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "କଭର ଲେଟରରେ ସମାନ ପ୍ରଥମ ପୃଷ୍ଠା ହେଡର ଦେଖାନ୍ତୁ।" + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "ଶିରୋନାମା" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "ଆପଣଙ୍କ ଆକାଉଣ୍ଟ ବିଲୋପ କରିବା ପାଇଁ, ଆପଣକୁ ନିଶ୍ଚିତିକରଣ ପାଠ୍ୟ ପ୍ରବେଶ କରି ତଳେ ଥିବା ବଟନ୍‌କୁ କ୍ଲିକ୍ କରିବାକୁ ପଡିବ।" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "ଏକାଠି.ଆଇ" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "ଏକ ଗୁଳିର ମୂଲ୍ୟ |" msgid "X (Twitter)" msgstr "X (ଟ୍ୱିଟର)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI ଗ୍ରୋକ୍" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "ହଁ, Reactive Resume ଅନେକ ଭାଷାରେ ଉପଲବ୍ଧ। ଆପଣ ସେଟିଂସ୍ ପେଜ୍‌ରେ, କିମ୍ବା ଡାହାଣ ପର୍ଯ୍ୟନ୍ତ ଉପର କୋଣରେ ଥିବା ଭାଷା ସ୍ୱିଚ୍‌ର ବ୍ୟବହାର କରି ପସନ୍ଦକ୍ରାତ ଭାଷା ଚୟନ କରିପାରିବେ। ଯଦି ଆପଣ ଆପଣଙ୍କ ଭାଷାକୁ ଦେଖୁନଥିବେ, କିମ୍ବା ଅବସ୍ଥିତ ଅନୁବାଦଗୁଡିକୁ ଉନ୍ନତ କରିବାକୁ ଚାହାଁନ୍ତି, ତେବେ ଆପଣ <0>Crowdin ରେ ଅନୁବାଦଗୁଡିକୁ ଅବଦାନ ଦେଇପାରିବେ<1> (ନୂତନ ଟାବ୍‌ରେ ଖୋଲେ)।" diff --git a/apps/web/locales/pl-PL.po b/apps/web/locales/pl-PL.po index 0bf6102de..ebfa0c04e 100644 --- a/apps/web/locales/pl-PL.po +++ b/apps/web/locales/pl-PL.po @@ -8,7 +8,7 @@ msgstr "" "Language: pl\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Polish\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" @@ -758,6 +758,10 @@ msgstr "Kataloński" msgid "Center Align" msgstr "Wyrównaj do środka" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Mózgi" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Kliknij tutaj, aby wybrać plik do importu" msgid "Close AI assistant" msgstr "Zamknij asystenta AI" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Przystać do siebie" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Zmniejsz wcięcie" msgid "Decrease zoom" msgstr "Zmniejsz powiększenie" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Głębokie poszukiwania" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Stopień" @@ -1885,6 +1897,10 @@ msgstr "Znajdź słabe punkty i przepisz je, podając mocniejsze wyniki, liczby, msgid "Finnish" msgstr "Fiński" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Fajerwerki" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Dopasuj do widoku" @@ -2072,6 +2088,10 @@ msgstr "Grecki" msgid "Grid" msgstr "Siatka" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Rozszerz zespół" @@ -2271,6 +2291,10 @@ msgstr "Importowanie CV..." msgid "Importing…" msgstr "Importowanie…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Dołącz nagłówek CV" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Zwiększ wcięcie" @@ -2574,11 +2598,6 @@ msgstr "Lista" msgid "Lithuanian" msgstr "Litewski" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Podgląd na żywo Twojego CV w szablonie {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Ładowanie dostawców sztucznej inteligencji. Spróbuj ponownie za chwilę." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Brakuje CV" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Chmura Ollama" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Okres" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Zakłopotanie" + #: src/libs/locale.ts msgid "Persian" msgstr "Perski" @@ -3838,6 +3865,10 @@ msgstr "Proszę pokazać hasło" msgid "Show picture" msgstr "Pokaż zdjęcie" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Pokaż ten sam nagłówek pierwszej strony na liście motywacyjnym." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Tytuł" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Aby usunąć konto, wpisz tekst potwierdzający i kliknij przycisk poniżej." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Razem.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Warto spróbować" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Tak, Reactive Resume jest dostępne w wielu językach. Możesz wybrać preferowany język na stronie ustawień lub za pomocą przełącznika języka w prawym górnym rogu. Jeśli nie widzisz swojego języka lub chcesz ulepszyć istniejące tłumaczenia, możesz <0>współtworzyć tłumaczenia na Crowdin<1> (otwiera się w nowej karcie)." diff --git a/apps/web/locales/pt-BR.po b/apps/web/locales/pt-BR.po index fcf58bcf6..3e2961a11 100644 --- a/apps/web/locales/pt-BR.po +++ b/apps/web/locales/pt-BR.po @@ -8,7 +8,7 @@ msgstr "" "Language: pt\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Portuguese, Brazilian\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Catalão" msgid "Center Align" msgstr "Alinhar ao centro" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cérebros" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Clique aqui para selecionar um arquivo para importar" msgid "Close AI assistant" msgstr "Fechar assistente de IA" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Coerência" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Diminuir recuo" msgid "Decrease zoom" msgstr "Diminuir o zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Grau" @@ -1885,6 +1897,10 @@ msgstr "Identifique os pontos fracos e reescreva-os com resultados mais impactan msgid "Finnish" msgstr "Finlandês" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Fogos de artifício" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Adequado para visualização" @@ -2072,6 +2088,10 @@ msgstr "Grego" msgid "Grid" msgstr "Grid" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Aumentar a equipe" @@ -2271,6 +2291,10 @@ msgstr "Importando seu currículo..." msgid "Importing…" msgstr "Importando…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Incluir cabeçalho do currículo" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Aumentar recuo" @@ -2574,11 +2598,6 @@ msgstr "Lista" msgid "Lithuanian" msgstr "Lituano" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Pré-visualização em tempo real do seu currículo no modelo {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Carregando provedores de IA. Tente novamente em instantes." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Currículo de trabalho ausente" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "IA Mistral" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modelo" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Nuvem de Ollama" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Período" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Perplexidade" + #: src/libs/locale.ts msgid "Persian" msgstr "Persa" @@ -3838,6 +3865,10 @@ msgstr "Mostrar senha" msgid "Show picture" msgstr "Mostrar imagem" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Mostrar o mesmo cabeçalho da primeira página na carta de apresentação." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Título" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Para excluir sua conta, você precisa inserir o texto de confirmação e clicar no botão abaixo." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Juntos.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Vale a pena tentar" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Sim, o Reactive Resume está disponível em vários idiomas. Você pode escolher seu idioma preferido na página de configurações ou usando o seletor de idioma no canto superior direito. Se você não encontrar seu idioma ou quiser melhorar as traduções existentes, você pode <0>contribuir com as traduções no Crowdin<1> (abre em nova aba)." diff --git a/apps/web/locales/pt-PT.po b/apps/web/locales/pt-PT.po index 29998688f..c6d240958 100644 --- a/apps/web/locales/pt-PT.po +++ b/apps/web/locales/pt-PT.po @@ -8,7 +8,7 @@ msgstr "" "Language: pt\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Portuguese\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Catalão" msgid "Center Align" msgstr "Alinhar ao centro" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cérebros" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Clique aqui para selecionar um ficheiro para importar" msgid "Close AI assistant" msgstr "Fechar assistente de IA" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Coerência" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Diminuir recuo" msgid "Decrease zoom" msgstr "Diminuir o zoom" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Grau" @@ -1885,6 +1897,10 @@ msgstr "Identifique os pontos fracos e reescreva-os com resultados mais impactan msgid "Finnish" msgstr "Finlandês" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Fogos de artifício" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Adequado para visualização" @@ -2072,6 +2088,10 @@ msgstr "Grego" msgid "Grid" msgstr "Grelha" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Fazer crescer a equipa" @@ -2271,6 +2291,10 @@ msgstr "A importar o seu currículo..." msgid "Importing…" msgstr "Importando…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Incluir cabeçalho do CV" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Aumentar recuo" @@ -2574,11 +2598,6 @@ msgstr "Lista" msgid "Lithuanian" msgstr "Lituano" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Pré-visualização em tempo real do seu currículo no modelo {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Carregando fornecedores de IA. Tente novamente dentro de instantes." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Currículo de trabalho ausente" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "IA Mistral" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modelo" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Nuvem de Ollama" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Período" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Perplexidade" + #: src/libs/locale.ts msgid "Persian" msgstr "Persa" @@ -3838,6 +3865,10 @@ msgstr "Mostrar palavra-passe" msgid "Show picture" msgstr "Mostrar imagem" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Mostrar o mesmo cabeçalho da primeira página na carta de apresentação." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Título" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Para eliminar a sua conta, tem de introduzir o texto de confirmação e clicar no botão abaixo." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Juntos.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Vale a pena tentar" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Sim, o Reactive Resume está disponível em vários idiomas. Pode escolher o seu idioma preferido na página de configurações ou utilizando o seletor de idioma no canto superior direito. Se não vir o seu idioma ou quiser melhorar as traduções existentes, pode <0>contribuir para as traduções no Crowdin<1> (abre num novo separador)." diff --git a/apps/web/locales/ro-RO.po b/apps/web/locales/ro-RO.po index 12ca3d42c..b156851f6 100644 --- a/apps/web/locales/ro-RO.po +++ b/apps/web/locales/ro-RO.po @@ -8,7 +8,7 @@ msgstr "" "Language: ro\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Romanian\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100>0 && n%100<20)) ? 1 : 2);\n" @@ -758,6 +758,10 @@ msgstr "Catalană" msgid "Center Align" msgstr "Aliniere la centru" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cerebra" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Faceți clic aici pentru a selecta un fișier de importat" msgid "Close AI assistant" msgstr "Închide asistentul AI" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Coerență" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Micșorează indentarea" msgid "Decrease zoom" msgstr "Reduceți zoomul" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Căutare profundă" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Diplomă" @@ -1885,6 +1897,10 @@ msgstr "Găsește punctele slabe și rescrie-le cu rezultate, numere, domenii de msgid "Finnish" msgstr "Finlandeză" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Focuri de artificii" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Potrivire pentru vizualizare" @@ -2072,6 +2088,10 @@ msgstr "Greacă" msgid "Grid" msgstr "Grilă" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Extinde echipa" @@ -2271,6 +2291,10 @@ msgstr "Se importă CV-ul..." msgid "Importing…" msgstr "Importarea…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Include antetul CV-ului" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Măriți indentarea" @@ -2574,11 +2598,6 @@ msgstr "Listă" msgid "Lithuanian" msgstr "Lituaniană" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Previzualizare live a CV-ului dvs. în șablonul {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Se încarcă furnizorii de inteligență artificială. Vă rugăm să încercați din nou imediat." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "CV de lucru lipsă" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Norul Ollama" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Perioadă" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Perplexitate" + #: src/libs/locale.ts msgid "Persian" msgstr "Persană" @@ -3838,6 +3865,10 @@ msgstr "Afișați parola" msgid "Show picture" msgstr "Afișați imaginea" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Afișează același antet de primă pagină și pe scrisoarea de intenție." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Titlu" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Pentru a vă șterge contul, trebuie să introduceți textul de confirmare și să faceți clic pe butonul de mai jos." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Împreună.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Merită o șansă" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Da, Reactive Resume este disponibil în mai multe limbi. Puteți alege limba preferată în pagina de setări sau folosind comutatorul de limbă din colțul din dreapta sus. Dacă nu vedeți limba dvs. sau doriți să îmbunătățiți traducerile existente, puteți <0>contribui la traduceri pe Crowdin<1> (se deschide într-o filă nouă)." diff --git a/apps/web/locales/ru-RU.po b/apps/web/locales/ru-RU.po index cb4f11621..d69740082 100644 --- a/apps/web/locales/ru-RU.po +++ b/apps/web/locales/ru-RU.po @@ -8,7 +8,7 @@ msgstr "" "Language: ru\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Russian\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" @@ -758,6 +758,10 @@ msgstr "Каталанский" msgid "Center Align" msgstr "Выровнять по центру" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Мозги" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Нажмите здесь, чтобы выбрать файл для и msgid "Close AI assistant" msgstr "Закрыть ИИ-помощника" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Когере" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Уменьшить отступ" msgid "Decrease zoom" msgstr "Уменьшить масштаб" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Степень" @@ -1885,6 +1897,10 @@ msgstr "Найдите слабые пункты и переформулируй msgid "Finnish" msgstr "Финский" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Фейерверк" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Подходит для просмотра" @@ -2072,6 +2088,10 @@ msgstr "Греческий" msgid "Grid" msgstr "Плитка" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Грок" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Расширить команду" @@ -2271,6 +2291,10 @@ msgstr "Импорт вашего резюме..." msgid "Importing…" msgstr "Импорт…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Добавить заголовок резюме" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Увеличить отступ" @@ -2574,11 +2598,6 @@ msgstr "Список" msgid "Lithuanian" msgstr "Литовский" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Предварительный просмотр вашего резюме в шаблоне {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Загрузка поставщиков ИИ. Пожалуйста, попробуйте еще раз через минуту." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Отсутствует резюме с места работы." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Модель" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Ория" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Оллама" +msgid "Ollama Cloud" +msgstr "Облако Алламы" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Период" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Замешательство" + #: src/libs/locale.ts msgid "Persian" msgstr "Персидский" @@ -3838,6 +3865,10 @@ msgstr "Показать пароль" msgid "Show picture" msgstr "Показать картинку" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Показывать тот же заголовок первой страницы в сопроводительном письме." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Название" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Чтобы удалить учетную запись, вам нужно ввести текст подтверждения и нажать кнопку ниже." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Стоит попробовать" msgid "X (Twitter)" msgstr "X (Твиттер)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Да, Reactive Resume доступен на нескольких языках. Вы можете выбрать предпочитаемый язык на странице настроек или с помощью переключателя языка в правом верхнем углу. Если вы не видите свой язык или хотите улучшить существующие переводы, вы можете <0>поучаствовать в переводах на Crowdin<1> (открывается в новой вкладке)." diff --git a/apps/web/locales/sk-SK.po b/apps/web/locales/sk-SK.po index 08c19f574..dcb483cda 100644 --- a/apps/web/locales/sk-SK.po +++ b/apps/web/locales/sk-SK.po @@ -8,7 +8,7 @@ msgstr "" "Language: sk\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Slovak\n" "Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3;\n" @@ -758,6 +758,10 @@ msgstr "Katalánčina" msgid "Center Align" msgstr "Zarovnať na stred" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Mozgy" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Kliknutím sem vyber súbor na import" msgid "Close AI assistant" msgstr "Zatvoriť asistenta s umelou inteligenciou" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Súdržnosť" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Zmenšiť odsadenie" msgid "Decrease zoom" msgstr "Zmenšiť priblíženie" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Hlboké vyhľadávanie" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Titul" @@ -1885,6 +1897,10 @@ msgstr "Nájdite slabé odrážky a prepíšte ich so silnejšími výsledkami, msgid "Finnish" msgstr "Fínčina" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Ohňostroj" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Prispôsobiť zobrazeniu" @@ -2072,6 +2088,10 @@ msgstr "Gréčtina" msgid "Grid" msgstr "Mriežka" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Rozšíriť tím" @@ -2271,6 +2291,10 @@ msgstr "Importujem tvoj životopis..." msgid "Importing…" msgstr "Importuje sa…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Zahrnúť hlavičku životopisu" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Zväčšiť odsadenie" @@ -2574,11 +2598,6 @@ msgstr "Zoznam" msgid "Lithuanian" msgstr "Litovčina" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Živý náhľad vášho životopisu v šablóne {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Načítavajú sa poskytovatelia umelej inteligencie. Skúste to znova o chvíľu." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Chýbajúci pracovný životopis" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Urijčina" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Cloud" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Obdobie" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Zmätok" + #: src/libs/locale.ts msgid "Persian" msgstr "Perzština" @@ -3838,6 +3865,10 @@ msgstr "Zobraziť heslo" msgid "Show picture" msgstr "Zobraziť obrázok" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Zobraziť rovnakú hlavičku prvej strany aj v motivačnom liste." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Názov" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Na vymazanie účtu musíš zadať potvrdzujúci text a kliknúť na tlačidlo nižšie." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Spolu.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Stojí za to" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Áno, Reactive Resume je dostupné vo viacerých jazykoch. Uprednostňovaný jazyk si môžeš zvoliť na stránke nastavení alebo pomocou prepínača jazykov v pravom hornom rohu. Ak svoj jazyk nevidíš alebo chceš zlepšiť existujúce preklady, môžeš <0>prispieť k prekladom na Crowdin<1> (otvorí sa na novej karte)." diff --git a/apps/web/locales/sl-SI.po b/apps/web/locales/sl-SI.po index 2a97c69f1..739dead17 100644 --- a/apps/web/locales/sl-SI.po +++ b/apps/web/locales/sl-SI.po @@ -8,7 +8,7 @@ msgstr "" "Language: sl\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Slovenian\n" "Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;\n" @@ -758,6 +758,10 @@ msgstr "Katalonščina" msgid "Center Align" msgstr "Poravnava na sredino" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cerebras" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Kliknite tukaj za izbiro datoteke za uvoz" msgid "Close AI assistant" msgstr "Zapri pomočnika umetne inteligence" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Skladno" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Zmanjšaj zamik" msgid "Decrease zoom" msgstr "Zmanjšaj povečavo" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Globoko iskanje" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Stopnja" @@ -1885,6 +1897,10 @@ msgstr "Poiščite šibke točke in jih preoblikujte z močnejšimi rezultati, msgid "Finnish" msgstr "Finščina" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Ognjemet" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Prilagodi pogledu" @@ -2072,6 +2088,10 @@ msgstr "Grščina" msgid "Grid" msgstr "Mreža" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Povečaj ekipo" @@ -2271,6 +2291,10 @@ msgstr "Uvažanje vašega življenjepisa..." msgid "Importing…" msgstr "Uvažanje…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Vključi glavo življenjepisa" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Povečaj zamik" @@ -2574,11 +2598,6 @@ msgstr "Seznam" msgid "Lithuanian" msgstr "Litovščina" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Predogled vašega življenjepisa v živo v predlogi {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Nalaganje ponudnikov umetne inteligence. Poskusite znova čez trenutek." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Manjka delovni življenjepis" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "odijščina" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Cloud" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Obdobje" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Zmedenost" + #: src/libs/locale.ts msgid "Persian" msgstr "perzijščina" @@ -3838,6 +3865,10 @@ msgstr "Prikaži geslo" msgid "Show picture" msgstr "Prikaži sliko" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Prikaži enako glavo prve strani tudi na spremnem pismu." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Naziv" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Za izbris računa morate vnesti potrditveno besedilo in klikniti spodnji gumb." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Skupaj.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Vredno poskusiti" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Da, Reactive Resume je na voljo v več jezikih. Želeni jezik lahko izberete na strani z nastavitvami ali z izbirnikom jezika v zgornjem desnem kotu. Če svojega jezika ne najdete ali bi želeli izboljšati obstoječe prevode, lahko <0>prispevate prevode na Crowdin<1> (odpre se v novem zavihku)." diff --git a/apps/web/locales/sq-AL.po b/apps/web/locales/sq-AL.po index a736740e3..650204e71 100644 --- a/apps/web/locales/sq-AL.po +++ b/apps/web/locales/sq-AL.po @@ -8,7 +8,7 @@ msgstr "" "Language: sq\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Albanian\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Katalanisht" msgid "Center Align" msgstr "Rreshto në qendër" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cerebras" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Klikoni këtu për të zgjedhur një skedar për importim" msgid "Close AI assistant" msgstr "Mbyll asistentin e inteligjencës artificiale" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Koherë" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Zvogëlo indentin" msgid "Decrease zoom" msgstr "Zvogëlo zmadhimin" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Kërkim i thellë" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Diploma" @@ -1885,6 +1897,10 @@ msgstr "Gjej pikat e dobëta dhe rishkruani ato me rezultate, numra, fushëvepri msgid "Finnish" msgstr "Finlandisht" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Fishekzjarre" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "I përshtatshëm për t’u parë" @@ -2072,6 +2088,10 @@ msgstr "Greqisht" msgid "Grid" msgstr "Rrjetë" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Zmadho ekipin" @@ -2271,6 +2291,10 @@ msgstr "Po importohet CV-ja juaj..." msgid "Importing…" msgstr "Duke importuar…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Përfshi kokën e CV-së" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Rrit indentin" @@ -2574,11 +2598,6 @@ msgstr "Listë" msgid "Lithuanian" msgstr "Lituanisht" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Pamje paraprake e drejtpërdrejtë e CV-së suaj në shabllonin {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Duke ngarkuar ofruesit e inteligjencës artificiale. Ju lutemi provoni përsëri pas pak." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Mungon CV-ja e punës" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modeli" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Reja Ollama" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Periudha" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Hutim" + #: src/libs/locale.ts msgid "Persian" msgstr "Persisht" @@ -3838,6 +3865,10 @@ msgstr "Shfaq fjalëkalimin" msgid "Show picture" msgstr "Shfaq foton" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Shfaq të njëjtën kokë të faqes së parë edhe në letrën motivuese." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Titulli" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Për të fshirë llogarinë tuaj, duhet të shkruani tekstin e konfirmimit dhe të klikoni butonin më poshtë." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Së bashku.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Ia vlen një gjuajtje" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Po, Reactive Resume është i disponueshëm në shumë gjuhë. Mund të zgjidhni gjuhën tuaj të preferuar në faqen e parametrave, ose duke përdorur zgjedhësin e gjuhës në këndin e sipërm djathtas. Nëse nuk e shihni gjuhën tuaj, ose dëshironi të përmirësoni përkthimet ekzistuese, mund të <0>kontribuoni për përkthimet në Crowdin<1> (hapet në skedë të re)." diff --git a/apps/web/locales/sr-SP.po b/apps/web/locales/sr-SP.po index cee246ae4..4f0ca0c66 100644 --- a/apps/web/locales/sr-SP.po +++ b/apps/web/locales/sr-SP.po @@ -8,7 +8,7 @@ msgstr "" "Language: sr\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Serbian (Cyrillic)\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" @@ -758,6 +758,10 @@ msgstr "Каталонски" msgid "Center Align" msgstr "Поравнај по средини" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Церебрас" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Кликните овде да изаберете датотеку за msgid "Close AI assistant" msgstr "Затвори AI асистент" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Кохерентно" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Смањи увлачење" msgid "Decrease zoom" msgstr "Смањи зумирање" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "ДипСеек" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Степен" @@ -1885,6 +1897,10 @@ msgstr "Пронађите слабе тачке и препишите их са msgid "Finnish" msgstr "Фински" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Ватромет" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Прилагоди приказу" @@ -2072,6 +2088,10 @@ msgstr "Грчки" msgid "Grid" msgstr "Мрежа" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Грок" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Прошири тим" @@ -2271,6 +2291,10 @@ msgstr "Увоз вашег резимеа..." msgid "Importing…" msgstr "Увоз…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Укључи заглавље резимеа" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Повећај увлачење" @@ -2574,11 +2598,6 @@ msgstr "Листа" msgid "Lithuanian" msgstr "Литвански" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Преглед вашег животописа уживо у шаблону {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Учитавање добављача вештачке интелигенције. Молимо покушајте поново за тренутак." @@ -2698,6 +2717,10 @@ msgstr "Микрософт Ворд" msgid "Missing working resume" msgstr "Недостаје радни животопис" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Мистрал АИ" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Модел" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Одија" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Оллама" +msgid "Ollama Cloud" +msgstr "Олама Клауд" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "ПДФ" msgid "Period" msgstr "Период" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Збуњеност" + #: src/libs/locale.ts msgid "Persian" msgstr "Персијски" @@ -3838,6 +3865,10 @@ msgstr "Прикажи лозинку" msgid "Show picture" msgstr "Прикажи слику" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Прикажи исто заглавље прве стране и на пропратном писму." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Наслов" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Да бисте обрисали свој налог, потребно је да унесете потврдни текст и кликнете на дугме испод." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Заједно.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Вреди покушати" msgid "X (Twitter)" msgstr "X (Твитер)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Грок" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Да, Реактивни Резиме је доступан на више језика. Омиљени језик можете изабрати на страници подешавања или помоћу прекидача језика у горњем десном углу. Ако не видите свој језик или желите да побољшате постојеће преводе, можете <0>допринети преводима на Crowdin-у<1> (отвара се у новом језичку)." diff --git a/apps/web/locales/sv-SE.po b/apps/web/locales/sv-SE.po index 5396fdb41..2ff55dc79 100644 --- a/apps/web/locales/sv-SE.po +++ b/apps/web/locales/sv-SE.po @@ -8,7 +8,7 @@ msgstr "" "Language: sv\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Swedish\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Katalanska" msgid "Center Align" msgstr "Centrera" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Cerebras" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Klicka här för att välja en fil att importera" msgid "Close AI assistant" msgstr "Stäng AI-assistenten" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Sammanhängande" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Minska indrag" msgid "Decrease zoom" msgstr "Minska zoomen" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Examen" @@ -1885,6 +1897,10 @@ msgstr "Hitta svaga punkter och skriv om dem med starkare utfall, siffror, omfat msgid "Finnish" msgstr "Finska" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Fyrverkeri" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Anpassa för visning" @@ -2072,6 +2088,10 @@ msgstr "Grekiska" msgid "Grid" msgstr "Rutnät" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Väx teamet" @@ -2271,6 +2291,10 @@ msgstr "Importerar ditt CV..." msgid "Importing…" msgstr "Importerar…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Inkludera CV-sidhuvud" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Öka indraget" @@ -2574,11 +2598,6 @@ msgstr "Lista" msgid "Lithuanian" msgstr "Litauiska" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Förhandsvisning av ditt CV i realtid i mallen {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Laddar AI-leverantörer. Försök igen om en stund." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Saknar arbets-CV" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Modell" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama-molnet" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Period" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Bryderi" + #: src/libs/locale.ts msgid "Persian" msgstr "Persiska" @@ -3838,6 +3865,10 @@ msgstr "Visa lösenord" msgid "Show picture" msgstr "Visa bild" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Visa samma förstasidshuvud på det personliga brevet." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Titel" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "För att radera ditt konto måste du ange bekräftelsetexten och klicka på knappen nedan." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Tillsammans.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Värt ett försök" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Ja, Reactive Resume finns på flera språk. Du kan välja ditt föredragna språk på inställningssidan eller med språkväljaren uppe till höger. Om du inte ser ditt språk, eller vill förbättra de befintliga översättningarna, kan du <0>bidra till översättningarna på Crowdin<1> (öppnas i ny flik)." diff --git a/apps/web/locales/ta-IN.po b/apps/web/locales/ta-IN.po index 80595ef06..9383101af 100644 --- a/apps/web/locales/ta-IN.po +++ b/apps/web/locales/ta-IN.po @@ -8,7 +8,7 @@ msgstr "" "Language: ta\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Tamil\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "கட்டலான்" msgid "Center Align" msgstr "நடுவில் சீரமை" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "பெருமூளைகள்" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "இறக்குமதி செய்ய ஒரு கோப்பை msgid "Close AI assistant" msgstr "AI உதவியாளரை மூடு" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "கோஹியர்" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "உள் தள்ளலைக் குறைக்கவும்" msgid "Decrease zoom" msgstr "ஜூம் அளவைக் குறைக்கவும்" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "டீப்சீக்" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "பட்டம்" @@ -1885,6 +1897,10 @@ msgstr "பலவீனமான அம்சங்களைக் கண்ட msgid "Finnish" msgstr "ஃபின்னிஷ்" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "பட்டாசுகள்" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "பார்வைக்கு ஏற்றது" @@ -2072,6 +2088,10 @@ msgstr "கிரேக்கம்" msgid "Grid" msgstr "கட்டம்" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "க்ரோக்" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "அணியை வளர்த்தெடுக்கவும்" @@ -2271,6 +2291,10 @@ msgstr "உங்கள் ரெஸ்யூமியை இறக்கும msgid "Importing…" msgstr "… இறக்குமதி செய்கிறது" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "சுயவிவரத் தலைப்பைச் சேர்க்கவும்" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "உள் தள்ளலை அதிகரிக்கவும்" @@ -2574,11 +2598,6 @@ msgstr "பட்டியல்" msgid "Lithuanian" msgstr "லிதுவேனியன்" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} டெம்ப்ளேட்டில் உங்கள் ரெஸ்யூமேயின் நேரடி முன்னோட்டம்" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "செயற்கை நுண்ணறிவு வழங்குநர்கள் ஏற்றப்படுகின்றன. தயவுசெய்து சிறிது நேரத்தில் மீண்டும் முயற்சிக்கவும்." @@ -2698,6 +2717,10 @@ msgstr "மைக்ரோசாஃப்ட் வேர்ட்" msgid "Missing working resume" msgstr "வேலைக்கான ரெஸ்யூம் காணவில்லை" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "மிஸ்ட்ரல் ஏஐ" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "மாதிரி" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "ஒடியா" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "ஓல்லாமா" +msgid "Ollama Cloud" +msgstr "ஒல்லாமா கிளவுட்" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "பிடிஎஃப்" msgid "Period" msgstr "காலம்" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "குழப்பம்" + #: src/libs/locale.ts msgid "Persian" msgstr "பேர்ஷியன்" @@ -3838,6 +3865,10 @@ msgstr "கடவுச்சொல்லைக் காட்டு" msgid "Show picture" msgstr "படத்தைக் காட்டு" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "கவர் லெட்டரிலும் அதே முதல் பக்க தலைப்பைக் காட்டு." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "தலைப்பு" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "உங்கள் கணக்கை நீக்க, கீழே உள்ள உறுதிப்படுத்தல் உரையை உள்ளீடு செய்து, கீழே உள்ள பொத்தானை கிளிக் செய்ய வேண்டும்." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "ஒரு ஷாட் மதிப்பு" msgid "X (Twitter)" msgstr "X (ட்விட்டர்)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI க்ரோக்" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "ஆம், Reactive Resume பல மொழிகளில் கிடைக்கிறது. நீங்கள் அமைப்புகள் பக்கத்தில், அல்லது மேல் வலது மூலையில் உள்ள மொழி மாற்றியைப் பயன்படுத்தி உங்கள் விருப்பமான மொழியைத் தேர்ந்தெடுக்கலாம். உங்கள் மொழி பட்டியலில் தெரியவில்லையெனில், அல்லது ஏற்கனவே உள்ள மொழிபெயர்ப்புகளை மேம்படுத்த விரும்பினால், நீங்கள் <0>Crowdin-ல் உள்ள மொழிபெயர்ப்புகளுக்கு பங்களிக்கலாம்<1> (புதிய தாவலில் திறக்கிறது)." diff --git a/apps/web/locales/te-IN.po b/apps/web/locales/te-IN.po index baf1e1773..f74618f4d 100644 --- a/apps/web/locales/te-IN.po +++ b/apps/web/locales/te-IN.po @@ -8,7 +8,7 @@ msgstr "" "Language: te\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Telugu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "కాటలాన్" msgid "Center Align" msgstr "మద్యAlign" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "సెరెబ్రాస్" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "ఇంపోర్ట్ చేయడానికి ఫైల్ ను msgid "Close AI assistant" msgstr "AI సహాయకుడిని మూసివేయండి" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "పొందికగా" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "ఇండెంట్‌ను తగ్గించండి" msgid "Decrease zoom" msgstr "జూమ్‌ను తగ్గించండి" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "డీప్‌సీక్" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "డిగ్రీ" @@ -1885,6 +1897,10 @@ msgstr "బలహీనమైన అంశాలను గుర్తించ msgid "Finnish" msgstr "ఫిన్నిష్" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "బాణసంచా" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "వీక్షించడానికి సరిపోతుంది" @@ -2072,6 +2088,10 @@ msgstr "గ్రీకు" msgid "Grid" msgstr "గ్రిడ్" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "గ్రోక్" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "సమితిని అభివృద్ధి చేయండి" @@ -2271,6 +2291,10 @@ msgstr "మీ రిజ్యూమ్‌ను ఇంపోర్ట్ చే msgid "Importing…" msgstr "… దిగుమతి అవుతోంది" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "రెజ్యూమే హెడర్‌ను చేర్చండి" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "ఇండెంట్‌ను పెంచండి" @@ -2574,11 +2598,6 @@ msgstr "జాబితా" msgid "Lithuanian" msgstr "లిథువేనియన్" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} టెంప్లేట్‌లో మీ రెజ్యూమె యొక్క లైవ్ ప్రివ్యూ" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "AI ప్రొవైడర్లు లోడ్ అవుతున్నాయి. దయచేసి కాసేపటి తర్వాత మళ్ళీ ప్రయత్నించండి." @@ -2698,6 +2717,10 @@ msgstr "మైక్రోసాఫ్ట్ వర్డ్" msgid "Missing working resume" msgstr "తప్పిపోయిన వర్కింగ్ రెజ్యూమె" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "మిస్ట్రాల్ AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "మోడల్" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "ఒడియా" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "ఓల్లామా" +msgid "Ollama Cloud" +msgstr "ఒల్లామా క్లౌడ్" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "పిడిఎఫ్" msgid "Period" msgstr "కాలము" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "గందరగోళం" + #: src/libs/locale.ts msgid "Persian" msgstr "పర్షియన్" @@ -3838,6 +3865,10 @@ msgstr "పాస్‌వర్డ్ చూపించు" msgid "Show picture" msgstr "చిత్రాన్ని చూపించు" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "కవర్ లెటర్‌పై కూడా అదే మొదటి పేజీ హెడర్‌ను చూపించు." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "టైటిల్" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "మీ ఖాతాను తొలగించడానికి, కన్ఫర్మేషన్ టెక్స్ట్ ఇవ్వండి మరియు క్రింద ఉన్న బటన్‌ను నొక్కండి." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "కలిసి.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "ప్రయత్నించదగ్గది" msgid "X (Twitter)" msgstr "X (ట్విట్టర్)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI గ్రోక్" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "అవును, Reactive Resume అనేక భాషల్లో అందుబాటులో ఉంది. మీరు సెట్టింగ్స్ పేజీలో లేదా పై కోణంలో భాష మార్పిడి ద్వారా మీకు ఇష్టమైన భాషను ఎంచుకోవచ్చు. మీ భాష కనిపించకపోతే, లేకపోతే మీరు ప్రస్తుత అనువాదాలను మెరుగుపరచాలనుకుంటే, మీరు <0>Crowdinలో అనువాదాలకు ప్రయత్నించవచ్చు<1> (కొత్త ట్యాబ్‌లో తెరవబడుతుంది)." diff --git a/apps/web/locales/th-TH.po b/apps/web/locales/th-TH.po index 5e17f5371..a0d43338e 100644 --- a/apps/web/locales/th-TH.po +++ b/apps/web/locales/th-TH.po @@ -8,7 +8,7 @@ msgstr "" "Language: th\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Thai\n" "Plural-Forms: nplurals=1; plural=0;\n" @@ -758,6 +758,10 @@ msgstr "คาตาลัน" msgid "Center Align" msgstr "จัดกึ่งกลาง" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "เซเรบราส" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "คลิกที่นี่เพื่อเลือกไฟล์ msgid "Close AI assistant" msgstr "ปิดผู้ช่วย AI" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "โคฮีร์" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "ลดระยะห่าง" msgid "Decrease zoom" msgstr "ลดระดับการซูม" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "ดีพซีค" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "ปริญญา" @@ -1885,6 +1897,10 @@ msgstr "ค้นหาประเด็นสำคัญที่อ่อน msgid "Finnish" msgstr "ฟินแลนด์" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "ดอกไม้ไฟ" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "เหมาะสำหรับรับชม" @@ -2072,6 +2088,10 @@ msgstr "กรีก" msgid "Grid" msgstr "ตาราง" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "โกรค" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "ขยายทีม" @@ -2271,6 +2291,10 @@ msgstr "กำลังนำเข้าเรซูเม่ของคุณ msgid "Importing…" msgstr "กำลังนำเข้า…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "รวมส่วนหัวของเรซูเม่" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "เพิ่มระยะเยื้อง" @@ -2574,11 +2598,6 @@ msgstr "รายการ" msgid "Lithuanian" msgstr "ลิทัวเนีย" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "ดูตัวอย่างประวัติย่อของคุณแบบเรียลไทม์ในเทมเพลต {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "กำลังโหลดผู้ให้บริการ AI โปรดลองอีกครั้งในภายหลัง" @@ -2698,6 +2717,10 @@ msgstr "ไมโครซอฟต์ เวิร์ด" msgid "Missing working resume" msgstr "ประวัติการทำงานไม่ครบถ้วน" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "มิสทรัล AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "โมเดล" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "โอเดีย" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "โอลามา" +msgid "Ollama Cloud" +msgstr "โอลาม่าคลาวด์" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "ช่วงเวลา" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "ความสับสน" + #: src/libs/locale.ts msgid "Persian" msgstr "เปอร์เซีย" @@ -3838,6 +3865,10 @@ msgstr "แสดงรหัสผ่าน" msgid "Show picture" msgstr "แสดงรูปภาพ" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "แสดงส่วนหัวหน้าแรกเดียวกันบนจดหมายสมัครงาน" + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "ชื่อ" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "ในการลบบัญชีของคุณ กรุณากรอกข้อความยืนยันและคลิกปุ่มด้านล่าง" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "ทูธตี้.ไอ" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "น่าลอง" msgid "X (Twitter)" msgstr "X (ทวิตเตอร์)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "ใช่, Reactive Resume มีให้บริการหลายภาษา คุณสามารถเลือกภาษาที่คุณต้องการได้ในหน้าตั้งค่าหรือใช้ตัวสลับภาษาในมุมขวาบน หากคุณไม่เห็นภาษาของคุณ หรือหากคุณต้องการปรับปรุงคำแปลปัจจุบัน คุณสามารถ<0>ร่วมแปลบน Crowdin<1> (เปิดในแท็บใหม่) ได้" diff --git a/apps/web/locales/tr-TR.po b/apps/web/locales/tr-TR.po index 8c689c756..51df9e149 100644 --- a/apps/web/locales/tr-TR.po +++ b/apps/web/locales/tr-TR.po @@ -8,7 +8,7 @@ msgstr "" "Language: tr\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Turkish\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -758,6 +758,10 @@ msgstr "Katalanca" msgid "Center Align" msgstr "Ortala" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Beyinler" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "İçe aktarmak için bir dosya seçmek üzere buraya tıklayın" msgid "Close AI assistant" msgstr "Yapay zeka asistanını kapat" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Uyum" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Girintiyi azalt" msgid "Decrease zoom" msgstr "Yakınlaştırmayı azalt" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Derece" @@ -1885,6 +1897,10 @@ msgstr "Zayıf madde işaretlerini bulun ve daha güçlü sonuçlar, sayılar, k msgid "Finnish" msgstr "Fince" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Havai fişekler" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Görüntülemeye uygun" @@ -2072,6 +2088,10 @@ msgstr "Yunanca" msgid "Grid" msgstr "Izgara" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Ekibi Büyüt" @@ -2271,6 +2291,10 @@ msgstr "Özgeçmişiniz içe aktarılıyor..." msgid "Importing…" msgstr "… İçe Aktarılıyor" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Özgeçmiş başlığını dahil et" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Girintiyi artır" @@ -2574,11 +2598,6 @@ msgstr "Liste" msgid "Lithuanian" msgstr "Litvanca" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Özgeçmişinizin canlı önizlemesi {0} şablonunda" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Yapay zeka sağlayıcıları yükleniyor. Lütfen bir süre sonra tekrar deneyin." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Eksik iş özgeçmişi" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral Yapay Zeka" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odiya" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama Bulutu" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Dönem" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Şaşkınlık" + #: src/libs/locale.ts msgid "Persian" msgstr "Farsça" @@ -3838,6 +3865,10 @@ msgstr "Şifreyi göster" msgid "Show picture" msgstr "Resmi göster" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Ön yazıda da aynı ilk sayfa başlığını göster." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Başlık" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Hesabınızı silmek için onay metnini girmeniz ve aşağıdaki butona tıklamanız gerekir." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Birlikte.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Denemeye değer" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Evet, Reactive Özgeçmiş birçok dilde mevcuttur. Tercih ettiğiniz dili ayarlar sayfasından veya sağ üst köşedeki dil değiştiriciyi kullanarak seçebilirsiniz. Eğer dilinizi göremiyorsanız ya da mevcut çevirileri geliştirmek istiyorsanız, <0>Crowdin'de çevirilere katkıda bulunabilirsiniz<1> (yeni sekmede açılır)." diff --git a/apps/web/locales/uk-UA.po b/apps/web/locales/uk-UA.po index ca03f6224..53b3bdd4f 100644 --- a/apps/web/locales/uk-UA.po +++ b/apps/web/locales/uk-UA.po @@ -8,7 +8,7 @@ msgstr "" "Language: uk\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Ukrainian\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" @@ -758,6 +758,10 @@ msgstr "Каталонська" msgid "Center Align" msgstr "Вирівняти по центру" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Церебрас" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Натисніть тут, щоб вибрати файл для імп msgid "Close AI assistant" msgstr "Закрити помічника зі штучним інтелектом" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Зв'язати" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Зменшити відступ" msgid "Decrease zoom" msgstr "Зменшити масштаб" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Глибокий пошук" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Ступінь" @@ -1885,6 +1897,10 @@ msgstr "Знайдіть слабкі пункти та перепишіть ї msgid "Finnish" msgstr "Фінська" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Феєрверки" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Пристосувати до перегляду" @@ -2072,6 +2088,10 @@ msgstr "Грецька" msgid "Grid" msgstr "Сітка" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Грок" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Розширити команду" @@ -2271,6 +2291,10 @@ msgstr "Імпортуємо ваше резюме..." msgid "Importing…" msgstr "Імпорт…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Додати заголовок резюме" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Збільшити відступ" @@ -2574,11 +2598,6 @@ msgstr "Список" msgid "Lithuanian" msgstr "Литовська" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Попередній перегляд вашого резюме в шаблоні {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Завантаження постачальників ШІ. Будь ласка, спробуйте ще раз за мить." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Відсутнє робоче резюме" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Містраль ШІ" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Модель" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Одія" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Оллама." +msgid "Ollama Cloud" +msgstr "Хмара Оллама" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Період" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Збентеження" + #: src/libs/locale.ts msgid "Persian" msgstr "Перська" @@ -3838,6 +3865,10 @@ msgstr "Показати пароль" msgid "Show picture" msgstr "Показати зображення" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Показувати той самий заголовок першої сторінки в супровідному листі." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Назва" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Щоб видалити акаунт, введіть підтверджувальний текст і натисніть кнопку нижче." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Разом.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Варто спробувати" msgid "X (Twitter)" msgstr "Х (Твіттер)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Грок" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Так, Reactive Resume доступна багатьма мовами. Ви можете обрати бажану мову на сторінці налаштувань або через перемикач мови у верхньому правому кутку. Якщо ви не бачите своєї мови або хочете покращити існуючий переклад, ви можете <0>долучитися до перекладу на Crowdin<1> (відкриється у новій вкладці)." diff --git a/apps/web/locales/uz-UZ.po b/apps/web/locales/uz-UZ.po index 277728926..5885508c6 100644 --- a/apps/web/locales/uz-UZ.po +++ b/apps/web/locales/uz-UZ.po @@ -8,7 +8,7 @@ msgstr "" "Language: uz\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Uzbek\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" @@ -758,6 +758,10 @@ msgstr "Katalan tili" msgid "Center Align" msgstr "Markazda tekislash" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Miya" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Import qilish uchun faylni tanlash uchun shu yerni bosing" msgid "Close AI assistant" msgstr "Sun'iy intellekt yordamchisini yopish" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Cohere" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Xatcho'pni kamaytirish" msgid "Decrease zoom" msgstr "Masshtabni kichraytirish" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "DeepSeek" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Daraja" @@ -1885,6 +1897,10 @@ msgstr "Zaif o'qlarni toping va ularni kuchliroq natijalar, raqamlar, ko'lam va msgid "Finnish" msgstr "Fin tili" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Mushakbozlik" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Ko'rish uchun moslash" @@ -2072,6 +2088,10 @@ msgstr "Yunon tili" msgid "Grid" msgstr "Jadval" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Jamoani kengaytirish" @@ -2271,6 +2291,10 @@ msgstr "Rezyumengiz import qilinmoqda..." msgid "Importing…" msgstr "… import qilinmoqda" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Rezyume sarlavhasini qo‘shish" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Xoch chiziqni kattalashtirish" @@ -2574,11 +2598,6 @@ msgstr "Roʻyxat" msgid "Lithuanian" msgstr "Litva tili" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "{0} shablonida rezyumening jonli ko'rinishi" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Sun'iy intellekt provayderlari yuklanmoqda. Iltimos, bir zumda qayta urinib ko'ring." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Ishchi rezyume yo'q" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Mistral AI" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Model" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odiya tili" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Ollama buluti" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Davr" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Sarosimaga tushish" + #: src/libs/locale.ts msgid "Persian" msgstr "Fors tili" @@ -3838,6 +3865,10 @@ msgstr "Parolni ko'rsating" msgid "Show picture" msgstr "Rasmni ko'rsatish" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Xatda ham birinchi sahifadagi bir xil sarlavhani ko'rsatish." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Sarlavha" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Hisobingizni oʻchirish uchun tasdiqlash matnini kiriting va quyidagi tugmani bosing." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Sinab ko'rishga arziydi" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Ha, Reactive Resume bir nechta tillarda mavjud. Siz sozlamalar sahifasida yoki yuqori o'ng burchakdagi til almashtirgich yordamida o'zingizga qulay tilni tanlashingiz mumkin. Agar tilingiz ro'yxatda bo'lmasa yoki mavjud tarjimalarni yaxshilashni istasangiz, <0>Crowdin'da tarjimalarga hissa qo'shishingiz mumkin<1> (yangi tabda ochiladi)." diff --git a/apps/web/locales/vi-VN.po b/apps/web/locales/vi-VN.po index 372619c5c..e54e2ee2d 100644 --- a/apps/web/locales/vi-VN.po +++ b/apps/web/locales/vi-VN.po @@ -8,7 +8,7 @@ msgstr "" "Language: vi\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Vietnamese\n" "Plural-Forms: nplurals=1; plural=0;\n" @@ -758,6 +758,10 @@ msgstr "Tiếng Catalan" msgid "Center Align" msgstr "Căn giữa" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "Não bộ" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "Nhấn vào đây để chọn file cần nhập khẩu" msgid "Close AI assistant" msgstr "Trợ lý AI gần gũi" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "Liên kết" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "Giảm độ thụt lề" msgid "Decrease zoom" msgstr "Giảm độ phóng to" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "Tìm kiếm sâu" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "Bằng cấp" @@ -1885,6 +1897,10 @@ msgstr "Hãy tìm những gạch đầu dòng yếu và viết lại chúng vớ msgid "Finnish" msgstr "Tiếng Phần Lan" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "Pháo hoa" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "Phù hợp để xem" @@ -2072,6 +2088,10 @@ msgstr "Tiếng Hy Lạp" msgid "Grid" msgstr "Lưới" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "Groq" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "Phát triển đội ngũ" @@ -2271,6 +2291,10 @@ msgstr "Đang nhập sơ yếu lý lịch của bạn..." msgid "Importing…" msgstr "Đang nhập…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "Bao gồm đầu trang hồ sơ" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "Tăng khoảng cách thụt lề" @@ -2574,11 +2598,6 @@ msgstr "Danh sách" msgid "Lithuanian" msgstr "Tiếng Litva" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "Xem trước trực tiếp sơ yếu lý lịch của bạn trong mẫu {0}" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "Đang tải các nhà cung cấp AI. Vui lòng thử lại sau một lát." @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "Hồ sơ xin việc bị thiếu" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "Trí tuệ nhân tạo Mistral" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "Mô hình" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "Odia" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "Đám mây Ollama" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "Thời gian" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "Sự bối rối" + #: src/libs/locale.ts msgid "Persian" msgstr "Ba Tư" @@ -3838,6 +3865,10 @@ msgstr "Hiển thị mật khẩu" msgid "Show picture" msgstr "Hiển thị hình ảnh" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "Hiển thị cùng đầu trang của trang đầu tiên trên thư xin việc." + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "Tiêu đề" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "Để xóa tài khoản của bạn, bạn cần nhập văn bản xác nhận và nhấp vào nút bên dưới." +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "Đáng để thử" msgid "X (Twitter)" msgstr "X (Twitter)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "Vâng, Resume Phản Ứng có sẵn bằng nhiều ngôn ngữ. Bạn có thể chọn ngôn ngữ ưa thích ở trang cài đặt, hoặc dùng bộ chuyển đổi ngôn ngữ ở góc trên cùng bên phải. Nếu bạn không thấy ngôn ngữ của mình, hoặc muốn cải thiện bản dịch hiện tại, bạn có thể <0>đóng góp dịch thuật trên Crowdin<1> (mở ở tab mới)." diff --git a/apps/web/locales/zh-CN.po b/apps/web/locales/zh-CN.po index 34662d1c5..ae554d27c 100644 --- a/apps/web/locales/zh-CN.po +++ b/apps/web/locales/zh-CN.po @@ -8,7 +8,7 @@ msgstr "" "Language: zh\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Chinese Simplified\n" "Plural-Forms: nplurals=1; plural=0;\n" @@ -758,6 +758,10 @@ msgstr "加泰罗尼亚语" msgid "Center Align" msgstr "居中对齐" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "大脑" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "点击此处选择要导入的文件" msgid "Close AI assistant" msgstr "近距离人工智能助手" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "凝聚" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "减少缩进" msgid "Decrease zoom" msgstr "降低缩放比例" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "深潜" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "学位" @@ -1885,6 +1897,10 @@ msgstr "找出薄弱的要点,用更强有力的结果、数字、范围和更 msgid "Finnish" msgstr "芬兰语" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "烟花" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "适合观看" @@ -2072,6 +2088,10 @@ msgstr "希腊语" msgid "Grid" msgstr "网格" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "格罗克" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "扩充团队" @@ -2271,6 +2291,10 @@ msgstr "正在导入你的简历…" msgid "Importing…" msgstr "正在导入…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "包含简历页眉" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "增加缩进" @@ -2574,11 +2598,6 @@ msgstr "列表" msgid "Lithuanian" msgstr "立陶宛语" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "在 {0} 模板中实时预览您的简历" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "正在加载人工智能提供商。请稍后再试。" @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "缺少工作简历" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "米斯特拉尔人工智能" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "模型" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "奥里亚语" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "奥拉玛" +msgid "Ollama Cloud" +msgstr "奥拉玛云" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "起止时间" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "困惑" + #: src/libs/locale.ts msgid "Persian" msgstr "波斯语" @@ -3838,6 +3865,10 @@ msgstr "显示密码" msgid "Show picture" msgstr "显示图片" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "在求职信上显示相同的首页页眉。" + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "标题" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "要删除你的账号,你需要输入确认文本,然后点击下方按钮。" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "值得一试" msgid "X (Twitter)" msgstr "X(推特)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "是的,Reactive Resume 支持多种语言。你可以在设置页面或右上角的语言切换器中选择你偏好的语言。如果没有找到你的语言,或者你想改进现有翻译,可以<0>在 Crowdin 上参与翻译<1>(在新标签页中打开)。" diff --git a/apps/web/locales/zh-TW.po b/apps/web/locales/zh-TW.po index 754feaab5..cf2d23c67 100644 --- a/apps/web/locales/zh-TW.po +++ b/apps/web/locales/zh-TW.po @@ -8,7 +8,7 @@ msgstr "" "Language: zh\n" "Project-Id-Version: reactive-resume\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-07 15:03\n" +"PO-Revision-Date: 2026-07-08 16:53\n" "Last-Translator: \n" "Language-Team: Chinese Traditional\n" "Plural-Forms: nplurals=1; plural=0;\n" @@ -758,6 +758,10 @@ msgstr "加泰隆尼亞語" msgid "Center Align" msgstr "置中對齊" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "大腦" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -854,6 +858,10 @@ msgstr "按這裡選擇要匯入的檔案" msgid "Close AI assistant" msgstr "近距離人工智慧助手" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "凝聚" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1282,6 +1290,10 @@ msgstr "減少縮排" msgid "Decrease zoom" msgstr "降低縮放比例" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "深潛" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "學位" @@ -1885,6 +1897,10 @@ msgstr "找出薄弱的要點,用更強有力的結果、數字、範圍和更 msgid "Finnish" msgstr "芬蘭語" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "煙火" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "適合觀看" @@ -2072,6 +2088,10 @@ msgstr "希臘語" msgid "Grid" msgstr "網格" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "格羅克" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "擴大團隊" @@ -2271,6 +2291,10 @@ msgstr "正在匯入您的履歷…" msgid "Importing…" msgstr "正在導入…" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "包含履歷頁首" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "增加縮排" @@ -2574,11 +2598,6 @@ msgstr "列表" msgid "Lithuanian" msgstr "立陶宛語" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "在 {0} 範本中即時預覽您的履歷" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "正在加載人工智慧提供者。請稍後再試。" @@ -2698,6 +2717,10 @@ msgstr "Microsoft Word" msgid "Missing working resume" msgstr "缺少工作履歷" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "米斯特拉爾人工智慧" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "模型" @@ -2871,8 +2894,8 @@ msgid "Odia" msgstr "歐利亞語" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" -msgstr "Ollama" +msgid "Ollama Cloud" +msgstr "奧拉瑪雲" #: src/routes/_home/-sections/features.tsx msgid "One-Click Sign-In" @@ -3091,6 +3114,10 @@ msgstr "PDF" msgid "Period" msgstr "期間" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "困惑" + #: src/libs/locale.ts msgid "Persian" msgstr "波斯語" @@ -3838,6 +3865,10 @@ msgstr "顯示密碼" msgid "Show picture" msgstr "顯示圖片" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "在求職信上顯示相同的首頁頁首。" + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4407,6 +4438,10 @@ msgstr "標題" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "若要刪除帳戶,您必須先輸入確認文字,然後點擊下方按鈕。" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "Together.ai" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4861,6 +4896,10 @@ msgstr "值得一試" msgid "X (Twitter)" msgstr "X(推特)" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "xAI Grok" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "沒錯,Reactive Resume 支援多種語言。您可以在設定頁面或右上角的語言切換器中選擇偏好的語言。如果沒有找到您的語言,或是想改進現有翻譯,您可以<0>在 Crowdin 上貢獻翻譯<1>(在新分頁中開啟)。" diff --git a/apps/web/locales/zu-ZA.po b/apps/web/locales/zu-ZA.po index ea131873a..efe06434f 100644 --- a/apps/web/locales/zu-ZA.po +++ b/apps/web/locales/zu-ZA.po @@ -753,6 +753,10 @@ msgstr "" msgid "Center Align" msgstr "" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cerebras" +msgstr "" + #: src/dialogs/resume/sections/custom.tsx #: src/libs/resume/section-title.ts #: src/libs/resume/section.tsx @@ -849,6 +853,10 @@ msgstr "" msgid "Close AI assistant" msgstr "" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Cohere" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx #: src/routes/builder/$resumeId/-sidebar/left/shared/section-menu.tsx msgid "Columns" @@ -1277,6 +1285,10 @@ msgstr "" msgid "Decrease zoom" msgstr "" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "DeepSeek" +msgstr "" + #: src/dialogs/resume/sections/education.tsx msgid "Degree" msgstr "" @@ -1880,6 +1892,10 @@ msgstr "" msgid "Finnish" msgstr "" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Fireworks" +msgstr "" + #: src/routes/builder/$resumeId/-components/dock.tsx msgid "Fit to view" msgstr "" @@ -2067,6 +2083,10 @@ msgstr "" msgid "Grid" msgstr "" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Groq" +msgstr "" + #: src/routes/_home/-sections/donate.tsx msgid "Grow the Team" msgstr "" @@ -2266,6 +2286,10 @@ msgstr "" msgid "Importing…" msgstr "" +#: src/features/resume/export/download-dialog.tsx +msgid "Include resume header" +msgstr "" + #: src/components/input/rich-input.tsx msgid "Increase indent" msgstr "" @@ -2569,11 +2593,6 @@ msgstr "" msgid "Lithuanian" msgstr "" -#. placeholder {0}: metadata.name -#: src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx -msgid "Live preview of your resume in the {0} template" -msgstr "" - #: src/dialogs/resume/import.tsx msgid "Loading AI providers. Please try again in a moment." msgstr "" @@ -2693,6 +2712,10 @@ msgstr "" msgid "Missing working resume" msgstr "" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Mistral AI" +msgstr "" + #: src/features/settings/integrations/components/ai-section.tsx msgid "Model" msgstr "" @@ -2866,7 +2889,7 @@ msgid "Odia" msgstr "" #: src/features/settings/integrations/components/ai-section.tsx -msgid "Ollama" +msgid "Ollama Cloud" msgstr "" #: src/routes/_home/-sections/features.tsx @@ -3086,6 +3109,10 @@ msgstr "" msgid "Period" msgstr "" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Perplexity" +msgstr "" + #: src/libs/locale.ts msgid "Persian" msgstr "" @@ -3833,6 +3860,10 @@ msgstr "" msgid "Show picture" msgstr "" +#: src/features/resume/export/download-dialog.tsx +msgid "Show the same first-page header on the cover letter." +msgstr "" + #. placeholder {0}: rows.length #. placeholder {1}: applications.length #: src/features/applications/components/table-view.tsx @@ -4402,6 +4433,10 @@ msgstr "" msgid "To delete your account, you need to enter the confirmation text and click the button below." msgstr "" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "Together.ai" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/shared/section-base.tsx #: src/routes/builder/$resumeId/-sidebar/right/shared/section-base.tsx msgid "Toggle {sectionTitle} section" @@ -4856,6 +4891,10 @@ msgstr "" msgid "X (Twitter)" msgstr "" +#: src/features/settings/integrations/components/ai-section.tsx +msgid "xAI Grok" +msgstr "" + #: src/routes/_home/-sections/faq.tsx msgid "Yes, Reactive Resume is available in multiple languages. You can choose your preferred language in the settings page, or using the language switcher in the top right corner. If you don't see your language, or you would like to improve the existing translations, you can <0>contribute to the translations on Crowdin<1> (opens in new tab)." msgstr "" diff --git a/apps/web/package.json b/apps/web/package.json index 8e21fe15e..8b01fd6e8 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -16,20 +16,20 @@ "lingui:extract": "lingui extract --clean --overwrite" }, "dependencies": { - "@ai-sdk/react": "^4.0.16", + "@ai-sdk/react": "^4.0.19", "@base-ui/react": "^1.6.0", "@better-auth/api-key": "^1.6.23", - "@better-auth/infra": "^0.3.4", + "@better-auth/infra": "^0.3.5", "@better-auth/oauth-provider": "^1.6.23", "@better-auth/passkey": "^1.6.23", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@lingui/core": "^6.4.0", - "@lingui/react": "^6.4.0", - "@orpc/client": "^1.14.6", - "@orpc/server": "^1.14.6", - "@orpc/tanstack-query": "^1.14.6", + "@lingui/core": "^6.5.0", + "@lingui/react": "^6.5.0", + "@orpc/client": "^1.14.7", + "@orpc/server": "^1.14.7", + "@orpc/tanstack-query": "^1.14.7", "@phosphor-icons/react": "^2.1.10", "@react-pdf/renderer": "^4.5.1", "@reactive-resume/ai": "workspace:*", @@ -48,17 +48,17 @@ "@tanstack/react-hotkeys": "^0.10.0", "@tanstack/react-query": "^5.101.2", "@tanstack/react-router": "^1.170.17", - "@tiptap/extension-color": "^3.27.1", - "@tiptap/extension-highlight": "^3.27.1", - "@tiptap/extension-text-align": "^3.27.1", - "@tiptap/extension-text-style": "^3.27.1", - "@tiptap/pm": "^3.27.1", - "@tiptap/react": "^3.27.1", - "@tiptap/starter-kit": "^3.27.1", + "@tiptap/extension-color": "^3.27.3", + "@tiptap/extension-highlight": "^3.27.3", + "@tiptap/extension-text-align": "^3.27.3", + "@tiptap/extension-text-style": "^3.27.3", + "@tiptap/pm": "^3.27.3", + "@tiptap/react": "^3.27.3", + "@tiptap/starter-kit": "^3.27.3", "@types/js-cookie": "^3.0.6", "@uiw/color-convert": "^2.10.3", "@uiw/react-color-colorful": "^2.10.3", - "ai": "^7.0.15", + "ai": "^7.0.18", "better-auth": "1.6.23", "cmdk": "^1.1.1", "drizzle-orm": "1.0.0-rc.4", @@ -72,7 +72,7 @@ "qrcode.react": "^4.2.0", "react": "^19.2.7", "react-dom": "^19.2.7", - "react-easy-crop": "^6.1.0", + "react-easy-crop": "^6.2.2", "react-markdown": "^10.1.0", "react-resizable-panels": "^4.12.1", "react-window": "^2.2.7", @@ -86,10 +86,10 @@ }, "devDependencies": { "@babel/core": "^8.0.1", - "@lingui/babel-plugin-lingui-macro": "^6.4.0", - "@lingui/cli": "^6.4.0", - "@lingui/format-po": "^6.4.0", - "@lingui/vite-plugin": "^6.4.0", + "@lingui/babel-plugin-lingui-macro": "^6.5.0", + "@lingui/cli": "^6.5.0", + "@lingui/format-po": "^6.5.0", + "@lingui/vite-plugin": "^6.5.0", "@reactive-resume/config": "workspace:*", "@rolldown/plugin-babel": "^0.2.3", "@tanstack/devtools-vite": "^0.8.1", @@ -101,12 +101,12 @@ "@types/pg": "^8.20.0", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", - "@typescript/native-preview": "7.0.0-dev.20260705.1", + "@typescript/native-preview": "7.0.0-dev.20260707.2", "@vitejs/plugin-react": "^6.0.3", "babel-plugin-macros": "^3.1.0", "babel-plugin-react-compiler": "^1.0.0", "rimraf": "^6.1.3", - "typescript": "^6.0.3", + "typescript": "^7.0.2", "vite": "^8.1.3" } } diff --git a/apps/web/src/components/typography/combobox.tsx b/apps/web/src/components/typography/combobox.tsx index 6bd0d792e..2a0b28be2 100644 --- a/apps/web/src/components/typography/combobox.tsx +++ b/apps/web/src/components/typography/combobox.tsx @@ -5,25 +5,25 @@ import { cn } from "@reactive-resume/utils/style"; import { Combobox } from "@/components/ui/combobox"; import { FontDisplay } from "./font-display"; +// Options depend only on the static font list, so compute them once per process +// instead of per component instance (the body + heading pickers rendered identical output twice). +const FONT_FAMILY_OPTIONS = fontList.map((font) => ({ + value: font.family, + keywords: getFontSearchKeywords(font.family), + label: ( + + ), +})); + type FontFamilyComboboxProps = Omit; export function FontFamilyCombobox({ className, ...props }: FontFamilyComboboxProps) { - const options = useMemo(() => { - return fontList.map((font) => ({ - value: font.family, - keywords: getFontSearchKeywords(font.family), - label: ( - - ), - })); - }, []); - - return ; + return ; } type FontWeightComboboxProps = Omit & { fontFamily: string }; diff --git a/apps/web/src/features/command-palette/index.tsx b/apps/web/src/features/command-palette/index.tsx index 81d680b33..eb9fa51c9 100644 --- a/apps/web/src/features/command-palette/index.tsx +++ b/apps/web/src/features/command-palette/index.tsx @@ -1,7 +1,7 @@ import { t } from "@lingui/core/macro"; import { Trans } from "@lingui/react/macro"; import { useHotkeys } from "@tanstack/react-hotkeys"; -import { useRef } from "react"; +import { useEffect, useRef, useState } from "react"; import { Command, CommandEmpty, CommandInput, CommandList } from "@reactive-resume/ui/components/command"; import { Dialog, @@ -17,10 +17,13 @@ import { useCommandPaletteStore } from "./store"; export function CommandPalette() { const inputRef = useRef(null); + const commandRef = useRef(null); + const [selectedValue, setSelectedValue] = useState(); const { open, search, pages, setOpen, setSearch, goBack } = useCommandPaletteStore(); const isFirstPage = pages.length === 0; const currentPage = pages[pages.length - 1]; + const commandListPage = currentPage ?? "root"; // Toggle command palette with Cmd+K / Ctrl+K useHotkeys([ @@ -67,6 +70,18 @@ export function CommandPalette() { setSearch(value); }; + useEffect(() => { + if (!open) return; + + const firstItem = commandRef.current?.querySelector( + `[data-command-page="${commandListPage}"] [cmdk-item]:not([aria-disabled="true"])`, + ); + const value = firstItem?.getAttribute("data-value"); + + if (value) setSelectedValue(value); + inputRef.current?.focus(); + }, [open, commandListPage]); + return ( @@ -97,7 +112,10 @@ export function CommandPalette() { } > - + The command you're looking for doesn't exist. diff --git a/apps/web/src/features/command-palette/pages/resumes.test.tsx b/apps/web/src/features/command-palette/pages/resumes.test.tsx index 202f7351e..3e90b4472 100644 --- a/apps/web/src/features/command-palette/pages/resumes.test.tsx +++ b/apps/web/src/features/command-palette/pages/resumes.test.tsx @@ -1,6 +1,7 @@ // @vitest-environment happy-dom import { fireEvent, render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"; import { i18n } from "@lingui/core"; import { I18nProvider } from "@lingui/react"; @@ -21,6 +22,10 @@ vi.mock("@tanstack/react-query", () => ({ useQuery: vi.fn(), })); +vi.mock("@tanstack/react-hotkeys", () => ({ + useHotkeys: vi.fn(), +})); + vi.mock("@tanstack/react-router", () => ({ useNavigate: () => mocks.navigate, useRouteContext: () => ({ session: { user: { id: "user-1" } } }), @@ -36,6 +41,10 @@ vi.mock("@/features/applications/queries", () => ({ applicationsListQueryOptions: mocks.applicationsListQueryOptions, })); +vi.mock("@/features/theme/provider", () => ({ + useTheme: () => ({ setTheme: vi.fn(), theme: "light", toggleTheme: vi.fn() }), +})); + vi.mock("@/libs/orpc/client", () => ({ orpc: { resume: { @@ -53,6 +62,7 @@ vi.mock("@/libs/orpc/client", () => ({ }, })); +const { CommandPalette } = await import("../index"); const { ResumesCommandGroup } = await import("./resumes"); const { NavigationCommandGroup } = await import("./navigation"); @@ -83,8 +93,67 @@ const renderGroup = () => , ); +function TestCommandPalette() { + return ( + + + + ); +} + describe("ResumesCommandGroup", () => { - it("loads resumes with the default list input on the resumes page", () => { + it.each([ + ["resumes", "", "Create a new resume"], + ["applications", "{ArrowDown}", "New Application"], + ["threads", "{ArrowDown}{ArrowDown}", "New Thread"], + ])("opens the %s list page from the root palette with Enter", async (page, keys, createLabel) => { + mockUseQueryData((entity) => { + if (entity === "resumes") return [{ id: "resume-1", name: "Evil Apricot Pike", slug: "apricot" }]; + if (entity === "applications") + return [{ id: "application-1", company: "Umbrella", role: "Staff Engineer", archived: false }]; + if (entity === "threads") + return [{ id: "thread-1", title: "Cover letter rewrite", resumeName: "Product Resume" }]; + return []; + }); + + useCommandPaletteStore.setState({ open: true }); + render(); + await userEvent.click(screen.getByRole("combobox")); + await userEvent.keyboard(`${keys}{Enter}`); + + expect(useCommandPaletteStore.getState().pages).toEqual([page]); + expect(await screen.findByText(createLabel)).toBeInTheDocument(); + expect(screen.queryByText("The command you're looking for doesn't exist.")).not.toBeInTheDocument(); + }); + + it.each([ + ["resumes", "", "Create a new resume", "Evil Apricot Pike"], + ["applications", "{ArrowDown}", "New Application", "Umbrella"], + ["threads", "{ArrowDown}{ArrowDown}", "New Thread", "Cover letter rewrite"], + ])("keeps arrow-key navigation active on the %s list page", async (_page, keys, createLabel, itemLabel) => { + mockUseQueryData((entity) => { + if (entity === "resumes") return [{ id: "resume-1", name: "Evil Apricot Pike", slug: "apricot" }]; + if (entity === "applications") + return [{ id: "application-1", company: "Umbrella", role: "Staff Engineer", archived: false }]; + if (entity === "threads") + return [{ id: "thread-1", title: "Cover letter rewrite", resumeName: "Product Resume" }]; + return []; + }); + + useCommandPaletteStore.setState({ open: true }); + render(); + await userEvent.click(screen.getByRole("combobox")); + await userEvent.keyboard(`${keys}{Enter}`); + const createItem = await screen.findByText(createLabel); + await userEvent.keyboard("{ArrowDown}"); + + expect((await screen.findByText(itemLabel)).closest("[cmdk-item]")).toHaveAttribute("aria-selected", "true"); + await userEvent.keyboard("{ArrowUp}"); + + expect(createItem.closest("[cmdk-item]")).toHaveAttribute("aria-selected", "true"); + }); + + it("does not show resume results beside the root categories on the resumes route", () => { mocks.pathname = "/dashboard/resumes"; mockUseQueryData((entity) => entity === "resumes" ? [{ id: "resume-1", name: "Evil Apricot Pike", slug: "apricot" }] : [], @@ -92,6 +161,19 @@ describe("ResumesCommandGroup", () => { renderGroup(); + expect(screen.getAllByText("Resumes")).toHaveLength(1); + expect(screen.queryByText("Create a new resume")).not.toBeInTheDocument(); + expect(screen.queryByText("Evil Apricot Pike")).not.toBeInTheDocument(); + }); + + it("loads resumes with the default list input after opening the resumes command page", () => { + useCommandPaletteStore.setState({ pages: ["resumes"] }); + mockUseQueryData((entity) => + entity === "resumes" ? [{ id: "resume-1", name: "Evil Apricot Pike", slug: "apricot" }] : [], + ); + + renderGroup(); + expect(mocks.resumeQueryOptions).toHaveBeenCalledWith({ enabled: true, input: { sort: "lastUpdatedAt", tags: [] }, @@ -100,8 +182,7 @@ describe("ResumesCommandGroup", () => { }); it("filters resume results from the command palette search", () => { - mocks.pathname = "/dashboard/resumes"; - useCommandPaletteStore.setState({ search: "apri" }); + useCommandPaletteStore.setState({ pages: ["resumes"], search: "apri" }); mockUseQueryData((entity) => entity === "resumes" ? [ @@ -118,7 +199,7 @@ describe("ResumesCommandGroup", () => { }); it("loads applications on the applications page", () => { - mocks.pathname = "/dashboard/applications"; + useCommandPaletteStore.setState({ pages: ["applications"] }); mockUseQueryData((entity) => entity === "applications" ? [{ id: "application-1", company: "Umbrella", role: "Staff Engineer", archived: false }] @@ -132,8 +213,7 @@ describe("ResumesCommandGroup", () => { }); it("filters application results from the command palette search", () => { - mocks.pathname = "/dashboard/applications"; - useCommandPaletteStore.setState({ search: "umbrella" }); + useCommandPaletteStore.setState({ pages: ["applications"], search: "umbrella" }); mockUseQueryData((entity) => entity === "applications" ? [ @@ -150,7 +230,7 @@ describe("ResumesCommandGroup", () => { }); it("opens the selected application by id", () => { - mocks.pathname = "/dashboard/applications"; + useCommandPaletteStore.setState({ pages: ["applications"] }); mockUseQueryData((entity) => entity === "applications" ? [{ id: "application-1", company: "Umbrella", role: "Staff Engineer", archived: false }] @@ -167,7 +247,7 @@ describe("ResumesCommandGroup", () => { }); it("loads threads on agent pages", () => { - mocks.pathname = "/agent"; + useCommandPaletteStore.setState({ pages: ["threads"] }); mockUseQueryData((entity) => entity === "threads" ? [{ id: "thread-1", title: "Cover letter rewrite", resumeName: "Product Resume" }] : [], ); @@ -179,8 +259,7 @@ describe("ResumesCommandGroup", () => { }); it("filters thread results from the command palette search", () => { - mocks.pathname = "/agent"; - useCommandPaletteStore.setState({ search: "cover" }); + useCommandPaletteStore.setState({ pages: ["threads"], search: "cover" }); mockUseQueryData((entity) => entity === "threads" ? [ diff --git a/apps/web/src/features/command-palette/pages/resumes.tsx b/apps/web/src/features/command-palette/pages/resumes.tsx index b0a915f43..f102950e4 100644 --- a/apps/web/src/features/command-palette/pages/resumes.tsx +++ b/apps/web/src/features/command-palette/pages/resumes.tsx @@ -3,7 +3,7 @@ import { t } from "@lingui/core/macro"; import { Trans } from "@lingui/react/macro"; import { BriefcaseIcon, ChatCircleDotsIcon, PlusIcon, ReadCvLogoIcon } from "@phosphor-icons/react"; import { useQuery } from "@tanstack/react-query"; -import { useNavigate, useRouteContext, useRouterState } from "@tanstack/react-router"; +import { useNavigate, useRouteContext } from "@tanstack/react-router"; import { CommandLoading } from "cmdk"; import { CommandItem, CommandShortcut } from "@reactive-resume/ui/components/command"; import { Kbd } from "@reactive-resume/ui/components/kbd"; @@ -20,12 +20,6 @@ type SearchPage = "resumes" | "applications" | "threads"; const isSearchPage = (page: string | undefined): page is SearchPage => page === "resumes" || page === "applications" || page === "threads"; -const getRouteSearchPage = (pathname: string): SearchPage | undefined => { - if (pathname.startsWith("/dashboard/resumes")) return "resumes"; - if (pathname.startsWith("/dashboard/applications")) return "applications"; - if (pathname.startsWith("/agent")) return "threads"; -}; - const matchesSearch = (search: string, values: Array) => { const query = search.trim().toLowerCase(); return !query || values.some((value) => value?.toLowerCase().includes(query)); @@ -35,7 +29,6 @@ export function ResumesCommandGroup() { const navigate = useNavigate(); const { openDialog } = useDialogStore(); const { session } = useRouteContext({ strict: false }); - const pathname = useRouterState({ select: (state) => state.location.pathname }); const reset = useCommandPaletteStore((state) => state.reset); const peekPage = useCommandPaletteStore((state) => state.peekPage); const pushPage = useCommandPaletteStore((state) => state.pushPage); @@ -43,7 +36,7 @@ export function ResumesCommandGroup() { const commandPage = peekPage(); const commandSearchPage = isSearchPage(commandPage) ? commandPage : undefined; - const searchPage = commandSearchPage ?? (!commandPage ? getRouteSearchPage(pathname) : undefined); + const searchPage = commandSearchPage; const { data: resumes, isLoading } = useQuery( orpc.resume.list.queryOptions({ diff --git a/apps/web/src/features/resume/export/download-dialog.tsx b/apps/web/src/features/resume/export/download-dialog.tsx index 63536296e..5ebf3c2c2 100644 --- a/apps/web/src/features/resume/export/download-dialog.tsx +++ b/apps/web/src/features/resume/export/download-dialog.tsx @@ -11,7 +11,7 @@ import { FileTextIcon, MarkdownLogoIcon, } from "@phosphor-icons/react"; -import { useState } from "react"; +import { useId, useState } from "react"; import { Button } from "@reactive-resume/ui/components/button"; import { Dialog, @@ -21,6 +21,7 @@ import { DialogTitle, DialogTrigger, } from "@reactive-resume/ui/components/dialog"; +import { Switch } from "@reactive-resume/ui/components/switch"; import { Tabs, TabsList, TabsTrigger } from "@reactive-resume/ui/components/tabs"; import { cn } from "@reactive-resume/utils/style"; import { useResumeExport } from "./use-resume-export"; @@ -63,6 +64,8 @@ function FormatRow({ action, description, disabled, icon, title }: FormatRowProp export function ResumeDownloadDialog({ resume, trigger }: ResumeDownloadDialogProps) { const [open, setOpen] = useState(false); const [scope, setScope] = useState("resume"); + const [includeCoverLetterHeader, setIncludeCoverLetterHeader] = useState(false); + const includeHeaderSwitchId = useId(); const { hasCoverLetter, isExporting, onDownloadDOCX, onDownloadJSON, onDownloadMarkdown, onDownloadPDF } = useResumeExport(resume); const disabled = !resume || isExporting; @@ -102,6 +105,28 @@ export function ResumeDownloadDialog({ resume, trigger }: ResumeDownloadDialogPr + {activeScope === "cover-letter" && ( + + )} +
run(() => onDownloadPDF(activeScope))} + onClick={() => run(() => onDownloadPDF(activeScope, { includeCoverLetterHeader }))} > Download diff --git a/apps/web/src/features/resume/export/pdf-document.tsx b/apps/web/src/features/resume/export/pdf-document.tsx index 7cfb864d7..195a7c280 100644 --- a/apps/web/src/features/resume/export/pdf-document.tsx +++ b/apps/web/src/features/resume/export/pdf-document.tsx @@ -5,6 +5,10 @@ import { createResumePdfBlob as createPdfBlob } from "@reactive-resume/pdf/brows import { ResumeDocument } from "@reactive-resume/pdf/document"; import { createSectionTitleResolverForLocale, useSectionTitleResolver } from "@/libs/resume/section-title-locale"; +type ResumePdfRenderOptions = { + includeCoverLetterHeader?: boolean; +}; + export const useLocalizedResumeDocument = (data?: ResumeData, template?: Template) => { const sectionTitleResolver = useSectionTitleResolver(data?.metadata.page.locale); @@ -21,12 +25,17 @@ export const useLocalizedResumeDocument = (data?: ResumeData, template?: Templat }, [data, template, sectionTitleResolver]); }; -export const createResumePdfBlob = async (data: ResumeData, template?: Template) => { +export const createResumePdfBlob = async ( + data: ResumeData, + template?: Template, + renderOptions?: ResumePdfRenderOptions, +) => { const sectionTitleResolver = await createSectionTitleResolverForLocale(data.metadata.page.locale); return createPdfBlob({ data, template, + ...(renderOptions ? { renderOptions } : {}), resolveSectionTitle: sectionTitleResolver, }); }; diff --git a/apps/web/src/features/resume/export/use-resume-export.ts b/apps/web/src/features/resume/export/use-resume-export.ts index f35d44901..8fa5a5166 100644 --- a/apps/web/src/features/resume/export/use-resume-export.ts +++ b/apps/web/src/features/resume/export/use-resume-export.ts @@ -33,6 +33,10 @@ const getExportName = (resume: ExportableResume) => resume.name || resume.data.b const getTargetExportName = (resume: ExportableResume, target: ResumeExportTarget) => target === "cover-letter" ? `${getExportName(resume)} Cover Letter` : getExportName(resume); +type DownloadPdfOptions = { + includeCoverLetterHeader?: boolean; +}; + /** * Single source of truth for resume export (PDF / DOCX / JSON / Print). Previously duplicated verbatim * between the builder dock and the right-panel Export section (#17). @@ -76,14 +80,18 @@ export function useResumeExport(resume: ExportableResume | undefined) { ); const onDownloadPDF = useCallback( - async (target: ResumeExportTarget = "resume") => { + async (target: ResumeExportTarget = "resume", options?: DownloadPdfOptions) => { if (!resume) return; if (target === "cover-letter" && !resumeHasCoverLetter(resume.data)) return; const toastId = toast.loading(t`Please wait while your PDF is being generated...`); setIsExporting(true); try { const data = getResumeExportData(resume.data, target); - const blob = await createResumePdfBlob(data); + const blob = await createResumePdfBlob( + data, + undefined, + target === "cover-letter" ? { includeCoverLetterHeader: options?.includeCoverLetterHeader } : undefined, + ); downloadWithAnchor(blob, generateFilename(getTargetExportName(resume, target), "pdf")); } catch { toast.error(t`There was a problem while generating the PDF, please try again.`); diff --git a/apps/web/src/features/settings/integrations/components/ai-section.test.tsx b/apps/web/src/features/settings/integrations/components/ai-section.test.tsx index f668cb376..2224e10b3 100644 --- a/apps/web/src/features/settings/integrations/components/ai-section.test.tsx +++ b/apps/web/src/features/settings/integrations/components/ai-section.test.tsx @@ -142,6 +142,27 @@ describe("AISettingsSection", () => { mutations.delete.mockReset(); }); + it("offers popular AI SDK providers and labels Ollama as cloud-hosted", () => { + renderSection(); + + for (const label of [ + "Mistral AI", + "Cohere", + "xAI Grok", + "Groq", + "DeepSeek", + "Together.ai", + "Fireworks", + "Cerebras", + "Perplexity", + "Ollama Cloud", + ]) { + expect(screen.getByRole("option", { name: label })).toBeInTheDocument(); + } + + expect(screen.queryByRole("option", { name: "Ollama" })).not.toBeInTheDocument(); + }); + it("uses the save-and-test result as the connected provider row", async () => { const created = provider({}); const tested = provider({ enabled: true, testStatus: "success", lastTestedAt: new Date("2026-07-04T01:00:00Z") }); diff --git a/apps/web/src/features/settings/integrations/components/ai-section.tsx b/apps/web/src/features/settings/integrations/components/ai-section.tsx index 9326a9939..c3b121236 100644 --- a/apps/web/src/features/settings/integrations/components/ai-section.tsx +++ b/apps/web/src/features/settings/integrations/components/ai-section.tsx @@ -64,10 +64,73 @@ const providerOptions: AIProviderOption[] = [ defaultBaseURL: AI_PROVIDER_DEFAULT_BASE_URLS.openrouter, defaultModel: "openai/gpt-4.1", }, + { + value: "mistral", + label: t`Mistral AI`, + keywords: ["mistral", "magistral"], + defaultBaseURL: AI_PROVIDER_DEFAULT_BASE_URLS.mistral, + defaultModel: "mistral-large-latest", + }, + { + value: "cohere", + label: t`Cohere`, + keywords: ["cohere", "command"], + defaultBaseURL: AI_PROVIDER_DEFAULT_BASE_URLS.cohere, + defaultModel: "command-a-03-2025", + }, + { + value: "xai", + label: t`xAI Grok`, + keywords: ["xai", "grok"], + defaultBaseURL: AI_PROVIDER_DEFAULT_BASE_URLS.xai, + defaultModel: "grok-4", + }, + { + value: "groq", + label: t`Groq`, + keywords: ["groq", "llama"], + defaultBaseURL: AI_PROVIDER_DEFAULT_BASE_URLS.groq, + defaultModel: "llama-3.3-70b-versatile", + }, + { + value: "deepseek", + label: t`DeepSeek`, + keywords: ["deepseek"], + defaultBaseURL: AI_PROVIDER_DEFAULT_BASE_URLS.deepseek, + defaultModel: "deepseek-chat", + }, + { + value: "togetherai", + label: t`Together.ai`, + keywords: ["together", "togetherai", "llama"], + defaultBaseURL: AI_PROVIDER_DEFAULT_BASE_URLS.togetherai, + defaultModel: "meta-llama/Meta-Llama-3.3-70B-Instruct-Turbo", + }, + { + value: "fireworks", + label: t`Fireworks`, + keywords: ["fireworks", "llama", "deepseek"], + defaultBaseURL: AI_PROVIDER_DEFAULT_BASE_URLS.fireworks, + defaultModel: "accounts/fireworks/models/llama-v3p3-70b-instruct", + }, + { + value: "cerebras", + label: t`Cerebras`, + keywords: ["cerebras", "llama"], + defaultBaseURL: AI_PROVIDER_DEFAULT_BASE_URLS.cerebras, + defaultModel: "llama3.3-70b", + }, + { + value: "perplexity", + label: t`Perplexity`, + keywords: ["perplexity", "sonar"], + defaultBaseURL: AI_PROVIDER_DEFAULT_BASE_URLS.perplexity, + defaultModel: "sonar-pro", + }, { value: "ollama", - label: t`Ollama`, - keywords: ["ollama", "local"], + label: t`Ollama Cloud`, + keywords: ["ollama", "cloud"], defaultBaseURL: AI_PROVIDER_DEFAULT_BASE_URLS.ollama, defaultModel: "llama3.1", }, diff --git a/apps/web/src/libs/resume/section-actions.test.ts b/apps/web/src/libs/resume/section-actions.test.ts index a940f9574..777d70a87 100644 --- a/apps/web/src/libs/resume/section-actions.test.ts +++ b/apps/web/src/libs/resume/section-actions.test.ts @@ -92,7 +92,8 @@ describe("updateSectionItem", () => { }); const customSection = result.customSections.find((s) => s.id === "custom-1"); - expect((customSection?.items[0] as { value?: string }).value).toBe("new"); + if (!customSection) throw new Error("Custom section not found"); + expect((customSection.items[0] as { value?: string }).value).toBe("new"); }); it("does nothing when custom section is not found", () => { diff --git a/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/layout/pages.test.tsx b/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/layout/pages.test.tsx new file mode 100644 index 000000000..9d047ea9a --- /dev/null +++ b/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/layout/pages.test.tsx @@ -0,0 +1,13 @@ +import { readFileSync } from "node:fs"; +import { describe, expect, it } from "vitest"; + +const source = readFileSync("src/routes/builder/$resumeId/-sidebar/right/sections/layout/pages.tsx", "utf8"); + +describe("layout page header", () => { + it("uses container queries to prevent narrow sidebar control collisions", () => { + expect(source).toContain("@container bg-secondary/50"); + expect(source).toContain("grid-cols-[minmax(0,1fr)_auto]"); + expect(source).toContain("@max-[22rem]:grid-cols-1"); + expect(source).toContain("flex min-w-0 flex-wrap"); + }); +}); diff --git a/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/layout/pages.tsx b/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/layout/pages.tsx index 18de71656..0618ce5ad 100644 --- a/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/layout/pages.tsx +++ b/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/layout/pages.tsx @@ -297,31 +297,37 @@ function PageContainer({ return (
-
-
- - Page {pageIndex + 1} - - -
{ const img = screen.getByAltText("Ditto") as HTMLImageElement; expect(img.src).toContain("/templates/jpg/ditto.jpg"); }); + + it("keeps the template preview inline instead of mounting a hover card", () => { + const source = readFileSync("src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx", "utf8"); + + expect(source).not.toContain("@reactive-resume/ui/components/hover-card"); + expect(source).not.toContain("HoverCardContent"); + }); }); diff --git a/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx b/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx index 2f939e0a9..111cfb9a5 100644 --- a/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx +++ b/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/template.tsx @@ -1,23 +1,12 @@ -import { t } from "@lingui/core/macro"; import { useLingui } from "@lingui/react"; import { SwapIcon } from "@phosphor-icons/react"; -import { lazy, Suspense } from "react"; import { Badge } from "@reactive-resume/ui/components/badge"; import { Button } from "@reactive-resume/ui/components/button"; -import { HoverCard, HoverCardContent, HoverCardTrigger } from "@reactive-resume/ui/components/hover-card"; import { templates } from "@/dialogs/resume/template/data"; import { useDialogStore } from "@/dialogs/store"; import { useCurrentResume } from "@/features/resume/builder/draft"; import { SectionBase } from "../shared/section-base"; -// Lazy so the browser PDF pipeline (pdf.js) loads only when a preview card actually opens, keeping it out -// of the SSR/module graph — mirrors the `ResumePreview` entry convention. -const TemplateLivePreview = lazy(() => - import("@/features/resume/preview/template-live-preview").then((module) => ({ - default: module.TemplateLivePreview, - })), -); - export function TemplateSectionBuilder() { return ( @@ -40,43 +29,19 @@ function TemplateSectionForm() { return (
- - -
- {metadata.name} -
+ - } - /> - - - - {metadata.name} -
- } - > - - - - +
+ +
+
diff --git a/docs/adr/0002-structured-style-rules-for-react-pdf.md b/docs/adr/0002-structured-style-rules-for-react-pdf.md deleted file mode 100644 index d23322736..000000000 --- a/docs/adr/0002-structured-style-rules-for-react-pdf.md +++ /dev/null @@ -1,5 +0,0 @@ -# Structured Style Rules for React PDF - -Reactive Resume no longer renders final PDFs through browser HTML/CSS, so end-user custom CSS would create a misleading contract: React PDF accepts style objects on renderer components, not arbitrary browser selectors. Resume appearance customization is therefore modeled as structured Style Rules in resume metadata, targeting semantic section and rich-text slots that the PDF package translates into safe React PDF styles. - -This preserves user-controlled section styling while keeping PDF rendering portable across preview, export, public resume views, templates, and server generation. Raw CSS, raw React PDF style objects, section-item targeting, and direct PDF-preview selection are intentionally out of v1; they can be revisited only if the product needs that power enough to accept the additional validation and layout-breakage risk. diff --git a/docs/changelog/index.mdx b/docs/changelog/index.mdx index cb88d9587..5f2bf63a3 100644 --- a/docs/changelog/index.mdx +++ b/docs/changelog/index.mdx @@ -4,6 +4,43 @@ description: "Release notes for Reactive Resume covering new features, resume bu rss: true --- + +## Highlights + +- **More AI provider choices.** The AI settings page now supports Mistral AI, Cohere, xAI Grok, Groq, DeepSeek, Together.ai, Fireworks, Cerebras, and Perplexity, with provider defaults filled in for each. Ollama is now labeled as Ollama Cloud to make the hosted integration clearer. +- **Cleaner cover-letter exports.** Cover-letter PDF, DOCX, and Markdown downloads now export the letter without resume header chrome by default, and PDF downloads include a new toggle for adding the resume header back when needed. [8570c1c70](https://github.com/amruthpillai/reactive-resume/commit/8570c1c70) +- **More accurate public resume statistics.** Rapid repeat views from the same client are now de-duplicated before incrementing public resume view counts. [97ab3c973](https://github.com/amruthpillai/reactive-resume/commit/97ab3c973) + +## AI & Integrations + +- Added first-class AI SDK support for Mistral AI, Cohere, xAI, Groq, DeepSeek, Together.ai, Fireworks, Cerebras, and Perplexity across saved provider settings and AI service calls. +- Made AI provider connection tests work with OpenAI-compatible models that do not support structured output, with a clearer error when a model returns too much text during the test. +- Published Reactive Resume MCP registry metadata so MCP clients and directories can discover the hosted remote server. [73daf22b2](https://github.com/amruthpillai/reactive-resume/commit/73daf22b2) + +## Resume Builder & Exports + +- Fixed cover-letter-only exports across PDF, DOCX, and Markdown so they no longer include resume contact details or a redundant cover-letter heading. [8570c1c70](https://github.com/amruthpillai/reactive-resume/commit/8570c1c70) +- Added an **Include resume header** option for cover-letter PDF downloads. +- Improved the layout page header so the **Full Width** and **Delete Page** controls fit better in narrow builder sidebars. +- Simplified the current-template card by removing its hover live preview; template switching still opens the full template gallery. + +## Reliability & Self-Hosting + +- Added report-only CSP, frame blocking, `nosniff`, and stricter referrer headers to web app shell responses, and tightened public upload headers to rely on same-site resource policy instead of an unconditional CORS header. [9bde7d544](https://github.com/amruthpillai/reactive-resume/commit/9bde7d544) +- Limited application bulk update and delete requests to 200 selected items per operation to avoid oversized bulk actions. [c9b3fa5c1](https://github.com/amruthpillai/reactive-resume/commit/c9b3fa5c1) +- Resume lock and password mutations now return `NOT_FOUND` when the resume is missing instead of silently succeeding. [e47cf6e77](https://github.com/amruthpillai/reactive-resume/commit/e47cf6e77) +- Reduced repeated work in the font picker by computing the font family options once per app process. [7e0657946](https://github.com/amruthpillai/reactive-resume/commit/7e0657946) +- Refreshed workspace dependencies, including AI SDK provider packages, Lingui, oRPC, Hono, Tiptap, and test tooling. + +## Documentation & Localization + +- Tightened SEO titles and descriptions across the documentation site. [5270a2a9a](https://github.com/amruthpillai/reactive-resume/commit/5270a2a9a) +- Corrected the README feature list to describe structured Style Rules instead of custom CSS. [66078609a](https://github.com/amruthpillai/reactive-resume/commit/66078609a) +- Synced Crowdin translation catalogs and added locale strings for the new AI providers and cover-letter export option. [b87a9d828](https://github.com/amruthpillai/reactive-resume/commit/b87a9d828), [25021507a](https://github.com/amruthpillai/reactive-resume/commit/25021507a) + +**Full Changelog**: [v5.2.2...v5.2.3](https://github.com/amruthpillai/reactive-resume/compare/v5.2.2...v5.2.3) + + ## Highlights diff --git a/docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md b/docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md deleted file mode 100644 index ca2823f58..000000000 --- a/docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md +++ /dev/null @@ -1,241 +0,0 @@ -# Monorepo Architecture Reorg Handoff - -This handoff is the coordination entrypoint for the Reactive Resume architecture reorganization. It intentionally references the implementation plan instead of duplicating it. - -## Primary Plan - -- Plan: `docs/superpowers/plans/2026-05-14-monorepo-architecture-reorg.md` -- Worklog: `docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md` -- Branch at start: `feat/explore-hono-orpc-migration` - -## Current Operating Rules - -- Preserve existing unrelated local changes: - - `apps/server/package.json` - - `package.json` - - `packages/api/package.json` - - `packages/env/package.json` - - `packages/utils/package.json` - - `pnpm-lock.yaml` -- Do not use `git reset --hard` or destructive checkout commands. -- Use green internal commits if committing is requested/appropriate. -- Use root `AGENTS.md` as the final normative architecture source of truth. -- Do not create local package READMEs for architecture rules unless a package has unavoidable operational constraints. - -## Suggested Skills for Future Agents - -- `subagent-driven-development` for executing one task slice with review gates. -- `executing-plans` for sequential execution from the plan. -- `documentation-writer` for `AGENTS.md`, ADR, and public architecture docs. -- `handoff` when pausing or delegating a task outside Codex. -- `turborepo` when editing `turbo.json`, package tags, or task graph rules. -- `context7-mcp` if checking current docs for library/framework behavior. - -## Delegation Guidance - -External agents should be handed exactly one task from the plan plus this handoff path. They should report: - -- Status: `DONE`, `DONE_WITH_CONCERNS`, `BLOCKED`, or `NEEDS_CONTEXT` -- Files changed -- Tests/commands run -- Any plan deviations -- Follow-up tasks needed - -## Task Ownership Status - -- Task 0 Coordination Artifacts: done -- Task 1 Pure Resume Domain Package: done -- Task 2 DOCX Package: done -- Task 3 PDF Package Browser/Server Generation Surface: done -- Task 4 MCP Package and Shared Tool Contracts: done -- Task 5 API Feature Reorganization: done -- Task 6 Server Adapter Reorganization: done -- Task 7 Domain-First Web Reorganization: done -- Task 8 Dialog Registry Rework: done -- Task 9 Boundary Enforcement: done -- Task 10 Documentation and Source of Truth: done -- Task 11 Final Validation and Handoff: done - -## Architecture Decisions Already Locked - -- `@reactive-resume/schema` is Zod/types only. -- `@reactive-resume/resume` owns pure resume-domain behavior. -- `@reactive-resume/ai` owns model contracts, not DB-backed agent runtime. -- Agent runtime remains in `packages/api/features/agent`. -- MCP uses an in-process oRPC `RouterClient`. -- MCP tools move to canonical unprefixed snake_case names, no old aliases. -- `@reactive-resume/pdf` owns PDF generation helpers but not PDF.js viewer UI. -- `apps/web` uses domain-first features and generic-only `src/components`. -- `packages/db` remains centralized. - -## Latest Task 1 Result - -- Created `@reactive-resume/resume` with source-consumed exports: - - `@reactive-resume/resume/patch` - - `@reactive-resume/resume/icons` -- Moved JSON Patch behavior/tests and social network icon mapping/tests out of `@reactive-resume/utils`. -- Updated consumers in `packages/ai`, `packages/api`, `packages/db`, `packages/import`, and `apps/web`. -- Removed old utils exports for `./resume/patch` and `./network-icons`. -- Removed `fast-json-patch` from `@reactive-resume/utils` and `@reactive-resume/ai`; it now belongs to `@reactive-resume/resume`. -- Task 2 later removed `@reactive-resume/schema` from `@reactive-resume/utils` after moving DOCX code into `@reactive-resume/docx`. - -## Latest Task 2 Result - -- Created `@reactive-resume/docx` with source-consumed root export `@reactive-resume/docx`. -- Moved the DOCX builder, HTML conversion, link utilities, section renderers, and colocated tests from `packages/utils/src/resume/docx` to `packages/docx/src`. -- Updated web DOCX export callers and the export-section test mock to import from `@reactive-resume/docx`. -- Removed the old `@reactive-resume/utils/resume/docx` export and removed `docx` plus `@reactive-resume/schema` from `@reactive-resume/utils`. -- Validation passed for `@reactive-resume/docx` tests/typecheck, `@reactive-resume/utils` typecheck, `web` typecheck, focused web export test command, and focused Biome check. - -## Latest Task 3 Notes - -- Added `@reactive-resume/pdf/browser` and `@reactive-resume/pdf/server` exports. -- `createResumePdfBlob({ data, template, resolveSectionTitle })` delegates to `pdf().toBlob()`. -- `createResumePdfFile({ data, filename, template, resolveSectionTitle })` delegates to `renderToBuffer()` and preserves the existing `File` response body shape. -- Lingui locale loading stays in the web-local wrappers under `apps/web/src/features/resume/export`; those wrappers resolve section titles and pass `resolveSectionTitle` into the package helpers. -- The PDF.js viewer/canvas components remain in web. `apps/web/src/features/resume/preview/preview.browser.tsx` now calls the web-local blob wrapper instead of importing `@react-pdf/renderer` directly. -- The authenticated PDF export path now reaches `@reactive-resume/pdf/server` through `packages/api/src/features/resume/export.ts`; `apps/server` consumes the explicit API feature export instead of owning PDF rendering logic directly. -- Validation passed for `@reactive-resume/pdf` tests/typecheck, `web` typecheck, `server` typecheck, focused web PDF export/viewer tests, and focused Biome check. - -## Latest Task 4 Notes - -- Created `@reactive-resume/mcp` with source-consumed exports for the compact public surface plus direct subpaths for server card, tool names, tools, prompts, and resources. -- Moved MCP tools, prompts, resources, server-card generation, tool annotations, and colocated tests from `apps/web/src/routes/mcp/-helpers` to `packages/mcp/src`. -- `apps/server/src/mcp/handler.ts` and `apps/server/src/openapi/metadata.ts` now import from `@reactive-resume/mcp`; server-side MCP execution still uses the injected in-process oRPC `RouterClient`. -- Canonical MCP tool names are unprefixed snake_case. Key renames: `read_resume` replaces the old get-resume tool name, and `apply_resume_patch` replaces the old patch tool name. No `reactive_resume_*` aliases remain. -- Added `@reactive-resume/ai/tools/resume-tool-contracts` and reused its JSON Patch operations schema from MCP while keeping MCP-specific `id` context in the MCP input schema. -- Validation passed for `@reactive-resume/mcp` tests/typecheck, `server` typecheck, `@reactive-resume/ai` typecheck, focused Biome check, and the app-to-app import scan. - -## Latest Task 5 Notes - -- `packages/api/src` is now organized by feature/capability under `packages/api/src/features`. -- The root router still exports the same top-level API contract from `packages/api/src/routers/index.ts`, but it imports feature routers from `features/*/router`. -- Agent modules now live under `features/agent`, with separate procedure modules for threads, messages, attachments, and actions; run-state lives in `runs.ts`, tool construction in `tools.ts`, and the remaining shared orchestration stays in `service.ts`. -- Resume modules now live under `features/resume`, with capability procedure modules for CRUD, tags, statistics, analysis, events, sharing, and export. Access helpers and resume update events are feature-owned. -- The authenticated PDF download procedure moved to `packages/api/src/features/resume/export.ts` and calls `@reactive-resume/pdf/server`. -- `@reactive-resume/api` no longer exports `./services/*` or `./helpers/*`; explicit exports now cover routers, context, flags type, resume runtime/export, and storage runtime. -- `apps/server` imports storage and the PDF procedure from explicit API feature exports. `apps/web` API imports remain type-only. -- Follow-up risk: `features/agent/service.ts` and `features/resume/service.ts` are still large DB-backed facades. They are feature-owned now, but further splitting should be handled as behavior-preserving follow-up work with targeted tests around run lifecycle, patch transactions, notifications, and storage cleanup. -- Validation passed for API tests/typecheck, server typecheck, web typecheck, MCP typecheck, focused Biome, and old service/helper import/export scans. - -## Latest Task 6 Notes - -- `apps/server/src` now reads as a runtime adapter app: - - `http`: route composition, auth/health HTTP handlers, common header/cookie helpers - - `rpc`: oRPC fetch handler and request-locale extraction - - `mcp`: MCP auth, per-request server setup, and streamable HTTP transport handler - - `openapi`: OpenAPI handler plus OAuth/OpenID/MCP well-known metadata - - `static`: upload serving, `/schema.json`, and `apps/web/dist` static/SPA fallback serving - - `startup`: database migrations and local-storage path checks -- `apps/server/src/index.ts` now only re-exports `createApp`, runs startup checks, computes the port, and starts the Hono server. -- The route order and public paths from the previous `index.ts` were preserved, including `/api/rpc`, `/api/openapi`, `/api/auth/*`, `/api/health`, `/uploads/*`, `/schema.json`, `/auth/oauth`, `/mcp`, `/.well-known/*`, and the web-dist fallback. -- Server-side API imports remain on explicit runtime exports only; no `@reactive-resume/api/services/*` or `apps/web/src` imports were introduced. -- Validation passed for server test/typecheck during implementation. Final Task 6 validation commands should still be listed in the worklog/final response after the executing agent's last run. - -## Latest Task 7 Slice 1 Notes - -- Resume-owned web code now starts under `apps/web/src/features/resume`: - - `builder/draft.ts` owns the builder resume draft store/hooks. - - `preview/*` owns the builder preview shell, PDF.js canvas renderer, shared preview helpers/tests, and dashboard thumbnail PDF rendering helpers. - - `export/pdf-document*.tsx` owns web-local PDF document/blob/file wrappers around `@reactive-resume/pdf`. - - `public/*` owns the public resume view, public PDF.js viewer, CSS, and tests. -- The old generic resume component folder and public-route private component folder were removed after their files moved. -- Direct `pdfjs-dist` imports are expected only under `apps/web/src/features/resume`; do not move them into `packages/pdf`. -- The public resume route remains responsible for loader/error/head composition, keeps `ssr: "data-only"`, and lazy-loads `@/features/resume/public/public-resume`. -- The builder preview route keeps `ssr: false` and lazy-loads the preview page composition. -- Remaining Task 7 work should continue moving non-resume web domains out of generic `components`/routes. Task 8 still owns dialog registry decomposition beyond import updates caused by the draft-store move. - -## Latest Task 7 Slice 2 Notes - -- App-shell code now starts under feature folders: - - `apps/web/src/features/command-palette` owns the command palette implementation and tests. - - `apps/web/src/features/theme` owns the theme provider, combobox, toggle button, and tests. - - `apps/web/src/features/locale` owns the locale combobox and tests. - - `apps/web/src/features/user` owns the user dropdown. -- Auth route UI now lives under `apps/web/src/features/auth`; route files under `apps/web/src/routes/auth` keep redirects/search validation and compose the feature pages. -- Settings page UI now lives under `apps/web/src/features/settings`; route files under `apps/web/src/routes/dashboard/settings` keep dashboard header composition and redirects. `job-search.tsx` remains route-only because it is already just a redirect shim. -- The old `@/components/{command-palette,theme,locale,user}` import paths should not be reintroduced; current consumers import from `@/features/*`. -- `apps/web/src/components` now contains remaining generic primitive/screen folders only. -- Task 8 still owns dialog registry decomposition; this slice did not decompose dialog definitions. - -## Latest Task 8 Notes - -- `apps/web/src/dialogs/store.ts` remains the single global dialog runtime and still exports `useDialogStore` plus `DialogProps` for existing callers. -- Dialog schemas now compose through `apps/web/src/dialogs/schemas.ts` from domain-owned schema entries in `dialogs/auth/schema.ts`, `dialogs/api-key/schema.ts`, and `dialogs/resume/schema.ts`. -- Dialog rendering now composes through `apps/web/src/dialogs/renderers.tsx` from domain-owned renderer registries in `dialogs/auth/registry.tsx`, `dialogs/api-key/registry.tsx`, and `dialogs/resume/registry.tsx`. -- `apps/web/src/dialogs/manager.tsx` only imports the dialog shell, `renderDialog`, and the global store; it no longer imports every dialog implementation directly. -- No settings/auth-specific dialog tests existed beyond the shared dialog store and resume template tests. - -## Latest Task 9 Notes - -- `turbo.json` now has executable `boundaries` config: - - Global dependencies deny `web` and `server`, preventing package-to-app and app-to-app dependency edges. - - Root test tools are explicit `implicitDependencies`: `vitest`, `@testing-library/jest-dom`, `@testing-library/react`, and `@testing-library/user-event`. - - Tag rules cover app, server, browser, universal, domain, and UI layers. -- Workspace `turbo.json` files now exist for both apps and every package. Each extends root config with `extends: ["//"]` and declares tags used by the root boundaries. -- Every workspace `vitest.config.ts` keeps its legitimate root shared config import with `// @boundaries-ignore root shared Vitest config` immediately above `import { createVitestProjectConfig } from "../../vitest.shared";`. -- `biome.json` now enables `style.noRestrictedImports` for forbidden cross-workspace source/path imports: - - `@reactive-resume/*/src/**` - - `apps/**` - - `packages/**` -- `biome.json` also registers `tooling/grit/no-cross-workspace-src-imports.grit`, which flags import/export/dynamic import sources that reach into another workspace's `src` tree. -- `apps/web/tsconfig.json` no longer maps `@reactive-resume/ui/*` directly to `../../packages/ui/src/*`; the web app uses `@reactive-resume/ui` package exports instead. -- Files changed by Task 9: - - `turbo.json` - - `apps/*/turbo.json` - - `packages/*/turbo.json` - - `biome.json` - - `tooling/grit/no-cross-workspace-src-imports.grit` - - `apps/web/tsconfig.json` - - `apps/server/vitest.config.ts` - - `apps/web/vitest.config.ts` - - `packages/*/vitest.config.ts` - - `docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md` - - `docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md` -- Validation passed: - - `pnpm exec turbo boundaries` - - `pnpm exec biome check biome.json turbo.json tooling/grit/no-cross-workspace-src-imports.grit apps/web/tsconfig.json apps/server/turbo.json apps/web/turbo.json packages/*/turbo.json` - - `pnpm --filter web typecheck` - - `pnpm --filter @reactive-resume/api typecheck` - - `pnpm --filter server typecheck` -- Remaining risks: - - The Turbo tag set is intentionally coarse and may need finer per-package rules as future browser/server package classes settle. - - The GritQL plugin only inspects code import/export sources; keep the package export-map and tsconfig scans in the final validation list. - - The root shared Vitest config remains an intentional boundary ignore; moving it behind a package export would be a separate test-infra cleanup. - -## Latest Task 10 Notes - -- `AGENTS.md` is now the operational source of truth for package roles, runtime tags, import rules, placement decisions, and validation commands. -- `docs/contributing/architecture.mdx` is now a public contributor overview of the current monorepo layout instead of the removed single-`src` architecture. -- `docs/adr/0001-workspace-boundaries.md` records the rationale for domain-first packages, explicit export maps, `turbo boundaries`, and Biome/Grit import enforcement. -- MCP user docs already list canonical unprefixed tool names from Task 4. AI Agent tool docs already list `read_resume` and `apply_resume_patch`; no Task 10 changes were needed there. -- Follow-up documentation audit on 2026-05-15 reconciled AGENTS and public docs with the final `apps/server` Hono adapter shape, current Node/pnpm prerequisites, Base UI wording, provider-native web research behavior, and the current env schema. -- Docs validation available in-repo is limited: - - Stale-text scan passed except expected `ORPCClient` diagram labels. - - Biome ignored Markdown/MDX and reported that no files were processed for the docs paths. - - No dedicated docs build/check script exists in `package.json`. - -## Latest Task 11 Notes - -- Final cleanup after `pnpm knip`: - - Removed stale app dependencies from `apps/server/package.json` and `apps/web/package.json`. - - Deleted the unused web server PDF wrapper at `apps/web/src/features/resume/export/pdf-document.server.tsx`. - - Removed unnecessary exported markers from internal helper functions/constants. - - Added `pdfExportRateLimit` to `packages/api/src/features/resume/export.ts`. - - Removed unused jobs rate-limit middleware entries that no current router uses. -- Final validation commands passed: - - `pnpm install --lockfile-only` - - `pnpm install` - - `pnpm exec biome check .` - - `pnpm exec turbo boundaries` - - `pnpm knip` - - `pnpm typecheck` - - `pnpm test` - - `pnpm build` -- `pnpm knip` still prints a non-failing configuration hint: `src/server.ts apps/web knip.json Refine entry pattern (no matches)`. -- Useful review anchors: - - Architecture rules: `AGENTS.md`, `docs/contributing/architecture.mdx`, `docs/adr/0001-workspace-boundaries.md`. - - Boundary enforcement: `turbo.json`, workspace `turbo.json` files, `biome.json`, `tooling/grit/no-cross-workspace-src-imports.grit`. - - API feature tree: `packages/api/src/features`. - - Server adapter tree: `apps/server/src/{http,rpc,mcp,openapi,static,startup}`. - - Web feature tree: `apps/web/src/features`. diff --git a/docs/superpowers/plans/2026-05-14-monolith-and-split-deployment-architecture.md b/docs/superpowers/plans/2026-05-14-monolith-and-split-deployment-architecture.md deleted file mode 100644 index 6e9ac79dd..000000000 --- a/docs/superpowers/plans/2026-05-14-monolith-and-split-deployment-architecture.md +++ /dev/null @@ -1,1143 +0,0 @@ -# Monolith and Split Deployment Architecture Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -> **Status note:** This is a historical proposal, not the current architecture source of truth. Before executing any task from this plan, verify paths and route ownership against `AGENTS.md`, `docs/contributing/architecture.mdx`, and the current `apps/server/src/{http,rpc,mcp,openapi,static,startup}` tree. - -**Goal:** Preserve the existing one-image Docker contract for open-source self-hosters while enabling the same codebase to run as an edge/static frontend plus Node backend for hosted and VPS split deployments. - -**Architecture:** Reactive Resume should have one route ownership model and multiple deployment compositions. The OSS Docker image remains a monolith: one image, one port, backend routes plus static SPA fallback. Hosted/split deployments serve the built SPA statically from Cloudflare/S3/NGINX/Caddy and route only backend-owned paths to the Node server, where unknown frontend routes return `404`. - -**Tech Stack:** Hono, Better Auth, Vite, Turborepo, Docker, optional NGINX/Caddy/CDN routing, Zod JSON Schema generation. - ---- - -## Decisions Locked By This Plan - -- Keep the official Docker image as a complete monolith. -- Do not make NGINX a required wrapper for the official OSS image. -- Use Hono static serving as the Docker/self-host fallback. -- Prefer edge/static frontend plus Node backend for hosted Reactive Resume. -- Do not pursue Cloudflare Worker backend support in this phase. -- Keep backend logic Node-first and platform-independent where practical, but do not contort PDF, database, storage, or auth runtime code for Worker compatibility yet. -- Move custom OAuth bridge behavior under `/api/auth/oauth`. -- Keep `/.well-known/*` backend-owned because OAuth/MCP metadata is runtime-owned. -- Make `/schema.json` frontend/static-owned by generating it during build/source preparation. -- In split backend mode, unknown non-backend routes return `404`. - -## Deployment Modes - -### Mode 1: Docker Monolith - -**Audience:** OSS users and current Docker image consumers. - -```txt -Request -> Node/Hono server - /api/* -> backend - /api/auth/oauth -> custom OAuth bridge - /mcp, /mcp/* -> backend - /.well-known/* -> backend - /uploads/* -> backend unless object storage owns this later - /schema.json -> static file from apps/web/dist - static assets -> static file from apps/web/dist - non-file GET/HEAD -> apps/web/dist/index.html - file-looking miss -> 404 -``` - -### Mode 2: Split VPS - -**Audience:** Advanced self-hosters or the project owner's VPS migration path. - -```txt -Request -> NGINX/Caddy - static files -> apps/web/dist - SPA fallback -> apps/web/dist/index.html - backend routes -> proxy to Node - -Request -> Node/Hono backend-only app - backend routes -> backend - unknown routes -> 404 -``` - -### Mode 3: Hosted Edge Frontend + Node Backend - -**Audience:** Cloud hosted Reactive Resume. - -```txt -Request -> Cloudflare/S3/CDN - static files -> edge object/static hosting - SPA fallback -> edge index.html - backend routes -> proxy/fetch to Node backend - -Request -> Node backend - backend routes -> backend - unknown routes -> 404 -``` - ---- - -## Route Ownership Contract - -### Backend-Owned Routes - -```txt -/api/* -/api/auth/oauth -/mcp -/mcp/* -/.well-known/* -/uploads/* -``` - -`/uploads/*` remains backend-owned while local filesystem uploads are supported. If uploads move fully to S3/R2 public or signed URLs later, this can become object-storage-owned. - -### Frontend/Static-Owned Routes - -```txt -/schema.json -/assets/* -/templates/* -/favicon.ico -/favicon.svg -/manifest.webmanifest -/robots.txt -/sitemap.xml -/fonts/* -/icon/* -/logo/* -/opengraph/* -/photos/* -/pwa-*.png -/sounds/* -/videos/* -``` - -### Frontend SPA-Owned Routes - -```txt -/auth/* -/dashboard/* -/builder/* -/agent/* -/$username/$slug -all other non-file GET/HEAD frontend routes -``` - -In Docker monolith mode, Node serves the SPA fallback. In split modes, the static frontend host serves the SPA fallback and Node returns `404` for unknown non-backend routes. - ---- - -## File Structure - -- Create `packages/server` - - Owns route ownership constants and shared Hono app composition. - - Exposes `createBackendApp()` and `createMonolithApp()`. -- Modify `apps/server/src/index.ts` - - Becomes a thin Node entrypoint around `@reactive-resume/server/node`. - - Selects monolith/backend-only mode through explicit env/config. -- Modify `apps/server/src/handlers/*` - - Move or re-export handlers into `packages/server` only after package boundaries are clear. - - Keep this as a later task if direct movement is too large. -- Modify `packages/auth/src/config.ts` - - Change OAuth provider `loginPage` and `consentPage` to `/api/auth/oauth`. -- Modify `apps/server/src/handlers/auth.ts` - - Change callback preservation to `/api/auth/oauth`. -- Create `packages/scripts/schema/generate.ts` - - Generates both package and web-public schema artifacts. -- Create `apps/web/public/schema.json` - - Static schema artifact for Vite, Docker monolith, S3, and edge hosting. -- Modify `apps/web/package.json` - - Runs schema generation before build. -- Modify `apps/web/vite.config.ts` - - Remove dev proxies that become unnecessary after route/static ownership cleanup. -- Modify `Dockerfile` - - Preserve one-image behavior. - - Make runtime default to monolith mode. -- Create `docs/deployment/architecture.mdx` - - Explains monolith vs split modes. -- Create `docs/deployment/split-vps.mdx` - - Shows NGINX/Caddy examples. -- Create `docs/deployment/edge-frontend-node-backend.mdx` - - Shows Cloudflare/S3/CDN static frontend plus Node backend. -- Create or update `AGENTS.md` - - Records route ownership and deployment-mode rules as normative architecture guidance. - ---- - -## Task 1: Document The Deployment Contract First - -**Files:** -- Create: `docs/deployment/architecture.mdx` -- Create: `docs/deployment/split-vps.mdx` -- Create: `docs/deployment/edge-frontend-node-backend.mdx` -- Modify: `AGENTS.md` - -- [ ] **Step 1: Write `docs/deployment/architecture.mdx`** - -Create the document with these sections: - -```mdx -# Deployment Architecture - -Reactive Resume supports multiple deployment compositions from one codebase. - -## Default: Docker Monolith - -The official Docker image remains a complete application image. It exposes one port and serves backend routes, static assets, and SPA fallback from the same Node process. - -This is the compatibility contract for open-source self-hosters. - -## Split Frontend And Backend - -Split deployments serve `apps/web/dist` from a static host and route backend-owned paths to the Node server. - -The Node server does not serve SPA fallback in backend-only mode. Unknown non-backend routes return `404`. - -## Route Ownership - -Backend-owned: - -- `/api/*` -- `/api/auth/oauth` -- `/mcp` -- `/mcp/*` -- `/.well-known/*` -- `/uploads/*` - -Frontend/static-owned: - -- `/schema.json` -- `/assets/*` -- `/templates/*` -- `/favicon.ico` -- `/favicon.svg` -- `/manifest.webmanifest` -- `/robots.txt` -- `/sitemap.xml` -- `/fonts/*` -- `/icon/*` -- `/logo/*` -- `/opengraph/*` -- `/photos/*` -- `/pwa-*.png` -- `/sounds/*` -- `/videos/*` - -Frontend SPA-owned: - -- `/auth/*` -- `/dashboard/*` -- `/builder/*` -- `/agent/*` -- public resume pages -- all other non-file frontend routes - -## Runtime Modes - -- `monolith`: backend routes plus static SPA serving. -- `backend-only`: backend routes only; unknown routes return `404`. -``` - -- [ ] **Step 2: Write `docs/deployment/split-vps.mdx`** - -Include this minimal NGINX shape: - -```nginx -server { - listen 80; - server_name example.com; - - root /srv/reactive-resume/web; - index index.html; - - location ^~ /api/ { - proxy_pass http://127.0.0.1:3000; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } - - location = /mcp { - proxy_pass http://127.0.0.1:3000; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } - - location ^~ /mcp/ { - proxy_pass http://127.0.0.1:3000; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } - - location ^~ /.well-known/ { - proxy_pass http://127.0.0.1:3000; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } - - location ^~ /uploads/ { - proxy_pass http://127.0.0.1:3000; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } - - location / { - try_files $uri $uri/ /index.html; - } -} -``` - -Add a note that `APP_URL` must be the public origin. - -- [ ] **Step 3: Write `docs/deployment/edge-frontend-node-backend.mdx`** - -Include: - -```mdx -# Edge Frontend With Node Backend - -Build `apps/web/dist` and upload it to the static host. Route backend-owned paths to the Node backend. - -Backend route patterns: - -- `/api/*` -- `/mcp` -- `/mcp/*` -- `/.well-known/*` -- `/uploads/*` - -The frontend host owns `/schema.json` and SPA fallback. - -The Node backend should run in backend-only mode so unknown frontend routes return `404`. -``` - -- [ ] **Step 4: Update `AGENTS.md`** - -Add a short normative section: - -```md -### Deployment route ownership - -The official Docker image is a monolith and must keep serving the full application from one image and one port. - -Split deployments are supported by serving `apps/web/dist` statically and routing backend-owned paths to Node. In backend-only mode, Node returns `404` for unknown frontend routes. - -Do not add new backend routes outside `/api/*`, `/mcp`, `/.well-known/*`, or explicitly documented exceptions without updating the route ownership docs. -``` - -- [ ] **Step 5: Commit** - -```bash -git add docs/deployment/architecture.mdx docs/deployment/split-vps.mdx docs/deployment/edge-frontend-node-backend.mdx AGENTS.md -git commit -m "docs: define monolith and split deployment contract" -``` - ---- - -## Task 2: Create Route Ownership Primitives - -**Files:** -- Create: `packages/server/package.json` -- Create: `packages/server/tsconfig.json` -- Create: `packages/server/vitest.config.ts` -- Create: `packages/server/src/routes/ownership.ts` -- Create: `packages/server/src/routes/ownership.test.ts` - -- [ ] **Step 1: Write the failing ownership tests** - -Create `packages/server/src/routes/ownership.test.ts`: - -```ts -import { describe, expect, it } from "vitest"; -import { getRouteOwner } from "./ownership"; - -describe("getRouteOwner", () => { - it.each([ - ["/api/rpc", "backend"], - ["/api/auth/oauth", "backend"], - ["/mcp", "backend"], - ["/mcp/tools", "backend"], - ["/.well-known/oauth-protected-resource", "backend"], - ["/uploads/avatar.png", "backend"], - ["/schema.json", "static"], - ["/assets/app.js", "static"], - ["/templates/jpg/azurill.jpg", "static"], - ["/auth/login", "spa"], - ["/dashboard", "spa"], - ["/builder/abc", "spa"], - ["/agent/thread", "spa"], - ["/amruth/resume", "spa"], - ])("classifies %s as %s", (pathname, owner) => { - expect(getRouteOwner(pathname)).toBe(owner); - }); - - it.each(["/missing.js", "/unknown.css", "/image.png"])("classifies file-looking misses as static", (pathname) => { - expect(getRouteOwner(pathname)).toBe("static"); - }); -}); -``` - -- [ ] **Step 2: Add package scaffolding** - -Create `packages/server/package.json`: - -```json -{ - "name": "@reactive-resume/server", - "version": "0.0.0", - "type": "module", - "private": true, - "exports": { - "./routes/ownership": "./src/routes/ownership.ts" - }, - "scripts": { - "typecheck": "tsgo --noEmit", - "test": "vitest run --passWithNoTests" - }, - "devDependencies": { - "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260514.1", - "typescript": "^6.0.3" - } -} -``` - -Create `packages/server/tsconfig.json`: - -```json -{ - "extends": "@reactive-resume/config/tsconfig.base.json" -} -``` - -Create `packages/server/vitest.config.ts`: - -```ts -import { createVitestProjectConfig } from "@reactive-resume/config/vitest"; - -export default createVitestProjectConfig({ - name: "@reactive-resume/server", -}); -``` - -- [ ] **Step 3: Run the failing tests** - -```bash -pnpm --filter @reactive-resume/server test -- src/routes/ownership.test.ts -``` - -Expected: fails because `ownership.ts` does not exist. - -- [ ] **Step 4: Implement route ownership** - -Create `packages/server/src/routes/ownership.ts`: - -```ts -export type RouteOwner = "backend" | "static" | "spa"; - -const backendExactRoutes = new Set(["/mcp"]); -const backendPrefixes = ["/api/", "/mcp/", "/.well-known/", "/uploads/"]; -const staticExactRoutes = new Set([ - "/schema.json", - "/favicon.ico", - "/favicon.svg", - "/manifest.webmanifest", - "/robots.txt", - "/sitemap.xml", -]); -const staticPrefixes = [ - "/assets/", - "/templates/", - "/fonts/", - "/icon/", - "/logo/", - "/opengraph/", - "/photos/", - "/sounds/", - "/videos/", -]; - -function looksLikeFile(pathname: string) { - const lastSegment = pathname.split("/").pop() ?? ""; - return lastSegment.includes("."); -} - -export function getRouteOwner(pathname: string): RouteOwner { - if (backendExactRoutes.has(pathname)) return "backend"; - if (backendPrefixes.some((prefix) => pathname.startsWith(prefix))) return "backend"; - if (staticExactRoutes.has(pathname)) return "static"; - if (staticPrefixes.some((prefix) => pathname.startsWith(prefix))) return "static"; - if (/^\/pwa-\d+x\d+\.png$/.test(pathname)) return "static"; - if (looksLikeFile(pathname)) return "static"; - return "spa"; -} - -export function isBackendRoute(pathname: string) { - return getRouteOwner(pathname) === "backend"; -} - -export function isStaticRoute(pathname: string) { - return getRouteOwner(pathname) === "static"; -} -``` - -- [ ] **Step 5: Verify route ownership tests** - -```bash -pnpm --filter @reactive-resume/server test -- src/routes/ownership.test.ts -pnpm --filter @reactive-resume/server typecheck -``` - -Expected: both pass. - -- [ ] **Step 6: Commit** - -```bash -git add packages/server -git commit -m "feat(server): add route ownership contract" -``` - ---- - -## Task 3: Move Custom OAuth Bridge To `/api/auth/oauth` - -**Files:** -- Modify: `apps/server/src/handlers/auth.test.ts` -- Create: `apps/server/src/index.test.ts` -- Modify: `apps/server/src/index.ts` -- Modify: `apps/server/src/handlers/auth.ts` -- Modify: `packages/auth/src/config.ts` -- Modify: `apps/web/vite.config.ts` - -- [ ] **Step 1: Update the handler test first** - -In `apps/server/src/handlers/auth.test.ts`, change the request URL and expected callback path: - -```ts -const response = await handleOAuth( - new Request( - "http://localhost:3001/api/auth/oauth?client_id=test-client&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&state=abc&exp=123&sig=456", - ), -); - -expect(callbackUrl.pathname).toBe("/api/auth/oauth"); -``` - -- [ ] **Step 2: Add a route precedence test** - -Create `apps/server/src/index.test.ts`: - -```ts -import { beforeEach, describe, expect, it, vi } from "vitest"; - -const mocks = vi.hoisted(() => ({ - handleAuth: vi.fn(), - handleOAuth: vi.fn(), -})); - -vi.mock("./handlers/auth", () => ({ - handleAuth: mocks.handleAuth, - handleOAuth: mocks.handleOAuth, -})); - -vi.mock("./handlers/health", () => ({ handleHealth: () => Response.json({ ok: true }) })); -vi.mock("./handlers/mcp", () => ({ handleMcp: () => new Response("mcp") })); -vi.mock("./handlers/metadata", () => ({ - handleMcpServerCard: () => Response.json({}), - handleOAuthAuthorizationServer: () => Response.json({}), - handleOAuthProtectedResource: () => Response.json({}), - handleOpenIdConfiguration: () => Response.json({}), - handleWellKnownFallback: () => new Response("OK"), -})); -vi.mock("./handlers/openapi", () => ({ handleOpenApi: () => Response.json({}) })); -vi.mock("./handlers/rpc", () => ({ handleRpc: () => Response.json({}) })); -vi.mock("./handlers/uploads", () => ({ handleUpload: () => new Response("upload") })); - -describe("createApp route ownership", () => { - beforeEach(() => { - mocks.handleAuth.mockReset(); - mocks.handleOAuth.mockReset(); - mocks.handleAuth.mockResolvedValue(Response.json({ route: "auth" })); - mocks.handleOAuth.mockResolvedValue(Response.json({ route: "oauth" })); - }); - - it("routes /api/auth/oauth to the custom OAuth bridge before the Better Auth catch-all", async () => { - const { createApp } = await import("./index"); - const response = await createApp().request("http://localhost:3001/api/auth/oauth?client_id=test"); - - await expect(response.json()).resolves.toEqual({ route: "oauth" }); - expect(mocks.handleOAuth).toHaveBeenCalledTimes(1); - expect(mocks.handleAuth).not.toHaveBeenCalled(); - }); - - it("keeps other /api/auth/* requests on the Better Auth handler", async () => { - const { createApp } = await import("./index"); - const response = await createApp().request("http://localhost:3001/api/auth/session"); - - await expect(response.json()).resolves.toEqual({ route: "auth" }); - expect(mocks.handleAuth).toHaveBeenCalledTimes(1); - expect(mocks.handleOAuth).not.toHaveBeenCalled(); - }); -}); -``` - -- [ ] **Step 3: Run failing tests** - -```bash -pnpm --filter server test -- src/handlers/auth.test.ts src/index.test.ts -``` - -Expected: tests fail because the implementation still uses `/auth/oauth`. - -- [ ] **Step 4: Update server route order** - -In `apps/server/src/index.ts`, register the custom route before Better Auth catch-all: - -```ts -app.get("/api/auth/oauth", (c) => handleOAuth(c.req.raw)); -app.on(["GET", "POST"], "/api/auth/*", (c) => handleAuth(c.req.raw)); -``` - -Remove: - -```ts -app.get("/auth/oauth", (c) => handleOAuth(c.req.raw)); -``` - -- [ ] **Step 5: Update callback preservation** - -In `apps/server/src/handlers/auth.ts`, change: - -```ts -loginUrl.searchParams.set("callbackURL", `/auth/oauth?${oauthParams.toString()}`); -``` - -to: - -```ts -loginUrl.searchParams.set("callbackURL", `/api/auth/oauth?${oauthParams.toString()}`); -``` - -- [ ] **Step 6: Update Better Auth OAuth provider pages** - -In `packages/auth/src/config.ts`, change: - -```ts -oauthProvider({ - loginPage: "/api/auth/oauth", - consentPage: "/api/auth/oauth", -``` - -- [ ] **Step 7: Remove old dev proxy** - -In `apps/web/vite.config.ts`, remove the `"/auth/oauth"` proxy entry. `/api/auth/oauth` is covered by the existing `"/api"` proxy. - -- [ ] **Step 8: Verify and commit** - -```bash -pnpm --filter server test -- src/handlers/auth.test.ts src/index.test.ts -pnpm --filter server typecheck -pnpm --filter @reactive-resume/auth typecheck -``` - -Expected: all pass. - -```bash -git add apps/server/src/handlers/auth.test.ts apps/server/src/index.test.ts apps/server/src/index.ts apps/server/src/handlers/auth.ts packages/auth/src/config.ts apps/web/vite.config.ts -git commit -m "fix(auth): move OAuth bridge under api auth routes" -``` - ---- - -## Task 4: Make `/schema.json` Static - -**Files:** -- Create: `packages/scripts/schema/generate.ts` -- Create: `packages/scripts/schema/generate.test.ts` -- Modify: `packages/scripts/package.json` -- Modify: `apps/web/package.json` -- Create: `apps/web/public/schema.json` -- Modify: `apps/web/vite.config.ts` -- Modify: `apps/server/src/index.ts` -- Modify: `apps/server/src/handlers/metadata.ts` - -- [ ] **Step 1: Write generator test first** - -Create `packages/scripts/schema/generate.test.ts`: - -```ts -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import { describe, expect, it } from "vitest"; -import { generateResumeSchemaJson } from "./generate"; - -describe("generateResumeSchemaJson", () => { - it("writes identical resume JSON Schema to every target", async () => { - const directory = await fs.mkdtemp(path.join(os.tmpdir(), "resume-schema-")); - const firstTarget = path.join(directory, "schema-a.json"); - const secondTarget = path.join(directory, "nested", "schema-b.json"); - - await generateResumeSchemaJson([firstTarget, secondTarget]); - - const first = await fs.readFile(firstTarget, "utf-8"); - const second = await fs.readFile(secondTarget, "utf-8"); - - expect(JSON.parse(first)).toEqual(JSON.parse(second)); - expect(JSON.parse(first)).toHaveProperty("properties.basics"); - expect(first.endsWith("\n")).toBe(true); - }); -}); -``` - -- [ ] **Step 2: Add script package entries** - -In `packages/scripts/package.json`, add: - -```json -"schema:generate": "tsx schema/generate.ts", -"test": "vitest run --passWithNoTests" -``` - -Add missing dev dependencies: - -```json -"@reactive-resume/schema": "workspace:*", -"vitest": "^4.1.6", -"zod": "^4.4.3" -``` - -- [ ] **Step 3: Run failing generator test** - -```bash -pnpm --filter @reactive-resume/scripts test -- schema/generate.test.ts -``` - -Expected: fails because `generate.ts` does not exist. - -- [ ] **Step 4: Implement generator** - -Create `packages/scripts/schema/generate.ts`: - -```ts -import fs from "node:fs/promises"; -import path from "node:path"; -import { fileURLToPath, pathToFileURL } from "node:url"; -import z from "zod"; -import { resumeDataSchema } from "@reactive-resume/schema/resume/data"; - -const defaultTargets = [ - new URL("../../schema/schema.json", import.meta.url), - new URL("../../../apps/web/public/schema.json", import.meta.url), -]; - -function toPath(target: string | URL) { - return target instanceof URL ? fileURLToPath(target) : target; -} - -export async function generateResumeSchemaJson(targets: Array = defaultTargets) { - const schema = z.toJSONSchema(resumeDataSchema); - const contents = `${JSON.stringify(schema, null, "\t")}\n`; - - await Promise.all( - targets.map(async (target) => { - const targetPath = toPath(target); - await fs.mkdir(path.dirname(targetPath), { recursive: true }); - await fs.writeFile(targetPath, contents); - }), - ); -} - -if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { - await generateResumeSchemaJson(); -} -``` - -- [ ] **Step 5: Wire generation into web build** - -In `apps/web/package.json`, add: - -```json -"prebuild": "pnpm --filter @reactive-resume/scripts schema:generate" -``` - -Keep: - -```json -"build": "rm -rf dist && vite build" -``` - -- [ ] **Step 6: Remove backend runtime schema route** - -In `apps/server/src/index.ts`, remove the `handleSchemaJson` import and: - -```ts -app.get("/schema.json", () => handleSchemaJson()); -``` - -In `apps/server/src/handlers/metadata.ts`, remove: - -```ts -import z from "zod"; -import { resumeDataSchema } from "@reactive-resume/schema/resume/data"; -``` - -and delete `handleSchemaJson()`. - -- [ ] **Step 7: Remove web dev proxy for schema** - -In `apps/web/vite.config.ts`, remove the `"/schema.json"` proxy entry. - -- [ ] **Step 8: Generate and verify** - -```bash -pnpm --filter @reactive-resume/scripts schema:generate -pnpm --filter @reactive-resume/scripts test -- schema/generate.test.ts -pnpm --filter @reactive-resume/scripts typecheck -pnpm --filter server typecheck -pnpm --filter web build -test -f apps/web/dist/schema.json -cmp packages/schema/schema.json apps/web/public/schema.json -``` - -Expected: all commands pass. - -- [ ] **Step 9: Commit** - -```bash -git add packages/scripts/schema packages/scripts/package.json apps/web/package.json apps/web/public/schema.json apps/web/vite.config.ts apps/server/src/index.ts apps/server/src/handlers/metadata.ts packages/schema/schema.json -git commit -m "feat(web): serve resume schema as static asset" -``` - ---- - -## Task 5: Split Server App Composition Into Backend-Only And Monolith - -**Files:** -- Create: `apps/server/src/app.ts` -- Create: `apps/server/src/app.test.ts` -- Modify: `apps/server/src/index.ts` -- Modify: `apps/server/package.json` - -- [ ] **Step 1: Add tests for deployment mode behavior** - -Create `apps/server/src/app.test.ts`: - -```ts -import { describe, expect, it, vi } from "vitest"; - -vi.mock("./handlers/auth", () => ({ - handleAuth: () => Response.json({ route: "auth" }), - handleOAuth: () => Response.json({ route: "oauth" }), -})); -vi.mock("./handlers/health", () => ({ handleHealth: () => Response.json({ ok: true }) })); -vi.mock("./handlers/mcp", () => ({ handleMcp: () => new Response("mcp") })); -vi.mock("./handlers/metadata", () => ({ - handleMcpServerCard: () => Response.json({}), - handleOAuthAuthorizationServer: () => Response.json({}), - handleOAuthProtectedResource: () => Response.json({}), - handleOpenIdConfiguration: () => Response.json({}), - handleWellKnownFallback: () => new Response("OK"), -})); -vi.mock("./handlers/openapi", () => ({ handleOpenApi: () => Response.json({}) })); -vi.mock("./handlers/rpc", () => ({ handleRpc: () => Response.json({}) })); -vi.mock("./handlers/uploads", () => ({ handleUpload: () => new Response("upload") })); - -describe("server app deployment modes", () => { - it("returns 404 for frontend routes in backend-only mode", async () => { - const { createBackendApp } = await import("./app"); - const response = await createBackendApp().request("http://localhost:3001/dashboard"); - - expect(response.status).toBe(404); - }); - - it("keeps backend routes available in backend-only mode", async () => { - const { createBackendApp } = await import("./app"); - const response = await createBackendApp().request("http://localhost:3001/api/auth/oauth"); - - expect(response.status).toBe(200); - await expect(response.json()).resolves.toEqual({ route: "oauth" }); - }); -}); -``` - -- [ ] **Step 2: Run failing tests** - -```bash -pnpm --filter server test -- src/app.test.ts -``` - -Expected: fails because `app.ts` does not exist. - -- [ ] **Step 3: Extract backend app composition** - -Create `apps/server/src/app.ts`: - -```ts -import fs from "node:fs/promises"; -import { fileURLToPath } from "node:url"; -import { serveStatic } from "@hono/node-server/serve-static"; -import { Hono } from "hono"; -import { handleAuth, handleOAuth } from "./handlers/auth"; -import { handleHealth } from "./handlers/health"; -import { handleMcp } from "./handlers/mcp"; -import { - handleMcpServerCard, - handleOAuthAuthorizationServer, - handleOAuthProtectedResource, - handleOpenIdConfiguration, - handleWellKnownFallback, -} from "./handlers/metadata"; -import { handleOpenApi } from "./handlers/openapi"; -import { handleRpc } from "./handlers/rpc"; -import { handleUpload } from "./handlers/uploads"; - -const staticRoot = fileURLToPath(new URL("../../web/dist", import.meta.url)); -const indexHtmlPath = fileURLToPath(new URL("../../web/dist/index.html", import.meta.url)); - -function registerBackendRoutes(app: Hono) { - app.all("/api/rpc", (c) => handleRpc(c.req.raw)); - app.all("/api/rpc/*", (c) => handleRpc(c.req.raw)); - app.all("/api/openapi", (c) => handleOpenApi(c.req.raw)); - app.all("/api/openapi/*", (c) => handleOpenApi(c.req.raw)); - app.get("/api/auth/oauth", (c) => handleOAuth(c.req.raw)); - app.on(["GET", "POST"], "/api/auth/*", (c) => handleAuth(c.req.raw)); - app.get("/api/health", () => handleHealth()); - app.get("/api/uploads/*", (c) => handleUpload(c.req.raw)); - app.get("/uploads/*", (c) => handleUpload(c.req.raw)); - app.all("/mcp", (c) => handleMcp(c.req.raw)); - app.all("/mcp/*", (c) => handleMcp(c.req.raw)); - app.get("/.well-known/mcp/server-card.json", () => handleMcpServerCard()); - app.get("/.well-known/oauth-authorization-server", (c) => handleOAuthAuthorizationServer(c.req.raw)); - app.get("/.well-known/oauth-authorization-server/*", (c) => handleOAuthAuthorizationServer(c.req.raw)); - app.get("/.well-known/openid-configuration", (c) => handleOpenIdConfiguration(c.req.raw)); - app.get("/.well-known/oauth-protected-resource", () => handleOAuthProtectedResource()); - app.get("/.well-known/oauth-protected-resource/*", () => handleOAuthProtectedResource()); - app.get("/.well-known/*", () => handleWellKnownFallback()); - app.on(["HEAD"], "/.well-known/*", () => handleWellKnownFallback()); -} - -export function createBackendApp() { - const app = new Hono(); - registerBackendRoutes(app); - app.all("/*", () => new Response("Not Found", { status: 404 })); - return app; -} - -export function createMonolithApp() { - const app = new Hono(); - registerBackendRoutes(app); - - app.use("/*", serveStatic({ root: staticRoot, precompressed: true })); - app.get("/*", async (c) => { - const pathname = new URL(c.req.url).pathname; - if (pathname.split("/").pop()?.includes(".")) return c.text("Not Found", 404); - - const html = await fs.readFile(indexHtmlPath, "utf-8"); - return c.html(html); - }); - app.on(["HEAD"], "/*", async (c) => { - const pathname = new URL(c.req.url).pathname; - if (pathname.split("/").pop()?.includes(".")) return c.body(null, 404); - - return c.body(null, 200, { "Content-Type": "text/html; charset=UTF-8" }); - }); - - return app; -} -``` - -- [ ] **Step 4: Make index choose mode** - -In `apps/server/src/index.ts`, replace inline app creation with: - -```ts -import { pathToFileURL } from "node:url"; -import { serve } from "@hono/node-server"; -import { env } from "@reactive-resume/env/server"; -import { createBackendApp, createMonolithApp } from "./app"; -import { runStartupChecks } from "./lib/startup"; - -export function createApp() { - return process.env.SERVER_MODE === "backend-only" ? createBackendApp() : createMonolithApp(); -} - -async function main() { - await runStartupChecks(); - - const port = - process.env.NODE_ENV === "production" ? Number.parseInt(process.env.PORT ?? "3000", 10) : env.SERVER_PORT; - const app = createApp(); - - serve( - { - fetch: app.fetch, - port, - }, - (info) => { - console.info(`🚀 Up and running on http://localhost:${info.port}`); - }, - ); -} - -if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { - await main(); -} -``` - -- [ ] **Step 5: Verify** - -```bash -pnpm --filter server test -- src/app.test.ts src/index.test.ts -pnpm --filter server typecheck -``` - -Expected: pass. - -- [ ] **Step 6: Commit** - -```bash -git add apps/server/src/app.ts apps/server/src/app.test.ts apps/server/src/index.ts apps/server/package.json -git commit -m "feat(server): split backend and monolith app modes" -``` - ---- - -## Task 6: Preserve Docker Monolith Contract - -**Files:** -- Modify: `Dockerfile` -- Modify: `compose.yml` -- Modify: `compose.dev.yml` only if needed -- Modify: `docs/deployment/architecture.mdx` - -- [ ] **Step 1: Make Docker default explicit** - -In `Dockerfile`, add: - -```dockerfile -ENV NODE_ENV="production" \ - SERVER_MODE="monolith" \ - PORT=3000 \ - LOCAL_STORAGE_PATH=/app/data -``` - -- [ ] **Step 2: Document backend-only override** - -In `docs/deployment/architecture.mdx`, add: - -```mdx -## Server Mode - -`SERVER_MODE=monolith` is the default Docker mode. - -`SERVER_MODE=backend-only` disables static serving and SPA fallback. Use this behind an external static host or edge frontend. -``` - -- [ ] **Step 3: Verify Docker build path at least compiles** - -Run: - -```bash -pnpm build -``` - -Expected: build passes. If full repo build is too noisy due unrelated dirty work, run: - -```bash -pnpm --filter web build -pnpm --filter server build -``` - -Expected: both pass. - -- [ ] **Step 4: Commit** - -```bash -git add Dockerfile docs/deployment/architecture.mdx -git commit -m "chore(docker): keep monolith server mode as default" -``` - ---- - -## Task 7: Final Verification And Stale Reference Search - -**Files:** no new files. - -- [ ] **Step 1: Run focused tests** - -```bash -pnpm --filter @reactive-resume/server test -pnpm --filter server test -- src/handlers/auth.test.ts src/index.test.ts src/app.test.ts -pnpm --filter @reactive-resume/scripts test -- schema/generate.test.ts -``` - -Expected: all pass. - -- [ ] **Step 2: Run focused typechecks** - -```bash -pnpm --filter @reactive-resume/server typecheck -pnpm --filter server typecheck -pnpm --filter @reactive-resume/scripts typecheck -pnpm --filter @reactive-resume/auth typecheck -pnpm --filter web typecheck -``` - -Expected: all pass. - -- [ ] **Step 3: Verify static schema build** - -```bash -pnpm --filter @reactive-resume/scripts schema:generate -pnpm --filter web build -test -f apps/web/dist/schema.json -cmp packages/schema/schema.json apps/web/public/schema.json -``` - -Expected: all pass. - -- [ ] **Step 4: Search stale route references** - -```bash -rg '"/auth/oauth"|/auth/oauth|handleSchemaJson|app\\.get\\("/schema\\.json"|SERVER_MODE|backend-only|monolith' apps packages docs Dockerfile AGENTS.md -``` - -Expected: -- No runtime `/auth/oauth` references remain. -- No `handleSchemaJson` references remain. -- `SERVER_MODE`, `backend-only`, and `monolith` appear only in app composition, Docker, and docs. - -- [ ] **Step 5: Run non-mutating formatting/lint check on touched files** - -Use the repo's Biome config without writing: - -```bash -pnpm exec biome check apps/server/src apps/web/vite.config.ts packages/auth/src/config.ts packages/scripts packages/server docs/deployment AGENTS.md Dockerfile -``` - -Expected: no errors. If formatting errors appear, run Biome write only on touched source/doc files, then rerun this non-mutating check. - ---- - -## Self-Review - -- Spec coverage: - - Preserve single Docker image: Tasks 1 and 6. - - Enable edge/S3/static frontend plus Node backend: Tasks 1, 2, 5, and 6. - - Keep backend Node-first: Tasks 5 and 6. - - Return 404 from backend for unknown split-mode routes: Task 5. - - Move `/auth/oauth` to `/api/auth/oauth`: Task 3. - - Make `/schema.json` static: Task 4. - - Keep `/.well-known/*` backend-owned: Tasks 1 and 5. -- Placeholder scan: - - No TBD/TODO/fill-in steps remain. -- Type consistency: - - Route ownership terms are consistently `backend`, `static`, and `spa`. - - Server modes are consistently `monolith` and `backend-only`. - - The OAuth bridge route is consistently `/api/auth/oauth`. - - Static schema targets are consistently `packages/schema/schema.json` and `apps/web/public/schema.json`. diff --git a/docs/superpowers/plans/2026-05-14-monorepo-architecture-reorg.md b/docs/superpowers/plans/2026-05-14-monorepo-architecture-reorg.md deleted file mode 100644 index db1fef39d..000000000 --- a/docs/superpowers/plans/2026-05-14-monorepo-architecture-reorg.md +++ /dev/null @@ -1,277 +0,0 @@ -# Monorepo Architecture Reorganization Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use `subagent-driven-development` or `executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -> **Status note:** This implementation plan has been executed and may contain historical intermediate paths. Use `AGENTS.md`, `docs/contributing/architecture.mdx`, `docs/adr/0001-workspace-boundaries.md`, and `docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md` for current architecture guidance. - -**Goal:** Reorganize Reactive Resume into clear domain/package boundaries so server, web, API, MCP, PDF, resume-domain logic, and documentation are easier to debug and enforce. - -**Architecture:** This is one PR with green internal commits. Packages expose role-based explicit public surfaces, web routes become thin shells over domain features, API code is colocated by feature/capability, and boundary rules prevent app-to-app source imports and private package source imports. - -**Tech Stack:** pnpm 11, Turborepo 2, TypeScript/tsgo, Vite, React 19, TanStack Router, oRPC, Drizzle, React PDF, PDF.js, MCP SDK, Biome/GritQL, Vitest. - ---- - -## Non-Negotiable Decisions - -- Root `AGENTS.md` is the single normative architecture source of truth. -- `docs/adr/0001-workspace-boundaries.md` records rationale only; it must not duplicate the full operational rule set. -- `docs/contributing/architecture.mdx` is a descriptive overview, not a second source of truth. -- Keep one PR and green internal commits; no compatibility wrappers or old import-path shims. -- Preserve existing unrelated user changes in manifests and lockfile. Do not reset or revert them. -- Keep `apps/server` and `apps/web` split. `apps/server` may serve `apps/web/dist`; app-to-app `src` imports are banned. -- `apps/web` may import `packages/api` types only. Runtime imports from `packages/api` in web are banned. -- `apps/server` may import explicit runtime exports from `packages/api`. -- Tests remain colocated with moved code. - -## Task 0: Coordination Artifacts - -**Files:** -- Modify: `docs/superpowers/plans/2026-05-14-monorepo-architecture-reorg.md` -- Modify: `docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md` -- Modify: `docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md` - -- [ ] Keep this plan updated when implementation discoveries force refinements. -- [ ] Keep the handoff file focused on current task ownership and next-agent startup context. -- [ ] Keep the worklog append-only with commands, validation results, blockers, and changed ownership decisions. - -## Task 1: Pure Resume Domain Package - -**Goal:** Create `@reactive-resume/resume` for pure resume-domain behavior, keeping `@reactive-resume/schema` validation-only and `@reactive-resume/utils` generic. - -**Files:** -- Create: `packages/resume/package.json` -- Create: `packages/resume/tsconfig.json` -- Create: `packages/resume/vitest.config.ts` -- Move/create: `packages/resume/src/patch.ts` -- Move/create: `packages/resume/src/icons.ts` -- Move tests from `packages/utils/src/resume/patch.test.ts` -- Move tests for `packages/utils/src/network-icons.test.ts` -- Modify importers/callers currently using `@reactive-resume/utils/resume/patch` -- Modify importers/callers currently using `@reactive-resume/utils/network-icons` -- Modify `packages/utils/package.json` -- Modify root workspace manifests/lockfile as needed - -- [x] Create the new package using the repo's source-consumed package pattern. -- [x] Move JSON Patch schema/types/application/comparison/error into `@reactive-resume/resume/patch`. -- [x] Move social network to icon-name mapping into `@reactive-resume/resume/icons`. -- [x] Update all runtime and test imports. -- [x] Remove `@reactive-resume/schema` dependency from `@reactive-resume/utils`. -- [x] Run `pnpm --filter @reactive-resume/resume test`. -- [x] Run `pnpm --filter @reactive-resume/resume typecheck`. -- [x] Run targeted typechecks for known consumers: `@reactive-resume/api`, `@reactive-resume/ai`, `web`. - -## Task 2: DOCX Package - -**Goal:** Create `@reactive-resume/docx` as the dedicated DOCX export package. - -**Files:** -- Create: `packages/docx/package.json` -- Create: `packages/docx/tsconfig.json` -- Create: `packages/docx/vitest.config.ts` -- Move: `packages/utils/src/resume/docx/*` to `packages/docx/src/*` -- Modify web export callers currently using `@reactive-resume/utils/resume/docx` -- Modify package dependencies/lockfile - -- [x] Create `@reactive-resume/docx` with explicit export `"."` or `"./builder"` as appropriate. -- [x] Move DOCX implementation and tests unchanged except import paths. -- [x] Update web callers to import DOCX export from `@reactive-resume/docx`. -- [x] Remove DOCX dependencies from `@reactive-resume/utils` if no longer used there. -- [x] Run `pnpm --filter @reactive-resume/docx test`. -- [x] Run `pnpm --filter @reactive-resume/docx typecheck`. -- [x] Run focused web export tests/typecheck. - -## Task 3: PDF Package Browser/Server Generation Surface - -**Goal:** Keep `@reactive-resume/pdf` focused on document/template/font rendering and pure generation adapters. Do not move PDF.js viewer UI into the PDF package. - -**Files:** -- Create: `packages/pdf/src/browser.tsx` -- Create: `packages/pdf/src/server.tsx` -- Modify: `packages/pdf/package.json` -- Modify: web PDF generation callers currently using `apps/web/src/libs/resume/pdf-document.tsx` -- Modify: `apps/server`/API PDF download code after Task 5 - -- [x] Add data-plus-options generation APIs: - - `createResumePdfBlob({ data, template, resolveSectionTitle })` - - `createResumePdfFile({ data, filename, template, resolveSectionTitle })` -- [x] Keep Lingui locale loading in `apps/web`; pass `resolveSectionTitle` into PDF helpers. -- [x] Keep `ResumeDocument` as the underlying render surface. -- [x] Add/update tests for the browser/server helpers where practical. -- [x] Run `pnpm --filter @reactive-resume/pdf test`. -- [x] Run `pnpm --filter @reactive-resume/pdf typecheck`. - -## Task 4: MCP Package and Shared Tool Contracts - -**Goal:** Extract MCP implementation from web route helpers into `@reactive-resume/mcp`; share model-facing tool contracts from `@reactive-resume/ai`. - -**Files:** -- Create: `packages/mcp/package.json` -- Create: `packages/mcp/tsconfig.json` -- Create: `packages/mcp/vitest.config.ts` -- Move: `apps/web/src/routes/mcp/-helpers/*` to `packages/mcp/src/*` -- Create/modify: `packages/ai/src/tools/resume-tool-contracts.ts` -- Modify: `packages/ai/package.json` -- Modify: `apps/server/src/handlers/mcp.ts` -- Modify: `apps/server/src/handlers/metadata.ts` -- Remove old web helper imports - -- [x] Move MCP tools/prompts/resources/metadata card generation and tests into `@reactive-resume/mcp`. -- [x] Keep MCP execution through an injected/in-process oRPC `RouterClient`. -- [x] Rename MCP tools to canonical unprefixed snake_case names such as `list_resumes`, `read_resume`, `apply_resume_patch`. -- [x] Do not keep old `reactive_resume_*` aliases. -- [x] Use shared base tool contracts from `@reactive-resume/ai`, with MCP-specific schema extensions for explicit context fields such as `resumeId`. -- [ ] Update MCP docs/card version and cache-refresh guidance later in documentation tasks. -- [x] Run `pnpm --filter @reactive-resume/mcp test`. -- [x] Run `pnpm --filter @reactive-resume/mcp typecheck`. -- [x] Run `pnpm --filter server typecheck`. - -## Task 5: API Feature Reorganization - -**Goal:** Move `packages/api/src` from technical layers into feature/capability modules with explicit public exports. - -**Files:** -- Reorganize under `packages/api/src/features/*` -- Modify: `packages/api/src/routers/index.ts` -- Modify: `packages/api/package.json` -- Modify consumers in `apps/server`, `apps/web` type imports, and packages - -- [x] Split `features/agent` into `threads`, `messages`, `attachments`, `actions`, `runs`, and `tools`. -- [x] Split `features/resume` by capability: `crud`, `tags`, `statistics`, `analysis`, `access`, `events`, `sharing`, `export`. -- [x] Move authenticated PDF download procedure into `features/resume/export`; it calls `@reactive-resume/pdf/server`. -- [x] Keep Drizzle schema centralized in `packages/db`; API features consume schema but do not own table definitions. -- [x] Remove `./services/*` and `./helpers/*` wildcard exports. -- [x] Add explicit runtime exports required by `apps/server`. -- [x] Preserve `apps/web` API imports as type-only. -- [x] Run `pnpm --filter @reactive-resume/api test`. -- [x] Run `pnpm --filter @reactive-resume/api typecheck`. -- [x] Run `pnpm --filter server typecheck`. -- [x] Run `pnpm --filter web typecheck`. - -## Task 6: Server Adapter Reorganization - -**Goal:** Make `apps/server` read as a runtime adapter app. - -**Files:** -- Reorganize `apps/server/src` into `http`, `rpc`, `mcp`, `openapi`, `static`, `startup` -- Modify: `apps/server/src/index.ts` -- Modify: `apps/server/package.json` if imports/dependencies change - -- [x] Move handlers into adapter folders. -- [x] Keep server logic thin: auth/session/HTTP transport/static serving/startup. -- [x] Use explicit API runtime exports only. -- [x] Keep serving `apps/web/dist` allowed. -- [x] Run `pnpm --filter server test`. -- [x] Run `pnpm --filter server typecheck`. - -## Task 7: Domain-First Web Reorganization - -**Goal:** Move web code into domain/workflow feature trees so routes become thin shells. - -**Files:** -- Create/reorganize under `apps/web/src/features/resume/*` -- Create/reorganize under `apps/web/src/features/{command-palette,theme,locale,user,auth,settings,dialogs}/*` -- Modify route imports and tests - -- [x] Move resume domain code into workflow folders: - - `builder` - - `preview` - - `public` - - `dialogs` - - `sections` - - `templates` - - `export` - - `pdf-viewer` -- [x] Move PDF.js viewer/canvas UI into web resume feature, not `@reactive-resume/pdf`. -- [x] Keep route files responsible for URL params, loaders, redirects, SSR settings, and composition. -- [x] Leave `apps/web/src/components` with generic app-level primitives/screens only. -- [x] Move app shell concerns into separate features: command palette, theme, locale, user. -- [x] Move auth workflows into `features/auth` and settings sections into `features/settings`. -- [x] Run focused moved tests. -- [x] Run `pnpm --filter web typecheck`. - -Slice 1 notes: - -- Moved resume builder draft state, builder preview, PDF.js canvas preview, dashboard thumbnail PDF rendering helpers, public resume PDF viewer, and web-local PDF document wrappers under `apps/web/src/features/resume/*`. -- Removed `apps/web/src/components/resume` and `apps/web/src/routes/$username/-components`; the public resume route now lazy-loads from `features/resume/public`. -- Kept PDF.js viewer/canvas code in `apps/web/src/features/resume` and left `@reactive-resume/pdf` limited to PDF generation helpers. -- Broader Task 7 remains open for non-resume web feature moves and deeper dialog registry work owned by Task 8. - -Slice 2 notes: - -- Moved command palette, theme, locale, and user shell components/tests from `apps/web/src/components/*` to `apps/web/src/features/{command-palette,theme,locale,user}` and updated consumers. -- Moved auth route UI, layout, and social auth component into `apps/web/src/features/auth`, leaving auth route files as guard/search/composition wrappers. -- Moved settings page UI and authentication/integration subcomponents into `apps/web/src/features/settings`, leaving settings route files as dashboard-header/composition wrappers; `job-search` stayed route-only because it is already a redirect shim. -- `apps/web/src/components` now contains only the remaining generic primitive/screen folders. -- Task 8 still owns dialog registry decomposition; this slice only updated imports around existing dialog usage. - -## Task 8: Dialog Registry Rework - -**Goal:** Keep one central dialog runtime but make domain modules own their dialog definitions/renderers. - -**Files:** -- Modify/create under `apps/web/src/features/dialogs` -- Modify/create domain dialog registry modules under relevant features -- Modify root dialog manager import - -- [x] Replace the single giant discriminated union/manager import hub with composable domain registries. -- [x] Keep one global dialog store/runtime. -- [x] Each domain exports its schema entries and renderers. -- [x] Preserve existing dialog behavior and tests. -- [x] Run dialog-focused tests. -- [x] Run `pnpm --filter web typecheck`. - -## Task 9: Boundary Enforcement - -**Goal:** Make architectural rules executable. - -**Files:** -- Modify: `turbo.json` -- Modify: `biome.json` -- Create: `tooling/grit/no-cross-workspace-src-imports.grit` -- Modify package manifests/tsconfigs to remove forbidden direct source path aliases - -- [x] Add `turbo boundaries` package/runtime rules. -- [x] Add a Biome GritQL plugin/rule for forbidden cross-workspace `src` imports and path aliases. -- [x] Enforce subpath runtime tags: root exports environment-neutral; browser/server code behind explicit subpaths. -- [x] Allow wildcard exports only for role-approved leaf libraries such as UI components/hooks. -- [x] Run `pnpm exec turbo boundaries`. -- [x] Run a focused Biome boundary check. - -## Task 10: Documentation and Source of Truth - -**Goal:** Document the final architecture without duplicating rules in multiple places. - -**Files:** -- Modify: `AGENTS.md` -- Create: `docs/adr/0001-workspace-boundaries.md` -- Modify: `docs/contributing/architecture.mdx` -- Modify: `docs/guides/using-the-mcp-server.mdx` if MCP tool names change -- Modify: `docs/guides/ai-agent-tools.mdx` if shared tool naming changes - -- [x] Update root `AGENTS.md` with the normative workspace map, import rules, package roles, runtime tags, validation commands, and placement decision tree. -- [x] Add ADR rationale for boundaries and rejected alternatives. -- [x] Refresh public architecture docs as overview only. -- [x] Update MCP docs to mention canonical unprefixed tool names and client refresh/cache-clear guidance. -- [x] Avoid local package READMEs for architecture rules unless unavoidable. -- [x] Run docs-related checks available in the repo. - -## Task 11: Final Validation and Handoff - -**Goal:** Finish with a validated branch and external-agent-ready handoff. - -**Files:** -- Modify: `docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md` -- Modify: `docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md` - -- [x] Run focused checks listed in earlier tasks. -- [ ] Run final repo checks: - - `pnpm install --lockfile-only` - - `pnpm exec biome check .` - - `pnpm exec turbo boundaries` - - `pnpm knip` - - `pnpm typecheck` - - `pnpm test` - - `pnpm build` -- [x] Update the handoff with completed tasks, remaining risks, commands run, and useful file paths. -- [x] Dispatch final review if subagents are available. diff --git a/docs/superpowers/plans/2026-05-15-docker-nightly-release-tags.md b/docs/superpowers/plans/2026-05-15-docker-nightly-release-tags.md deleted file mode 100644 index 51c1e6d6a..000000000 --- a/docs/superpowers/plans/2026-05-15-docker-nightly-release-tags.md +++ /dev/null @@ -1,214 +0,0 @@ -# Docker Nightly and Release Tags Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox syntax for tracking. - -**Goal:** Update the Docker image workflow so pushes to `main` publish amd64-only nightly tags, while manual runs and pushed version tags publish release tags with the existing multi-arch behavior. - -**Architecture:** Keep the existing digest-build and manifest-merge pipeline in `.github/workflows/docker-build.yml`. Add event-based mode expressions so nightly and release publishing share setup, registry auth, digest upload/download, signing, and inspection while differing only in triggers, platform inclusion, final tags, and redeploy behavior. - -**Tech Stack:** GitHub Actions, Docker Buildx, `docker/metadata-action@v6`, `docker/build-push-action@v7`, `docker buildx imagetools`, Cosign. - ---- - -### Task 1: Add Workflow Triggers and Mode Outputs - -**Files:** -- Modify: `.github/workflows/docker-build.yml` - -- [x] **Step 1: Update workflow triggers** - -Change the workflow `on` block to include: - -```yaml -on: - workflow_dispatch: - push: - branches: - - main - tags: - - "v*" -``` - -Expected behavior: -- `push` to `main` runs the workflow. -- `push` to tags matching `v*` runs the workflow. -- PR events do not run the workflow. -- Manual runs still run the workflow. - -- [x] **Step 2: Add a mode job** - -Add a `mode` job before `build`: - -```yaml - mode: - runs-on: ubuntu-latest - outputs: - nightly: ${{ steps.mode.outputs.nightly }} - release: ${{ steps.mode.outputs.release }} - matrix: ${{ steps.mode.outputs.matrix }} - steps: - - name: Determine publishing mode - id: mode - run: | - if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "nightly=true" >> "$GITHUB_OUTPUT" - echo "release=false" >> "$GITHUB_OUTPUT" - echo 'matrix={"include":[{"platform":"linux/amd64","runner":"ubuntu-latest","arch":"amd64"}]}' >> "$GITHUB_OUTPUT" - else - echo "nightly=false" >> "$GITHUB_OUTPUT" - echo "release=true" >> "$GITHUB_OUTPUT" - echo 'matrix={"include":[{"platform":"linux/amd64","runner":"ubuntu-latest","arch":"amd64"},{"platform":"linux/arm64","runner":"ubuntu-24.04-arm","arch":"arm64"}]}' >> "$GITHUB_OUTPUT" - fi -``` - -This job centralizes the event decision so later jobs do not duplicate the full expression. - -### Task 2: Generate the Platform Matrix from Mode - -**Files:** -- Modify: `.github/workflows/docker-build.yml` - -- [x] **Step 1: Make `build` depend on `mode`** - -Set: - -```yaml - needs: mode -``` - -on the `build` job. - -- [x] **Step 2: Replace the static build matrix with the mode output** - -Set the build strategy matrix to the JSON emitted by the `mode` job: - -```yaml - matrix: ${{ fromJSON(needs.mode.outputs.matrix) }} -``` - -Expected behavior: -- Nightly runs create only the `amd64` matrix entry. -- Release/manual/tag runs create both `amd64` and `arm64` matrix entries. - -### Task 3: Generate Conditional Final Tags - -**Files:** -- Modify: `.github/workflows/docker-build.yml` - -- [x] **Step 1: Make `merge` depend on `mode` and `build`** - -Set: - -```yaml - needs: - - mode - - build -``` - -on the `merge` job. - -- [x] **Step 2: Update final Docker metadata tags** - -In the merge job's Docker metadata step, replace the unconditional release tag list with conditional tags: - -```yaml - tags: | - type=sha,prefix=sha- - type=raw,value=nightly,enable=${{ needs.mode.outputs.nightly == 'true' }} - type=raw,value=nightly-{{date 'YYYYMMDDHHmmss' tz='UTC'}},enable=${{ needs.mode.outputs.nightly == 'true' }} - type=raw,value=latest,enable=${{ needs.mode.outputs.release == 'true' }} - type=raw,value=v${{ steps.version.outputs.version }},enable=${{ needs.mode.outputs.release == 'true' }} - type=raw,value=v${{ steps.semver.outputs.major }}.${{ steps.semver.outputs.minor }},enable=${{ needs.mode.outputs.release == 'true' }} - type=raw,value=v${{ steps.semver.outputs.major }},enable=${{ needs.mode.outputs.release == 'true' }} -``` - -Expected behavior: -- Nightly runs publish `nightly`, `nightly-{UTC timestamp}`, and SHA tags. -- Release/manual/tag runs publish `latest`, version aliases, and SHA tags. - -### Task 4: Make Post-Publish Steps Mode-Aware - -**Files:** -- Modify: `.github/workflows/docker-build.yml` - -- [x] **Step 1: Emit canonical image references from the manifest step** - -In `Create manifest list and push`, compute the canonical final tag from mode: - -```bash -if [[ "${{ needs.mode.outputs.nightly }}" == "true" ]]; then - FINAL_TAG="nightly" -else - FINAL_TAG="v${{ steps.version.outputs.version }}" -fi -``` - -Use `$FINAL_TAG` for both GHCR and Docker Hub digest lookup. - -- [x] **Step 2: Inspect the canonical final tag** - -Update `Inspect image` to inspect: - -```bash -docker buildx imagetools inspect ghcr.io/${{ env.IMAGE }}:${{ steps.manifest.outputs.final_tag }} -docker buildx imagetools inspect docker.io/${{ env.IMAGE }}:${{ steps.manifest.outputs.final_tag }} -``` - -- [x] **Step 3: Keep redeploy release-only** - -Add this condition to `Redeploy Stack`: - -```yaml - if: ${{ needs.mode.outputs.release == 'true' }} -``` - -Expected behavior: -- Nightly publishes images, signs them, and inspects them. -- Nightly does not redeploy the stack. -- Release/manual/tag publishes images, signs them, inspects them, and redeploys. - -### Task 5: Validate Workflow Logic - -**Files:** -- Test: `.github/workflows/docker-build.yml` - -- [x] **Step 1: Parse YAML** - -Run: - -```bash -ruby -e 'require "yaml"; YAML.load_file(".github/workflows/docker-build.yml"); puts "yaml ok"' -``` - -Expected output: - -```text -yaml ok -``` - -- [x] **Step 2: Review the workflow diff** - -Run: - -```bash -git diff -- .github/workflows/docker-build.yml docs/superpowers/plans/2026-05-15-docker-nightly-release-tags.md -``` - -Confirm these requirements in the diff: -- `push` to `main` is enabled. -- pushed tags matching `v*` are enabled. -- no `pull_request` trigger exists. -- the matrix output contains only amd64 when `nightly == 'true'`. -- nightly tags are enabled only for nightly mode. -- release tags are enabled only for release mode. -- redeploy is release-only. - -- [x] **Step 3: Check working tree scope** - -Run: - -```bash -git status --short .github/workflows/docker-build.yml docs/superpowers/plans/2026-05-15-docker-nightly-release-tags.md -``` - -Expected output includes only the workflow and this plan among files changed by this implementation. diff --git a/docs/superpowers/plans/2026-05-15-manifest-only-pwa.md b/docs/superpowers/plans/2026-05-15-manifest-only-pwa.md deleted file mode 100644 index 0cf76183f..000000000 --- a/docs/superpowers/plans/2026-05-15-manifest-only-pwa.md +++ /dev/null @@ -1,117 +0,0 @@ -# Manifest-Only PWA Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Remove Reactive Resume's service-worker and Workbox PWA behavior while keeping install metadata. - -**Architecture:** Keep the manifest link and install meta tags in the web root route. Keep manifest data in -`apps/web/public/manifest.webmanifest`, keep head meta tags in `apps/web/src/libs/pwa.ts`, and remove the -service-worker registration export plus the `vite-plugin-pwa` build plugin. - -**Tech Stack:** TanStack Start, Vite, TypeScript, pnpm, Vitest, Workbox removal. - ---- - -### Task 1: Remove service-worker wiring - -**Files:** -- Modify: `apps/web/index.html` -- Modify: `apps/web/vite.config.ts` -- Modify: `apps/web/src/libs/pwa.ts` -- Modify: `apps/web/src/routes/__root.tsx` -- Delete: `apps/web/src/libs/pwa.test.ts` - -- [x] **Step 1: Remove `vite-plugin-pwa` imports and plugin usage** - -In `apps/web/vite.config.ts`, remove: - -```ts -import { VitePWA } from "vite-plugin-pwa"; -import { pwaManifest } from "./src/libs/pwa"; -``` - -Delete the local `pwa()` helper and remove `pwa()` from the `plugins` array. - -- [x] **Step 2: Add install metadata to static HTML** - -In `apps/web/index.html`, add the manifest link, icon links, theme color, and Apple/mobile install meta tags inside -`` so install metadata is present without plugin HTML injection. - -- [x] **Step 3: Remove dead manifest export and runtime service-worker registration** - -In `apps/web/src/libs/pwa.ts`, remove the `pwaManifest` and `pwaServiceWorkerRegistrationScript` exports so the -module only owns head meta tags. - -In `apps/web/src/routes/__root.tsx`, change the PWA import to: - -```ts -import { pwaHeadMetaTags } from "@/libs/pwa"; -``` - -Remove the `scripts` entry that injects `pwaServiceWorkerRegistrationScript` in production. - -- [x] **Step 4: Delete obsolete PWA unit test** - -Delete `apps/web/src/libs/pwa.test.ts`, because the remaining PWA surface is static manifest/head metadata. - -### Task 2: Remove unused dependency graph - -**Files:** -- Modify: `apps/web/package.json` -- Modify: `pnpm-lock.yaml` - -- [x] **Step 1: Remove direct web dependency** - -Remove this dependency from `apps/web/package.json`: - -```json -"vite-plugin-pwa": "^1.3.0" -``` - -- [x] **Step 2: Refresh lockfile narrowly** - -Run: - -```sh -pnpm install --lockfile-only --offline --ignore-scripts -``` - -Expected: the lockfile no longer contains `vite-plugin-pwa` or unused Workbox packages required only by that -plugin. If the offline lockfile refresh is unavailable, edit the lockfile narrowly and verify with git diff. - -### Task 3: Validate manifest-only behavior - -**Files:** -- Inspect: `apps/web/.output` or `apps/web/dist` - -- [x] **Step 1: Run focused checks** - -Run: - -```sh -pnpm --filter web typecheck -pnpm --filter web build -``` - -Expected: both commands complete successfully. - -- [x] **Step 2: Inspect build output for service-worker artifacts** - -Run: - -```sh -find apps/web/.output apps/web/dist -name 'sw.js' -o -name 'workbox-*' -o -name 'registerSW.js' -``` - -Expected: no service-worker or Workbox files are printed. If one output directory does not exist, the command may -print a find warning for that path; inspect the directory that exists. - -- [x] **Step 3: Inspect source for removed service-worker registration** - -Run: - -```sh -rg -n "serviceWorker|register\\(\"/sw\\.js\"|VitePWA|vite-plugin-pwa|workbox" apps/web/src apps/web/vite.config.ts apps/web/package.json -``` - -Expected: no matches for the removed PWA service-worker path. diff --git a/docs/superpowers/plans/2026-05-15-unsafe-oauth-redirect-uri.md b/docs/superpowers/plans/2026-05-15-unsafe-oauth-redirect-uri.md deleted file mode 100644 index c126df788..000000000 --- a/docs/superpowers/plans/2026-05-15-unsafe-oauth-redirect-uri.md +++ /dev/null @@ -1,222 +0,0 @@ -# Unsafe OAuth Redirect URI Flag Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Replace `OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS` with `FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI`, preserving safe defaults and allowing any parseable redirect URI only when the flag is enabled. - -**Architecture:** Keep OAuth redirect URI policy centralized in `packages/utils/src/url-security.node.ts`. Pass the new env flag from both Better Auth hook validation and the server auth preflight so both paths make identical decisions. Update env/docs references and tests in the same slice. - -**Tech Stack:** TypeScript, Zod env schema, Better Auth hook middleware, Vitest, Turborepo env filtering, MDX docs. - ---- - -## File Structure - -- Modify `packages/utils/src/url-security.node.ts`: Change the OAuth redirect validator from allowlist-based to mode-based. -- Modify `packages/utils/src/url-security.node.test.ts`: Update safe-mode tests and add unsafe-mode coverage. -- Modify `packages/env/src/server.ts`: Remove the old allowlist env var and add `FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI`. -- Modify `packages/auth/src/config.ts`: Remove host-list parsing and pass `{ allowUnsafe: env.FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI }`. -- Modify `apps/server/src/http/auth.ts`: Remove host-list parsing and pass the same flag to the validator. -- Modify `apps/server/src/http/auth.test.ts`: Update env mock shape and preserve existing local edits. -- Modify `turbo.json`, `.env.example`, and MDX docs: Replace old env references with the new flag and warnings. - -### Task 1: URL Policy Tests And Validator - -**Files:** -- Modify: `packages/utils/src/url-security.node.test.ts` -- Modify: `packages/utils/src/url-security.node.ts` - -- [ ] **Step 1: Write the failing safe/unsafe OAuth redirect tests** - -Use this shape in `packages/utils/src/url-security.node.test.ts`: - -```ts -describe("isAllowedOAuthRedirectUri", () => { - const trustedOrigins = ["https://app.example.com"]; - - it("returns false for malformed URI", () => { - expect(isAllowedOAuthRedirectUri("nope", trustedOrigins)).toBe(false); - }); - - it("returns true for any parseable URI when unsafe mode is enabled", () => { - const options = { allowUnsafe: true }; - - expect(isAllowedOAuthRedirectUri("myapp://callback", trustedOrigins, options)).toBe(true); - expect(isAllowedOAuthRedirectUri("http://example.com/cb", trustedOrigins, options)).toBe(true); - expect(isAllowedOAuthRedirectUri("https://192.168.1.1/cb", trustedOrigins, options)).toBe(true); - expect(isAllowedOAuthRedirectUri("https://u:p@app.example.com/cb#x", trustedOrigins, options)).toBe(true); - expect(isAllowedOAuthRedirectUri("not a url", trustedOrigins, options)).toBe(false); - }); -}); -``` - -- [ ] **Step 2: Run the focused utils test and verify it fails** - -Run: `pnpm --filter @reactive-resume/utils test -- src/url-security.node.test.ts` - -Expected before implementation: TypeScript/test failure because `isAllowedOAuthRedirectUri` still requires the removed allowlist argument. - -- [ ] **Step 3: Implement mode-based OAuth redirect validation** - -Use this signature in `packages/utils/src/url-security.node.ts`: - -```ts -type OAuthRedirectUriOptions = { - allowUnsafe?: boolean; -}; - -export function isAllowedOAuthRedirectUri( - input: string, - trustedOrigins: string[], - options?: OAuthRedirectUriOptions, -) { - const parsed = parseUrl(input); - if (!parsed) return false; - if (options?.allowUnsafe) return true; - if (parsed.username || parsed.password) return false; - if (parsed.hash) return false; - - const origin = parsed.origin.toLowerCase(); - const hostname = normalizeHostname(parsed.hostname); - - if (parsed.protocol === "http:") return isOAuthLoopbackRedirectHost(hostname); - if (parsed.protocol !== "https:") return false; - if (isPrivateOrLoopbackHost(hostname)) return false; - - return trustedOrigins.includes(origin); -} -``` - -- [ ] **Step 4: Run the focused utils test and verify it passes** - -Run: `pnpm --filter @reactive-resume/utils test -- src/url-security.node.test.ts` - -Expected after implementation: all tests in `url-security.node.test.ts` pass. - -### Task 2: Env And Runtime Wiring - -**Files:** -- Modify: `packages/env/src/server.ts` -- Modify: `packages/auth/src/config.ts` -- Modify: `apps/server/src/http/auth.ts` -- Modify: `apps/server/src/http/auth.test.ts` -- Modify: `turbo.json` - -- [ ] **Step 1: Update env schema and Turbo env list** - -In `packages/env/src/server.ts`, remove: - -```ts -OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS: z.string().optional(), -``` - -Add with feature flags: - -```ts -FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI: z.stringbool().default(false), -``` - -In `turbo.json`, remove `"OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS"` and add `"FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI"` beside the other flags. - -- [ ] **Step 2: Wire the flag into Better Auth config** - -In `packages/auth/src/config.ts`, remove `parseAllowedHostList` usage and call: - -```ts -if ( - !isAllowedOAuthRedirectUri(uri, TRUSTED_ORIGINS, { - allowUnsafe: env.FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI, - }) -) { - throw new APIError("BAD_REQUEST", { - message: "redirect_uri is not allowed for dynamic client registration", - }); -} -``` - -- [ ] **Step 3: Wire the flag into server preflight** - -In `apps/server/src/http/auth.ts`, remove `parseAllowedHostList` usage and call: - -```ts -!isAllowedOAuthRedirectUri(redirectUri, oauthTrustedOrigins, { - allowUnsafe: env.FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI, -}) -``` - -Update the test env mock in `apps/server/src/http/auth.test.ts`: - -```ts -env: { - SERVER_PORT: 3001, - APP_URL: "http://localhost:3000", - FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI: false, -}, -``` - -- [ ] **Step 4: Run focused typechecks** - -Run: - -```sh -pnpm --filter @reactive-resume/auth typecheck -pnpm --filter server typecheck -``` - -Expected: both commands exit 0. - -### Task 3: Docs And Env Examples - -**Files:** -- Modify: `.env.example` -- Modify: `docs/self-hosting/docker.mdx` -- Modify: `docs/self-hosting/sso.mdx` -- Modify: `docs/getting-started/quickstart.mdx` - -- [ ] **Step 1: Replace old env docs with the new flag** - -Remove all `OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS` references. - -Add this warning wherever feature flags are documented: - -```md -`FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI`: Allows dynamic OAuth client registration to use any parseable redirect URI, including custom schemes, private hosts, and non-loopback `http://` URLs. Keep disabled unless this is a trusted self-hosted deployment. Enabling it on public or multi-tenant instances can enable phishing or token exfiltration. -``` - -- [ ] **Step 2: Verify the removed env is gone from product code and docs** - -Run: `rg -n "OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS" . --glob "!docs/superpowers/**"` - -Expected: no matches outside the approved design and implementation plan documents. - -Run: `rg -n "FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI" .` - -Expected: matches in env schema, Turbo config, docs, tests, and runtime validation paths. - -### Task 4: Final Verification - -**Files:** -- Verify all modified files. - -- [ ] **Step 1: Run focused tests** - -Run: - -```sh -pnpm --filter @reactive-resume/utils test -- src/url-security.node.test.ts -pnpm --filter server test -- src/http/auth.test.ts -``` - -Expected: both commands exit 0. - -- [ ] **Step 2: Run focused typechecks and boundaries** - -Run: - -```sh -pnpm --filter @reactive-resume/auth typecheck -pnpm --filter server typecheck -pnpm exec turbo boundaries -``` - -Expected: all commands exit 0. diff --git a/docs/superpowers/plans/2026-06-20-e2e-tests.md b/docs/superpowers/plans/2026-06-20-e2e-tests.md deleted file mode 100644 index d5cb80dc9..000000000 --- a/docs/superpowers/plans/2026-06-20-e2e-tests.md +++ /dev/null @@ -1,670 +0,0 @@ -# E2E Tests Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Build a Playwright E2E test setup that runs deterministic core Reactive Resume flows with ephemeral accounts/data locally and on GitHub Actions for every PR. - -**Architecture:** Add a root-level Playwright harness that targets the production server after `pnpm build`. Use hybrid fixtures: one browser-driven auth smoke spec, and helper-created authenticated browser state plus ephemeral database cleanup for resume flows. Keep initial PR-gated coverage to auth, sample resume creation, builder autosave, JSON export/import, and public sharing. - -**Tech Stack:** Playwright, TypeScript, pnpm, Turbo, GitHub Actions, PostgreSQL service container, Better Auth HTTP endpoints, Drizzle/Postgres cleanup helpers. - ---- - -## File structure - -- Create `playwright.config.ts`: Playwright projects, reporters, artifact policy, base URL, and production `webServer`. -- Create `tests/e2e/README.md`: local setup and CI behavior. -- Create `tests/e2e/fixtures/data.ts`: unique test identity and resume value generation. -- Create `tests/e2e/fixtures/auth.ts`: browser UI auth helpers and API-backed authenticated storage state helpers. -- Create `tests/e2e/fixtures/db.ts`: user cleanup by email/username prefix. -- Create `tests/e2e/fixtures/resume.ts`: UI helpers for creating sample resumes and accessing builder sections. -- Create `tests/e2e/fixtures/test.ts`: typed Playwright fixture composition. -- Create `tests/e2e/specs/auth.spec.ts`: browser registration/login smoke flow. -- Create `tests/e2e/specs/resume-lifecycle.spec.ts`: dashboard create sample resume and builder autosave flow. -- Create `tests/e2e/specs/json-export-import.spec.ts`: deterministic JSON backup/restore flow. -- Create `tests/e2e/specs/public-sharing.spec.ts`: public sharing flow with anonymous browser context. -- Create `.github/workflows/e2e.yml`: PR/push workflow with Postgres, build, Playwright install, E2E run, and report uploads. -- Modify `package.json`: add Playwright dependency and E2E scripts. -- Modify `turbo.json`: register E2E task if routed through package scripts. -- Modify targeted UI files only if accessible locators are not sufficient. - -## Task 1: Add Playwright dependency and scripts - -**Files:** -- Modify: `package.json` -- Modify: `pnpm-lock.yaml` -- Modify: `turbo.json` - -- [ ] **Step 1: Add Playwright with the package manager** - -Run: `pnpm add -D @playwright/test` - -Expected: `package.json` and `pnpm-lock.yaml` include `@playwright/test`. - -- [ ] **Step 2: Add root scripts** - -Change root `package.json` scripts to include: - -```json -{ - "test:e2e": "playwright test", - "test:e2e:ui": "playwright test --ui", - "test:e2e:ci": "playwright test" -} -``` - -- [ ] **Step 3: Register the Turbo task** - -Add this task entry to `turbo.json`: - -```json -"test:e2e": { - "cache": false -} -``` - -- [ ] **Step 4: Verify script discovery** - -Run: `pnpm exec playwright --version` - -Expected: Playwright prints a version and exits successfully. - -- [ ] **Step 5: Commit** - -Run: - -```bash -git add package.json pnpm-lock.yaml turbo.json -git commit -m "test: add playwright e2e scripts" -git push -u origin feat/e2e-test-plan-2b10 -``` - -## Task 2: Add Playwright configuration - -**Files:** -- Create: `playwright.config.ts` - -- [ ] **Step 1: Create the config** - -Create `playwright.config.ts`: - -```ts -import { defineConfig, devices } from "@playwright/test"; - -const port = Number.parseInt(process.env.PORT ?? "3000", 10); -const baseURL = process.env.APP_URL ?? `http://127.0.0.1:${port}`; -const isCI = process.env.CI === "true" || process.env.CI === "1"; - -export default defineConfig({ - testDir: "./tests/e2e/specs", - fullyParallel: true, - forbidOnly: isCI, - retries: isCI ? 2 : 0, - workers: isCI ? 2 : undefined, - reporter: isCI - ? [ - ["list"], - ["github"], - ["junit", { outputFile: "test-results/e2e-junit.xml" }], - ] - : [["list"], ["html", { open: "never" }]], - use: { - baseURL, - trace: "retain-on-failure", - screenshot: "only-on-failure", - video: "retain-on-failure", - }, - projects: [ - { - name: "chromium", - use: { ...devices["Desktop Chrome"] }, - }, - ], - webServer: { - command: "pnpm start", - url: `${baseURL}/api/health`, - reuseExistingServer: !isCI, - timeout: 120_000, - env: { - ...process.env, - PORT: String(port), - }, - }, -}); -``` - -- [ ] **Step 2: Verify config loads** - -Run: `pnpm exec playwright test --list` - -Expected: Playwright lists zero tests at this point without config errors. - -- [ ] **Step 3: Commit** - -Run: - -```bash -git add playwright.config.ts -git commit -m "test: configure playwright" -git push -u origin feat/e2e-test-plan-2b10 -``` - -## Task 3: Add E2E fixtures - -**Files:** -- Create: `tests/e2e/fixtures/data.ts` -- Create: `tests/e2e/fixtures/db.ts` -- Create: `tests/e2e/fixtures/auth.ts` -- Create: `tests/e2e/fixtures/resume.ts` -- Create: `tests/e2e/fixtures/test.ts` - -- [ ] **Step 1: Add test data helpers** - -Create `tests/e2e/fixtures/data.ts`: - -```ts -import type { TestInfo } from "@playwright/test"; - -const sanitize = (value: string) => value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, ""); - -export type E2EAccount = { - name: string; - username: string; - email: string; - password: string; -}; - -export function createRunSlug(testInfo: TestInfo) { - const worker = testInfo.workerIndex; - const title = sanitize(testInfo.titlePath.join("-")).slice(0, 40); - const suffix = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`; - return `e2e-${worker}-${title}-${suffix}`; -} - -export function createAccount(testInfo: TestInfo): E2EAccount { - const slug = createRunSlug(testInfo).replaceAll("-", "_").slice(0, 48); - return { - name: "E2E Test User", - username: slug, - email: `${slug}@example.test`, - password: "Password123!", - }; -} - -export function createResumeName(testInfo: TestInfo) { - return `E2E Resume ${createRunSlug(testInfo)}`; -} -``` - -- [ ] **Step 2: Add database cleanup** - -Create `tests/e2e/fixtures/db.ts`: - -```ts -import { eq, or } from "drizzle-orm"; -import { db, getPool } from "@reactive-resume/db/client"; -import { user } from "@reactive-resume/db/schema"; - -export async function deleteE2EUser(account: { email: string; username: string }) { - await db.delete(user).where(or(eq(user.email, account.email), eq(user.username, account.username))); -} - -export async function closeE2EDatabase() { - await getPool().end(); - globalThis.__pool = undefined; - globalThis.__drizzle = undefined; -} -``` - -- [ ] **Step 3: Add auth helpers** - -Create `tests/e2e/fixtures/auth.ts`: - -```ts -import type { Browser, Page } from "@playwright/test"; -import type { E2EAccount } from "./data"; - -export async function registerViaUi(page: Page, account: E2EAccount) { - await page.goto("/auth/register"); - await page.getByLabel("Name").fill(account.name); - await page.getByLabel("Username").fill(account.username); - await page.getByLabel("Email Address").fill(account.email); - await page.getByLabel("Password").fill(account.password); - await page.getByRole("button", { name: "Sign up" }).click(); - await page.getByRole("link", { name: /continue/i }).click(); - await page.waitForURL(/\/dashboard/); -} - -export async function loginViaUi(page: Page, account: E2EAccount) { - await page.goto("/auth/login"); - await page.getByLabel(/email|username/i).fill(account.email); - await page.getByLabel("Password").fill(account.password); - await page.getByRole("button", { name: "Sign in" }).click(); - await page.waitForURL(/\/dashboard/); -} - -export async function createAuthenticatedPage(browser: Browser, account: E2EAccount) { - const context = await browser.newContext(); - const page = await context.newPage(); - await registerViaUi(page, account); - return page; -} -``` - -- [ ] **Step 4: Add resume UI helpers** - -Create `tests/e2e/fixtures/resume.ts`: - -```ts -import type { Page, TestInfo } from "@playwright/test"; -import { expect } from "@playwright/test"; -import { createResumeName } from "./data"; - -export async function createSampleResumeFromDashboard(page: Page, testInfo: TestInfo) { - const resumeName = createResumeName(testInfo); - await page.goto("/dashboard/resumes"); - await page.getByText("Create a new resume").click(); - await page.getByRole("dialog", { name: "Create a new resume" }).getByLabel("Name").fill(resumeName); - await page.getByRole("button", { name: "Create resume with options" }).click(); - await page.getByRole("menuitem", { name: "Create a Sample Resume" }).click(); - await expect(page.getByText(resumeName)).toBeVisible(); - await page.getByText(resumeName).click(); - await page.waitForURL(/\/builder\/.+/); - return resumeName; -} - -export async function openRightSidebarSection(page: Page, name: string) { - await page.getByRole("button", { name }).click(); -} -``` - -- [ ] **Step 5: Add fixture composition** - -Create `tests/e2e/fixtures/test.ts`: - -```ts -import { test as base, expect } from "@playwright/test"; -import type { E2EAccount } from "./data"; -import { createAccount } from "./data"; -import { deleteE2EUser } from "./db"; -import { registerViaUi } from "./auth"; - -type Fixtures = { - account: E2EAccount; - authPage: import("@playwright/test").Page; -}; - -export const test = base.extend({ - account: async ({}, use, testInfo) => { - const account = createAccount(testInfo); - await use(account); - await deleteE2EUser(account); - }, - authPage: async ({ browser, account }, use) => { - const context = await browser.newContext(); - const page = await context.newPage(); - await registerViaUi(page, account); - await use(page); - await context.close(); - }, -}); - -export { expect }; -``` - -- [ ] **Step 6: Run type-aware feedback** - -Run: `pnpm exec tsc --noEmit --allowImportingTsExtensions false --moduleResolution bundler --target es2022 --module esnext tests/e2e/fixtures/*.ts` - -Expected: If direct `tsc` is too narrow for workspace exports, use `pnpm typecheck` after Task 6 instead. - -- [ ] **Step 7: Commit** - -Run: - -```bash -git add tests/e2e/fixtures -git commit -m "test: add e2e fixtures" -git push -u origin feat/e2e-test-plan-2b10 -``` - -## Task 4: Add core E2E specs - -**Files:** -- Create: `tests/e2e/specs/auth.spec.ts` -- Create: `tests/e2e/specs/resume-lifecycle.spec.ts` -- Create: `tests/e2e/specs/json-export-import.spec.ts` -- Create: `tests/e2e/specs/public-sharing.spec.ts` - -- [ ] **Step 1: Add auth smoke spec** - -Create `tests/e2e/specs/auth.spec.ts`: - -```ts -import { test, expect } from "../fixtures/test"; -import { loginViaUi, registerViaUi } from "../fixtures/auth"; - -test("registers and logs in with email credentials", async ({ page, account }) => { - await registerViaUi(page, account); - await expect(page.getByRole("heading", { name: "Resumes" })).toBeVisible(); - await page.getByRole("button", { name: /user menu|account|profile/i }).click(); - await page.getByRole("menuitem", { name: /logout|sign out/i }).click(); - await loginViaUi(page, account); - await expect(page.getByRole("heading", { name: "Resumes" })).toBeVisible(); -}); -``` - -- [ ] **Step 2: Add resume lifecycle spec** - -Create `tests/e2e/specs/resume-lifecycle.spec.ts`: - -```ts -import { test, expect } from "../fixtures/test"; -import { createSampleResumeFromDashboard } from "../fixtures/resume"; - -test("creates a sample resume and persists a basics edit", async ({ authPage: page }, testInfo) => { - await createSampleResumeFromDashboard(page, testInfo); - const updatedName = `E2E Edited ${Date.now()}`; - await page.getByRole("button", { name: "Basics" }).click(); - await page.getByLabel("Name").fill(updatedName); - await page.reload(); - await page.getByRole("button", { name: "Basics" }).click(); - await expect(page.getByLabel("Name")).toHaveValue(updatedName); -}); -``` - -- [ ] **Step 3: Add JSON export/import spec** - -Create `tests/e2e/specs/json-export-import.spec.ts`: - -```ts -import { test, expect } from "../fixtures/test"; -import { createSampleResumeFromDashboard } from "../fixtures/resume"; - -test("exports and imports a resume JSON backup", async ({ authPage: page }, testInfo) => { - const resumeName = await createSampleResumeFromDashboard(page, testInfo); - await page.getByRole("button", { name: "Export" }).click(); - const downloadPromise = page.waitForEvent("download"); - await page.getByRole("button", { name: /^JSON$/ }).click(); - const download = await downloadPromise; - expect(download.suggestedFilename()).toMatch(/\.json$/); - const path = await download.path(); - expect(path).toBeTruthy(); - if (!path) throw new Error("Expected Playwright to provide a downloaded JSON path."); - await page.goto("/dashboard/resumes"); - await page.getByText("Import an existing resume").click(); - await page.getByRole("combobox").click(); - await page.getByRole("option", { name: "Reactive Resume (JSON)" }).click(); - await page.getByText("Click here to select a file to import").setInputFiles(path); - await page.getByRole("button", { name: "Import" }).click(); - await page.waitForURL(/\/builder\/.+/); - await expect(page.getByText(resumeName)).toBeVisible(); -}); -``` - -- [ ] **Step 4: Add public sharing spec** - -Create `tests/e2e/specs/public-sharing.spec.ts`: - -```ts -import { test, expect } from "../fixtures/test"; -import { createSampleResumeFromDashboard } from "../fixtures/resume"; - -test("publishes a resume and renders it for an anonymous visitor", async ({ browser, authPage: page }, testInfo) => { - await createSampleResumeFromDashboard(page, testInfo); - await page.getByRole("button", { name: "Sharing" }).click(); - await page.getByLabel("Allow Public Access").click(); - const publicUrl = await page.getByLabel("URL").inputValue(); - const anonymous = await browser.newPage(); - await anonymous.goto(publicUrl); - await expect(anonymous.getByRole("button", { name: /download/i })).toBeVisible(); - await anonymous.close(); -}); -``` - -- [ ] **Step 5: Run list mode** - -Run: `pnpm test:e2e -- --list` - -Expected: Four Chromium tests are listed. - -- [ ] **Step 6: Commit** - -Run: - -```bash -git add tests/e2e/specs -git commit -m "test: add core e2e specs" -git push -u origin feat/e2e-test-plan-2b10 -``` - -## Task 5: Add documentation - -**Files:** -- Create: `tests/e2e/README.md` - -- [ ] **Step 1: Add E2E README** - -Create `tests/e2e/README.md`: - -```md -# E2E Tests - -Reactive Resume uses Playwright for PR-gated browser coverage of deterministic core flows. - -## Local setup - -Start PostgreSQL: - -`sudo docker compose -f compose.dev.yml up -d postgres` - -Generate local test secrets: - -`export AUTH_SECRET=$(openssl rand -hex 32)` - -`export ENCRYPTION_SECRET=$(openssl rand -hex 32)` - -Run database migrations: - -`APP_URL=http://localhost:3000 PORT=3000 DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres FLAG_DISABLE_SIGNUPS=false FLAG_DISABLE_EMAIL_AUTH=false FLAG_DISABLE_API_RATE_LIMIT=true LOCAL_STORAGE_PATH=/workspace/data/e2e pnpm db:migrate` - -Build the production app: - -`APP_URL=http://localhost:3000 PORT=3000 DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres FLAG_DISABLE_SIGNUPS=false FLAG_DISABLE_EMAIL_AUTH=false FLAG_DISABLE_API_RATE_LIMIT=true LOCAL_STORAGE_PATH=/workspace/data/e2e pnpm build` - -Run tests: - -`APP_URL=http://localhost:3000 PORT=3000 DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres FLAG_DISABLE_SIGNUPS=false FLAG_DISABLE_EMAIL_AUTH=false FLAG_DISABLE_API_RATE_LIMIT=true LOCAL_STORAGE_PATH=/workspace/data/e2e pnpm test:e2e` - -## Coverage - -- Email/password auth smoke. -- Dashboard sample resume creation. -- Builder basics edit and autosave persistence. -- JSON export/import. -- Public sharing for anonymous visitors. - -PDF, DOCX, OAuth, passkeys, 2FA, password reset, and AI flows are intentionally outside the initial PR gate. -``` - -- [ ] **Step 2: Commit** - -Run: - -```bash -git add tests/e2e/README.md -git commit -m "docs: document e2e workflow" -git push -u origin feat/e2e-test-plan-2b10 -``` - -## Task 6: Add GitHub Actions workflow - -**Files:** -- Create: `.github/workflows/e2e.yml` - -- [ ] **Step 1: Add workflow** - -Create `.github/workflows/e2e.yml`: - -```yaml -name: E2E Tests - -on: - pull_request: - push: - branches: ["main"] - -permissions: - contents: read - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - APP_URL: http://localhost:3000 - PORT: "3000" - DATABASE_URL: postgresql://postgres:postgres@localhost:5432/postgres - FLAG_DISABLE_SIGNUPS: "false" - FLAG_DISABLE_EMAIL_AUTH: "false" - FLAG_DISABLE_API_RATE_LIMIT: "true" - LOCAL_STORAGE_PATH: /tmp/reactive-resume-e2e-storage - -jobs: - e2e: - runs-on: ubuntu-latest - timeout-minutes: 30 - - services: - postgres: - image: postgres:16 - env: - POSTGRES_DB: postgres - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - ports: - - 5432:5432 - options: >- - --health-cmd "pg_isready -U postgres -d postgres" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - steps: - - name: Checkout Repository - uses: actions/checkout@v6 - with: - persist-credentials: false - - - name: Install pnpm - uses: pnpm/action-setup@v6 - - - name: Setup Node - uses: actions/setup-node@v6 - with: - node-version: "24" - cache: "pnpm" - - - name: Install Dependencies - run: pnpm install --frozen-lockfile - - - name: Install Playwright Browser - run: pnpm exec playwright install --with-deps chromium - - - name: Generate Test Secrets - run: | - echo "AUTH_SECRET=$(openssl rand -hex 32)" >> "$GITHUB_ENV" - echo "ENCRYPTION_SECRET=$(openssl rand -hex 32)" >> "$GITHUB_ENV" - - - name: Prepare Storage - run: mkdir -p "$LOCAL_STORAGE_PATH" - - - name: Run Database Migrations - run: pnpm db:migrate - - - name: Build - run: pnpm build - - - name: Run E2E Tests - run: pnpm test:e2e:ci - - - name: Upload Playwright Report - if: always() - uses: actions/upload-artifact@v7 - with: - name: playwright-report - path: | - playwright-report - test-results - if-no-files-found: ignore - retention-days: 7 -``` - -- [ ] **Step 2: Commit** - -Run: - -```bash -git add .github/workflows/e2e.yml -git commit -m "ci: run e2e tests on pull requests" -git push -u origin feat/e2e-test-plan-2b10 -``` - -## Task 7: Verify and stabilize - -**Files:** -- Modify any E2E files that fail due to actual labels or app behavior. -- Modify targeted UI files only if no stable accessible locator exists. - -- [ ] **Step 1: Run non-mutating checks** - -Run: `pnpm exec biome check package.json turbo.json playwright.config.ts tests/e2e .github/workflows/e2e.yml` - -Expected: No Biome errors. - -- [ ] **Step 2: Run typecheck** - -Run: `pnpm typecheck` - -Expected: Typecheck passes for all workspaces. - -- [ ] **Step 3: Start PostgreSQL** - -Run: `sudo docker compose -f compose.dev.yml up -d postgres` - -Expected: Postgres container is healthy. - -- [ ] **Step 4: Build production app** - -Run: - -```bash -export AUTH_SECRET=$(openssl rand -hex 32) -export ENCRYPTION_SECRET=$(openssl rand -hex 32) -APP_URL=http://localhost:3000 PORT=3000 DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres FLAG_DISABLE_SIGNUPS=false FLAG_DISABLE_EMAIL_AUTH=false FLAG_DISABLE_API_RATE_LIMIT=true LOCAL_STORAGE_PATH=/workspace/data/e2e pnpm build -``` - -Expected: web and server production builds complete. - -- [ ] **Step 5: Run E2E suite** - -Run: - -```bash -APP_URL=http://localhost:3000 PORT=3000 DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres FLAG_DISABLE_SIGNUPS=false FLAG_DISABLE_EMAIL_AUTH=false FLAG_DISABLE_API_RATE_LIMIT=true LOCAL_STORAGE_PATH=/workspace/data/e2e pnpm test:e2e -``` - -Expected: All Chromium specs pass. - -- [ ] **Step 6: Commit stabilization changes** - -Run: - -```bash -git add . -git commit -m "test: stabilize e2e suite" -git push -u origin feat/e2e-test-plan-2b10 -``` - -## Self-review - -- Spec coverage: Tasks cover Playwright setup, production-build target, hybrid fixtures, ephemeral data cleanup, core deterministic flows, CI workflow, and documentation. -- Placeholder scan: No placeholder steps remain; each task names exact files, commands, and expected outcomes. -- Type consistency: Fixture types are introduced before specs use them, and all helper names match across tasks. diff --git a/docs/superpowers/plans/2026-07-07-applications-rest-mcp-parity.md b/docs/superpowers/plans/2026-07-07-applications-rest-mcp-parity.md deleted file mode 100644 index 318614494..000000000 --- a/docs/superpowers/plans/2026-07-07-applications-rest-mcp-parity.md +++ /dev/null @@ -1,1372 +0,0 @@ -# Application Tracker REST and MCP Parity Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Expose every shipped Application Tracker capability through public REST/OpenAPI, Reactive Resume MCP tools, and the bundled `resume-builder` skill. - -**Architecture:** Reuse the existing `packages/api/src/features/applications` oRPC procedures and `applicationService` as the single business layer. Add the one missing public REST capability, application document attach/remove, then register MCP tools that call the injected in-process oRPC `RouterClient` rather than importing database code. - -**Tech Stack:** TypeScript, oRPC, Zod v4, Drizzle, Vitest, MCP TypeScript SDK, existing Reactive Resume storage service, Biome. - -## Global Constraints - -- Campaign tracking is out of scope. -- Fixed stages remain `saved`, `applied`, `screening`, `interview`, `offer`, `rejected`. -- Public REST endpoints live under `/api/openapi` and are generated from oRPC route metadata. -- Generic storage routes stay tagged `Internal`; public application document upload/remove belongs under the Applications tag. -- Application documents are PDFs only. -- Document uploads keep the existing 10MB storage limit. -- MCP tool names use canonical unprefixed `snake_case`. -- MCP handlers use the injected in-process oRPC `RouterClient`. -- No new dependencies. -- Do not refactor the Application Tracker UI. - ---- - -## File Structure - -- Modify `packages/api/src/dto/application.ts`: add document kind/upload/delete DTO schemas. -- Modify `packages/api/src/dto/application.test.ts`: test document DTO constraints. -- Modify `packages/api/src/features/applications/service.ts`: add `attachDocument` and `removeDocument` service methods, reusing existing ownership and storage cleanup helpers. -- Modify `packages/api/src/features/applications/service.test.ts`: cover document attachment/removal behavior and storage cleanup. -- Modify `packages/api/src/features/applications/crud.ts`: add public REST document routes. -- Modify `packages/api/src/features/applications/router.ts`: expose document route procedures under `applications`. -- Modify `packages/mcp/src/mcp-tool-names.ts`: add application MCP tool names. -- Modify `packages/mcp/src/tool-meta.ts`: add application tool input schemas and metadata. -- Modify `packages/mcp/src/tool-annotations.ts`: add annotations for new tools. -- Modify `packages/mcp/src/tools.ts`: register application tool handlers. -- Modify `packages/mcp/src/tool-annotations.test.ts`, `packages/mcp/src/mcp-server-card.test.ts`, and `packages/mcp/src/tools.test.ts`: cover registration and handler behavior. -- Modify `skills/resume-builder/SKILL.md`: tell agents application MCP tools exist. -- Modify `docs/guides/using-the-mcp-server.mdx`: document application tools and examples. -- Modify `docs/use-cases/api-mcp-resume-automation.mdx`: expand use case from resume-only automation to resume plus application tracking. -- Modify `docs/spec.json`: refresh OpenAPI output after API route changes. - ---- - -### Task 1: Public REST Document Attach/Remove - -**Files:** -- Modify: `packages/api/src/dto/application.ts` -- Modify: `packages/api/src/dto/application.test.ts` -- Modify: `packages/api/src/features/applications/service.ts` -- Modify: `packages/api/src/features/applications/service.test.ts` -- Modify: `packages/api/src/features/applications/crud.ts` -- Modify: `packages/api/src/features/applications/router.ts` - -**Interfaces:** -- Consumes: existing `applicationService.update(input)` and existing storage helpers in `packages/api/src/features/storage/service.ts`. -- Produces: - - `applicationDto.attachDocument.input`: `{ id: string; kind: "resume" | "cover-letter"; file: File }` - - `applicationDto.removeDocument.input`: `{ id: string; kind: "resume" | "cover-letter" }` - - `applicationService.attachDocument(input: { id: string; userId: string; kind: ApplicationDocumentKind; fileName: string; data: Uint8Array; contentType: string }): Promise` - - `applicationService.removeDocument(input: { id: string; userId: string; kind: ApplicationDocumentKind }): Promise` - - `crudRouter.attachDocument` - - `crudRouter.removeDocument` - -- [ ] **Step 1: Add failing DTO tests** - -Append to `packages/api/src/dto/application.test.ts`: - -```ts -describe("applicationDto document uploads", () => { - it("accepts PDF application documents", () => { - const file = new File(["%PDF-1.4"], "resume.pdf", { type: "application/pdf" }); - - const parsed = applicationDto.attachDocument.input.parse({ - id: "application-1", - kind: "resume", - file, - }); - - expect(parsed.kind).toBe("resume"); - expect(parsed.file.name).toBe("resume.pdf"); - }); - - it("rejects non-PDF application documents", () => { - const file = new File(["hello"], "cover.txt", { type: "text/plain" }); - - expect(() => - applicationDto.attachDocument.input.parse({ - id: "application-1", - kind: "cover-letter", - file, - }), - ).toThrow(); - }); - - it("rejects unknown application document kinds", () => { - const file = new File(["%PDF-1.4"], "resume.pdf", { type: "application/pdf" }); - - expect(() => - applicationDto.attachDocument.input.parse({ - id: "application-1", - kind: "portfolio", - file, - }), - ).toThrow(); - }); -}); -``` - -- [ ] **Step 2: Run DTO test to verify it fails** - -Run: - -```bash -pnpm --filter @reactive-resume/api test -- src/dto/application.test.ts -``` - -Expected: FAIL because `applicationDto.attachDocument` is undefined. - -- [ ] **Step 3: Add document DTO schemas** - -In `packages/api/src/dto/application.ts`, add near the top-level constants: - -```ts -const MAX_APPLICATION_DOCUMENT_BYTES = 10 * 1024 * 1024; - -const applicationDocumentKindSchema = z.enum(["resume", "cover-letter"]); - -const applicationDocumentFileSchema = z - .file() - .max(MAX_APPLICATION_DOCUMENT_BYTES, "File size must be less than 10MB") - .mime(["application/pdf"], "Application documents must be PDF files."); -``` - -Add to `applicationDto`: - -```ts - attachDocument: { - input: z.object({ - id: z.string(), - kind: applicationDocumentKindSchema, - file: applicationDocumentFileSchema, - }), - output: applicationSchema.omit({ userId: true }), - }, - - removeDocument: { - input: z.object({ - id: z.string(), - kind: applicationDocumentKindSchema, - }), - output: applicationSchema.omit({ userId: true }), - }, -``` - -Also export the kind type at the end of the file: - -```ts -export type ApplicationDocumentKind = z.infer; -``` - -- [ ] **Step 4: Run DTO tests to verify they pass** - -Run: - -```bash -pnpm --filter @reactive-resume/api test -- src/dto/application.test.ts -``` - -Expected: PASS. - -- [ ] **Step 5: Add failing service tests** - -Modify the hoisted mocks in `packages/api/src/features/applications/service.test.ts`: - -```ts -const storageDeleteMock = vi.hoisted(() => vi.fn()); -const uploadFileMock = vi.hoisted(() => vi.fn()); -``` - -Replace the storage service mock with: - -```ts -vi.mock("../storage/service", () => ({ - getStorageService: () => ({ delete: storageDeleteMock }), - uploadFile: uploadFileMock, -})); -``` - -Add to `beforeEach`: - -```ts - uploadFileMock.mockReset(); - uploadFileMock.mockResolvedValue({ url: "/api/uploads/user-1/pictures/new.pdf", key: "uploads/user-1/pictures/new.pdf" }); -``` - -Append tests: - -```ts -describe("applicationService.attachDocument", () => { - it("uploads a PDF resume document and stores it on the application", async () => { - const set = vi.fn(() => ({ where: () => ({ returning: () => Promise.resolve([{ ...existing }]) }) })); - dbMock.update.mockReturnValue({ set }); - - await applicationService.attachDocument({ - id: "app-1", - userId: "user-1", - kind: "resume", - fileName: "sent-resume.pdf", - contentType: "application/pdf", - data: new Uint8Array([1, 2, 3]), - }); - - expect(uploadFileMock).toHaveBeenCalledWith({ - userId: "user-1", - contentType: "application/pdf", - data: new Uint8Array([1, 2, 3]), - }); - expect(set).toHaveBeenCalledWith( - expect.objectContaining({ - resumeFileUrl: "/api/uploads/user-1/pictures/new.pdf", - resumeFileName: "sent-resume.pdf", - }), - ); - }); - - it("rejects non-PDF documents before upload", async () => { - await expect( - applicationService.attachDocument({ - id: "app-1", - userId: "user-1", - kind: "cover-letter", - fileName: "cover.txt", - contentType: "text/plain", - data: new Uint8Array([1]), - }), - ).rejects.toMatchObject({ code: "BAD_REQUEST" }); - - expect(uploadFileMock).not.toHaveBeenCalled(); - }); -}); - -describe("applicationService.removeDocument", () => { - it("clears and deletes an owned cover letter document", async () => { - const set = vi.fn(() => ({ where: () => ({ returning: () => Promise.resolve([{ ...existing }]) }) })); - dbMock.update.mockReturnValue({ set }); - - await applicationService.removeDocument({ id: "app-1", userId: "user-1", kind: "cover-letter" }); - - expect(set).toHaveBeenCalledWith( - expect.objectContaining({ - coverLetterUrl: null, - coverLetterName: null, - }), - ); - expect(storageDeleteMock).toHaveBeenCalledWith("uploads/user-1/pictures/cover.pdf"); - }); -}); -``` - -- [ ] **Step 6: Run service tests to verify they fail** - -Run: - -```bash -pnpm --filter @reactive-resume/api test -- src/features/applications/service.test.ts -``` - -Expected: FAIL because `applicationService.attachDocument` and `applicationService.removeDocument` are undefined. - -- [ ] **Step 7: Add service implementation** - -In `packages/api/src/features/applications/service.ts`, update imports: - -```ts -import type { ApplicationDocumentKind } from "../../dto/application"; -import { getStorageService, uploadFile } from "../storage/service"; -``` - -Add this helper near `deleteApplicationAttachments`: - -```ts -function documentFields(kind: ApplicationDocumentKind) { - return kind === "resume" - ? ({ - url: "resumeFileUrl", - name: "resumeFileName", - } as const) - : ({ - url: "coverLetterUrl", - name: "coverLetterName", - } as const); -} -``` - -Add methods to `applicationService` after `update`: - -```ts - attachDocument: async (input: { - id: string; - userId: string; - kind: ApplicationDocumentKind; - fileName: string; - data: Uint8Array; - contentType: string; - }) => { - if (input.contentType !== "application/pdf") { - throw new ORPCError("BAD_REQUEST", { message: "Application documents must be PDF files." }); - } - - const existing = await requireOwned(input.id, input.userId); - const fields = documentFields(input.kind); - const uploaded = await uploadFile({ - userId: input.userId, - data: input.data, - contentType: input.contentType, - }); - - try { - const updated = await applicationService.update({ - id: input.id, - userId: input.userId, - [fields.url]: uploaded.url, - [fields.name]: input.fileName, - }); - - await deleteApplicationAttachments(input.userId, [ - { - resumeFileUrl: fields.url === "resumeFileUrl" ? existing.resumeFileUrl : null, - coverLetterUrl: fields.url === "coverLetterUrl" ? existing.coverLetterUrl : null, - }, - ]); - - return updated; - } catch (error) { - await getStorageService().delete(uploaded.key).catch(() => false); - throw error; - } - }, - - removeDocument: async (input: { id: string; userId: string; kind: ApplicationDocumentKind }) => { - const existing = await requireOwned(input.id, input.userId); - const fields = documentFields(input.kind); - const updated = await applicationService.update({ - id: input.id, - userId: input.userId, - [fields.url]: null, - [fields.name]: null, - }); - - await deleteApplicationAttachments(input.userId, [ - { - resumeFileUrl: fields.url === "resumeFileUrl" ? existing.resumeFileUrl : null, - coverLetterUrl: fields.url === "coverLetterUrl" ? existing.coverLetterUrl : null, - }, - ]); - - return updated; - }, -``` - -- [ ] **Step 8: Run service tests to verify they pass** - -Run: - -```bash -pnpm --filter @reactive-resume/api test -- src/features/applications/service.test.ts -``` - -Expected: PASS. - -- [ ] **Step 9: Add REST routes** - -In `packages/api/src/features/applications/crud.ts`, add methods before `stats`: - -```ts - attachDocument: protectedProcedure - .route({ - method: "POST", - path: "/applications/{id}/documents/{kind}", - tags: ["Applications"], - operationId: "attachApplicationDocument", - summary: "Attach an application document", - description: - "Uploads and attaches a PDF document to an application. Kind must be either resume or cover-letter. Requires authentication.", - successDescription: "The updated application.", - requestBodyHint: "form-data", - }) - .input(applicationDto.attachDocument.input) - .use(resumeMutationRateLimit) - .output(applicationDto.attachDocument.output) - .handler(async ({ input, context }) => { - const buffer = await input.file.arrayBuffer(); - return applicationService.attachDocument({ - id: input.id, - userId: context.user.id, - kind: input.kind, - fileName: input.file.name, - contentType: input.file.type, - data: new Uint8Array(buffer), - }); - }), - - removeDocument: protectedProcedure - .route({ - method: "DELETE", - path: "/applications/{id}/documents/{kind}", - tags: ["Applications"], - operationId: "removeApplicationDocument", - summary: "Remove an application document", - description: - "Removes a resume or cover-letter PDF from an application and clears the stored document fields. Requires authentication.", - successDescription: "The updated application.", - }) - .input(applicationDto.removeDocument.input) - .use(resumeMutationRateLimit) - .output(applicationDto.removeDocument.output) - .handler(async ({ input, context }) => { - return applicationService.removeDocument({ id: input.id, userId: context.user.id, kind: input.kind }); - }), -``` - -In `packages/api/src/features/applications/router.ts`, add: - -```ts - attachDocument: crudRouter.attachDocument, - removeDocument: crudRouter.removeDocument, -``` - -- [ ] **Step 10: Run API typecheck** - -Run: - -```bash -pnpm --filter @reactive-resume/api typecheck -``` - -Expected: PASS. - -- [ ] **Step 11: Commit REST/API task** - -Run: - -```bash -git add packages/api/src/dto/application.ts packages/api/src/dto/application.test.ts packages/api/src/features/applications/service.ts packages/api/src/features/applications/service.test.ts packages/api/src/features/applications/crud.ts packages/api/src/features/applications/router.ts -git commit -m "feat: add application document API" -``` - -Expected: commit succeeds. - ---- - -### Task 2: MCP Tool Names, Metadata, and Annotations - -**Files:** -- Modify: `packages/mcp/src/mcp-tool-names.ts` -- Modify: `packages/mcp/src/tool-meta.ts` -- Modify: `packages/mcp/src/tool-annotations.ts` -- Modify: `packages/mcp/src/tool-annotations.test.ts` -- Modify: `packages/mcp/src/mcp-server-card.test.ts` - -**Interfaces:** -- Consumes: `applicationStatusSchema` and `contactSchema` from `@reactive-resume/schema/applications/data`. -- Produces: new `MCP_TOOL_NAME` values and `TOOL_META` entries used by `registerTools` in Task 3. - -- [ ] **Step 1: Add failing MCP metadata tests** - -In `packages/mcp/src/tool-annotations.test.ts`, add after the canonical read/patch names test: - -```ts - it("uses canonical application tool names", () => { - expect(MCP_TOOL_NAME.listApplications).toBe("list_applications"); - expect(MCP_TOOL_NAME.readApplication).toBe("read_application"); - expect(MCP_TOOL_NAME.createApplication).toBe("create_application"); - expect(MCP_TOOL_NAME.attachApplicationDocument).toBe("attach_application_document"); - expect(MCP_TOOL_NAME.autofillApplicationFromJob).toBe("autofill_application_from_job"); - }); -``` - -In the read-only annotation test list, add: - -```ts - MCP_TOOL_NAME.listApplications, - MCP_TOOL_NAME.readApplication, - MCP_TOOL_NAME.listApplicationTags, - MCP_TOOL_NAME.getApplicationStats, -``` - -Add tests before the open-world test: - -```ts - it("marks application delete tools as destructive", () => { - for (const name of [MCP_TOOL_NAME.deleteApplication, MCP_TOOL_NAME.bulkDeleteApplications]) { - const annotations = TOOL_ANNOTATIONS[name]; - expect(annotations.readOnlyHint, name).toBe(false); - expect(annotations.destructiveHint, name).toBe(true); - } - }); - - it("marks only job-posting autofill as open-world", () => { - expect(TOOL_ANNOTATIONS[MCP_TOOL_NAME.autofillApplicationFromJob].openWorldHint).toBe(true); - }); -``` - -In `packages/mcp/src/mcp-server-card.test.ts`, add: - -```ts - it("advertises application tracker tools", () => { - const names = card.tools.map((tool) => tool.name); - - expect(names).toContain("list_applications"); - expect(names).toContain("create_application"); - expect(names).toContain("attach_application_document"); - expect(names).toContain("tailor_resume_for_application"); - }); -``` - -- [ ] **Step 2: Run MCP metadata tests to verify they fail** - -Run: - -```bash -pnpm --filter @reactive-resume/mcp test -- src/tool-annotations.test.ts src/mcp-server-card.test.ts -``` - -Expected: FAIL because the new MCP tool names do not exist. - -- [ ] **Step 3: Add MCP tool names** - -In `packages/mcp/src/mcp-tool-names.ts`, add these properties to `MCP_TOOL_NAME`: - -```ts - listApplications: "list_applications", - readApplication: "read_application", - listApplicationTags: "list_application_tags", - getApplicationStats: "get_application_stats", - createApplication: "create_application", - updateApplication: "update_application", - addApplicationNote: "add_application_note", - deleteApplication: "delete_application", - bulkUpdateApplications: "bulk_update_applications", - bulkDeleteApplications: "bulk_delete_applications", - importApplications: "import_applications", - attachApplicationDocument: "attach_application_document", - removeApplicationDocument: "remove_application_document", - autofillApplicationFromJob: "autofill_application_from_job", - scoreApplicationMatch: "score_application_match", - tailorResumeForApplication: "tailor_resume_for_application", - draftApplicationMessage: "draft_application_message", -``` - -- [ ] **Step 4: Add MCP metadata schemas** - -In `packages/mcp/src/tool-meta.ts`, add imports: - -```ts -import { applicationStatusSchema, contactSchema } from "@reactive-resume/schema/applications/data"; -``` - -Add shared schemas near `resumeIdSchema`: - -```ts -const applicationIdSchema = z.string().min(1).describe(`Application ID. Use \`${T.listApplications}\` to find valid IDs.`); -const applicationDocumentKindSchema = z.enum(["resume", "cover-letter"]); -const pdfBase64Schema = z - .string() - .min(1) - .describe("Base64-encoded PDF bytes. Only application/pdf documents are accepted."); - -const applicationEditableSchema = { - company: z.string().min(1).optional().describe("Company name."), - role: z.string().min(1).optional().describe("Role or job title."), - status: applicationStatusSchema.optional().describe("Pipeline stage."), - archived: z.boolean().optional().describe("Whether the application is hidden from active views."), - location: z.string().nullable().optional(), - salary: z.string().nullable().optional(), - source: z.string().nullable().optional(), - sourceUrl: z.string().url().nullable().optional(), - jobDescription: z.string().max(20_000).nullable().optional(), - notes: z.string().nullable().optional(), - resumeId: z.string().nullable().optional(), - resumeFileUrl: z.string().nullable().optional(), - resumeFileName: z.string().nullable().optional(), - coverLetterUrl: z.string().nullable().optional(), - coverLetterName: z.string().nullable().optional(), - followUpAt: z.coerce.date().nullable().optional(), - followUpNote: z.string().nullable().optional(), - contacts: z.array(contactSchema).optional(), - tags: z.array(z.string()).optional(), -} as const; - -const createApplicationSchema = z.object({ - ...applicationEditableSchema, - company: z.string().min(1).describe("Company name."), - role: z.string().min(1).describe("Role or job title."), -}); -``` - -Add these `TOOL_META` entries after resume tools or in a separate Applications block: - -```ts - [T.listApplications]: { - title: "List Applications", - description: - "List job applications for the authenticated account. Use this before reading or updating existing applications.", - inputSchema: z.object({ - status: applicationStatusSchema.optional(), - tags: z.array(z.string()).optional().default([]), - includeArchived: z.boolean().optional().default(false), - }), - annotations: TOOL_ANNOTATIONS[T.listApplications], - }, - [T.readApplication]: { - title: "Read Application", - description: "Read one full job application, including contacts, document URLs, follow-up details, and timeline.", - inputSchema: z.object({ id: applicationIdSchema }), - annotations: TOOL_ANNOTATIONS[T.readApplication], - }, - [T.listApplicationTags]: { - title: "List Application Tags", - description: "Return every distinct tag used across job applications.", - inputSchema: z.object({}), - annotations: TOOL_ANNOTATIONS[T.listApplicationTags], - }, - [T.getApplicationStats]: { - title: "Get Application Stats", - description: "Return aggregate application counts by pipeline stage and source for insights.", - inputSchema: z.object({}), - annotations: TOOL_ANNOTATIONS[T.getApplicationStats], - }, - [T.createApplication]: { - title: "Create Application", - description: "Create a tracked job application. Company and role are required.", - inputSchema: createApplicationSchema, - annotations: TOOL_ANNOTATIONS[T.createApplication], - }, - [T.updateApplication]: { - title: "Update Application", - description: "Update application fields, move stages, archive/unarchive, edit contacts, follow-up, tags, or linked resume.", - inputSchema: z.object({ id: applicationIdSchema, ...applicationEditableSchema }), - annotations: TOOL_ANNOTATIONS[T.updateApplication], - }, - [T.addApplicationNote]: { - title: "Add Application Note", - description: "Append a free-text note to an application's timeline.", - inputSchema: z.object({ id: applicationIdSchema, text: z.string().min(1) }), - annotations: TOOL_ANNOTATIONS[T.addApplicationNote], - }, - [T.deleteApplication]: { - title: "Delete Application", - description: "Permanently delete one job application and its owned uploaded documents.", - inputSchema: z.object({ id: applicationIdSchema }), - annotations: TOOL_ANNOTATIONS[T.deleteApplication], - }, - [T.bulkUpdateApplications]: { - title: "Bulk Update Applications", - description: "Move, archive/unarchive, or add tags to multiple applications.", - inputSchema: z.object({ - ids: z.array(z.string()).min(1), - status: applicationStatusSchema.optional(), - archived: z.boolean().optional(), - addTags: z.array(z.string()).optional(), - }), - annotations: TOOL_ANNOTATIONS[T.bulkUpdateApplications], - }, - [T.bulkDeleteApplications]: { - title: "Bulk Delete Applications", - description: "Permanently delete multiple applications.", - inputSchema: z.object({ ids: z.array(z.string()).min(1) }), - annotations: TOOL_ANNOTATIONS[T.bulkDeleteApplications], - }, - [T.importApplications]: { - title: "Import Applications", - description: "Bulk-create application rows parsed from CSV or another source. Maximum 500 items.", - inputSchema: z.object({ items: z.array(createApplicationSchema).min(1).max(500) }), - annotations: TOOL_ANNOTATIONS[T.importApplications], - }, - [T.attachApplicationDocument]: { - title: "Attach Application Document", - description: "Attach a sent resume or cover-letter PDF to an application using base64-encoded PDF bytes.", - inputSchema: z.object({ - id: applicationIdSchema, - kind: applicationDocumentKindSchema, - fileName: z.string().min(1), - contentType: z.literal("application/pdf"), - dataBase64: pdfBase64Schema, - }), - annotations: TOOL_ANNOTATIONS[T.attachApplicationDocument], - }, - [T.removeApplicationDocument]: { - title: "Remove Application Document", - description: "Remove a sent resume or cover-letter PDF from an application.", - inputSchema: z.object({ id: applicationIdSchema, kind: applicationDocumentKindSchema }), - annotations: TOOL_ANNOTATIONS[T.removeApplicationDocument], - }, - [T.autofillApplicationFromJob]: { - title: "Autofill Application From Job", - description: "Use AI to extract company, role, location, salary, and job description from a job URL or pasted posting.", - inputSchema: z.object({ - sourceUrl: z.string().url().optional(), - jobDescription: z.string().max(20_000).optional(), - }), - annotations: TOOL_ANNOTATIONS[T.autofillApplicationFromJob], - }, - [T.scoreApplicationMatch]: { - title: "Score Application Match", - description: "Score the linked resume against the application's job description and persist match metadata.", - inputSchema: z.object({ id: applicationIdSchema }), - annotations: TOOL_ANNOTATIONS[T.scoreApplicationMatch], - }, - [T.tailorResumeForApplication]: { - title: "Tailor Resume For Application", - description: "Create and link a tailored copy of the application's linked resume.", - inputSchema: z.object({ id: applicationIdSchema }), - annotations: TOOL_ANNOTATIONS[T.tailorResumeForApplication], - }, - [T.draftApplicationMessage]: { - title: "Draft Application Message", - description: "Draft either a cover letter or recruiter follow-up from application and resume context.", - inputSchema: z.object({ id: applicationIdSchema, kind: z.enum(["cover-letter", "follow-up"]) }), - annotations: TOOL_ANNOTATIONS[T.draftApplicationMessage], - }, -``` - -- [ ] **Step 5: Add annotations** - -In `packages/mcp/src/tool-annotations.ts`, add: - -```ts -const READ_OPEN_WORLD_NON_IDEMPOTENT: ToolAnnotations = { - readOnlyHint: true, - destructiveHint: false, - idempotentHint: false, - openWorldHint: true, -}; -``` - -Add mappings: - -```ts - [MCP_TOOL_NAME.listApplications]: READ_IDEMPOTENT, - [MCP_TOOL_NAME.readApplication]: READ_IDEMPOTENT, - [MCP_TOOL_NAME.listApplicationTags]: READ_IDEMPOTENT, - [MCP_TOOL_NAME.getApplicationStats]: READ_IDEMPOTENT, - [MCP_TOOL_NAME.createApplication]: WRITE_NON_IDEMPOTENT, - [MCP_TOOL_NAME.updateApplication]: WRITE_IDEMPOTENT, - [MCP_TOOL_NAME.addApplicationNote]: WRITE_NON_IDEMPOTENT, - [MCP_TOOL_NAME.deleteApplication]: WRITE_DESTRUCTIVE, - [MCP_TOOL_NAME.bulkUpdateApplications]: WRITE_IDEMPOTENT, - [MCP_TOOL_NAME.bulkDeleteApplications]: WRITE_DESTRUCTIVE, - [MCP_TOOL_NAME.importApplications]: WRITE_NON_IDEMPOTENT, - [MCP_TOOL_NAME.attachApplicationDocument]: WRITE_NON_IDEMPOTENT, - [MCP_TOOL_NAME.removeApplicationDocument]: WRITE_IDEMPOTENT, - [MCP_TOOL_NAME.autofillApplicationFromJob]: READ_OPEN_WORLD_NON_IDEMPOTENT, - [MCP_TOOL_NAME.scoreApplicationMatch]: WRITE_NON_IDEMPOTENT, - [MCP_TOOL_NAME.tailorResumeForApplication]: WRITE_NON_IDEMPOTENT, - [MCP_TOOL_NAME.draftApplicationMessage]: READ_NON_IDEMPOTENT, -``` - -Update the existing "declares no tools as open-world by default" test to skip `MCP_TOOL_NAME.autofillApplicationFromJob`: - -```ts - for (const [name, annotations] of Object.entries(TOOL_ANNOTATIONS)) { - if (name === MCP_TOOL_NAME.autofillApplicationFromJob) continue; - expect(annotations.openWorldHint).toBe(false); - } -``` - -- [ ] **Step 6: Run MCP metadata tests** - -Run: - -```bash -pnpm --filter @reactive-resume/mcp test -- src/tool-annotations.test.ts src/mcp-server-card.test.ts -``` - -Expected: PASS. - -- [ ] **Step 7: Commit metadata task** - -Run: - -```bash -git add packages/mcp/src/mcp-tool-names.ts packages/mcp/src/tool-meta.ts packages/mcp/src/tool-annotations.ts packages/mcp/src/tool-annotations.test.ts packages/mcp/src/mcp-server-card.test.ts -git commit -m "feat: describe application MCP tools" -``` - -Expected: commit succeeds. - ---- - -### Task 3: MCP Application Tool Handlers - -**Files:** -- Modify: `packages/mcp/src/tools.ts` -- Modify: `packages/mcp/src/tools.test.ts` - -**Interfaces:** -- Consumes: `MCP_TOOL_NAME` values and `TOOL_META` entries from Task 2. -- Consumes: API procedures exposed from Task 1. -- Produces: registered MCP handlers for every application tool. - -- [ ] **Step 1: Add failing handler tests** - -In `packages/mcp/src/tools.test.ts`, change `ToolHandler` to accept any object: - -```ts -type ToolHandler = (input: Record) => Promise<{ - content: Array<{ type: "text"; text: string }>; - isError?: boolean; -}>; -``` - -Extend `clientMock` with: - -```ts - applications: { - list: vi.fn(), - getById: vi.fn(), - tags: vi.fn(), - stats: vi.fn(), - create: vi.fn(), - update: vi.fn(), - addNote: vi.fn(), - delete: vi.fn(), - bulkUpdate: vi.fn(), - bulkDelete: vi.fn(), - import: vi.fn(), - attachDocument: vi.fn(), - removeDocument: vi.fn(), - ai: { - autofill: vi.fn(), - matchScore: vi.fn(), - tailorResume: vi.fn(), - draftMessage: vi.fn(), - }, - }, -``` - -Add tests: - -```ts - it("registers application tracker tools", () => { - const { server, registered } = makeFakeServer(); - registerTools(server as never, clientMock as never, new Headers()); - - const names = registered.map((item) => item.name); - expect(names).toContain("list_applications"); - expect(names).toContain("create_application"); - expect(names).toContain("attach_application_document"); - expect(names).toContain("draft_application_message"); - }); - - it("lists applications as JSON", async () => { - clientMock.applications.list.mockResolvedValueOnce([{ id: "app-1", company: "Acme", role: "Engineer" }]); - const { server, registered } = makeFakeServer(); - registerTools(server as never, clientMock as never, new Headers()); - - const tool = registered.find((item) => item.name === "list_applications")!; - const result = await tool.handler({ includeArchived: true, tags: ["remote"] }); - - expect(clientMock.applications.list).toHaveBeenCalledWith({ includeArchived: true, tags: ["remote"] }); - expect(JSON.parse(result.content[0]!.text)).toEqual([{ id: "app-1", company: "Acme", role: "Engineer" }]); - }); - - it("creates applications through the router client", async () => { - clientMock.applications.create.mockResolvedValueOnce("app-1"); - const { server, registered } = makeFakeServer(); - registerTools(server as never, clientMock as never, new Headers()); - - const tool = registered.find((item) => item.name === "create_application")!; - const result = await tool.handler({ company: "Acme", role: "Engineer", status: "saved" }); - - expect(clientMock.applications.create).toHaveBeenCalledWith({ - company: "Acme", - role: "Engineer", - status: "saved", - }); - expect(JSON.parse(result.content[0]!.text)).toEqual({ id: "app-1" }); - }); - - it("attaches a base64 PDF document through the router client", async () => { - clientMock.applications.attachDocument.mockResolvedValueOnce({ id: "app-1", resumeFileName: "resume.pdf" }); - const { server, registered } = makeFakeServer(); - registerTools(server as never, clientMock as never, new Headers()); - - const tool = registered.find((item) => item.name === "attach_application_document")!; - const result = await tool.handler({ - id: "app-1", - kind: "resume", - fileName: "resume.pdf", - contentType: "application/pdf", - dataBase64: Buffer.from("%PDF-1.4").toString("base64"), - }); - - const call = clientMock.applications.attachDocument.mock.calls[0]?.[0] as { file: File }; - expect(call.file).toBeInstanceOf(File); - expect(call.file.name).toBe("resume.pdf"); - expect(call.file.type).toBe("application/pdf"); - expect(JSON.parse(result.content[0]!.text)).toEqual({ id: "app-1", resumeFileName: "resume.pdf" }); - }); - - it("rejects non-PDF application document attachments before calling the client", async () => { - const { server, registered } = makeFakeServer(); - registerTools(server as never, clientMock as never, new Headers()); - - const tool = registered.find((item) => item.name === "attach_application_document")!; - const result = await tool.handler({ - id: "app-1", - kind: "resume", - fileName: "resume.txt", - contentType: "text/plain", - dataBase64: Buffer.from("hello").toString("base64"), - }); - - expect(result.isError).toBe(true); - expect(clientMock.applications.attachDocument).not.toHaveBeenCalled(); - }); -``` - -- [ ] **Step 2: Run handler tests to verify they fail** - -Run: - -```bash -pnpm --filter @reactive-resume/mcp test -- src/tools.test.ts -``` - -Expected: FAIL because application tools are not registered. - -- [ ] **Step 3: Add JSON and File helpers** - -In `packages/mcp/src/tools.ts`, add an import: - -```ts -import { Buffer } from "node:buffer"; -``` - -Add helper near `text()`: - -```ts -function json(value: unknown): CallToolResult { - return text(JSON.stringify(value, null, 2)); -} - -function fileFromBase64(input: { fileName: string; contentType: string; dataBase64: string }): File { - if (input.contentType !== "application/pdf") throw new Error("Application documents must be PDF files."); - - const bytes = Buffer.from(input.dataBase64, "base64"); - if (bytes.length === 0) throw new Error("Application document cannot be empty."); - - return new File([bytes], input.fileName, { type: input.contentType }); -} -``` - -- [ ] **Step 4: Register read/discovery handlers** - -In `registerTools`, after resume statistics or in a clearly labelled Applications block, add: - -```ts - server.registerTool( - T.listApplications, - TOOL_META[T.listApplications], - withErrorHandling("listing applications", async (params) => { - return json(await client.applications.list(params as { status?: never; tags?: string[]; includeArchived?: boolean })); - }), - ); - - server.registerTool( - T.readApplication, - TOOL_META[T.readApplication], - withErrorHandling("reading application", async ({ id }: { id: string }) => { - return json(await client.applications.getById({ id })); - }), - ); - - server.registerTool( - T.listApplicationTags, - TOOL_META[T.listApplicationTags], - withErrorHandling("listing application tags", async () => { - return json(await client.applications.tags()); - }), - ); - - server.registerTool( - T.getApplicationStats, - TOOL_META[T.getApplicationStats], - withErrorHandling("getting application stats", async () => { - return json(await client.applications.stats()); - }), - ); -``` - -- [ ] **Step 5: Register write handlers** - -Add: - -```ts - server.registerTool( - T.createApplication, - TOOL_META[T.createApplication], - withErrorHandling("creating application", async (params) => { - const id = await client.applications.create(params as never); - return json({ id }); - }), - ); - - server.registerTool( - T.updateApplication, - TOOL_META[T.updateApplication], - withErrorHandling("updating application", async (params) => { - return json(await client.applications.update(params as never)); - }), - ); - - server.registerTool( - T.addApplicationNote, - TOOL_META[T.addApplicationNote], - withErrorHandling("adding application note", async ({ id, text: noteText }: { id: string; text: string }) => { - return json(await client.applications.addNote({ id, text: noteText })); - }), - ); - - server.registerTool( - T.deleteApplication, - TOOL_META[T.deleteApplication], - withErrorHandling("deleting application", async ({ id }: { id: string }) => { - await client.applications.delete({ id }); - return text(`Deleted application (${id}).`); - }), - ); - - server.registerTool( - T.bulkUpdateApplications, - TOOL_META[T.bulkUpdateApplications], - withErrorHandling("bulk updating applications", async (params) => { - return json(await client.applications.bulkUpdate(params as never)); - }), - ); - - server.registerTool( - T.bulkDeleteApplications, - TOOL_META[T.bulkDeleteApplications], - withErrorHandling("bulk deleting applications", async ({ ids }: { ids: string[] }) => { - return json(await client.applications.bulkDelete({ ids })); - }), - ); - - server.registerTool( - T.importApplications, - TOOL_META[T.importApplications], - withErrorHandling("importing applications", async (params) => { - return json(await client.applications.import(params as never)); - }), - ); -``` - -- [ ] **Step 6: Register document handlers** - -Add: - -```ts - server.registerTool( - T.attachApplicationDocument, - TOOL_META[T.attachApplicationDocument], - withErrorHandling( - "attaching application document", - async ({ - id, - kind, - fileName, - contentType, - dataBase64, - }: { - id: string; - kind: "resume" | "cover-letter"; - fileName: string; - contentType: string; - dataBase64: string; - }) => { - const file = fileFromBase64({ fileName, contentType, dataBase64 }); - return json(await client.applications.attachDocument({ id, kind, file })); - }, - ), - ); - - server.registerTool( - T.removeApplicationDocument, - TOOL_META[T.removeApplicationDocument], - withErrorHandling( - "removing application document", - async ({ id, kind }: { id: string; kind: "resume" | "cover-letter" }) => { - return json(await client.applications.removeDocument({ id, kind })); - }, - ), - ); -``` - -- [ ] **Step 7: Register AI handlers** - -Add: - -```ts - server.registerTool( - T.autofillApplicationFromJob, - TOOL_META[T.autofillApplicationFromJob], - withErrorHandling("autofilling application from job", async (params) => { - return json(await client.applications.ai.autofill(params as { sourceUrl?: string; jobDescription?: string })); - }), - ); - - server.registerTool( - T.scoreApplicationMatch, - TOOL_META[T.scoreApplicationMatch], - withErrorHandling("scoring application match", async ({ id }: { id: string }) => { - return json(await client.applications.ai.matchScore({ id })); - }), - ); - - server.registerTool( - T.tailorResumeForApplication, - TOOL_META[T.tailorResumeForApplication], - withErrorHandling("tailoring resume for application", async ({ id }: { id: string }) => { - return json(await client.applications.ai.tailorResume({ id })); - }), - ); - - server.registerTool( - T.draftApplicationMessage, - TOOL_META[T.draftApplicationMessage], - withErrorHandling("drafting application message", async ({ id, kind }: { id: string; kind: "cover-letter" | "follow-up" }) => { - return json(await client.applications.ai.draftMessage({ id, kind })); - }), - ); -``` - -- [ ] **Step 8: Run MCP handler tests** - -Run: - -```bash -pnpm --filter @reactive-resume/mcp test -- src/tools.test.ts -``` - -Expected: PASS. - -- [ ] **Step 9: Run MCP typecheck** - -Run: - -```bash -pnpm --filter @reactive-resume/mcp typecheck -``` - -Expected: PASS. - -- [ ] **Step 10: Commit MCP handler task** - -Run: - -```bash -git add packages/mcp/src/tools.ts packages/mcp/src/tools.test.ts -git commit -m "feat: add application MCP tools" -``` - -Expected: commit succeeds. - ---- - -### Task 4: Skill, MCP Docs, and OpenAPI Spec - -**Files:** -- Modify: `skills/resume-builder/SKILL.md` -- Modify: `docs/guides/using-the-mcp-server.mdx` -- Modify: `docs/use-cases/api-mcp-resume-automation.mdx` -- Modify: `docs/spec.json` - -**Interfaces:** -- Consumes: MCP tool names from Task 2 and route changes from Task 1. -- Produces: user-facing docs and skill guidance that describe application tracking through MCP. - -- [ ] **Step 1: Update the resume-builder skill** - -In `skills/resume-builder/SKILL.md`, add after the Workflow section heading and before "Step 1": - -```md -### MCP Application Tracking - -Reactive Resume MCP can manage job applications as well as resumes. When the user wants to track applications through an agent, use the application tools instead of asking them to open the web UI. - -- Use `list_applications` before changing existing records. -- Use `create_application` for one new opportunity or `import_applications` for spreadsheet/CSV rows. -- Use `update_application` to move stages, archive/unarchive, edit contacts, set follow-ups, link a resume, or update job details. -- Use `add_application_note` to log timeline activity. -- Use `attach_application_document` and `remove_application_document` for sent resume or cover-letter PDFs. -- Use `score_application_match`, `tailor_resume_for_application`, and `draft_application_message` for Application Copilot workflows after a linked resume and job description exist. -- Review AI-generated cover letters and follow-ups before sending them. -``` - -- [ ] **Step 2: Update the MCP server guide tool table** - -In `docs/guides/using-the-mcp-server.mdx`, extend the Available Tools table with: - -```md -| `list_applications` | List tracked job applications. Supports stage, tag, and archived filters | -| `read_application` | Read one full application record with contacts, follow-up details, documents, and timeline | -| `list_application_tags` | List every distinct tag used across applications | -| `get_application_stats` | Get aggregate application counts by stage and source | -| `create_application` | Create a tracked job application | -| `update_application` | Update fields, move stage, archive/unarchive, edit contacts/follow-ups/tags, or link a resume | -| `add_application_note` | Append a note to an application's activity timeline | -| `delete_application` | Permanently delete one application and its owned uploaded documents | -| `bulk_update_applications` | Move, archive/unarchive, or add tags to multiple applications | -| `bulk_delete_applications` | Permanently delete multiple applications | -| `import_applications` | Bulk-create parsed application rows, up to 500 items | -| `attach_application_document` | Attach a sent resume or cover-letter PDF from base64-encoded PDF bytes | -| `remove_application_document` | Remove a sent resume or cover-letter PDF | -| `autofill_application_from_job` | Use AI to extract job details from a URL or pasted job description | -| `score_application_match` | Score the linked resume against the application job description | -| `tailor_resume_for_application` | Create and link a tailored resume copy for an application | -| `draft_application_message` | Draft a cover letter or recruiter follow-up from application and resume context | -``` - -- [ ] **Step 3: Add application MCP usage examples** - -In the Usage Examples section of `docs/guides/using-the-mcp-server.mdx`, add a subsection after Browsing: - -```md -### Tracking Applications - -- "Create an application for Senior Frontend Engineer at Acme, stage saved, source LinkedIn." -- "List my archived applications tagged remote." -- "Move my Acme application to interview and add a note that the technical screen is next Tuesday." -- "Attach this resume PDF to the Acme application." -- "Score the resume linked to this application against the job description." -- "Create a tailored resume copy for this application." -- "Draft a follow-up message for the recruiter." -``` - -Add a troubleshooting row: - -```md -| "Application documents must be PDF files" | `attach_application_document` only accepts `contentType: "application/pdf"` and base64-encoded PDF bytes | -``` - -- [ ] **Step 4: Update the API/MCP automation use case** - -Replace the first paragraph in `docs/use-cases/api-mcp-resume-automation.mdx` with: - -```md -Reactive Resume supports automation through authenticated API access and an MCP server that lets compatible tools work with resumes and job applications. Agents can list, read, create, import, duplicate, and patch resumes, then track applications, move opportunities through stages, add notes and follow-ups, attach sent documents, and run Application Copilot actions. -``` - -Add to "Common automation workflows": - -```md -- Track job applications end to end from an MCP client. -- Import existing application rows from a spreadsheet parser. -- Move applications through stages and log timeline notes. -- Attach the resume or cover-letter PDF sent for an application. -- Score a linked resume against a job description and create a tailored resume copy. -- Draft cover letters and recruiter follow-ups from saved application context. -``` - -- [ ] **Step 5: Refresh docs/spec.json** - -Start the dev server in one terminal: - -```bash -dotenvx run -f .env.local -- pnpm dev -``` - -In another terminal, after the server reports it is listening on port 3000, run: - -```bash -curl -fsS http://localhost:3000/api/openapi/spec.json -o docs/spec.json -``` - -Expected: `docs/spec.json` contains `/applications` paths: - -```bash -rg -n '"/applications|attachApplicationDocument|removeApplicationDocument' docs/spec.json -``` - -Expected: matches for the application paths and document operations. - -- [ ] **Step 6: Run docs/skill checks** - -Run: - -```bash -rg -n "list_applications|attach_application_document|tailor_resume_for_application" skills/resume-builder/SKILL.md docs/guides/using-the-mcp-server.mdx docs/use-cases/api-mcp-resume-automation.mdx -rg -n '"/applications|attachApplicationDocument|removeApplicationDocument' docs/spec.json -``` - -Expected: all commands print matching lines. - -- [ ] **Step 7: Commit docs task** - -Run: - -```bash -git add skills/resume-builder/SKILL.md docs/guides/using-the-mcp-server.mdx docs/use-cases/api-mcp-resume-automation.mdx docs/spec.json -git commit -m "docs: document application MCP automation" -``` - -Expected: commit succeeds. - ---- - -### Task 5: Final Validation and Boundary Check - -**Files:** -- No planned source edits. - -**Interfaces:** -- Consumes: all previous task outputs. -- Produces: verified implementation ready for review. - -- [ ] **Step 1: Run focused tests** - -Run: - -```bash -pnpm --filter @reactive-resume/api test -- src/dto/application.test.ts src/features/applications/service.test.ts -pnpm --filter @reactive-resume/mcp test -- src/tools.test.ts src/tool-annotations.test.ts src/mcp-server-card.test.ts -``` - -Expected: PASS. - -- [ ] **Step 2: Run focused typechecks** - -Run: - -```bash -pnpm --filter @reactive-resume/api typecheck -pnpm --filter @reactive-resume/mcp typecheck -``` - -Expected: PASS. - -- [ ] **Step 3: Run boundary check** - -Run: - -```bash -pnpm exec turbo boundaries -``` - -Expected: PASS. - -- [ ] **Step 4: Run non-mutating Biome check on touched files** - -Run: - -```bash -pnpm exec biome check packages/api/src/dto/application.ts packages/api/src/dto/application.test.ts packages/api/src/features/applications/service.ts packages/api/src/features/applications/service.test.ts packages/api/src/features/applications/crud.ts packages/api/src/features/applications/router.ts packages/mcp/src/mcp-tool-names.ts packages/mcp/src/tool-meta.ts packages/mcp/src/tool-annotations.ts packages/mcp/src/tools.ts packages/mcp/src/tool-annotations.test.ts packages/mcp/src/mcp-server-card.test.ts packages/mcp/src/tools.test.ts skills/resume-builder/SKILL.md docs/guides/using-the-mcp-server.mdx docs/use-cases/api-mcp-resume-automation.mdx docs/spec.json -``` - -Expected: PASS. If Biome reports formatting fixes, run the same command with `--write`, inspect the diff, and commit only formatting changes. - -- [ ] **Step 5: Inspect final diff** - -Run: - -```bash -git status --short -git log --oneline -5 -``` - -Expected: worktree is clean after the task commits, and recent commits are the REST/API, MCP metadata, MCP handler, and docs commits from this plan. diff --git a/docs/superpowers/specs/2026-05-11-react-pdf-html-prose-spacing-design.md b/docs/superpowers/specs/2026-05-11-react-pdf-html-prose-spacing-design.md deleted file mode 100644 index 00ed00b11..000000000 --- a/docs/superpowers/specs/2026-05-11-react-pdf-html-prose-spacing-design.md +++ /dev/null @@ -1,55 +0,0 @@ -# React PDF HTML Prose Spacing Design - -## Context - -Resume rich-text fields are rendered in PDF through `packages/pdf/src/templates/shared/rich-text.tsx`, which wraps normalized HTML with `react-pdf-html`. Each template currently supplies body-derived styles such as `richParagraph`, `richListItemRow`, `richListItemMarker`, and `richListItemContent`. Those styles intentionally keep rich text aligned with the template typography. - -The current PDF rich-text spacing differs from what users see in Tailwind Typography prose. Paragraphs and list items are effectively flattened by zero margins, while browser prose gives paragraphs and list items vertical rhythm and trims the outside edges of the rich-text flow. - -## Goals - -- Add vertical spacing to `react-pdf-html` paragraphs and list items in the shared `RichText` path. -- Match Tailwind Typography `prose-sm` spacing proportions without importing Tailwind's browser font size into PDF output. -- Preserve each resume template's body font size and line height for rich text and adjacent non-rich-text PDF elements. -- Remove the outer top margin from the first renderable rich-text block and the outer bottom margin from the last renderable rich-text block. -- Keep the change shared and template-compatible unless a future template needs an explicit exception. - -## Non-Goals - -- Do not change web editor `.wysiwyg` styles. -- Do not change template body or heading font sizes. -- Do not add a new PDF typography system. -- Do not restyle headings, blockquotes, tables, or other HTML tags beyond paragraph and list item spacing. - -## Recommended Approach - -Use Tailwind Typography `prose-sm` spacing ratios and derive the final PDF spacing from the current template body font size. Tailwind Typography's `prose-sm` paragraph spacing is `16 / 14` of the body size, and list item spacing is `4 / 14` of the body size. The PDF renderer should use those ratios against the resolved body font size already present in the template styles. - -This keeps rich-text content visually consistent with Tailwind Typography while respecting the resume template's PDF typography scale. - -## Implementation Shape - -The shared `RichText` component should: - -1. Continue normalizing input through `normalizeRichTextHtml`. -2. Inspect the normalized HTML to identify renderable top-level prose blocks relevant to this change: paragraphs and list items. -3. Apply derived paragraph spacing to `p` through the `react-pdf-html` stylesheet. -4. Apply derived list item spacing to the custom `li` renderer row container. -5. Trim `marginTop` on the first relevant rich-text element and `marginBottom` on the last relevant rich-text element. -6. Merge spacing after template styles where needed so old `margin: 0` template defaults do not suppress the new shared prose rhythm. - -For list items, the spacing belongs on the custom `li` row container. Marker and content styles should continue coming from template slots so bullets, numbers, font size, and line height remain template-owned. - -## Testing - -Add focused tests around the shared rich-text spacing behavior. Coverage should include: - -- A single paragraph has both outer margins trimmed. -- Multiple paragraphs keep internal paragraph spacing and trim only the first top and last bottom edge. -- Multiple list items get list-item vertical spacing with first top and last bottom trimmed. -- Mixed paragraph/list content trims the first and last relevant elements across element types. -- Rich-text font sizing remains template-derived rather than hard-coded to Tailwind's browser `14px`. - -## Open Decisions - -No open decisions remain. The approved behavior is to use Tailwind Typography spacing ratios derived from the resume template body font size. diff --git a/docs/superpowers/specs/2026-05-15-docker-nightly-release-tags-design.md b/docs/superpowers/specs/2026-05-15-docker-nightly-release-tags-design.md deleted file mode 100644 index 3f6d343a9..000000000 --- a/docs/superpowers/specs/2026-05-15-docker-nightly-release-tags-design.md +++ /dev/null @@ -1,94 +0,0 @@ -# Docker Nightly and Release Tagging Design - -## Goal - -Update `.github/workflows/docker-build.yml` so the existing Docker build pipeline supports two publishing modes without duplicating the workflow: - -- Nightly publishing on pushes to the default branch, `main`. -- Release publishing only on manual workflow runs or pushed Git tags. - -## Trigger Rules - -The workflow should run for: - -- `workflow_dispatch`, which publishes release tags. -- `push` to `main`, which publishes nightly tags only. -- `push` to Git tags matching `v*`, which publishes release tags. - -Pull request events should not publish Docker images. This avoids exposing registry credentials to PR contexts and keeps nightly publishing tied to commits that have actually landed on `main`. - -## Publishing Modes - -### Nightly Mode - -Nightly mode applies when: - -- `github.event_name == "push"` -- `github.ref == "refs/heads/main"` - -Nightly mode should push these tags to both GHCR and Docker Hub: - -- `nightly` -- `nightly-{timestamp}` - -The timestamp should be generated by the workflow at publish time in UTC using `YYYYMMDDHHmmss`, for example `nightly-20260515143000`. - -Nightly builds should use only the `linux/amd64` platform. They should not build or publish `linux/arm64`. - -### Release Mode - -Release mode applies when: - -- The workflow is run manually with `workflow_dispatch`. -- A Git tag is pushed. - -Release mode should preserve the existing release tag behavior: - -- `latest` -- `v{VERSION}` from root `package.json` -- `v{MAJOR}.{MINOR}` -- `v{MAJOR}` - -Release builds should preserve the current multi-platform behavior: - -- `linux/amd64` -- `linux/arm64` - -## Workflow Shape - -Keep a single `.github/workflows/docker-build.yml` file. The current workflow already has the useful structure: - -1. Build per-platform images and push them by digest. -2. Upload digest artifacts. -3. Merge digests into final manifest tags. -4. Sign and inspect final images. -5. Redeploy the stack. - -The implementation should add a small mode-detection step or expression-based conditions rather than creating a second near-identical workflow. - -The build matrix should include both architectures, but the arm64 build should be skipped during nightly mode. This keeps release behavior unchanged while making nightly pushes cheaper and faster. - -The merge job should generate final tags conditionally: - -- Nightly mode emits `nightly` and `nightly-{timestamp}`. -- Release mode emits `latest` and version aliases. - -The merge job should inspect and sign whichever final manifest tag is authoritative for the current mode: - -- Nightly mode can inspect/sign `nightly`. -- Release mode can inspect/sign `v{VERSION}`. - -## Deployment - -The existing `Redeploy Stack` step should remain release-only. Nightly pushes should publish images but should not redeploy the running stack. - -## Validation - -Validate the change by reviewing the workflow syntax and checking that: - -- A `push` to `main` resolves to a single `linux/amd64` build and nightly tags. -- A `workflow_dispatch` run resolves to both architectures and release tags. -- A pushed Git tag resolves to both architectures and release tags. -- No PR event can publish images. - -If local workflow lint tooling is unavailable, inspect the YAML and relevant GitHub Actions expressions directly. diff --git a/docs/superpowers/specs/2026-05-15-manifest-only-pwa-design.md b/docs/superpowers/specs/2026-05-15-manifest-only-pwa-design.md deleted file mode 100644 index 43dfeda93..000000000 --- a/docs/superpowers/specs/2026-05-15-manifest-only-pwa-design.md +++ /dev/null @@ -1,99 +0,0 @@ -# Manifest-Only PWA Design - -Date: 2026-05-15 - -## Goal - -Reduce Reactive Resume's PWA implementation to install metadata only. - -The site should remain installable on supported phones and desktops through the web app manifest, icons, -screenshots, and mobile app meta tags. The PWA implementation should not generate, register, or rely on a -service worker, and it should not provide offline support, app-shell precaching, runtime caching, or fallback -navigation. - -## Non-Goals - -- Do not add offline support. -- Do not add a no-op service worker. -- Do not add runtime caching rules for app assets, API responses, uploaded files, generated PDFs, or routes. -- Do not change product UI, routing, auth, resume editing, public resume pages, or PDF generation behavior. -- Do not change normal browser or HTTP caching behavior owned by the browser or server. - -## Architecture - -Keep install metadata in `apps/web/public/manifest.webmanifest`. That static manifest remains the source of truth -for app name, description, theme color, background color, icons, screenshots, categories, scope, and start URL. - -Keep mobile install/open-as-app meta tags in `apps/web/src/libs/pwa.ts`. That module continues to own: - -- `pwaHeadMetaTags` -- app name and theme color used by those head meta tags - -Add the same manifest, icon, and mobile install hints directly to `apps/web/index.html` so install metadata is -present in the initial HTML without relying on `vite-plugin-pwa` HTML injection or client-side route head updates. - -Remove the service-worker part of the current architecture: - -- Remove `VitePWA` usage from `apps/web/vite.config.ts`. -- Remove the `vite-plugin-pwa` dependency from `apps/web/package.json` and the lockfile. -- Remove the now-unused `pwaManifest` and `pwaServiceWorkerRegistrationScript` exports from `apps/web/src/libs/pwa.ts`. -- Stop injecting the production `navigator.serviceWorker.register("/sw.js", { scope: "/" })` script from - `apps/web/src/routes/__root.tsx`. - -The root route keeps the existing manifest link: - -```tsx -{ rel: "manifest", href: "/manifest.webmanifest", crossOrigin: "use-credentials" } -``` - -The root route also keeps the PWA-related head meta tags, including `theme-color` and Apple mobile web app tags, -because those are part of the install/open-as-app experience rather than offline behavior. - -## Data Flow - -Browsers discover install metadata by reading the root document head and fetching `/manifest.webmanifest`. - -Manifest-linked assets continue to be served as static public assets from `apps/web/public`, including: - -- favicon assets -- PWA icons -- maskable icon -- Apple touch icon -- installation screenshots - -No service worker is emitted by the web build, no service worker is registered at runtime, and no Workbox -precache manifest is produced. - -## Error Handling - -There is no PWA-controlled offline fallback. - -When the network is unavailable, the app behaves like a normal website: navigations, API calls, uploaded assets, -and generated downloads fail according to the browser and server behavior already in place. This is intentional -because installability is the only remaining PWA goal. - -## Testing - -Remove `apps/web/src/libs/pwa.test.ts`. - -The file currently tests both install metadata and service-worker registration behavior. After this change, the -remaining PWA surface is static manifest/head metadata with no behavior-specific module contract worth preserving -as a dedicated unit test. - -Implementation should still verify by inspection and build output that: - -- `apps/web/dist/index.html` includes the manifest link and mobile install meta tags -- the root route keeps the manifest link -- PWA head meta tags remain present -- no service-worker registration script is exported or injected by the root route -- no `sw.js` or Workbox precache output is emitted by the web build - -Focused validation after implementation: - -```sh -pnpm --filter web typecheck -pnpm --filter web build -``` - -If the package dependency removal changes the lockfile, verify the lockfile remains scoped to removing -`vite-plugin-pwa` and its now-unused Workbox dependency graph. diff --git a/docs/superpowers/specs/2026-05-15-unsafe-oauth-redirect-uri-design.md b/docs/superpowers/specs/2026-05-15-unsafe-oauth-redirect-uri-design.md deleted file mode 100644 index 03b0323b6..000000000 --- a/docs/superpowers/specs/2026-05-15-unsafe-oauth-redirect-uri-design.md +++ /dev/null @@ -1,95 +0,0 @@ -# Unsafe OAuth Redirect URI Flag Design - -Date: 2026-05-15 - -## Goal - -Replace `OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS` with a single explicit escape hatch: -`FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI`. - -By default, dynamic OAuth client registration keeps the existing safe behavior: redirect URIs are allowed only when they target the app origin or local loopback callback hosts. When the flag is enabled, trusted self-hosted deployments may register any parseable redirect URI, including private network URLs, non-loopback `http://` URLs, and custom schemes such as `myapp://callback`. - -## Non-Goals - -- Do not change whether dynamic OAuth client registration is enabled. -- Do not change MCP OAuth audience handling, login, consent, token issuance, or public client registration defaults. -- Do not reuse `FLAG_ALLOW_UNSAFE_AI_BASE_URL`; OAuth redirect handling is a separate trust boundary. -- Do not keep a curated redirect-host allowlist after this change. - -## Architecture - -The existing redirect URI policy remains centralized in `@reactive-resume/utils/url-security.node`. - -Introduce a mode-based OAuth redirect validator API, for example: - -```ts -isAllowedOAuthRedirectUri(input, trustedOrigins, { allowUnsafe }) -``` - -Safe mode keeps the current rules: - -- Reject malformed URIs. -- Reject embedded credentials. -- Reject URI fragments. -- Allow `http://localhost`, `http://127.0.0.1`, and `http://[::1]` callbacks. -- Allow `https://` callbacks whose origin matches `APP_URL`. -- Reject other public HTTPS hosts, private HTTPS hosts, non-loopback HTTP hosts, and non-HTTP schemes. - -Unsafe mode deliberately weakens the redirect URI trust check: - -- Allow any URI accepted by the platform URL parser. -- Allow custom schemes such as `myapp://callback`. -- Allow private and loopback hosts on any supported URL scheme. -- Allow non-loopback `http://` URLs. - -Unsafe mode should still reject strings that are not parseable as URLs. It does not preserve the current credentials or fragment restrictions, because the requested behavior is absolute unsafe: any parseable URI scheme is accepted. - -## Data Flow - -`packages/env/src/server.ts` defines `FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI` as a `z.stringbool().default(false)` feature flag and removes `OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS`. - -`packages/auth/src/config.ts` uses the flag in the Better Auth `hooks.before` validation for `/oauth2/register`. - -`apps/server/src/http/auth.ts` uses the same flag in the server-level registration preflight before forwarding the request to Better Auth. - -Both validation paths must make the same allow or reject decision for the same redirect URI. The server preflight remains useful because it returns OAuth-shaped registration errors before the request enters Better Auth, while the Better Auth hook remains a defense-in-depth check. - -## Documentation - -Remove `OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS` from: - -- `packages/env/src/server.ts` -- `turbo.json` -- `.env.example` -- Docker and self-hosting docs -- Quickstart docs - -Add `FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI` to the feature flag sections and env examples with a warning that it is only appropriate for trusted self-hosted deployments. The warning should call out that enabling it permits arbitrary OAuth redirect URIs and can enable phishing or token exfiltration if used on public or multi-tenant instances. - -## Error Handling - -Rejected safe-mode redirects continue to return the existing error shape: - -- Better Auth hook: `BAD_REQUEST` with `redirect_uri is not allowed for dynamic client registration`. -- Server preflight: `400` with `invalid_redirect_uri`. - -Unsafe mode only returns those errors when the redirect URI cannot be parsed as a URL or a non-string entry is supplied in `redirect_uris`. - -## Testing - -Update focused tests in the relevant packages: - -- URL policy tests cover safe mode preserving current allowed and rejected cases. -- URL policy tests cover unsafe mode allowing custom schemes, private hosts, non-loopback `http://`, credentials, and fragments when the URI is parseable. -- Auth/server tests cover the env mock shape after removing `OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS`. -- Documentation and env references no longer mention the removed variable. - -Run focused validation after implementation: - -```sh -pnpm --filter @reactive-resume/utils test -- src/url-security.node.test.ts -pnpm --filter server test -- src/http/auth.test.ts -pnpm --filter @reactive-resume/auth typecheck -pnpm --filter server typecheck -pnpm exec turbo boundaries -``` diff --git a/docs/superpowers/specs/2026-05-19-agent-snapshot-rollback-design.md b/docs/superpowers/specs/2026-05-19-agent-snapshot-rollback-design.md deleted file mode 100644 index c4e6198f8..000000000 --- a/docs/superpowers/specs/2026-05-19-agent-snapshot-rollback-design.md +++ /dev/null @@ -1,29 +0,0 @@ -# Agent Snapshot Rollback Design - -## Context - -The AI Agent currently stores inverse JSON Patch operations for every applied resume patch. That lets the UI offer a revert action, but it rejects some valid JSON Patch operations because the server must be able to invert them before applying the patch. - -## Goal - -Use persisted resume snapshots for agent rollback so valid JSON Patch operations can be applied without first generating inverse operations. - -## Design - -Agent patch actions store the original JSON Patch operations for audit/debugging and a `snapshotData` copy of the resume data from immediately before the patch was applied. The database column is `snapshot_data`. - -When `apply_resume_patch` runs, the server reads the current working resume, stores `resume.data` as `snapshotData`, applies the model-generated JSON Patch through the existing resume patch validator, and records the resulting `appliedUpdatedAt`. - -The existing action revert endpoint becomes snapshot rollback. Rolling back an action restores that action's `snapshotData`, which means the resume returns to the state before that patch. If the selected action is older than the latest applied action, every applied patch action at or after the selected action is marked `rolled_back` so the chat remains auditable and the UI can show which actions were undone. - -Rollback keeps the version guard. The restore is allowed only when the current resume version still matches the latest applied patch action for that resume/thread. If the builder or another process changed the resume after the latest agent patch, rollback marks the selected action `conflicted` and does not replace the resume JSON. - -Existing rows that only have `inverse_operations` are legacy non-revertible actions after the migration. The migration removes `inverse_operations` and adds nullable `snapshot_data`. - -## UI - -The latest applied patch can be undone with the existing action button. Older applied patches can also be restored, but the label should make the destructive effect clear: rolling back to an older action discards that action and later applied agent patches. Actions with status `rolled_back` display as rolled back and cannot be rolled back again. - -## Testing - -Service tests cover storing `snapshotData`, restoring a snapshot, marking later applied actions as `rolled_back`, conflict handling, and rejecting legacy actions without `snapshotData`. Schema tests cover the `snapshotData` column replacing `inverseOperations`. diff --git a/docs/superpowers/specs/2026-05-26-custom-styles-header-targets-design.md b/docs/superpowers/specs/2026-05-26-custom-styles-header-targets-design.md deleted file mode 100644 index ea6fbc0e8..000000000 --- a/docs/superpowers/specs/2026-05-26-custom-styles-header-targets-design.md +++ /dev/null @@ -1,129 +0,0 @@ -# Custom Styles Header Targets Design - -## Context - -Reactive Resume now stores user-defined custom styling as structured style rules in `metadata.styleRules`. The current rule system targets semantic section content and rich-text slots, then resolves those rules in `packages/pdf` through the shared section-style context. - -The resume header is not currently part of that section-style context. Profile pictures, `basics.name`, `basics.headline`, and contact items are rendered directly inside each template header. That means users can style normal sections but cannot target the highest-visibility identity and contact content. - -## Goals - -- Make the profile picture targetable by Custom Styles. -- Make the resume title and subtitle targetable by Custom Styles. -- Make contact items targetable as a grouped v1 surface. -- Keep the feature inside the existing `metadata.styleRules` model. -- Preserve existing template header layouts and template-owned base styles. -- Keep contact styling grouped in v1 instead of targeting email, phone, location, website, or custom fields separately. - -## Non-Goals - -- Do not add per-contact-type targeting in v1. -- Do not expose picture source, upload, crop, or visibility settings through style rules. -- Do not redesign template headers or normalize every header into one layout. -- Do not add a second metadata object for header-specific custom styles. -- Do not make `sectionItem` targeting part of this work. - -## Approved Approach - -Extend the existing structured Style Rules system with a new header target and header-specific slots. - -Add a new target scope: - -- `header` - -Add header slots: - -- `picture` -- `title` -- `subtitle` -- `contactList` -- `contactItem` -- `contactText` -- `contactLink` -- `contactIcon` - -The header target applies only to the resume header/basic-info area. Global rules can also apply to matching header slots, which lets users define broad defaults such as "all contact text red." Header-targeted rules override global header-slot rules. - -## UI Behavior - -The Custom Styles panel should add `Header` to the target scope selector. - -Slot availability should depend on target scope: - -- `Header`: show only header slots. -- `Section type` and `Specific section`: show section and rich-text slots only. -- `All sections`: show all semantic slot groups, including the header group, because global rules apply anywhere the selected slot exists. - -Header labels should be user-facing and concrete: - -- `Picture` -- `Title` -- `Subtitle` -- `Contact list` -- `Contact item` -- `Contact text` -- `Contact link` -- `Contact icon` - -Applied rule labels should remain readable, for example `Header: Contact text` or `All sections: Contact text`. - -## Rendering Design - -Keep section rendering as-is with `SectionStyleProvider`. - -Add a header/basic-info resolver path next to the section-style path. The resolver should use the same style intent translation and safety constraints as section slots, but it should resolve against header context instead of section context. - -Template header elements should compose styles in this order: - -1. Template defaults. -2. Global rules for the selected header slot. -3. Header-targeted rules for the selected header slot. -4. Renderer safety styles where applicable. - -Each template keeps its current layout and structure. The integration only layers resolved custom styles onto existing elements: - -- `picture`: the profile `Image`. -- `title`: `basics.name`. -- `subtitle`: `basics.headline`. -- `contactList`: the contact list container. -- `contactItem`: each contact item wrapper or row. -- `contactText`: text inside contact items. -- `contactLink`: linked contact wrappers such as email, phone, website, and linked custom fields. -- `contactIcon`: icons inside contact items. - -Grouped contact styling means email, phone, location, website, and custom fields share the same contact slots. Templates with special wrapper structures, such as Rhyhorn separators, should keep those wrappers and apply the closest matching grouped slot. - -## Data Flow - -1. The web UI writes header rules into `resume.data.metadata.styleRules`. -2. The schema validates `header` targets and header slots. -3. PDF rendering resolves header slots through the shared style-rule resolver. -4. Template headers compose resolved styles with their existing styles. -5. Preview, export, and public PDF paths receive the behavior automatically because they all render from resume metadata. - -## Testing - -Add focused coverage in three layers: - -- Schema tests: - - Accept `header` targets. - - Accept header slots. - - Reject unsupported slots and unsupported raw layout properties. - - Preserve grouped contact style rules in `metadata.styleRules`. -- PDF resolver tests: - - Resolve global header-slot rules. - - Resolve header-targeted rules. - - Let header-targeted rules override global header-slot rules. - - Ignore disabled header rules. - - Keep section rules from applying to header slots. -- Web UI tests: - - `Header` appears as a target scope. - - Header target limits slot options to header slots. - - Header rules can be created, updated, toggled, displayed, managed, and deleted. - - Applied rules display readable labels such as `Header: Contact text`. - -Template rendering tests should focus on the common resolver/contact behavior and one or two representative templates rather than snapshotting every template header. The implementation still needs to wire the new slots into each template header. - -## Open Decisions - -No open decisions remain. Contact styling is grouped for v1, and the approved target model is a new `header` scope plus header-specific slots inside the existing `metadata.styleRules` system. diff --git a/docs/superpowers/specs/2026-06-19-e2e-tests-design.md b/docs/superpowers/specs/2026-06-19-e2e-tests-design.md deleted file mode 100644 index 11fc70616..000000000 --- a/docs/superpowers/specs/2026-06-19-e2e-tests-design.md +++ /dev/null @@ -1,262 +0,0 @@ -# E2E Tests Design - -## Context - -Reactive Resume is a pnpm/Turborepo monorepo with two deployable apps: - -- `apps/web`: TanStack Start / React / Vite user interface. -- `apps/server`: Hono / Node.js server that owns API, auth, MCP, static uploads, OpenAPI, and production web serving. - -The product is a resume builder. The highest-value browser journeys are: - -1. Create an account and authenticate. -2. Create a resume from the dashboard. -3. Open the builder and edit resume basics. -4. Persist builder edits through autosave. -5. Export and import structured resume JSON. -6. Enable public sharing and view the resume as an anonymous visitor. - -The repository currently has broad Vitest coverage but no Playwright or Cypress harness. GitHub Actions currently runs autofix/lint behavior on PRs and Docker image publishing on pushes/tags, but no PR-gated E2E workflow. - -Context7 was requested for current framework guidance, but the configured Context7 quota was exhausted in this environment. The implementation plan should re-check current Playwright docs when Context7 access is available. - -## Goals - -- Add a working Playwright E2E setup. -- Run E2E tests against the production build path, not only Vite dev mode. -- Use ephemeral accounts and data for each run. -- Cover deterministic core UX flows on every PR. -- Keep CI runtime and flake risk low enough for a default PR gate. -- Leave room to add PDF, DOCX, OAuth, passkey, 2FA, and AI flows later without bloating the initial gate. - -## Non-goals - -- Do not add PDF or DOCX download validation to the initial PR gate. -- Do not automate OAuth, passkeys, 2FA, or password reset in the first suite. -- Do not include AI Agent, AI import, or resume analysis flows in the first suite. -- Do not add a cross-browser matrix initially. -- Do not assert pixel-perfect PDF/canvas rendering. - -## Recommended approach - -Use a root-level Playwright harness that runs Chromium against a production build: - -1. CI installs dependencies and Playwright Chromium. -2. CI starts PostgreSQL. -3. CI sets test environment variables. -4. CI builds the app with `pnpm build`. -5. Playwright starts the production server with `pnpm start`. -6. E2E specs exercise browser flows against `APP_URL`. - -Use hybrid fixtures: - -- The auth smoke test registers and logs in through the browser UI. -- Non-auth specs create ephemeral users and authenticated browser state through test helpers. -- Resume setup can use helper APIs or direct database helpers when the setup itself is not the behavior under test. -- Each test uses unique data and cleans up its own ephemeral user. - -This keeps the suite close to user reality while avoiding repeated slow setup in every test. - -## File layout - -Add: - -- `playwright.config.ts` -- `tests/e2e/README.md` -- `tests/e2e/fixtures/test.ts` -- `tests/e2e/fixtures/auth.ts` -- `tests/e2e/fixtures/db.ts` -- `tests/e2e/fixtures/resume.ts` -- `tests/e2e/specs/auth.spec.ts` -- `tests/e2e/specs/resume-lifecycle.spec.ts` -- `tests/e2e/specs/json-export-import.spec.ts` -- `tests/e2e/specs/public-sharing.spec.ts` -- `.github/workflows/e2e.yml` - -Update: - -- root `package.json` scripts -- `turbo.json` tasks, if root scripts are routed through Turbo -- lockfile after adding Playwright -- contributing docs if a short root README is not enough - -## Playwright configuration - -The initial config should: - -- Use Chromium only. -- Read `baseURL` from `APP_URL`, defaulting to `http://localhost:3000`. -- Use traces, screenshots, and videos on failure. -- Use a local-friendly reporter plus a CI reporter/artifact format. -- Start `pnpm start` through `webServer`. -- Reuse an existing local server outside CI when possible. -- Prefer role, label, and accessible-name locators. -- Add targeted `data-testid` attributes only when accessibility locators are not stable enough. - -Recommended root scripts: - -- `test:e2e`: run Playwright. -- `test:e2e:ui`: run Playwright UI mode. -- `test:e2e:ci`: run Playwright with CI reporter settings. - -## Environment and infrastructure - -Minimum E2E environment: - -- `APP_URL=http://localhost:3000` -- `PORT=3000` -- `DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres` -- `AUTH_SECRET=` -- `FLAG_DISABLE_SIGNUPS=false` -- `FLAG_DISABLE_EMAIL_AUTH=false` -- `FLAG_DISABLE_API_RATE_LIMIT=true` -- `LOCAL_STORAGE_PATH=` - -S3, Redis, SMTP, and AI provider variables are not required for the initial deterministic suite. - -PostgreSQL should be isolated for CI runs. The simplest PR workflow can use a GitHub Actions Postgres service container and a clean database per job. Local development can use `compose.dev.yml` to start Postgres. - -## Ephemeral data strategy - -Each worker/test should generate unique identities: - -- Email: `e2e---@example.test` -- Username: `e2e___` -- Resume names/slugs prefixed with `e2e-` - -Cleanup should delete the ephemeral user and rely on database cascade relationships for related resumes, sessions, accounts, API keys, and related records. - -Use helper setup where it improves speed and stability: - -- Create authenticated storage state for non-auth specs. -- Create seeded resumes for tests that are about builder/export/sharing behavior rather than resume creation. -- Keep one browser-driven auth spec to ensure registration/login still works end to end. - -## Initial PR-gated specs - -### Auth smoke - -Flow: - -1. Visit `/auth/register`. -2. Register a unique user through the UI. -3. Continue to `/dashboard`. -4. Log out. -5. Log in with the same credentials. -6. Assert the dashboard resumes page loads. - -Purpose: - -- Proves email/password auth, session cookies, redirects, and dashboard access work. - -### Resume lifecycle - -Flow: - -1. Start authenticated as an ephemeral user. -2. Visit `/dashboard/resumes`. -3. Create a sample resume through the UI. -4. Open the resume in the builder. -5. Edit the basics name field. -6. Wait for autosave. -7. Reload the builder. -8. Assert the edited value persisted. - -Purpose: - -- Proves dashboard create, builder load, form editing, API update, and autosave persistence. - -### JSON export and import - -Flow: - -1. Start authenticated with a sample resume. -2. Open the builder. -3. Export JSON. -4. Assert a JSON download is created and parseable. -5. Return to dashboard. -6. Import the downloaded JSON through the import dialog. -7. Assert the imported resume opens in the builder. - -Purpose: - -- Proves deterministic backup/restore without AI or binary rendering dependencies. - -### Public sharing - -Flow: - -1. Start authenticated with a sample resume. -2. Open builder sharing settings. -3. Enable public access. -4. Read the generated public URL. -5. Open a fresh unauthenticated browser context. -6. Visit the public URL. -7. Assert the public resume viewer renders expected resume content. - -Purpose: - -- Proves sharing state updates, public routing, anonymous access, and public resume rendering. - -## CI workflow - -Add `.github/workflows/e2e.yml`: - -- Trigger on `pull_request` and pushes to `main`. -- Use Node 24. -- Use pnpm via Corepack or `pnpm/action-setup`. -- Cache pnpm dependencies through `actions/setup-node`. -- Start PostgreSQL service. -- Install dependencies with `pnpm install --frozen-lockfile`. -- Install Playwright Chromium. -- Run `pnpm build`. -- Run `pnpm test:e2e:ci`. -- Upload Playwright reports, traces, screenshots, and videos on failure. - -The workflow should avoid secrets. All test credentials should be generated during the run. - -## Selector strategy - -Prefer stable user-facing locators: - -- Roles: buttons, links, dialogs, textboxes, comboboxes. -- Labels: form inputs and switches. -- URLs: route assertions after navigation. - -Add `data-testid` only where necessary: - -- Builder canvas/PDF viewer surfaces that lack accessible names. -- Download/import controls if file input access is otherwise too implementation-dependent. -- Toast-independent save-state assertions if no visible stable status exists. - -Keep test IDs narrow and product-neutral. - -## Reliability considerations - -- Autosave currently debounces changes by 500ms. Tests should wait for persisted state through reload or API-visible state, not arbitrary sleeps. -- Public resume viewer uses browser PDF/canvas behavior. Assert meaningful content or viewer presence, not pixels. -- JSON export/import is deterministic and should be the first export/import loop. -- Disable API rate limiting in test env to avoid worker-order flakes. -- Pin locale to the default English path or use role/label selectors robust to translations where practical. -- Keep the initial suite serial only where shared worker state forces it; otherwise allow Playwright worker isolation. - -## Future expansion - -After the initial suite is stable: - -1. Add PDF download validation as a separate optional or nightly job. -2. Add DOCX download validation if the PDF job proves stable. -3. Add password-protected public sharing. -4. Add dashboard management flows: duplicate, lock, delete, tag filtering, list/grid view. -5. Add settings flows: profile update, API key creation/deletion. -6. Add AI flows only with mocked providers or a deterministic local provider. -7. Add browser matrix only after the Chromium gate has low flake rates. - -## Success criteria - -- `pnpm test:e2e` runs locally against a built app and Postgres. -- `pnpm test:e2e:ci` runs in GitHub Actions on every PR. -- Tests create no persistent shared seed data. -- Tests clean up ephemeral users and related data. -- The initial suite covers auth, dashboard creation, builder autosave, JSON export/import, and public sharing. -- CI uploads useful artifacts for diagnosing failures. diff --git a/docs/superpowers/specs/2026-07-05-applications-tracker-design.md b/docs/superpowers/specs/2026-07-05-applications-tracker-design.md deleted file mode 100644 index 490489c05..000000000 --- a/docs/superpowers/specs/2026-07-05-applications-tracker-design.md +++ /dev/null @@ -1,94 +0,0 @@ -# Applications Tracker — Roadmap & Status - -**Status legend:** ✅ done · 🟡 in progress · ⬜ not started · 🧊 deferred (intentional, revisit when needed) - -A job-application tracker built inside Reactive Resume. Each application points at the live -resume the user sent (`resumeId`), which is why it lives in-product rather than a generic -tracker. Built from the claude.ai/design prototype "Applications Tracker.dc.html". - -Owner dirs: `packages/db/src/schema/applications.ts`, `packages/schema/src/applications/`, -`packages/api/src/features/applications/`, `apps/web/src/features/applications/`, -`apps/web/src/routes/dashboard/applications/`. - ---- - -## Phase 0 — Core slice ✅ (shipped) - -The working vertical slice: data model, CRUD, board, add/detail panels. Zero new deps. - -- ✅ DB: `application` table (user FK cascade, `resumeId` FK set-null, JSONB `contacts`/`activity`, follow-up + AI-reservation columns). Migration `20260705090711_third_hercules`. -- ✅ Schema: `applicationStatusSchema`, `STAGES` (value/label/color), `contactSchema`, `activityEventSchema`, `aiMetadataSchema`. -- ✅ API: oRPC `applications.{list,getById,create,update,addNote,delete}` — `protectedProcedure`, `userId`-scoped via one `requireOwned`; `update` auto-logs stage-change activity. -- ✅ Web: sidebar nav item; `/dashboard/applications` route (empty state ↔ board). -- ✅ Board: dnd-kit drag across 6 fixed stages, optimistic move + rollback toast. -- ✅ Add slide-over: manual entry + link a live Reactive Resume; native date follow-up. -- ✅ Detail slide-over: key facts, stage stepper, linked resume, contacts, follow-up, activity timeline + add-note, archive/delete. -- ✅ Unit test: activity-logging path (`service.test.ts`). Typecheck / boundaries / biome clean. - -**Known small gaps — now closed (✅):** -- ✅ Lingui messages extracted (`pnpm --filter web lingui:extract`) so the new ``/`t` strings are translatable. -- ✅ Board caps rendered cards per column (`COLUMN_PAGE_SIZE = 50`) with a "Show N more" button, so a stage with hundreds of applications doesn't mount hundreds of draggable nodes. Server-side paging still unneeded (list payload is small). -- ✅ Contacts are editable from the Detail panel (`ContactsEditor`): add name/role/label, remove, persisted via API `update`'s existing `contacts` field. - ---- - -## Phase 1 — Table view + Insights ✅ (shipped) - -- ✅ **Table view** — paginated table (25/page), row selection + bulk actions (move stage, add tag, archive, delete). Added a wrapped `Checkbox` in `packages/ui`; hand-rolled table (no `@tanstack/react-table` dep). Board/Table/Insights toggle via URL `view` search param. -- ✅ **Insights view** — stat tiles, pipeline funnel (conversion per stage), source bars, and a shareable **funnel-flow SVG** with PNG export (canvas, no chart lib — kept the zero-dep property). Server aggregation `applications.stats` (per-stage/per-source counts); funnel/tiles derived client-side via `computeInsights()` (unit-tested). -- ✅ Tags: `tags text[]` column + filter UI + bulk "add tag" + `applications.tags` distinct list. -- ✅ Archived-toggle so archived rows can be reached and unarchived (closes the archive loop). - -## Phase 2 — Campaigns + import + uploads ✅ (shipped) - -- ✅ **Campaigns** — the `campaign` text field is now first-class: set on create (with a native `` autocomplete of existing campaigns), filter on board/table, per-campaign Insights scoping, and an `applications.campaigns` distinct-with-counts endpoint. (Kept it a text field, not a table — grouping/filtering/insights work without the join-table overhead.) -- ✅ **CSV import** — `Import CSV` opens a slide-over: paste rows or upload a `.csv`, a zero-dep parser (`csv.ts`, unit-tested) maps aliased headers (Company/Role/Stage/Salary/Source/Tags/…), previews recognized columns + ready/skipped counts, then bulk-creates via `applications.import` (max 500, each row gets a `created` activity event). Verified end-to-end in the browser. -- ✅ **Cover-letter upload** — `coverLetterUrl`/`coverLetterName` columns; the detail panel's Documents section attaches a PDF via the existing `orpc.storage.uploadFile`, shows a download link, and supports removal. - ---- - -## Phase 3 — AI agent integration ✅ (shipped, verified live) - -All four `applications.ai.*` procedures are implemented (`packages/api/src/features/applications/ai.ts`), resolving the user's default provider via `aiProvidersService.getDefaultRunnable` → `getModel` → `generateText`, with tolerant JSON parsing. Rate-limited via `aiRequestRateLimit`. - -- ✅ **Job-posting autofill** — paste a URL → server fetches + strips the page → LLM extracts company/role/location/salary/jobDescription → prefills the Add form. (`jobDescription` is now a user-editable field so it persists for match/tailor.) -- ✅ **Resume↔job match score** — scores the linked resume vs the job description, persists `matchScore` + gaps in `aiMetadata`. Rendered as a **fit ring** in the redesigned copilot. -- ✅ **Tailor resume** — one-shot: duplicates the linked resume, regenerates a job-tailored `summary`, links the copy to the application, logs a timeline event. (No agent/REDIS dependency.) -- ✅ **Draft cover letter / follow-up** — generates from application + resume context; shown inline with copy/dismiss. -- ✅ **UX**: the AI section was redesigned into an **"Application Copilot"** module — a resume-fit ring (band-colored) as the signature element + a capability menu (icon + title + description) instead of plain buttons. - -Verified live against a real OpenAI provider (autofill, match score, tailor resume). - -### Extra polish shipped alongside (from review + user requests) -- ✅ **Edit an application** — the Add sheet became `ApplicationFormSheet`, edit-capable; reachable from the detail-panel "Edit" button and the context menu. -- ✅ **Context menus** — kebab "⋯" on board cards (hover) and table rows: Edit / Move to ▸ / Archive / Delete (`application-actions-menu.tsx`). -- ✅ Review fixes: bulk stage-moves log activity; single-statement note append; "Mark rejected" + "no results" states; CSV BOM strip + 500-row cap + file-input reset. - -### ✅ Cover-letter upload (re-enabled) -Un-deferred. The blocker was `storage/service.ts` hardcoding a `.jpeg` key for every upload, so a PDF was read back as an image. Fixed by deriving the key extension from the content type the router already passes (`buildFileKey` + `EXTENSION_BY_CONTENT_TYPE`) — images stay `.jpeg` (unchanged for avatars), PDFs get `.pdf` and the static handler's existing `.pdf` force-download path serves them correctly. Re-added `coverLetterUrl`/`coverLetterName` columns (migration `20260705125353_yielding_star_brand`), DTO editable fields, and a Documents-section upload/download/remove in the detail sheet (PDF-only, best-effort `storage.deleteFile` on remove). Link-to-Reactive-Resume remains the primary document feature; the cover letter sits alongside it. - ---- - -## (historical) Phase 3 plan — reservations in place, no model wired yet - -Reservations already shipped: schema fields (`sourceUrl`, `jobDescription`, `matchScore`, -`aiMetadata`) and stubbed `applications.ai.*` procedures that throw `NOT_IMPLEMENTED` -(`packages/api/src/features/applications/ai.ts`). Each stub below just needs its handler -implemented against `@reactive-resume/ai` and the existing agent/thread tables -(`agentThread`, `agentAction` in `packages/db/src/schema/agent.ts`). - -- ⬜ **Job-posting autofill** (`applications.ai.autofill`) — fetch `sourceUrl` (or accept pasted text) → LLM extracts company/role/location/salary/jobDescription → return a prefill object for the Add form; persist raw extraction in `aiMetadata`. UI: enable the disabled "Auto-fill" button in `add-application-sheet.tsx`. -- ⬜ **Resume ↔ job match score** (`applications.ai.matchScore`) — compare the linked resume's data against `jobDescription` → write `matchScore` (0–100) + a gap list into `aiMetadata`. UI: surface a score badge on the card + a gaps section in the Detail panel. -- ⬜ **Tailor resume for this job** (`applications.ai.tailorResume`) — spawn an agent thread that duplicates the linked resume and edits it for the posting (reuse the agent JSON-patch pipeline); link the new `resumeId` back to the application and log a timeline event. -- ⬜ **Cover-letter / follow-up drafting** (`applications.ai.draftMessage`) — generate a cover letter or recruiter follow-up from application + resume + contact context. UI: the disabled "AI actions" block in `application-detail-sheet.tsx`. -- ⬜ **Rate-limiting & provider check** — reuse `aiRequestRateLimit` (already exists) and gate on a configured AI provider (`aiProviders` table) before calling any of the above. - -**Suggested order:** autofill (highest user value, self-contained) → match score → draft -message → tailor resume (most complex, depends on the agent pipeline). - ---- - -## Verification (each phase) -- `pnpm --filter @reactive-resume/api test` + `typecheck`, `pnpm --filter web typecheck`, `pnpm exec turbo boundaries`, `pnpm check`. -- DB changes: `dotenvx run -f .env.local -- pnpm db:generate` → review SQL → `pnpm db:migrate`. -- Manual: `dotenvx run -f .env.local -- pnpm dev` (:3000) → exercise the new surface end-to-end. diff --git a/docs/superpowers/specs/2026-07-07-applications-rest-mcp-parity-design.md b/docs/superpowers/specs/2026-07-07-applications-rest-mcp-parity-design.md deleted file mode 100644 index 901ed9bd9..000000000 --- a/docs/superpowers/specs/2026-07-07-applications-rest-mcp-parity-design.md +++ /dev/null @@ -1,215 +0,0 @@ -# Application Tracker REST and MCP Parity - -## Status - -Approved design for implementation planning. Campaign tracking is out of scope because the current app, database schema, changelog, guides, and tests do not ship a campaign field or campaign endpoint. - -## Goal - -Make every shipped Application Tracker capability available outside the web UI through: - -- the public REST/OpenAPI surface under `/api/openapi`; -- Reactive Resume MCP tools for agent-only workflows; -- the bundled `resume-builder` skill, so agents know the application tracker tools exist. - -The result should let a user track applications through an MCP client alone: create records, import existing rows, move stages, log notes, manage contacts and follow-ups, attach sent documents, run AI copilot actions, and inspect pipeline health. - -## Current Shipped Capabilities - -The current application tracker supports: - -- application records with company, role, location, salary, source, source URL, job description, notes, tags, status, archive state, linked resume, sent resume PDF, cover-letter PDF, contacts, follow-up date/note, applied date, and activity timeline; -- fixed stages: `saved`, `applied`, `screening`, `interview`, `offer`, `rejected`; -- create, edit, archive/unarchive, mark rejected, move stage, delete; -- board, table, search, sort, tag filter, archived toggle, and command-palette open/create shortcuts; -- bulk table actions: move stage, add tag, archive, delete; -- CSV import with header mapping and a 500-row cap; -- insights from aggregate stage/source counts plus client-derived weekly application velocity; -- timeline notes and automatic created/stage activity entries; -- contacts embedded on each application; -- Application Copilot actions: job-posting autofill, resume match score, tailored resume copy, cover-letter draft, follow-up draft; -- PDF upload/remove for resume file and cover letter through the generic storage route. - -## Existing API Coverage - -The app already routes most behavior through `packages/api/src/features/applications`: - -- `list`, `getById`, `create`, `import`, `update`, `addNote`, `delete`; -- `bulkUpdate`, `bulkDelete`, `stats`, `tags`; -- `ai.autofill`, `ai.matchScore`, `ai.draftMessage`, `ai.tailorResume`. - -These procedures are already authenticated and user-scoped through `protectedProcedure` and `applicationService`. The implementation should reuse them instead of adding a parallel controller or new business layer. - -## REST Design - -Keep the existing application procedures and improve parity with the public OpenAPI surface. - -### Public Application Endpoints - -Existing endpoints remain: - -- `GET /applications` -- `GET /applications/{id}` -- `POST /applications` -- `POST /applications/import` -- `PUT /applications/{id}` -- `POST /applications/{id}/notes` -- `DELETE /applications/{id}` -- `POST /applications/bulk-update` -- `POST /applications/bulk-delete` -- `GET /applications/stats` -- `GET /applications/tags` -- `POST /applications/ai/autofill` -- `POST /applications/{id}/ai/match-score` -- `POST /applications/{id}/ai/draft-message` -- `POST /applications/{id}/ai/tailor-resume` - -Add public document endpoints under the Applications tag: - -- `POST /applications/{id}/documents/{kind}` where `kind` is `resume` or `cover-letter`. - - Accept a PDF file via OpenAPI file upload. - - Store through the existing storage service. - - Update only the matching application fields: - - resume: `resumeFileUrl`, `resumeFileName`; - - cover letter: `coverLetterUrl`, `coverLetterName`. - - Return the updated application. -- `DELETE /applications/{id}/documents/{kind}`. - - Delete the owned storage object best-effort. - - Clear only the matching application fields. - - Return the updated application. - -This makes the document upload/remove UI available through public REST without exposing the generic storage route, which remains tagged `Internal` because it also serves profile-picture use cases. - -### REST Behavior Details - -- Use existing ownership checks: every application mutation must be scoped by `userId`. -- Reject non-PDF document uploads, matching the UI. -- Keep file size at the existing storage limit: 10MB. -- Preserve existing delete cleanup for uploaded documents when an application is deleted. -- Do not add server-side search/sort endpoints for board/table parity. The UI derives search and sort from `list`, and external clients can do the same. `list` already exposes status, tags, and archive filtering. -- Do not add campaign fields or endpoints. -- Regenerate or update `docs/spec.json` so the public API reference includes all application endpoints. - -## MCP Design - -Add application tools to `packages/mcp` using the existing metadata pattern: - -- add names to `MCP_TOOL_NAME`; -- add schemas/descriptions to `TOOL_META`; -- add behavior hints to `TOOL_ANNOTATIONS`; -- register handlers in `registerTools`; -- let `buildMcpServerCard` derive tool entries from `TOOL_META`; -- add focused tests so tool registration, annotations, and server card stay synchronized. - -All MCP handlers should call the injected in-process oRPC `RouterClient`. They should not import database code or reimplement ownership checks. - -### MCP Tools - -Read/discovery: - -- `list_applications`: list applications, with optional `status`, `tags`, and `includeArchived`. -- `read_application`: read one full application by ID. -- `list_application_tags`: list distinct tags. -- `get_application_stats`: return aggregate stage/source counts. - -Write: - -- `create_application`: create an application. -- `update_application`: update editable fields, including stage, archive state, contacts, follow-up, tags, linked resume, source URL, job description, notes, and document URLs. -- `add_application_note`: append a timeline note. -- `delete_application`: permanently delete one application. -- `bulk_update_applications`: move, archive/unarchive, or add tags to multiple applications. -- `bulk_delete_applications`: permanently delete multiple applications. -- `import_applications`: bulk-create parsed application rows, matching the REST `import` shape. -- `attach_application_document`: attach a sent resume or cover letter PDF. -- `remove_application_document`: remove a sent resume or cover letter PDF. - -AI: - -- `autofill_application_from_job`: extract company, role, location, salary, and job description from a job posting URL or pasted job description. -- `score_application_match`: score the linked resume against the job description and persist match metadata. -- `tailor_resume_for_application`: create and link a tailored resume copy. -- `draft_application_message`: draft either a cover letter or follow-up message. - -### MCP Attachment Input - -`attach_application_document` should support agent-only use. The tool should accept: - -- `id`; -- `kind`: `resume` or `cover-letter`; -- `fileName`; -- `contentType`: `application/pdf`; -- `dataBase64`: PDF bytes encoded as base64. - -The handler can decode the base64 and call the same shared application-document service used by the public REST file upload. This avoids forcing MCP clients to provide browser `File` objects while still giving agents the same document capability as the UI. - -### MCP Output Shape - -Prefer JSON text outputs for data-bearing tools. Human-readable success strings are fine for destructive/simple tools only when no structured data is useful. For create/update/read/list/stats/AI tools, return JSON so agents can chain calls reliably. - -### Tool Annotations - -- Read tools: read-only, idempotent, non-destructive. -- AI generation tools: - - `autofill_application_from_job` is read-only but non-idempotent if it fetches a URL or calls AI. - - `draft_application_message` is read-only but non-idempotent. - - `score_application_match` and `tailor_resume_for_application` are write, non-idempotent. -- Delete tools are destructive. -- `update_application`, `bulk_update_applications`, and document remove are write/idempotent when the same input repeats, except tag append remains effectively idempotent because the service de-duplicates tags. -- `create_application`, `import_applications`, note append, and document attach are write/non-idempotent. -- `openWorldHint` should be `false` for closed account data tools and `true` only for job-posting autofill because it can fetch an external URL. - -## Skill Update - -Update `skills/resume-builder/SKILL.md` in place. - -Add concise guidance that Reactive Resume MCP can manage applications as well as resumes. The skill should tell agents: - -- use application tools when the user wants to track job applications, import a spreadsheet, move an opportunity through stages, add notes/contacts/follow-ups, attach sent documents, or use Application Copilot; -- use `list_applications` before acting on existing records; -- use `create_application` or `import_applications` for new records; -- use `tailor_resume_for_application` after a linked resume and job description exist; -- review AI-generated cover letters and follow-ups before sending. - -Do not turn the skill into a full API reference. Keep it short and point agents at MCP tools by name. - -## Documentation Updates - -Update: - -- `docs/guides/using-the-mcp-server.mdx`: add Application Tracker tools, examples, and troubleshooting notes. -- `docs/use-cases/api-mcp-resume-automation.mdx`: expand scope from resume-only automation to resume plus application tracking. -- `docs/spec.json`: refresh the public OpenAPI spec so docs show application routes. - -The existing job application and CSV guides already describe the UI behavior accurately and should not need broad rewrites. - -## Testing Plan - -Focused tests: - -- API/service tests for attaching/removing resume and cover-letter documents, including ownership and storage cleanup. -- DTO/router tests for application document upload constraints if the route logic is not already covered through service tests. -- MCP tests that: - - every `MCP_TOOL_NAME` has metadata and annotations; - - server card includes the new tools; - - `registerTools` registers application tools; - - one read handler and one write handler call the expected oRPC client procedure; - - base64 document attachment rejects non-PDF input. - -Validation commands: - -- `pnpm --filter @reactive-resume/api test` -- `pnpm --filter @reactive-resume/mcp test` -- `pnpm --filter @reactive-resume/api typecheck` -- `pnpm --filter @reactive-resume/mcp typecheck` -- `pnpm exec turbo boundaries` -- a focused Biome check on touched files; use a non-mutating check first unless formatting edits are intentionally being applied. - -## Non-Goals - -- Custom stages. -- Campaign tracking. -- Server-side board/search/sort endpoints. -- A standalone application schema resource in MCP. -- New dependencies. -- Refactoring the application tracker UI. diff --git a/docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md b/docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md deleted file mode 100644 index d046dc05c..000000000 --- a/docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md +++ /dev/null @@ -1,323 +0,0 @@ -# Monorepo Architecture Reorg Worklog - -Append-only log for implementation, validation, and delegation notes. - -> **Status note:** This file is chronological. Earlier entries may mention paths that were moved by later tasks. Use the latest handoff plus `AGENTS.md` and `docs/contributing/architecture.mdx` for current-state guidance. - -## 2026-05-14 - -- Started implementation on branch `feat/explore-hono-orpc-migration`. -- Initial dirty files existed before architecture implementation: - - `apps/server/package.json` - - `package.json` - - `packages/api/package.json` - - `packages/env/package.json` - - `packages/utils/package.json` - - `pnpm-lock.yaml` -- Created coordination artifacts: - - `docs/superpowers/plans/2026-05-14-monorepo-architecture-reorg.md` - - `docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md` - - `docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md` -- Task 1 completed: - - Created `packages/resume` as `@reactive-resume/resume`. - - Moved `packages/utils/src/resume/patch.ts` to `packages/resume/src/patch.ts`. - - Moved `packages/utils/src/network-icons.ts` to `packages/resume/src/icons.ts`. - - Moved the patch and network icon tests into `packages/resume/src`. - - Updated all old `@reactive-resume/utils/resume/patch` and `@reactive-resume/utils/network-icons` imports to `@reactive-resume/resume/patch` and `@reactive-resume/resume/icons`. - - Updated package manifests and `pnpm-lock.yaml` for the new package and consumer dependency edges. - - Removed `fast-json-patch` from `@reactive-resume/utils` and `@reactive-resume/ai`; it now belongs to `@reactive-resume/resume`. - - Did not remove `@reactive-resume/schema` from `@reactive-resume/utils` because DOCX files still import schema and Task 2 owns that extraction. -- Validation for Task 1: - - Initial `pnpm --filter @reactive-resume/resume test` failed before Vitest because pnpm wanted to refresh modules in a non-TTY. - - Retried with `CI=true`; it failed because the new workspace package was not yet represented in the frozen lockfile. - - Ran `pnpm install --lockfile-only --no-frozen-lockfile`; completed with no downloads. - - A later test run triggered pnpm dependency status install, but `node_modules` had been purged and registry access was blocked by sandbox DNS (`ENOTFOUND` / `fetch failed`). - - Ran `pnpm install --no-frozen-lockfile` with network approval to restore `node_modules`; completed. - - `pnpm --filter @reactive-resume/resume test` passed: 2 files, 43 tests. - - `pnpm --filter @reactive-resume/resume typecheck` passed. - - `pnpm --filter @reactive-resume/ai typecheck` passed. - - `pnpm --filter @reactive-resume/api typecheck` passed. - - `pnpm --filter web typecheck` passed. - - Additional direct-consumer checks passed: `pnpm --filter @reactive-resume/db typecheck`, `pnpm --filter @reactive-resume/import typecheck`, and `pnpm --filter @reactive-resume/utils typecheck`. - - Focused `pnpm exec biome check ...` initially found import-order/type-import issues; `pnpm exec biome check --write ...` fixed 10 touched files. - - Focused `pnpm exec biome check ...` passed afterward on the touched package/source/manifests. -- Task 1 review correction: - - Spec review found `packages/db` had a type-only manifest dependency on `@reactive-resume/resume`. - - Replaced the DB import with a local structural `StoredJsonPatchOperation` type for JSONB column annotations in `packages/db/src/schema/agent.ts`. - - Removed `@reactive-resume/resume` from `packages/db/package.json` and `pnpm-lock.yaml`. -- Task 1 review validation: - - `pnpm --filter @reactive-resume/db typecheck` passed after the DB boundary correction. - - `pnpm --filter @reactive-resume/api typecheck` passed. - - `pnpm --filter web typecheck` passed. - - `pnpm --filter @reactive-resume/resume test` passed: 2 files, 43 tests. - - `pnpm --filter @reactive-resume/resume typecheck` passed. - - Code-quality review noted unrelated dependency bumps in package manifests; those files were already dirty before this architecture work and were not treated as part of Task 1. -- Task 2 completed: - - Created `packages/docx` as `@reactive-resume/docx` with source-consumed root export. - - Moved DOCX implementation/tests from `packages/utils/src/resume/docx` into `packages/docx/src`. - - Updated web DOCX callers to import `buildDocx` from `@reactive-resume/docx`. - - Removed the old `@reactive-resume/utils/resume/docx` export. - - Removed `docx` and `@reactive-resume/schema` from `@reactive-resume/utils`. - - Added `@reactive-resume/docx` as a web dependency. -- Task 2 validation: - - `pnpm --filter @reactive-resume/docx test` passed: 5 files, 46 tests. - - `pnpm --filter @reactive-resume/docx typecheck` passed. - - `pnpm --filter @reactive-resume/utils typecheck` passed. - - `pnpm --filter web typecheck` passed. - - Spec review found only stale coordination text; plan and handoff were corrected. -- Task 2 completed: - - Created `packages/docx` as `@reactive-resume/docx` with source-consumed root export `"." -> "./src/index.ts"`. - - Moved `packages/utils/src/resume/docx/*` to `packages/docx/src/*`, keeping the implementation and tests colocated. - - Updated builder DOCX export callers and the export-section test mock from `@reactive-resume/utils/resume/docx` to `@reactive-resume/docx`. - - Removed the old `@reactive-resume/utils` `./resume/docx` export. - - Removed `docx` and `@reactive-resume/schema` from `@reactive-resume/utils`; the new DOCX package owns those dependencies and depends on `@reactive-resume/utils` only for shared color parsing. - - Added `@reactive-resume/docx` as a web dependency and refreshed `pnpm-lock.yaml`. -- Validation for Task 2: - - Initial `pnpm --filter @reactive-resume/docx test` failed on pnpm's non-TTY dependency-status install guard. - - `CI=true pnpm --filter @reactive-resume/docx test` then failed because sandbox DNS blocked registry fetches while pnpm recreated `node_modules`. - - Retried `CI=true pnpm --filter @reactive-resume/docx test` with network approval; passed: 5 files, 46 tests. - - `pnpm --filter @reactive-resume/docx typecheck` passed. - - `pnpm --filter @reactive-resume/utils typecheck` passed. - - `pnpm --filter web typecheck` passed. - - `pnpm --filter web test -- 'src/routes/builder/$resumeId/-sidebar/right/sections/export.test.tsx'` passed; Vitest reported 78 files and 430 tests. - - Focused `pnpm exec biome check --write ...` passed on the moved DOCX package, touched web callers, and package manifests; no fixes were applied. -- Task 3 in progress: - - Added `packages/pdf/src/browser.tsx` with `createResumePdfBlob({ data, template, resolveSectionTitle })`. - - Added `packages/pdf/src/server.tsx` with `createResumePdfFile({ data, filename, template, resolveSectionTitle })`. - - Added `@reactive-resume/pdf/browser` and `@reactive-resume/pdf/server` package exports. - - Kept Lingui locale loading in `apps/web/src/libs/resume/pdf-document.tsx`; the web wrapper now resolves localized section titles and delegates blob generation to `@reactive-resume/pdf/browser`. - - Updated `apps/web/src/libs/resume/pdf-document.server.tsx` to delegate file generation to `@reactive-resume/pdf/server` after resolving localized section titles. - - Updated `apps/web/src/components/resume/preview.browser.tsx` so the PDF.js canvas viewer remains in web but PDF blob generation goes through the web-local wrapper. - - Updated `apps/server/src/handlers/resume-pdf.tsx` to reuse `@reactive-resume/pdf/server` and preserve the existing `File` response body flow. - - Added package helper tests for browser/server generation adapters. -- Task 3 validation so far: - - Red test: `pnpm --filter @reactive-resume/pdf test -- src/browser.test.tsx src/server.test.tsx` failed because `packages/pdf/src/browser.tsx` and `packages/pdf/src/server.tsx` did not exist. - - Interim implementation test exposed Vitest/Rolldown JSX transform limits for newly imported package TSX helpers; helpers now use `createElement` while keeping requested `.tsx` filenames. - - `pnpm --filter @reactive-resume/pdf test -- src/browser.test.tsx src/server.test.tsx` passed; Vitest reported 17 files and 139 tests. - - Initial focused web preview test failed because the test still mocked the old `useLocalizedResumeDocument` generation path. - - Updated `apps/web/src/components/resume/preview.browser.test.tsx` to mock/assert `createResumePdfBlob`. - - `pnpm --filter web test -- src/components/resume/preview.browser.test.tsx` passed; Vitest reported 78 files and 430 tests. - - `pnpm --filter web test -- 'src/routes/builder/$resumeId/-sidebar/right/sections/export.test.tsx' 'src/routes/$username/-components/public-resume.test.tsx' 'src/routes/$username/-components/pdf-viewer.test.tsx'` passed; Vitest reported 78 files and 430 tests. -- Task 4 completed: - - Created `packages/mcp` as `@reactive-resume/mcp` with source-consumed exports for the compact public surface and direct server-card/tool/prompt/resource subpaths. - - Moved MCP helper implementation and tests from `apps/web/src/routes/mcp/-helpers` into `packages/mcp/src`, then removed the empty web MCP helper route directory. - - Updated `apps/server/src/handlers/mcp.ts` and `apps/server/src/handlers/metadata.ts` to import from `@reactive-resume/mcp`, removing the app-to-app source imports from `apps/server` into `apps/web`. - - Preserved in-process MCP execution through the injected oRPC `RouterClient`; no HTTP RPC calls were introduced inside the server process. - - Renamed MCP tool values to canonical unprefixed snake_case names: `list_resumes`, `list_resume_tags`, `read_resume`, `get_resume_analysis`, `create_resume`, `import_resume`, `duplicate_resume`, `apply_resume_patch`, `update_resume`, `delete_resume`, `lock_resume`, `unlock_resume`, and `get_resume_statistics`. - - Updated prompts, server instructions, server-card metadata, and tests to use the canonical names and removed `reactive_resume_*` aliases/instructions. - - Added `packages/ai/src/tools/resume-tool-contracts.ts` with the shared JSON Patch operations contract and reused it from `packages/ai/src/tools/patch-resume.ts` and MCP patch schemas. - - Updated package manifests and `pnpm-lock.yaml`; `web` no longer owns `@modelcontextprotocol/sdk`, and `server` now depends on `@reactive-resume/mcp`. -- Validation for Task 4: - - Initial `pnpm --filter @reactive-resume/mcp test` reported no matching package before creation. - - After package creation, `pnpm --filter @reactive-resume/mcp test` hit pnpm's non-TTY dependency-status install guard. - - `CI=true pnpm --filter @reactive-resume/mcp test` then failed with a frozen-lockfile mismatch after moving dependencies. - - Ran `pnpm install --lockfile-only --no-frozen-lockfile`; completed. - - A later `CI=true pnpm --filter @reactive-resume/mcp test` failed because sandbox DNS blocked registry fetches while pnpm restored `node_modules`. - - Retried `CI=true pnpm --filter @reactive-resume/mcp test` with network approval; passed: 4 files, 29 tests. - - `pnpm --filter @reactive-resume/mcp typecheck` initially failed because the package type graph reaches API/auth TSX and tests had optional text access; fixed by enabling JSX in the package tsconfig and narrowing test content access. - - Final validation commands passed: `pnpm --filter @reactive-resume/mcp test`, `pnpm --filter @reactive-resume/mcp typecheck`, `pnpm --filter server typecheck`, `pnpm --filter @reactive-resume/ai typecheck`, focused `pnpm exec biome check ...`, and `rg -n "\\.\\./\\.\\./\\.\\./web/src|apps/web/src|web/src/routes/mcp" apps/server/src packages/mcp/src`. - - Initial final validation found `pnpm exec biome check ...` import/format issues in touched PDF/web files and type errors around the React element type passed into `pdf(...)` and `renderToBuffer(...)`. - - Added narrow render-boundary casts using `Parameters[0]` and `Parameters[0]`. - - Ran `pnpm exec biome check --write ...`; Biome fixed 4 touched files. - - `pnpm --filter @reactive-resume/pdf test` passed: 17 files, 139 tests. - - `pnpm --filter @reactive-resume/pdf typecheck` passed. - - `pnpm --filter web typecheck` passed. - - `pnpm --filter server typecheck` passed. - - `pnpm exec biome check packages/pdf/src/browser.tsx packages/pdf/src/server.tsx packages/pdf/src/browser.test.tsx packages/pdf/src/server.test.tsx packages/pdf/package.json apps/web/src/libs/resume/pdf-document.tsx apps/web/src/libs/resume/pdf-document.server.tsx apps/web/src/components/resume/preview.browser.tsx apps/web/src/components/resume/preview.browser.test.tsx apps/server/src/handlers/resume-pdf.tsx docs/superpowers/plans/2026-05-14-monorepo-architecture-reorg.md docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md` passed. - - `pnpm --filter web test -- src/components/resume/preview.browser.test.tsx` passed; Vitest reported 78 files and 430 tests. - - `pnpm --filter web test -- 'src/routes/builder/$resumeId/-sidebar/right/sections/export.test.tsx' 'src/routes/$username/-components/public-resume.test.tsx' 'src/routes/$username/-components/pdf-viewer.test.tsx'` passed; Vitest reported 78 files and 430 tests. -- Task 4 review correction: - - Spec review found stale MCP guide references to removed prefixed tool names and the unavailable `tailor_resume` prompt. - - Updated `docs/guides/using-the-mcp-server.mdx` to document canonical tool names such as `list_resumes`, `read_resume`, and `apply_resume_patch`, and removed `tailor_resume`. - - Removed the last code-side literal reference to the old prefixed tool-name family from `packages/mcp/src/tool-annotations.test.ts`. - - Re-ran `rg "reactive_resume_|tailor_resume|web/src/routes/mcp|apps/web/src|\\.\\./\\.\\./\\.\\./web" apps/server packages/mcp packages/ai/src docs/guides/using-the-mcp-server.mdx -n`; no matches. - - Re-ran `pnpm --filter @reactive-resume/mcp test`, `pnpm --filter @reactive-resume/mcp typecheck`, `pnpm --filter server typecheck`, `pnpm --filter @reactive-resume/ai typecheck`, and focused `pnpm exec biome check ...`; all passed. -- Task 5 review correction: - - Spec review found stale root project guidance that still pointed API work at `packages/api/src/routers/*` and `packages/api/src/services/*`. - - Updated `AGENTS.md` so the normative guidance now points API work at `packages/api/src/features/*` and documents the new `resume`, `docx`, `pdf`, and `mcp` package ownership boundaries. - - Re-ran `pnpm --filter @reactive-resume/api test`: 19 files, 155 tests passed. - - Re-ran `pnpm --filter @reactive-resume/api typecheck`, `pnpm --filter server typecheck`, and `pnpm --filter web typecheck`; all passed. - - Re-ran focused `pnpm exec biome check ...` on `AGENTS.md`, API/server/web touchpoints, and coordination docs; passed. -- Task 7 slice 1 review correction: - - Spec review found the moved public resume route missing its expected `ssr: "data-only"` setting and the builder preview route missing `ssr: false`. - - Restored `ssr: "data-only"` in `apps/web/src/routes/$username/$slug.tsx`. - - Restored `ssr: false` in `apps/web/src/routes/builder/$resumeId/index.tsx`. - - Updated `AGENTS.md` and the handoff notes to point browser-only resume preview/public viewer code at `apps/web/src/features/resume/*` instead of the removed `components/resume` and `libs/resume` paths. -- Task 5 completed: - - Moved API routers and service/helpers from the old technical-layer folders into `packages/api/src/features/*`. - - Agent is now feature-owned under `features/agent`, with procedure modules for `threads`, `messages`, `attachments`, and `actions`, run-state in `runs`, tool construction in `tools`, and remaining shared runtime orchestration in `service.ts`. - - Finer-grained follow-up: `features/agent/service.ts` still contains shared thread/message/action orchestration because the run lifecycle, message persistence, attachment linking, and patch transaction helpers are tightly coupled; splitting that service body further should be a dedicated follow-up with behavior-specific tests. - - Resume is now feature-owned under `features/resume`, with procedure modules for `crud`, `tags`, `statistics`, `analysis`, `event-router`, `sharing`, and `export`; access helpers and event publication moved under the same feature. - - Finer-grained follow-up: `features/resume/service.ts` remains the DB-backed facade for shared transaction helpers, update notifications, access/statistics coupling, and storage cleanup. The public procedure surface is capability-split, and further DB-service extraction should preserve the existing transaction and event behavior. - - Moved the authenticated PDF download procedure from `apps/server/src/handlers/resume-pdf.tsx` into `packages/api/src/features/resume/export.ts`; it now calls `@reactive-resume/pdf/server`. - - Removed the old API package `./services/*` and `./helpers/*` wildcard exports. - - Added explicit API runtime/type exports for `./features/storage`, `./features/resume`, `./features/resume/export`, and `./features/flags`. - - Updated `apps/server` to import storage/PDF runtime surfaces from explicit API feature exports. - - Updated `apps/web` to keep API imports type-only, including the `FeatureFlags` type from `@reactive-resume/api/features/flags`. - - Added `@reactive-resume/pdf` as an API package dependency and refreshed `pnpm-lock.yaml`. -- Validation for Task 5: - - Initial `pnpm --filter @reactive-resume/api typecheck` failed because pnpm attempted a non-TTY dependency-status install after package metadata changes. - - Retried with `CI=true`; sandbox DNS blocked registry fetches while rebuilding `node_modules`. - - Retried `CI=true pnpm --filter @reactive-resume/api typecheck` with network approval; dependency restoration completed and the first compiler pass found moved import paths that needed correction. - - `pnpm --filter @reactive-resume/api test` initially failed because the moved agent service test mocked the new `./service` module instead of its relocated AI/resume dependencies; fixed the mocks. - - Final focused validations passed: `pnpm --filter @reactive-resume/api test`, `pnpm --filter @reactive-resume/api typecheck`, `pnpm --filter server typecheck`, `pnpm --filter web typecheck`, and `pnpm --filter @reactive-resume/mcp typecheck`. - - Focused Biome check initially reported import-order/format issues; `pnpm exec biome check --write ...` fixed 7 touched API files. - - Re-ran focused Biome check after the write pass; it passed. - - Repo scans passed for no remaining `@reactive-resume/api/services/*` or `@reactive-resume/api/helpers/*` imports outside `packages/api`, no internal `../services` or `../helpers` imports, and no `./services/*` or `./helpers/*` wildcard exports in `packages/api/package.json`. -- Task 6 completed: - - Reorganized `apps/server/src` into runtime adapter areas: `http`, `rpc`, `mcp`, `openapi`, `static`, and `startup`. - - Moved route registration into `apps/server/src/http/app.ts` and kept `apps/server/src/index.ts` as the process entrypoint that runs startup checks and starts Hono. - - Moved common response/cookie helpers to `http/headers.ts`, auth and health HTTP handlers to `http`, oRPC request handling and locale extraction to `rpc`, MCP auth/server setup/transport handling to `mcp`, OpenAPI and well-known metadata to `openapi`, uploads/schema/web-dist serving to `static`, and migrations/local-storage lifecycle checks to `startup`. - - Kept the public route order and paths from the previous `index.ts`, including serving `apps/web/dist`. - - Preserved explicit API runtime imports only: `@reactive-resume/api/routers`, `@reactive-resume/api/features/storage`, and `@reactive-resume/api/features/resume/export`. -- Validation for Task 6: - - Baseline before moving files: `pnpm --filter server test` passed: 1 file, 1 test. - - Interim validation after moving files: `pnpm --filter server typecheck` passed. - - Interim validation after moving files: `pnpm --filter server test` passed: 1 file, 1 test. - - Final `pnpm --filter server test` passed: 1 file, 1 test. - - Final `pnpm --filter server typecheck` passed. - - Final `pnpm --filter @reactive-resume/api typecheck` passed. - - Focused `pnpm exec biome check apps/server/src docs/superpowers/plans/2026-05-14-monorepo-architecture-reorg.md docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md` initially found import-order issues in `apps/server/src/http/app.ts` and `apps/server/src/mcp/handler.ts`; after manual import ordering fixes, the same command passed. - - `rg -n "apps/web/src|from ['\"][^'\"]*web/src|@reactive-resume/api/services/" apps/server/src` returned no matches. - - `rg -n "@reactive-resume/api/services/" apps/server packages/api apps/web packages` returned no matches. - - `rg -n "from ['\"][^'\"]*apps/web/src|from ['\"][^'\"]*web/src|apps/web/src" apps/server` returned no matches. -- Task 7 slice 1 completed: - - Moved `apps/web/src/components/resume/builder-resume-draft.ts` to `apps/web/src/features/resume/builder/draft.ts` and updated builder/dialog consumers to import the feature-owned draft store directly. - - Moved builder preview files and colocated tests from `apps/web/src/components/resume` to `apps/web/src/features/resume/preview`, including `preview.tsx`, `preview.browser.tsx`, `preview.shared.tsx`, `pdf-canvas.tsx`, and preview shared tests. - - Moved dashboard resume thumbnail sizing helpers to `features/resume/preview/resume-thumbnail.shared.ts` and moved PDF.js thumbnail rendering into `features/resume/preview/pdf-thumbnail.ts`, so direct `pdfjs-dist` usage stays under `features/resume`. - - Moved web-local PDF document wrappers from `apps/web/src/libs/resume/pdf-document*.tsx` to `apps/web/src/features/resume/export/pdf-document*.tsx`; the wrappers still resolve localized section titles in web and call `@reactive-resume/pdf/browser` or `@reactive-resume/pdf/server`. - - Moved public resume route components and tests from `apps/web/src/routes/$username/-components` to `apps/web/src/features/resume/public`, including `public-resume.tsx`, `pdf-viewer.tsx`, `pdf-viewer.css`, and their tests. - - Updated the public resume route to lazy-load `features/resume/public/public-resume` while preserving its loader, redirects, metadata, and route settings. - - Removed the now-empty `apps/web/src/components/resume` and `apps/web/src/routes/$username/-components` directories. - - Broader Task 7 remains open for command palette, theme, locale, user, auth, settings, and Task 8 dialog-registry work. -- Task 7 slice 2 completed: - - Moved command palette implementation/tests to `apps/web/src/features/command-palette`. - - Moved theme provider, combobox, toggle button, and tests to `apps/web/src/features/theme`. - - Moved locale combobox implementation/tests to `apps/web/src/features/locale`. - - Moved user dropdown implementation to `apps/web/src/features/user`. - - Moved auth layout, page UI, and social auth component into `apps/web/src/features/auth`; auth route files now keep route guards/search validation and compose feature pages. - - Moved settings page UI and authentication/integration subcomponents into `apps/web/src/features/settings`; settings route files now keep dashboard headers and compose feature pages. - - Left `apps/web/src/routes/dashboard/settings/job-search.tsx` route-only because it is already a redirect shim. - - `pnpm --filter web test -- src/features/command-palette src/features/theme src/features/locale` passed; Vitest reported 74 files and 402 tests. - - `pnpm --filter web typecheck` passed. - - Focused Biome passed on the moved shell/auth/settings files and their route/import consumers; it checked 64 files with no fixes applied after a formatting write pass. - - `rg -n "@/components/(command-palette|theme|locale|user)" apps/web/src` and `rg -n "components/(command-palette|theme|locale|user)" apps/web/src` returned no matches. -- Task 8 completed: - - Added dialog schema registries under `apps/web/src/dialogs/{auth,api-key,resume}/schema.ts` and composed them through `apps/web/src/dialogs/schemas.ts`. - - Added domain renderer registries under `apps/web/src/dialogs/{auth,api-key,resume}/registry.tsx`, with shared renderer helper types in `apps/web/src/dialogs/renderer-registry.ts`. - - Reduced `apps/web/src/dialogs/store.ts` to the single global dialog runtime/store while preserving typed `openDialog(type, data)` and `DialogProps` exports. - - Reduced `apps/web/src/dialogs/manager.tsx` to render via composed registries instead of directly importing all auth/API-key/resume dialog components. - - Added a store test assertion that the central schema union is built from the domain schema registries. -- Validation for Task 8 so far: - - Red check: `pnpm --filter web test -- src/dialogs/store.test.ts` failed because `./schemas` did not exist. - - `pnpm --filter web test -- src/dialogs/store.test.ts` passed after the registry implementation. - - Initial `pnpm --filter web typecheck` found renderer-entry variance errors; fixed by typing renderer entries as an existential union of concrete dialog renderers. - - `pnpm --filter web typecheck` passed after the renderer type fix. - - `pnpm --filter web test -- src/dialogs/store.test.ts src/dialogs/resume/template/data.test.ts src/dialogs/resume/template/gallery.test.tsx` passed; Vitest reported 74 files and 403 tests. - - Final `pnpm --filter web typecheck` passed. - - Final `pnpm --filter web test -- src/dialogs/store.test.ts src/dialogs/resume/template/data.test.ts src/dialogs/resume/template/gallery.test.tsx` passed; Vitest reported 74 files and 403 tests. - - Focused `pnpm exec biome check ...` passed on the touched dialog registry/store/manager files and Task 8 coordination docs; Biome checked 12 TypeScript files and ignored Markdown. - - `rg -n "ts-pattern|Create[A-Za-z]+Dialog|Update[A-Za-z]+Dialog|TemplateGalleryDialog|from \"\\./(api-key|auth|resume)" apps/web/src/dialogs/manager.tsx` returned no matches. - - `rg -n "@reactive-resume/schema/resume/data|awardItemSchema|certificationItemSchema|coverLetterItemSchema|customSectionSchema|educationItemSchema|experienceItemSchema|interestItemSchema|languageItemSchema|profileItemSchema|projectItemSchema|publicationItemSchema|referenceItemSchema|skillItemSchema|summaryItemSchema|volunteerItemSchema|z\\.object\\(\\{ type" apps/web/src/dialogs/store.ts` returned no matches. -- Task 9 completed: - - Inspected installed Turbo and Biome versions and local schemas/docs: - - `pnpm exec turbo --version`: `2.9.12` - - `pnpm exec biome --version`: `2.4.15` - - `node_modules/.pnpm/turbo@2.9.12/node_modules/turbo/schema.json` includes root `boundaries`, `dependencies`, `dependents`, `implicitDependencies`, and workspace `tags`. - - Context7/Biome docs and `node_modules/@biomejs/biome/configuration_schema.json` confirm local `.grit` plugins can be loaded through `biome.json` `plugins`. - - Updated `turbo.json` with executable boundaries: - - Deny dependencies on app workspaces `web` and `server`, preventing package-to-app and app-to-app imports. - - Add root test-tool implicit dependencies for `vitest`, `@testing-library/jest-dom`, `@testing-library/react`, and `@testing-library/user-event` so test imports do not require duplicating root test devDependencies in every workspace package. - - Add tag rules for app, server, browser, universal, domain, and UI layers. - - Added workspace `turbo.json` files with `extends: ["//"]` and boundary tags for both apps and all packages. - - Added `@boundaries-ignore root shared Vitest config` to every workspace `vitest.config.ts` import of `../../vitest.shared`; this is the only allowed cross-package source import left for the shared root test config. - - Updated `biome.json` with `style.noRestrictedImports` patterns for: - - `@reactive-resume/*/src/**` - - `apps/**` - - `packages/**` - - Added `tooling/grit/no-cross-workspace-src-imports.grit` and registered it in `biome.json` as a second layer for import/export/dynamic import sources that reference another workspace's `src` tree. - - Removed the cross-workspace `@reactive-resume/ui/* -> ../../packages/ui/src/*` path alias from `apps/web/tsconfig.json`; web now relies on the UI package export map. -- Files changed for Task 9: - - `turbo.json` - - `apps/server/turbo.json` - - `apps/web/turbo.json` - - `apps/web/tsconfig.json` - - `biome.json` - - `tooling/grit/no-cross-workspace-src-imports.grit` - - `apps/server/vitest.config.ts` - - `apps/web/vitest.config.ts` - - `packages/ai/turbo.json` - - `packages/ai/vitest.config.ts` - - `packages/api/turbo.json` - - `packages/api/vitest.config.ts` - - `packages/auth/turbo.json` - - `packages/auth/vitest.config.ts` - - `packages/config/turbo.json` - - `packages/config/vitest.config.ts` - - `packages/db/turbo.json` - - `packages/db/vitest.config.ts` - - `packages/docx/turbo.json` - - `packages/docx/vitest.config.ts` - - `packages/email/turbo.json` - - `packages/email/vitest.config.ts` - - `packages/env/turbo.json` - - `packages/env/vitest.config.ts` - - `packages/fonts/turbo.json` - - `packages/fonts/vitest.config.ts` - - `packages/import/turbo.json` - - `packages/import/vitest.config.ts` - - `packages/mcp/turbo.json` - - `packages/mcp/vitest.config.ts` - - `packages/pdf/turbo.json` - - `packages/pdf/vitest.config.ts` - - `packages/resume/turbo.json` - - `packages/resume/vitest.config.ts` - - `packages/runtime-externals/turbo.json` - - `packages/schema/turbo.json` - - `packages/schema/vitest.config.ts` - - `packages/scripts/turbo.json` - - `packages/ui/turbo.json` - - `packages/ui/vitest.config.ts` - - `packages/utils/turbo.json` - - `packages/utils/vitest.config.ts` - - `docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md` - - `docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md` -- Validation for Task 9: - - Baseline `pnpm exec turbo boundaries` failed with 321 issues before configuration, mostly undeclared root test-tool imports and shared root Vitest config imports. - - Intermediate `pnpm exec turbo boundaries` passed after adding implicit dependencies and the Vitest config boundary-ignore comments. - - Final `pnpm exec turbo boundaries` passed: checked 660 files in 20 packages, no issues found. - - `pnpm exec biome check biome.json turbo.json tooling/grit/no-cross-workspace-src-imports.grit apps/web/tsconfig.json apps/server/turbo.json apps/web/turbo.json packages/*/turbo.json` passed: checked 24 files, no fixes applied. - - `pnpm --filter web typecheck` passed. - - `pnpm --filter @reactive-resume/api typecheck` passed. - - `pnpm --filter server typecheck` passed. -- Remaining risks for Task 9: - - The current Turbo tags are coarse layer tags. They enforce the current obvious app/browser/server/domain/UI direction, but future package splits may need more granular tags or per-package dependency/dependent rules. - - The GritQL plugin is intentionally narrow: it only covers code import/export sources. JSON/tsconfig source-path aliases are covered separately by `noRestrictedImports`, manual scans, and the removal of the web-to-UI source alias. - - The shared root `vitest.shared` import remains intentionally ignored in workspace Vitest configs. Moving that helper into a package would remove the ignore comments but would be a broader test-infra reorg. -- Task 10 completed: - - Updated `AGENTS.md` with executable boundary rules, package-role/runtime tags, a placement decision tree, and the `pnpm exec turbo boundaries` validation command. - - Replaced the stale public architecture guide at `docs/contributing/architecture.mdx`, which still described an old single-`src` layout, with the current monorepo runtime map, workspace ownership table, boundary rules, feature placement guide, API layout, PDF/DOCX boundaries, and MCP boundary. - - Added `docs/adr/0001-workspace-boundaries.md` with the accepted decision, context, consequences, and rejected alternatives. - - Left MCP and AI Agent user guides unchanged in this task because Task 4 already updated MCP tool names, and `docs/guides/ai-agent-tools.mdx` already documents the canonical `read_resume` and `apply_resume_patch` tool names. - - Did not add local package READMEs; `AGENTS.md`, the architecture guide, the ADR, `turbo.json`, workspace `turbo.json` tags, and `biome.json` are the source of truth. -- Validation for Task 10: - - `rg -n "src/integrations|src/components/resume|packages/api/src/services|packages/api/src/helpers|reactive_resume_|tailor_resume|Radix UI|ORPC" AGENTS.md docs/contributing/architecture.mdx docs/adr/0001-workspace-boundaries.md docs/guides/using-the-mcp-server.mdx docs/guides/ai-agent-tools.mdx` returned only the expected `ORPCClient` labels in the architecture mermaid diagram. - - `pnpm exec biome check AGENTS.md docs/contributing/architecture.mdx docs/adr/0001-workspace-boundaries.md docs/superpowers/plans/2026-05-14-monorepo-architecture-reorg.md docs/superpowers/worklogs/2026-05-14-monorepo-architecture-reorg.md docs/superpowers/handoffs/2026-05-14-monorepo-architecture-reorg.md` did not process files because this Biome config ignores Markdown/MDX; there is no dedicated docs check script in `package.json`. -- Task 11 completed: - - Ran `pnpm install --lockfile-only`; first pass was already up to date, and a later pass updated `pnpm-lock.yaml` after removing stale app dependencies. - - Ran `pnpm install` after manifest cleanup so pnpm's dependency-status check would stop trying to purge modules from non-TTY subcommands. - - Cleaned up final `pnpm knip` findings: - - Deleted unused `apps/web/src/features/resume/export/pdf-document.server.tsx`. - - Removed unused app dependencies from `apps/server/package.json` and `apps/web/package.json`. - - Removed unused internal exports in dialog registries, startup checks, API AI helpers, and agent tool helpers. - - Reattached `pdfExportRateLimit` to `downloadResumePdfProcedure`. - - Removed stale jobs rate-limit middleware exports that no current router uses. - - `pnpm knip` now exits successfully with only the existing configuration hint: `src/server.ts apps/web knip.json Refine entry pattern (no matches)`. -- Final validation for Task 11: - - `pnpm install --lockfile-only` passed. - - `pnpm exec biome check .` passed: 756 files checked, no fixes applied. - - `pnpm exec turbo boundaries` passed: 659 files checked in 20 packages, no issues found. - - `pnpm knip` passed with one configuration hint and no unused files/dependencies/exports. - - `pnpm typecheck` passed: 18 successful tasks. - - `pnpm test` passed: 18 successful tasks; notable totals include web 74 files/403 tests, UI 42 files/421 tests, API 19 files/155 tests, PDF 17 files/139 tests. - - `pnpm build` passed: web and server builds completed. diff --git a/docs/superpowers/worklogs/2026-07-07-mcp-and-directory-submissions.md b/docs/superpowers/worklogs/2026-07-07-mcp-and-directory-submissions.md deleted file mode 100644 index 0384beefb..000000000 --- a/docs/superpowers/worklogs/2026-07-07-mcp-and-directory-submissions.md +++ /dev/null @@ -1,55 +0,0 @@ -# MCP and Directory Submissions Worklog - -Date: 2026-07-07 - -## MCP registries - -Submitted: - -- [mcpservers.org](https://mcpservers.org/submit) - submitted free listing for `Reactive Resume`. -- [mcp.so](https://mcp.so/) - submitted via GitHub issue: [chatmcp/mcpso#3058](https://github.com/chatmcp/mcpso/issues/3058). The issue was reformatted to match recent submissions. -- [mcp.directory](https://mcp.directory/submit) - submitted the GitHub repository and MCP summary. -- [Influzer MCP Directory](https://www.influzer.ai/mcp/submit) - submitted via form. The form reset after submission but did not show a confirmation message. -- [Official MCP Registry](https://registry.modelcontextprotocol.io/) - published `io.github.amruthpillai/reactive-resume` version `5.2.2`; verified active/latest at [`/v0.1/servers/io.github.amruthpillai%2Freactive-resume/versions/latest`](https://registry.modelcontextprotocol.io/v0.1/servers/io.github.amruthpillai%2Freactive-resume/versions/latest). - -Worth doing next: - -- [Smithery](https://smithery.ai/docs/build/publish) - supports direct URL publishing for remote Streamable HTTP MCP servers. Needs account/auth flow. -- [McpMux](https://mcpmux.com/) - registry is open source and accepts PRs; see [server definitions](https://mcpmux.com/docs/server-definitions/). -- [AgenticSkills](https://agenticskills.io/mcp) - has a `Submit MCP` flow, likely manual/account gated. -- [Glama](https://glama.ai/mcp/servers) - has an `Add Server` button, but the automated session could not open the flow. - -Skip for now: - -- [PulseMCP](https://www.pulsemcp.com/submit) - blocked by Cloudflare in automation and says it ingests the Official MCP Registry. -- [MCP Market](https://mcpmarket.com/submit) - already has an unofficial RxResume listing at [mcpmarket.com/server/rxresume](https://mcpmarket.com/server/rxresume); handle as a claim/update, not a duplicate. -- [MCP Server Hub](https://mcpserverhub.net/submit) - free path appears backlink-gated. -- [Cline MCP Marketplace](https://github.com/cline/mcp-marketplace) - asks submitters to verify installation with Cline first. - -## SaaS, free, and open-source directories - -Already listed: - -- [Product Hunt](https://www.producthunt.com/products/reactive-resume) -- [AlternativeTo](https://alternativeto.net/software/reactive-resume/) -- [SaaSHub](https://www.saashub.com/reactive-resume) -- [LibHunt](https://www.libhunt.com/r/Reactive-Resume/Reactive-Resume) -- [SourceForge](https://sourceforge.net/projects/reactive-resume.mirror/) -- [Docker Hub](https://hub.docker.com/r/amruthpillai/reactive-resume) - -Worth doing next: - -- [Awesome-Selfhosted](https://github.com/awesome-selfhosted/awesome-selfhosted) - PR-based; add data in [awesome-selfhosted-data](https://github.com/awesome-selfhosted/awesome-selfhosted-data/blob/master/CONTRIBUTING.md). -- [selfh.st Apps](https://selfh.st/apps/) - self-hosted app directory with a submit-content link. -- [OpenAlternative](https://openalternative.co/) - open-source alternative directory; Reactive Resume was not found in the page search. -- [Free Software Directory](https://directory.fsf.org/wiki/Main_Page) - good fit if FSF-free-software expectations are met. -- [Open Source Software Directory](https://opensourcesoftwaredirectory.com/) - broad free/open-source software directory. -- [Uneed](https://www.uneed.best/submit-a-tool) - account required after preview; broad product launch directory. -- [Fazier](https://fazier.com/submit) - free startup/product submission flow. -- [StartupBase](https://startupbase.io/) - account-gated startup/product launch directory. - -Low priority: - -- [BetaList](https://betalist.com/criteria) - early-stage startup positioning is weaker for an already-established open-source app. -- G2/Capterra/GetApp-style review sites - useful only if there is a review-generation plan. -- AI-only directories - submit only if positioning is specifically around the AI Agent/MCP workflow. diff --git a/knip.json b/knip.json index 259101cc9..191c470d9 100644 --- a/knip.json +++ b/knip.json @@ -17,9 +17,18 @@ "apps/server": { "ignoreDependencies": [ "@ai-sdk/anthropic", + "@ai-sdk/cerebras", + "@ai-sdk/cohere", + "@ai-sdk/deepseek", + "@ai-sdk/fireworks", "@ai-sdk/google", + "@ai-sdk/groq", + "@ai-sdk/mistral", "@ai-sdk/openai", "@ai-sdk/openai-compatible", + "@ai-sdk/perplexity", + "@ai-sdk/togetherai", + "@ai-sdk/xai", "@aws-sdk/client-s3", "@better-auth/api-key", "@better-auth/drizzle-adapter", diff --git a/package.json b/package.json index 1e624ccda..490199878 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "reactive-resume", "description": "Reactive Resume is a free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume.", - "version": "5.2.2", + "version": "5.2.3", "private": true, "license": "MIT", "author": { @@ -22,15 +22,11 @@ "scripts": { "build": "turbo run build", "doctor": "turbo run doctor", - "check": "biome check --write --unsafe . && pnpm lint:docs:fix && pnpm lint:actions", + "check": "biome check --write --unsafe . && markdownlint-cli2 --fix && github-actionlint -shellcheck= -pyflakes=", "db:generate": "turbo run db:generate --filter=@reactive-resume/db", "db:migrate": "turbo run db:migrate --filter=@reactive-resume/db", "db:studio": "turbo run db:studio --filter=@reactive-resume/db", "lingui:extract": "turbo run lingui:extract --filter=web", - "lint": "pnpm lint:docs && pnpm lint:actions", - "lint:actions": "github-actionlint -shellcheck= -pyflakes=", - "lint:docs": "markdownlint-cli2", - "lint:docs:fix": "markdownlint-cli2 --fix", "dev": "turbo run dev", "dev:web": "turbo run dev --filter=web", "knip": "knip", @@ -45,8 +41,8 @@ "test:agent": "turbo run test:agent" }, "devDependencies": { - "@biomejs/biome": "^2.5.2", - "@commitlint/cli": "^21.2.0", + "@biomejs/biome": "^2.5.3", + "@commitlint/cli": "^21.2.1", "@commitlint/config-conventional": "^21.2.0", "@playwright/test": "^1.61.1", "@reactive-resume/config": "workspace:*", @@ -54,17 +50,17 @@ "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", - "@types/node": "^26.1.0", + "@types/node": "^26.1.1", "@types/pg": "^8.20.0", - "@vitest/coverage-v8": "^4.1.9", + "@vitest/coverage-v8": "^4.1.10", "github-actionlint": "1.7.12", "happy-dom": "^20.10.6", - "knip": "^6.24.0", - "lefthook": "^2.1.9", + "knip": "^6.25.0", + "lefthook": "^2.1.10", "markdownlint-cli2": "0.23.0", "pg": "^8.22.0", - "turbo": "^2.10.3", - "typescript": "^6.0.3", - "vitest": "^4.1.9" + "turbo": "^2.10.4", + "typescript": "^7.0.2", + "vitest": "^4.1.10" } } diff --git a/packages/ai/package.json b/packages/ai/package.json index f8eda9f01..0de827993 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -28,7 +28,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/packages/ai/src/types.test.ts b/packages/ai/src/types.test.ts new file mode 100644 index 000000000..bf8fee9c2 --- /dev/null +++ b/packages/ai/src/types.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it } from "vitest"; +import { AI_PROVIDER_DEFAULT_BASE_URLS, aiProviderSchema } from "./types"; + +const popularProviderDefaults = { + mistral: "https://api.mistral.ai/v1", + cohere: "https://api.cohere.com/v2", + xai: "https://api.x.ai/v1", + groq: "https://api.groq.com/openai/v1", + deepseek: "https://api.deepseek.com/v1", + togetherai: "https://api.together.xyz/v1", + fireworks: "https://api.fireworks.ai/inference/v1", + cerebras: "https://api.cerebras.ai/v1", + perplexity: "https://api.perplexity.ai", +} as const; + +describe("AI provider types", () => { + it("accepts popular AI SDK text providers with default base URLs", () => { + for (const [provider, baseURL] of Object.entries(popularProviderDefaults)) { + expect(aiProviderSchema.parse(provider)).toBe(provider); + expect(AI_PROVIDER_DEFAULT_BASE_URLS[provider as keyof typeof AI_PROVIDER_DEFAULT_BASE_URLS]).toBe(baseURL); + } + }); +}); diff --git a/packages/ai/src/types.ts b/packages/ai/src/types.ts index a10be8d48..6244113d4 100644 --- a/packages/ai/src/types.ts +++ b/packages/ai/src/types.ts @@ -6,6 +6,15 @@ const AI_PROVIDERS = [ "gemini", "vercel-ai-gateway", "openrouter", + "mistral", + "cohere", + "xai", + "groq", + "deepseek", + "togetherai", + "fireworks", + "cerebras", + "perplexity", "ollama", "openai-compatible", ] as const; @@ -20,6 +29,15 @@ export const AI_PROVIDER_DEFAULT_BASE_URLS: Record = { gemini: "https://generativelanguage.googleapis.com/v1beta", "vercel-ai-gateway": "https://ai-gateway.vercel.sh/v3/ai", openrouter: "https://openrouter.ai/api/v1", + mistral: "https://api.mistral.ai/v1", + cohere: "https://api.cohere.com/v2", + xai: "https://api.x.ai/v1", + groq: "https://api.groq.com/openai/v1", + deepseek: "https://api.deepseek.com/v1", + togetherai: "https://api.together.xyz/v1", + fireworks: "https://api.fireworks.ai/inference/v1", + cerebras: "https://api.cerebras.ai/v1", + perplexity: "https://api.perplexity.ai", ollama: "https://ollama.com/api", "openai-compatible": "", }; diff --git a/packages/api/package.json b/packages/api/package.json index a29910065..508aea58a 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -18,14 +18,23 @@ "test:agent": "vitest run --reporter=agent --reporter=json --outputFile.json=reports/vitest-results.json --passWithNoTests" }, "dependencies": { - "@ai-sdk/anthropic": "^4.0.8", - "@ai-sdk/google": "^4.0.8", - "@ai-sdk/openai": "^4.0.7", - "@ai-sdk/openai-compatible": "^3.0.5", - "@aws-sdk/client-s3": "^3.1079.0", - "@orpc/client": "^1.14.6", - "@orpc/experimental-ratelimit": "^1.14.6", - "@orpc/server": "^1.14.6", + "@ai-sdk/anthropic": "^4.0.10", + "@ai-sdk/cerebras": "^3.0.6", + "@ai-sdk/cohere": "^4.0.6", + "@ai-sdk/deepseek": "^3.0.6", + "@ai-sdk/fireworks": "^3.0.7", + "@ai-sdk/google": "^4.0.10", + "@ai-sdk/groq": "^4.0.6", + "@ai-sdk/mistral": "^4.0.7", + "@ai-sdk/openai": "^4.0.9", + "@ai-sdk/openai-compatible": "^3.0.6", + "@ai-sdk/perplexity": "^4.0.7", + "@ai-sdk/togetherai": "^3.0.7", + "@ai-sdk/xai": "^4.0.9", + "@aws-sdk/client-s3": "^3.1081.0", + "@orpc/client": "^1.14.7", + "@orpc/experimental-ratelimit": "^1.14.7", + "@orpc/server": "^1.14.7", "@reactive-resume/ai": "workspace:*", "@reactive-resume/auth": "workspace:*", "@reactive-resume/db": "workspace:*", @@ -34,14 +43,14 @@ "@reactive-resume/resume": "workspace:*", "@reactive-resume/schema": "workspace:*", "@reactive-resume/utils": "workspace:*", - "ai": "^7.0.15", + "ai": "^7.0.18", "bcrypt": "^6.0.0", "better-auth": "1.6.23", "drizzle-orm": "1.0.0-rc.4", "drizzle-zod": "1.0.0-beta.14-a36c63d", "es-toolkit": "^1.49.0", "ioredis": "^5.11.1", - "ollama-ai-provider-v2": "^3.6.0", + "ollama-ai-provider-v2": "^4.0.1", "react": "^19.2.7", "resumable-stream": "^2.2.12", "sharp": "^0.35.3", @@ -51,7 +60,7 @@ "devDependencies": { "@reactive-resume/config": "workspace:*", "@types/bcrypt": "^6.0.0", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/packages/api/src/dto/application.test.ts b/packages/api/src/dto/application.test.ts index b91108b73..ed3ad7410 100644 --- a/packages/api/src/dto/application.test.ts +++ b/packages/api/src/dto/application.test.ts @@ -83,3 +83,24 @@ describe("applicationDto zero-argument inputs", () => { expect(applicationDto.tags.input.parse(undefined)).toEqual({}); }); }); + +// Bulk operations cap `ids` at 200 to bound memory/DB work from a single call. +describe("applicationDto bulk id caps", () => { + const idsOfLength = (n: number) => Array.from({ length: n }, (_, i) => String(i)); + + it("rejects a bulkDelete ids array over the cap", () => { + expect(applicationDto.bulkDelete.input.safeParse({ ids: idsOfLength(201) }).success).toBe(false); + }); + + it("accepts a bulkDelete ids array at the cap", () => { + expect(applicationDto.bulkDelete.input.safeParse({ ids: idsOfLength(200) }).success).toBe(true); + }); + + it("rejects a bulkUpdate ids array over the cap", () => { + expect(applicationDto.bulkUpdate.input.safeParse({ ids: idsOfLength(201) }).success).toBe(false); + }); + + it("accepts a bulkUpdate ids array at the cap", () => { + expect(applicationDto.bulkUpdate.input.safeParse({ ids: idsOfLength(200) }).success).toBe(true); + }); +}); diff --git a/packages/api/src/dto/application.ts b/packages/api/src/dto/application.ts index 0fc0753fb..9f9e26255 100644 --- a/packages/api/src/dto/application.ts +++ b/packages/api/src/dto/application.ts @@ -162,7 +162,7 @@ export const applicationDto = { // Table bulk actions: move stage, archive/unarchive, add tags across a selection. bulkUpdate: { input: z.object({ - ids: z.array(z.string()).min(1), + ids: z.array(z.string()).min(1).max(200, "Too many items in a single bulk operation"), status: applicationStatusSchema.optional(), archived: z.boolean().optional(), addTags: z.array(z.string()).optional(), @@ -171,7 +171,7 @@ export const applicationDto = { }, bulkDelete: { - input: z.object({ ids: z.array(z.string()).min(1) }), + input: z.object({ ids: z.array(z.string()).min(1).max(200, "Too many items in a single bulk operation") }), output: z.object({ deleted: z.number() }), }, diff --git a/packages/api/src/features/ai-providers/inputs.ts b/packages/api/src/features/ai-providers/inputs.ts new file mode 100644 index 000000000..ceb800fd5 --- /dev/null +++ b/packages/api/src/features/ai-providers/inputs.ts @@ -0,0 +1,17 @@ +import z from "zod"; +import { aiProviderSchema } from "@reactive-resume/ai/types"; + +export const providerInput = z.object({ + label: z.string().trim().min(1), + provider: aiProviderSchema, + model: z.string().trim().min(1), + baseURL: z.string().trim().optional(), + apiKey: z.string().trim().min(1), +}); + +export const updateProviderInput = providerInput + .partial() + .extend({ id: z.string(), enabled: z.boolean().optional() }) + .refine((input) => Object.keys(input).some((key) => key !== "id"), { + message: "At least one field must be provided.", + }); diff --git a/packages/api/src/features/ai-providers/router.test.ts b/packages/api/src/features/ai-providers/router.test.ts new file mode 100644 index 000000000..00c4b554d --- /dev/null +++ b/packages/api/src/features/ai-providers/router.test.ts @@ -0,0 +1,8 @@ +import { describe, expect, it } from "vitest"; +import { updateProviderInput } from "./inputs"; + +describe("AI provider router input", () => { + it("does not default baseURL on switch-only updates", () => { + expect(updateProviderInput.parse({ id: "provider-1", enabled: false })).not.toHaveProperty("baseURL"); + }); +}); diff --git a/packages/api/src/features/ai-providers/router.ts b/packages/api/src/features/ai-providers/router.ts index 594c152f5..fd2d767d4 100644 --- a/packages/api/src/features/ai-providers/router.ts +++ b/packages/api/src/features/ai-providers/router.ts @@ -2,26 +2,11 @@ import type { AiProviderResponse } from "./service"; import { ORPCError } from "@orpc/client"; import { type } from "@orpc/server"; import z from "zod"; -import { aiProviderSchema } from "@reactive-resume/ai/types"; import { protectedProcedure } from "../../context"; import { aiRequestRateLimit } from "../../middleware/rate-limit"; +import { providerInput, updateProviderInput } from "./inputs"; import { aiProvidersService } from "./service"; -const providerInput = z.object({ - label: z.string().trim().min(1), - provider: aiProviderSchema, - model: z.string().trim().min(1), - baseURL: z.string().trim().optional().default(""), - apiKey: z.string().trim().min(1), -}); - -const updateProviderInput = providerInput - .partial() - .extend({ id: z.string(), enabled: z.boolean().optional() }) - .refine((input) => Object.keys(input).some((key) => key !== "id"), { - message: "At least one field must be provided.", - }); - function isAgentEnvironmentUnavailable(error: unknown) { return error instanceof Error && error.message === "AGENT_ENVIRONMENT_UNAVAILABLE"; } @@ -85,7 +70,7 @@ export const aiProvidersRouter = { label: input.label, provider: input.provider, model: input.model, - baseURL: input.baseURL, + ...(input.baseURL !== undefined ? { baseURL: input.baseURL } : {}), apiKey: input.apiKey, }); } catch (error) { diff --git a/packages/api/src/features/ai-providers/service.test.ts b/packages/api/src/features/ai-providers/service.test.ts new file mode 100644 index 000000000..59abbe5b9 --- /dev/null +++ b/packages/api/src/features/ai-providers/service.test.ts @@ -0,0 +1,122 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const { dbMock, queryMock, queryState } = vi.hoisted(() => { + const state = { + rows: [] as unknown[], + whereArg: undefined as unknown, + orderByArgs: [] as unknown[], + }; + const query = { + from: vi.fn(() => query), + where: vi.fn((arg: unknown) => { + state.whereArg = arg; + return query; + }), + orderBy: vi.fn((...args: unknown[]) => { + state.orderByArgs = args; + return query; + }), + limit: vi.fn(async () => state.rows), + }; + + return { + dbMock: { select: vi.fn(() => query) }, + queryMock: query, + queryState: state, + }; +}); + +vi.mock("@reactive-resume/db/client", () => ({ db: dbMock })); +vi.mock("@reactive-resume/db/schema", () => ({ + aiProvider: { + id: "ai_provider.id", + userId: "ai_provider.user_id", + label: "ai_provider.label", + provider: "ai_provider.provider", + model: "ai_provider.model", + baseUrl: "ai_provider.base_url", + encryptedApiKey: "ai_provider.encrypted_api_key", + apiKeySalt: "ai_provider.api_key_salt", + apiKeyHash: "ai_provider.api_key_hash", + apiKeyPreview: "ai_provider.api_key_preview", + testStatus: "ai_provider.test_status", + testError: "ai_provider.test_error", + lastTestedAt: "ai_provider.last_tested_at", + lastUsedAt: "ai_provider.last_used_at", + enabled: "ai_provider.enabled", + createdAt: "ai_provider.created_at", + updatedAt: "ai_provider.updated_at", + }, +})); +vi.mock("drizzle-orm", () => ({ + and: (...conditions: unknown[]) => ({ type: "and", conditions }), + asc: (value: unknown) => ({ type: "asc", value }), + desc: (value: unknown) => ({ type: "desc", value }), + eq: (left: unknown, right: unknown) => ({ type: "eq", left, right }), + sql: (strings: TemplateStringsArray, ...values: unknown[]) => ({ type: "sql", strings: [...strings], values }), +})); +vi.mock("../ai/credentials", () => ({ + assertCredentialEncryptionConfigured: vi.fn(), + decryptCredential: vi.fn(() => "decrypted-key"), + encryptCredential: vi.fn(), + redactEncryptedCredential: vi.fn(() => ({ + apiKeyFingerprint: "fingerprint", + apiKeyPreview: "sk-...test", + })), +})); +vi.mock("../ai/service", () => ({ testConnection: vi.fn() })); +vi.mock("../ai/url-policy", () => ({ resolveAiBaseUrl: vi.fn() })); + +const { aiProvidersService } = await import("./service"); + +function providerRow(overrides: Record = {}) { + return { + id: "provider-1", + userId: "user-1", + label: "OpenAI", + provider: "openai", + model: "gpt-5-mini", + baseUrl: null, + encryptedApiKey: "encrypted-key", + apiKeySalt: "salt", + apiKeyHash: "hash", + apiKeyPreview: "preview", + testStatus: "success", + testError: null, + lastTestedAt: new Date("2026-07-01T00:00:00Z"), + lastUsedAt: new Date("2026-07-07T00:00:00Z"), + enabled: true, + createdAt: new Date("2026-07-01T00:00:00Z"), + updatedAt: new Date("2026-07-01T00:00:00Z"), + ...overrides, + }; +} + +describe("aiProvidersService", () => { + beforeEach(() => { + vi.clearAllMocks(); + queryState.rows = []; + queryState.whereArg = undefined; + queryState.orderByArgs = []; + }); + + it("gets the first enabled and tested provider by creation order", async () => { + queryState.rows = [providerRow({ id: "first-created" })]; + + await expect(aiProvidersService.getDefaultRunnable({ userId: "user-1" })).resolves.toMatchObject({ + id: "first-created", + apiKey: "decrypted-key", + }); + + expect(queryState.whereArg).toEqual({ + type: "and", + conditions: [ + { type: "eq", left: "ai_provider.user_id", right: "user-1" }, + { type: "eq", left: "ai_provider.enabled", right: true }, + { type: "eq", left: "ai_provider.test_status", right: "success" }, + ], + }); + expect(queryState.orderByArgs).toEqual([{ type: "asc", value: "ai_provider.created_at" }]); + expect(queryMock.limit).toHaveBeenCalledWith(1); + }); +}); diff --git a/packages/api/src/features/ai-providers/service.ts b/packages/api/src/features/ai-providers/service.ts index defc81386..527e0acd6 100644 --- a/packages/api/src/features/ai-providers/service.ts +++ b/packages/api/src/features/ai-providers/service.ts @@ -143,7 +143,7 @@ export const aiProvidersService = { eq(schema.aiProvider.testStatus, "success"), ), ) - .orderBy(orderByLastUsedAtDescNullsLast(), asc(schema.aiProvider.createdAt)) + .orderBy(asc(schema.aiProvider.createdAt)) .limit(1); return provider diff --git a/packages/api/src/features/ai/service.docx.test.ts b/packages/api/src/features/ai/service.docx.test.ts new file mode 100644 index 000000000..10d87c2ae --- /dev/null +++ b/packages/api/src/features/ai/service.docx.test.ts @@ -0,0 +1,110 @@ +import { Buffer } from "node:buffer"; +import { deflateRawSync } from "node:zlib"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { defaultResumeData } from "@reactive-resume/schema/resume/default"; + +const generateTextMock = vi.hoisted(() => vi.fn()); +const envMock = vi.hoisted(() => ({ + FLAG_ALLOW_UNSAFE_AI_BASE_URL: false, +})); + +vi.mock("@reactive-resume/env/server", () => ({ env: envMock })); +vi.mock("ai", async (importOriginal) => { + const actual = await importOriginal(); + return { ...actual, generateText: generateTextMock }; +}); + +afterEach(() => { + generateTextMock.mockReset(); +}); + +const u16 = (value: number) => { + const buffer = Buffer.alloc(2); + buffer.writeUInt16LE(value); + return buffer; +}; + +const u32 = (value: number) => { + const buffer = Buffer.alloc(4); + buffer.writeUInt32LE(value); + return buffer; +}; + +function createDocxBase64(text: string): string { + const name = Buffer.from("word/document.xml"); + const data = Buffer.from( + `${text}`, + ); + const compressed = deflateRawSync(data); + const local = Buffer.concat([ + u32(0x04034b50), + u16(20), + u16(0), + u16(8), + u16(0), + u16(0), + u32(0), + u32(compressed.length), + u32(data.length), + u16(name.length), + u16(0), + name, + compressed, + ]); + const central = Buffer.concat([ + u32(0x02014b50), + u16(20), + u16(20), + u16(0), + u16(8), + u16(0), + u16(0), + u32(0), + u32(compressed.length), + u32(data.length), + u16(name.length), + u16(0), + u16(0), + u16(0), + u16(0), + u32(0), + u32(0), + name, + ]); + const eocd = Buffer.concat([ + u32(0x06054b50), + u16(0), + u16(0), + u16(1), + u16(1), + u32(central.length), + u32(local.length), + u16(0), + ]); + + return Buffer.concat([local, central, eocd]).toString("base64"); +} + +const { aiService } = await import("./service"); + +describe("AI DOCX parsing", () => { + it("sends DOCX content as extracted text instead of an unsupported file part", async () => { + generateTextMock.mockResolvedValue({ text: JSON.stringify(defaultResumeData) }); + + await aiService.parseDocx({ + provider: "openai-compatible", + model: "test-model", + apiKey: "test-key", + baseURL: "https://example.test/v1", + mediaType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + file: { name: "resume.docx", data: createDocxBase64("Jane Doe & Co") }, + }); + + const request = generateTextMock.mock.calls[0]?.[0] as { messages: unknown[] }; + const messages = JSON.stringify(request.messages); + + expect(messages).toContain("Jane Doe & Co"); + expect(messages).toContain("converted to plain text"); + expect(messages).not.toContain('"type":"file"'); + }); +}); diff --git a/packages/api/src/features/ai/service.test.ts b/packages/api/src/features/ai/service.test.ts index e293c5945..a2c623f63 100644 --- a/packages/api/src/features/ai/service.test.ts +++ b/packages/api/src/features/ai/service.test.ts @@ -1,8 +1,82 @@ import type { UIMessage } from "ai"; -import { describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { convertToModelMessages, modelMessageSchema } from "ai"; +const envMock = vi.hoisted(() => ({ + FLAG_ALLOW_UNSAFE_AI_BASE_URL: false, +})); + +vi.mock("@reactive-resume/env/server", () => ({ env: envMock })); + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +function stubOpenAICompatibleResponse(response?: { content?: string; finishReason?: string }) { + let requestBody: unknown; + + const fetchMock = vi.fn(async (_input: unknown, init?: { body?: unknown }) => { + const body = JSON.parse(String(init?.body ?? "{}")) as { max_tokens?: number }; + requestBody = body; + const hasEnoughOutputTokens = (body.max_tokens ?? 0) >= 128; + + return new Response( + JSON.stringify({ + id: "chatcmpl-test", + object: "chat.completion", + created: 1, + model: "test-model", + choices: [ + { + index: 0, + message: { role: "assistant", content: response?.content ?? (hasEnoughOutputTokens ? "1" : "") }, + finish_reason: response?.finishReason ?? (hasEnoughOutputTokens ? "stop" : "length"), + }, + ], + usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 }, + }), + { headers: { "Content-Type": "application/json" } }, + ); + }); + + vi.stubGlobal("fetch", fetchMock); + + return { fetchMock, getRequestBody: () => requestBody }; +} + +const { testConnection } = await import("./service"); + describe("AI chat service", () => { + it("tests OpenAI-compatible providers without requiring structured output", async () => { + const openAiCompatible = stubOpenAICompatibleResponse(); + + await expect( + testConnection({ + provider: "openai-compatible", + model: "test-model", + apiKey: "test-key", + baseURL: "https://example.test/v1", + }), + ).resolves.toBe(true); + + expect(openAiCompatible.fetchMock).toHaveBeenCalledTimes(1); + expect(openAiCompatible.getRequestBody()).not.toHaveProperty("response_format"); + expect(openAiCompatible.getRequestBody()).toMatchObject({ max_tokens: 128, temperature: 0 }); + }); + + it("explains when the provider test hits the output limit", async () => { + stubOpenAICompatibleResponse({ content: "1. The connection works.", finishReason: "length" }); + + await expect( + testConnection({ + provider: "openai-compatible", + model: "test-model", + apiKey: "test-key", + baseURL: "https://example.test/v1", + }), + ).rejects.toThrow("The model returned too much text during the provider test."); + }); + it("keeps proposal tool history valid for follow-up chat messages", async () => { const messages: UIMessage[] = [ { diff --git a/packages/api/src/features/ai/service.ts b/packages/api/src/features/ai/service.ts index 20f2959a0..98f50cb3b 100644 --- a/packages/api/src/features/ai/service.ts +++ b/packages/api/src/features/ai/service.ts @@ -2,12 +2,22 @@ import type { AIProvider } from "@reactive-resume/ai/types"; import type { ResumeAnalysis } from "@reactive-resume/schema/resume/analysis"; import type { ResumeData } from "@reactive-resume/schema/resume/data"; import type { ModelMessage, UIMessage } from "ai"; +import { inflateRawSync } from "node:zlib"; import { createAnthropic } from "@ai-sdk/anthropic"; +import { createCerebras } from "@ai-sdk/cerebras"; +import { createCohere } from "@ai-sdk/cohere"; +import { createDeepSeek } from "@ai-sdk/deepseek"; +import { createFireworks } from "@ai-sdk/fireworks"; import { createGoogleGenerativeAI } from "@ai-sdk/google"; +import { createGroq } from "@ai-sdk/groq"; +import { createMistral } from "@ai-sdk/mistral"; import { createOpenAI } from "@ai-sdk/openai"; import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; +import { createPerplexity } from "@ai-sdk/perplexity"; +import { createTogetherAI } from "@ai-sdk/togetherai"; +import { createXai } from "@ai-sdk/xai"; import { streamToEventIterator } from "@orpc/server"; -import { convertToModelMessages, createGateway, generateText, Output, stepCountIs, streamText, tool } from "ai"; +import { convertToModelMessages, createGateway, generateText, stepCountIs, streamText, tool } from "ai"; import { createOllama } from "ollama-ai-provider-v2"; import { match } from "ts-pattern"; import { z } from "zod"; @@ -72,6 +82,13 @@ type GetModelInput = { const MAX_AI_FILE_BYTES = 10 * 1024 * 1024; // 10MB const MAX_AI_FILE_BASE64_CHARS = Math.ceil((MAX_AI_FILE_BYTES * 4) / 3) + 4; +const TEST_CONNECTION_MAX_OUTPUT_TOKENS = 128; +const DOCX_DOCUMENT_XML_PATH = "word/document.xml"; +const ZIP_LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50; +const ZIP_CENTRAL_DIRECTORY_SIGNATURE = 0x02014b50; +const ZIP_END_OF_CENTRAL_DIRECTORY_SIGNATURE = 0x06054b50; +const ZIP_STORED_METHOD = 0; +const ZIP_DEFLATED_METHOD = 8; export function getModel(input: GetModelInput) { const { provider, model, apiKey } = input; @@ -83,6 +100,15 @@ export function getModel(input: GetModelInput) { .with("gemini", () => createGoogleGenerativeAI({ apiKey, baseURL }).languageModel(model)) .with("vercel-ai-gateway", () => createGateway({ apiKey, baseURL }).languageModel(model)) .with("openrouter", () => createOpenAICompatible({ name: "openrouter", apiKey, baseURL }).languageModel(model)) + .with("mistral", () => createMistral({ apiKey, baseURL }).languageModel(model)) + .with("cohere", () => createCohere({ apiKey, baseURL }).languageModel(model)) + .with("xai", () => createXai({ apiKey, baseURL }).languageModel(model)) + .with("groq", () => createGroq({ apiKey, baseURL }).languageModel(model)) + .with("deepseek", () => createDeepSeek({ apiKey, baseURL }).languageModel(model)) + .with("togetherai", () => createTogetherAI({ apiKey, baseURL }).languageModel(model)) + .with("fireworks", () => createFireworks({ apiKey, baseURL }).languageModel(model)) + .with("cerebras", () => createCerebras({ apiKey, baseURL }).languageModel(model)) + .with("perplexity", () => createPerplexity({ apiKey, baseURL }).languageModel(model)) .with("openai-compatible", () => createOpenAICompatible({ name: "openai-compatible", apiKey, baseURL }).languageModel(model), ) @@ -123,11 +149,15 @@ export async function testConnection(input: TestConnectionInput): Promise & { @@ -156,6 +186,20 @@ function buildResumeParsingMessages({ userPrompt, file, mediaType }: BuildResume ]; } +function buildResumeParsingTextMessages({ userPrompt, text }: { userPrompt: string; text: string }): ModelMessage[] { + return [ + { + role: "user", + content: [ + { + type: "text", + text: `${userPrompt}\n\nThe Microsoft Word file has been converted to plain text below.\n\n${text}`, + }, + ], + }, + ]; +} + async function parsePdf(input: ParsePdfInput): Promise { const model = getModel(input); @@ -177,17 +221,117 @@ type ParseDocxInput = z.infer & { mediaType: "application/msword" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; }; +function assertZipRange(buffer: Buffer, offset: number, length: number) { + if (offset < 0 || length < 0 || offset + length > buffer.length) throw new Error("Invalid DOCX archive."); +} + +function findEndOfCentralDirectory(buffer: Buffer): number { + const minOffset = Math.max(0, buffer.length - 0xffff - 22); + + for (let offset = buffer.length - 22; offset >= minOffset; offset--) { + if (buffer.readUInt32LE(offset) === ZIP_END_OF_CENTRAL_DIRECTORY_SIGNATURE) return offset; + } + + throw new Error("Invalid DOCX archive."); +} + +function readZipEntry(buffer: Buffer, entryName: string): Buffer { + const eocdOffset = findEndOfCentralDirectory(buffer); + assertZipRange(buffer, eocdOffset, 22); + + const centralDirectorySize = buffer.readUInt32LE(eocdOffset + 12); + const centralDirectoryOffset = buffer.readUInt32LE(eocdOffset + 16); + assertZipRange(buffer, centralDirectoryOffset, centralDirectorySize); + + let offset = centralDirectoryOffset; + const endOffset = centralDirectoryOffset + centralDirectorySize; + + while (offset < endOffset) { + assertZipRange(buffer, offset, 46); + if (buffer.readUInt32LE(offset) !== ZIP_CENTRAL_DIRECTORY_SIGNATURE) throw new Error("Invalid DOCX archive."); + + const compressionMethod = buffer.readUInt16LE(offset + 10); + const compressedSize = buffer.readUInt32LE(offset + 20); + const fileNameLength = buffer.readUInt16LE(offset + 28); + const extraFieldLength = buffer.readUInt16LE(offset + 30); + const commentLength = buffer.readUInt16LE(offset + 32); + const localHeaderOffset = buffer.readUInt32LE(offset + 42); + const fileNameOffset = offset + 46; + assertZipRange(buffer, fileNameOffset, fileNameLength); + + const fileName = buffer.toString("utf8", fileNameOffset, fileNameOffset + fileNameLength); + + if (fileName === entryName) { + assertZipRange(buffer, localHeaderOffset, 30); + if (buffer.readUInt32LE(localHeaderOffset) !== ZIP_LOCAL_FILE_HEADER_SIGNATURE) { + throw new Error("Invalid DOCX archive."); + } + + const localFileNameLength = buffer.readUInt16LE(localHeaderOffset + 26); + const localExtraFieldLength = buffer.readUInt16LE(localHeaderOffset + 28); + const dataOffset = localHeaderOffset + 30 + localFileNameLength + localExtraFieldLength; + assertZipRange(buffer, dataOffset, compressedSize); + + const compressed = buffer.subarray(dataOffset, dataOffset + compressedSize); + if (compressionMethod === ZIP_STORED_METHOD) return compressed; + if (compressionMethod === ZIP_DEFLATED_METHOD) return inflateRawSync(compressed); + + throw new Error("Unsupported DOCX archive compression."); + } + + offset = fileNameOffset + fileNameLength + extraFieldLength + commentLength; + } + + throw new Error("DOCX document content not found."); +} + +function decodeXmlEntities(value: string): string { + return value.replace(/&(#x[\da-f]+|#\d+|amp|lt|gt|quot|apos);/gi, (entity, token: string) => { + if (token === "amp") return "&"; + if (token === "lt") return "<"; + if (token === "gt") return ">"; + if (token === "quot") return '"'; + if (token === "apos") return "'"; + if (token.toLowerCase().startsWith("#x")) return String.fromCodePoint(Number.parseInt(token.slice(2), 16)); + if (token.startsWith("#")) return String.fromCodePoint(Number.parseInt(token.slice(1), 10)); + return entity; + }); +} + +function extractDocxText(file: z.infer): string { + const documentXml = readZipEntry(Buffer.from(file.data, "base64"), DOCX_DOCUMENT_XML_PATH).toString("utf8"); + // ponytail: minimal OOXML body-text extraction; add a DOCX parser dependency if tracked changes matter. + const text = decodeXmlEntities( + documentXml + .replace(/]*\/>/g, "\t") + .replace(/]*\/>/g, "\n") + .replace(/<\/w:p>/g, "\n") + .replace(/<[^>]+>/g, ""), + ) + .replace(/\r/g, "") + .replace(/[ \t]+\n/g, "\n") + .replace(/\n{3,}/g, "\n\n") + .trim(); + + if (!text) throw new Error("DOCX document content is empty."); + return text; +} + async function parseDocx(input: ParseDocxInput): Promise { const model = getModel(input); + const messages = + input.mediaType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ? buildResumeParsingTextMessages({ userPrompt: docxParserUserPrompt, text: extractDocxText(input.file) }) + : buildResumeParsingMessages({ + userPrompt: docxParserUserPrompt, + file: input.file, + mediaType: input.mediaType, + }); const result = await generateText({ model, system: buildResumeParsingSystemPrompt(docxParserSystemPrompt), - messages: buildResumeParsingMessages({ - userPrompt: docxParserUserPrompt, - file: input.file, - mediaType: input.mediaType, - }), + messages, }).catch((error: unknown) => logAndRethrow("Failed to generate the text with the model", error)); return parseAndValidateResumeJson(result.text); diff --git a/packages/api/src/features/resume/service.test.ts b/packages/api/src/features/resume/service.test.ts new file mode 100644 index 000000000..016b7407a --- /dev/null +++ b/packages/api/src/features/resume/service.test.ts @@ -0,0 +1,341 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +// Characterization tests for the resume service. The goal is to pin down CURRENT behavior +// (CRUD / lock / password / statistics branching) so later changes are deliberate. The DB +// layer and side-effecting helpers are mocked; the branching in service.ts is what's under test. + +const dbMock = vi.hoisted(() => ({ + select: vi.fn(), + insert: vi.fn(), + update: vi.fn(), + delete: vi.fn(), + transaction: vi.fn(), +})); +const hashMock = vi.hoisted(() => vi.fn()); +const compareMock = vi.hoisted(() => vi.fn()); +const publishResumeUpdatedMock = vi.hoisted(() => vi.fn()); +const grantResumeAccessMock = vi.hoisted(() => vi.fn()); +const hasResumeAccessMock = vi.hoisted(() => vi.fn()); +const storageDeleteMock = vi.hoisted(() => vi.fn()); + +vi.mock("@reactive-resume/db/client", () => ({ db: dbMock })); +vi.mock("@reactive-resume/db/schema", () => ({ + resume: { + id: "id", + userId: "user_id", + slug: "slug", + name: "name", + tags: "tags", + data: "data", + isPublic: "is_public", + isLocked: "is_locked", + password: "password", + updatedAt: "updated_at", + createdAt: "created_at", + }, + resumeStatistics: { + resumeId: "resume_id", + views: "views", + downloads: "downloads", + lastViewedAt: "last_viewed_at", + lastDownloadedAt: "last_downloaded_at", + }, + resumeStatisticsDaily: { + resumeId: "resume_id", + date: "date", + views: "views", + downloads: "downloads", + }, + resumeVersion: { + id: "id", + resumeId: "resume_id", + userId: "user_id", + data: "data", + label: "label", + createdAt: "created_at", + }, + resumeAnalysis: { resumeId: "resume_id", analysis: "analysis" }, + user: { id: "id", username: "username" }, +})); +vi.mock("drizzle-orm", () => ({ + and: (...a: unknown[]) => a, + arrayContains: (...a: unknown[]) => a, + asc: (x: unknown) => x, + desc: (x: unknown) => x, + eq: (...a: unknown[]) => a, + gte: (...a: unknown[]) => a, + isNotNull: (...a: unknown[]) => a, + notInArray: (...a: unknown[]) => a, + sql: Object.assign((strings: TemplateStringsArray, ...values: unknown[]) => ({ strings, values }), { + join: (values: unknown[]) => values, + }), +})); +vi.mock("bcrypt", () => ({ hash: hashMock, compare: compareMock })); +vi.mock("./events", () => ({ publishResumeUpdated: publishResumeUpdatedMock })); +vi.mock("./access", () => ({ + grantResumeAccess: grantResumeAccessMock, + hasResumeAccess: hasResumeAccessMock, +})); +vi.mock("../storage/service", () => ({ + getStorageService: () => ({ delete: storageDeleteMock }), +})); + +const { resumeService } = await import("./service"); + +// A `db.update(...).set(...).where(...).returning(...)` chain that resolves to `rows`. +const createUpdateChain = (rows: unknown[]) => { + const returning = vi.fn(() => Promise.resolve(rows)); + const where = vi.fn(() => ({ returning })); + const set = vi.fn(() => ({ where })); + return { chain: { set }, set, where, returning }; +}; + +// A `db.select(...).from(...).where(...)` chain that resolves to `rows`. +const createSelectChain = (rows: unknown[]) => ({ + from: () => ({ where: () => Promise.resolve(rows) }), +}); + +beforeEach(() => { + dbMock.select.mockReset(); + dbMock.insert.mockReset(); + dbMock.update.mockReset(); + dbMock.delete.mockReset(); + dbMock.transaction.mockReset(); + hashMock.mockReset(); + compareMock.mockReset(); + publishResumeUpdatedMock.mockReset(); + grantResumeAccessMock.mockReset(); + hasResumeAccessMock.mockReset(); + storageDeleteMock.mockReset(); + hashMock.mockResolvedValue("hashed-password"); + publishResumeUpdatedMock.mockResolvedValue(undefined); + storageDeleteMock.mockResolvedValue(true); +}); + +it("imports", () => { + expect(resumeService).toBeDefined(); +}); + +describe("update", () => { + it("throws RESUME_LOCKED when the pre-read reports the resume is locked", async () => { + dbMock.select.mockReturnValueOnce(createSelectChain([{ isLocked: true }])); + + await expect(resumeService.update({ id: "r1", userId: "u1", name: "New" })).rejects.toMatchObject({ + code: "RESUME_LOCKED", + }); + }); + + it("returns the updated row on success", async () => { + dbMock.select.mockReturnValueOnce(createSelectChain([{ isLocked: false }])); + const row = { + id: "r1", + name: "New", + slug: "slug", + tags: [], + data: {}, + isPublic: false, + isLocked: false, + updatedAt: new Date("2026-01-01T00:00:00Z"), + hasPassword: false, + }; + dbMock.update.mockReturnValueOnce(createUpdateChain([row]).chain); + + const result = await resumeService.update({ id: "r1", userId: "u1", name: "New" }); + + expect(result).toEqual(row); + expect(publishResumeUpdatedMock).toHaveBeenCalledTimes(1); + }); + + it("throws NOT_FOUND when the UPDATE ... RETURNING matches no row", async () => { + dbMock.select.mockReturnValueOnce(createSelectChain([{ isLocked: false }])); + dbMock.update.mockReturnValueOnce(createUpdateChain([]).chain); + + await expect(resumeService.update({ id: "r1", userId: "u1", name: "New" })).rejects.toMatchObject({ + code: "NOT_FOUND", + }); + }); + + it("maps a resume_slug_user_id_unique violation to RESUME_SLUG_ALREADY_EXISTS", async () => { + dbMock.select.mockReturnValueOnce(createSelectChain([{ isLocked: false }])); + dbMock.update.mockReturnValueOnce({ + set: () => ({ + where: () => ({ + returning: () => { + const error = new Error("duplicate key") as Error & { cause: { constraint: string } }; + error.cause = { constraint: "resume_slug_user_id_unique" }; + return Promise.reject(error); + }, + }), + }), + }); + + await expect(resumeService.update({ id: "r1", userId: "u1", slug: "taken" })).rejects.toMatchObject({ + code: "RESUME_SLUG_ALREADY_EXISTS", + }); + }); +}); + +describe("setLocked", () => { + it("resolves and notifies on success (mutation: lock)", async () => { + dbMock.update.mockReturnValueOnce( + createUpdateChain([{ id: "r1", updatedAt: new Date("2026-01-01T00:00:00Z") }]).chain, + ); + + await expect(resumeService.setLocked({ id: "r1", userId: "u1", isLocked: true })).resolves.toBeUndefined(); + + expect(publishResumeUpdatedMock).toHaveBeenCalledTimes(1); + expect(publishResumeUpdatedMock).toHaveBeenCalledWith(expect.objectContaining({ mutation: "lock" })); + }); + + // Plan 003: no matching row now rejects with NOT_FOUND (previously a silent resolve). + it("throws NOT_FOUND when no row matches, without notifying", async () => { + dbMock.update.mockReturnValueOnce(createUpdateChain([]).chain); + + await expect(resumeService.setLocked({ id: "r1", userId: "u1", isLocked: true })).rejects.toMatchObject({ + code: "NOT_FOUND", + }); + expect(publishResumeUpdatedMock).not.toHaveBeenCalled(); + }); +}); + +describe("setPassword", () => { + it("hashes the password then resolves and notifies on success (mutation: password)", async () => { + dbMock.update.mockReturnValueOnce( + createUpdateChain([{ id: "r1", updatedAt: new Date("2026-01-01T00:00:00Z") }]).chain, + ); + + await expect(resumeService.setPassword({ id: "r1", userId: "u1", password: "secret" })).resolves.toBeUndefined(); + + expect(hashMock).toHaveBeenCalledWith("secret", 10); + expect(publishResumeUpdatedMock).toHaveBeenCalledTimes(1); + expect(publishResumeUpdatedMock).toHaveBeenCalledWith(expect.objectContaining({ mutation: "password" })); + }); + + // Plan 003: no matching row now rejects with NOT_FOUND (previously a silent resolve). + it("throws NOT_FOUND when no row matches, without notifying", async () => { + dbMock.update.mockReturnValueOnce(createUpdateChain([]).chain); + + await expect(resumeService.setPassword({ id: "r1", userId: "u1", password: "secret" })).rejects.toMatchObject({ + code: "NOT_FOUND", + }); + expect(publishResumeUpdatedMock).not.toHaveBeenCalled(); + }); +}); + +describe("removePassword", () => { + it("resolves and notifies on success (mutation: password)", async () => { + dbMock.update.mockReturnValueOnce( + createUpdateChain([{ id: "r1", updatedAt: new Date("2026-01-01T00:00:00Z") }]).chain, + ); + + await expect(resumeService.removePassword({ id: "r1", userId: "u1" })).resolves.toBeUndefined(); + + expect(publishResumeUpdatedMock).toHaveBeenCalledTimes(1); + expect(publishResumeUpdatedMock).toHaveBeenCalledWith(expect.objectContaining({ mutation: "password" })); + }); + + // Plan 003: no matching row now rejects with NOT_FOUND (previously a silent resolve). + it("throws NOT_FOUND when no row matches, without notifying", async () => { + dbMock.update.mockReturnValueOnce(createUpdateChain([]).chain); + + await expect(resumeService.removePassword({ id: "r1", userId: "u1" })).rejects.toMatchObject({ + code: "NOT_FOUND", + }); + expect(publishResumeUpdatedMock).not.toHaveBeenCalled(); + }); +}); + +describe("verifyPassword", () => { + it("throws INVALID_PASSWORD when no matching row is found", async () => { + dbMock.select.mockReturnValueOnce({ + from: () => ({ innerJoin: () => ({ where: () => Promise.resolve([]) }) }), + }); + + await expect(resumeService.verifyPassword({ slug: "s", username: "u", password: "p" })).rejects.toMatchObject({ + code: "INVALID_PASSWORD", + }); + }); + + it("throws INVALID_PASSWORD when bcrypt.compare returns false", async () => { + dbMock.select.mockReturnValueOnce({ + from: () => ({ innerJoin: () => ({ where: () => Promise.resolve([{ id: "r1", password: "hash" }]) }) }), + }); + compareMock.mockResolvedValueOnce(false); + + await expect(resumeService.verifyPassword({ slug: "s", username: "u", password: "p" })).rejects.toMatchObject({ + code: "INVALID_PASSWORD", + }); + }); + + it("returns true and grants access when bcrypt.compare returns true", async () => { + dbMock.select.mockReturnValueOnce({ + from: () => ({ innerJoin: () => ({ where: () => Promise.resolve([{ id: "r1", password: "hash" }]) }) }), + }); + compareMock.mockResolvedValueOnce(true); + const responseHeaders = new Headers(); + + const result = await resumeService.verifyPassword({ + slug: "s", + username: "u", + password: "p", + responseHeaders, + }); + + expect(result).toBe(true); + expect(grantResumeAccessMock).toHaveBeenCalledWith(responseHeaders, "r1", "hash"); + }); +}); + +describe("delete", () => { + const runTransaction = (tx: unknown) => { + dbMock.transaction.mockImplementationOnce(async (cb: (tx: unknown) => Promise) => cb(tx)); + }; + + it("throws NOT_FOUND when the row is missing", async () => { + runTransaction({ + select: () => createSelectChain([]), + }); + + await expect(resumeService.delete({ id: "r1", userId: "u1" })).rejects.toMatchObject({ code: "NOT_FOUND" }); + }); + + it("throws RESUME_LOCKED when the row is locked", async () => { + runTransaction({ + select: () => createSelectChain([{ isLocked: true }]), + }); + + await expect(resumeService.delete({ id: "r1", userId: "u1" })).rejects.toMatchObject({ + code: "RESUME_LOCKED", + }); + }); + + it("deletes storage for screenshot and pdf keys on success", async () => { + const deleteWhere = vi.fn(() => Promise.resolve()); + runTransaction({ + select: () => createSelectChain([{ isLocked: false }]), + delete: () => ({ where: deleteWhere }), + }); + + await resumeService.delete({ id: "r1", userId: "u1" }); + + expect(deleteWhere).toHaveBeenCalledTimes(1); + expect(storageDeleteMock).toHaveBeenCalledWith("uploads/u1/screenshots/r1"); + expect(storageDeleteMock).toHaveBeenCalledWith("uploads/u1/pdfs/r1"); + expect(publishResumeUpdatedMock).toHaveBeenCalledWith(expect.objectContaining({ mutation: "delete" })); + }); +}); + +describe("statistics.increment", () => { + it("writes both resumeStatistics and resumeStatisticsDaily inside one transaction", async () => { + const values = vi.fn(() => ({ onConflictDoUpdate: vi.fn(() => Promise.resolve()) })); + const txInsert = vi.fn(() => ({ values })); + dbMock.transaction.mockImplementationOnce(async (cb: (tx: unknown) => Promise) => + cb({ insert: txInsert }), + ); + + await resumeService.statistics.increment({ id: "r1", views: true }); + + expect(dbMock.transaction).toHaveBeenCalledTimes(1); + expect(txInsert).toHaveBeenCalledTimes(2); + }); +}); diff --git a/packages/api/src/features/resume/service.ts b/packages/api/src/features/resume/service.ts index 36d847f49..909b13259 100644 --- a/packages/api/src/features/resume/service.ts +++ b/packages/api/src/features/resume/service.ts @@ -17,6 +17,7 @@ import { getStorageService } from "../storage/service"; import { grantResumeAccess, hasResumeAccess } from "./access"; import { assertCanView, isOwner, redactResumeForViewer, shouldCountForStatistics } from "./access-policy"; import { publishResumeUpdated } from "./events"; +import { clientKeyFromHeaders, shouldCountView } from "./view-dedup"; type DbOrTx = typeof db | Parameters[0]>[0]; @@ -503,7 +504,10 @@ export const resumeService = { } if (shouldCountForStatistics(resume, viewer)) { - await resumeService.statistics.increment({ id: resume.id, views: true }); + const key = `${resume.id}:${clientKeyFromHeaders(input.requestHeaders)}`; + if (shouldCountView(key, Date.now())) { + await resumeService.statistics.increment({ id: resume.id, views: true }); + } } return toSharedResumeResponse(redactResumeForViewer(resume, isOwner(resume, viewer)), resume.hasPassword); @@ -667,7 +671,7 @@ export const resumeService = { .where(and(eq(schema.resume.id, input.id), eq(schema.resume.userId, input.userId))) .returning({ id: schema.resume.id, updatedAt: schema.resume.updatedAt }); - if (!resume) return; + if (!resume) throw new ORPCError("NOT_FOUND"); await notifyResumeUpdated({ type: "resume.updated", @@ -687,7 +691,7 @@ export const resumeService = { .where(and(eq(schema.resume.id, input.id), eq(schema.resume.userId, input.userId))) .returning({ id: schema.resume.id, updatedAt: schema.resume.updatedAt }); - if (!resume) return; + if (!resume) throw new ORPCError("NOT_FOUND"); await notifyResumeUpdated({ type: "resume.updated", @@ -730,7 +734,7 @@ export const resumeService = { .where(and(eq(schema.resume.id, input.id), eq(schema.resume.userId, input.userId))) .returning({ id: schema.resume.id, updatedAt: schema.resume.updatedAt }); - if (!resume) return; + if (!resume) throw new ORPCError("NOT_FOUND"); await notifyResumeUpdated({ type: "resume.updated", diff --git a/packages/api/src/features/resume/view-dedup.test.ts b/packages/api/src/features/resume/view-dedup.test.ts new file mode 100644 index 000000000..a823689c7 --- /dev/null +++ b/packages/api/src/features/resume/view-dedup.test.ts @@ -0,0 +1,53 @@ +import { describe, expect, it } from "vitest"; +import { clientKeyFromHeaders, shouldCountView } from "./view-dedup"; + +// `seen` is module-level state shared across tests, so each test uses a unique key. +const WINDOW_MS = 60 * 60 * 1000; + +describe("shouldCountView", () => { + it("counts the first view, skips repeats within the window, counts again after it", () => { + const key = "resume-1:viewer-a"; + const t0 = 1_000_000; + + expect(shouldCountView(key, t0)).toBe(true); + expect(shouldCountView(key, t0 + 1)).toBe(false); + expect(shouldCountView(key, t0 + WINDOW_MS - 1)).toBe(false); + // Once now is past the window, the same key counts again. + expect(shouldCountView(key, t0 + WINDOW_MS + 1)).toBe(true); + }); + + it("treats different keys independently", () => { + const t0 = 2_000_000; + + expect(shouldCountView("resume-2:viewer-a", t0)).toBe(true); + expect(shouldCountView("resume-2:viewer-b", t0)).toBe(true); + expect(shouldCountView("resume-2:viewer-a", t0 + 1)).toBe(false); + }); +}); + +describe("clientKeyFromHeaders", () => { + it("derives distinct keys from distinct trusted-IP headers", () => { + const a = clientKeyFromHeaders(new Headers({ "X-Forwarded-For": "1.1.1.1" })); + const b = clientKeyFromHeaders(new Headers({ "X-Forwarded-For": "2.2.2.2" })); + + expect(a).toBe("ip:1.1.1.1"); + expect(a).not.toBe(b); + }); + + it("uses the first IP from a comma-delimited proxy chain", () => { + const key = clientKeyFromHeaders(new Headers({ "X-Forwarded-For": "3.3.3.3, 10.0.0.1" })); + expect(key).toBe("ip:3.3.3.3"); + }); + + it("falls back to a stable user-agent fingerprint when no trusted IP header is present", () => { + const headers = new Headers({ "user-agent": "Mozilla/5.0", "accept-language": "en-US,en" }); + + const first = clientKeyFromHeaders(headers); + const second = clientKeyFromHeaders(headers); + + expect(first).toBe(second); + expect(first.startsWith("fp:")).toBe(true); + // A different UA yields a different fallback key. + expect(clientKeyFromHeaders(new Headers({ "user-agent": "curl/8" }))).not.toBe(first); + }); +}); diff --git a/packages/api/src/features/resume/view-dedup.ts b/packages/api/src/features/resume/view-dedup.ts new file mode 100644 index 000000000..a699931a7 --- /dev/null +++ b/packages/api/src/features/resume/view-dedup.ts @@ -0,0 +1,45 @@ +import { TRUSTED_IP_HEADERS } from "@reactive-resume/utils/rate-limit"; + +// ponytail: in-memory per-process dedup window. Single-instance is the default deploy; for +// multi-instance, swap the Map for a Redis SETNX+EXPIRE keyed the same way (REDIS_URL already +// exists in env). Upgrade only if you scale out — each instance dedups independently otherwise. +const WINDOW_MS = 60 * 60 * 1000; // 1 hour +const MAX_ENTRIES = 50_000; // bound the Map; prune expired entries before growing past this. + +const seen = new Map(); // key -> expiry timestamp + +/** + * Returns `true` at most once per `key` per window. `now` is a parameter (not `Date.now()`) + * so callers stay testable with a driven clock. + */ +export function shouldCountView(key: string, now: number): boolean { + const expiry = seen.get(key); + if (expiry !== undefined && expiry > now) return false; + + if (seen.size >= MAX_ENTRIES) { + for (const [k, exp] of seen) { + if (exp <= now) seen.delete(k); + } + } + + seen.set(key, now + WINDOW_MS); + return true; +} + +// Mirrors the rate-limit middleware's client-key derivation so dedup and rate limiting agree on +// "who is this viewer": trusted proxy IP first, then a user-agent + language fingerprint fallback. +export function clientKeyFromHeaders(headers: Headers): string { + for (const headerName of TRUSTED_IP_HEADERS) { + const raw = headers.get(headerName)?.trim(); + if (!raw) continue; + + // Some proxies provide a comma-delimited chain; the first item is the original client. + const ip = raw.split(",")[0]?.trim(); + if (ip) return `ip:${ip}`; + } + + const userAgent = headers.get("user-agent")?.trim() ?? "unknown"; + const language = headers.get("accept-language")?.split(",")[0]?.trim() ?? "none"; + + return `fp:${userAgent.slice(0, 64)}:${language.slice(0, 16)}`; +} diff --git a/packages/auth/package.json b/packages/auth/package.json index 0f2fdb914..52557ddc9 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -17,7 +17,7 @@ "dependencies": { "@better-auth/api-key": "^1.6.23", "@better-auth/drizzle-adapter": "^1.6.23", - "@better-auth/infra": "^0.3.4", + "@better-auth/infra": "^0.3.5", "@better-auth/oauth-provider": "^1.6.23", "@better-auth/passkey": "^1.6.23", "@reactive-resume/db": "workspace:*", @@ -34,7 +34,7 @@ "@reactive-resume/config": "workspace:*", "@types/bcrypt": "^6.0.0", "@types/react": "^19.2.17", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/packages/db/package.json b/packages/db/package.json index aaba4fead..38b558b82 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -31,8 +31,8 @@ "devDependencies": { "@reactive-resume/config": "workspace:*", "@types/pg": "^8.20.0", - "@typescript/native-preview": "7.0.0-dev.20260705.1", + "@typescript/native-preview": "7.0.0-dev.20260707.2", "drizzle-kit": "1.0.0-rc.4", - "typescript": "^6.0.3" + "typescript": "^7.0.2" } } diff --git a/packages/docx/package.json b/packages/docx/package.json index a2d854cf1..932027f83 100644 --- a/packages/docx/package.json +++ b/packages/docx/package.json @@ -20,7 +20,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/packages/email/package.json b/packages/email/package.json index a9bb27de2..b6c1514e0 100644 --- a/packages/email/package.json +++ b/packages/email/package.json @@ -19,14 +19,14 @@ "@reactive-resume/env": "workspace:*", "nodemailer": "^9.0.3", "react": "^19.2.7", - "react-email": "^6.6.6" + "react-email": "^6.6.8" }, "devDependencies": { - "@react-email/ui": "^6.6.6", + "@react-email/ui": "^6.6.8", "@reactive-resume/config": "workspace:*", "@types/nodemailer": "^8.0.1", "@types/react": "^19.2.17", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/packages/env/package.json b/packages/env/package.json index 0c8539b62..b784a9489 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -20,8 +20,8 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@types/node": "^26.1.0", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@types/node": "^26.1.1", + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/packages/fonts/package.json b/packages/fonts/package.json index 96410a6fe..7f74cb2b6 100644 --- a/packages/fonts/package.json +++ b/packages/fonts/package.json @@ -19,7 +19,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/packages/import/package.json b/packages/import/package.json index 8c2de6442..9390fee61 100644 --- a/packages/import/package.json +++ b/packages/import/package.json @@ -23,7 +23,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/packages/mcp/package.json b/packages/mcp/package.json index cd4dd1960..84f4ce4c4 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@modelcontextprotocol/sdk": "^1.29.0", - "@orpc/server": "^1.14.6", + "@orpc/server": "^1.14.7", "@reactive-resume/ai": "workspace:*", "@reactive-resume/api": "workspace:*", "@reactive-resume/env": "workspace:*", @@ -29,8 +29,8 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3", - "vitest": "^4.1.9" + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2", + "vitest": "^4.1.10" } } diff --git a/packages/pdf/package.json b/packages/pdf/package.json index 7fc307f85..df13b3bf1 100644 --- a/packages/pdf/package.json +++ b/packages/pdf/package.json @@ -25,7 +25,7 @@ "@reactive-resume/schema": "workspace:*", "@reactive-resume/utils": "workspace:*", "cjk-regex": "^3.4.0", - "node-html-parser": "^8.0.4", + "node-html-parser": "^9.0.0", "phosphor-icons-react-pdf": "^0.1.3", "react": "^19.2.7", "react-pdf-html": "^2.1.5" @@ -34,7 +34,7 @@ "@react-pdf/types": "^2.11.1", "@reactive-resume/config": "workspace:*", "@types/react": "^19.2.17", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/packages/pdf/src/browser.tsx b/packages/pdf/src/browser.tsx index b87b16c96..437644b54 100644 --- a/packages/pdf/src/browser.tsx +++ b/packages/pdf/src/browser.tsx @@ -1,5 +1,6 @@ import type { ResumeData } from "@reactive-resume/schema/resume/data"; import type { Template } from "@reactive-resume/schema/templates"; +import type { ResumeRenderOptions } from "./context"; import type { SectionTitleResolver } from "./section-title"; import { createElement } from "react"; import { pdf } from "#react-pdf-renderer"; @@ -8,13 +9,20 @@ import { ResumeDocument } from "./document"; type CreateResumePdfBlobOptions = { data: ResumeData; template?: Template | undefined; + renderOptions?: ResumeRenderOptions | undefined; resolveSectionTitle?: SectionTitleResolver | undefined; }; -export const createResumePdfBlob = async ({ data, template, resolveSectionTitle }: CreateResumePdfBlobOptions) => { +export const createResumePdfBlob = async ({ + data, + template, + renderOptions, + resolveSectionTitle, +}: CreateResumePdfBlobOptions) => { const document = createElement(ResumeDocument, { data, template: template ?? data.metadata.template, + ...(renderOptions ? { renderOptions } : {}), resolveSectionTitle, }) as Parameters[0]; diff --git a/packages/pdf/src/context.tsx b/packages/pdf/src/context.tsx index 35d6913ea..83b4ebb9b 100644 --- a/packages/pdf/src/context.tsx +++ b/packages/pdf/src/context.tsx @@ -4,24 +4,36 @@ import type { SectionTitleResolver } from "./section-title"; import { createContext, use, useMemo } from "react"; import { isRTL } from "@reactive-resume/utils/locale"; +export type ResumeRenderOptions = { + includeCoverLetterHeader?: boolean; +}; + type RenderContextValue = ResumeData & { resolveSectionTitle?: SectionTitleResolver | undefined; + renderOptions: ResumeRenderOptions; rtl: boolean; }; const RenderContext = createContext(null); +const defaultRenderOptions: ResumeRenderOptions = {}; type RenderProviderProps = { data: ResumeData; resolveSectionTitle?: SectionTitleResolver | undefined; + renderOptions?: ResumeRenderOptions | undefined; children: ReactNode; }; -export const RenderProvider = ({ data, resolveSectionTitle, children }: RenderProviderProps) => { +export const RenderProvider = ({ + data, + resolveSectionTitle, + renderOptions = defaultRenderOptions, + children, +}: RenderProviderProps) => { const rtl = isRTL(data.metadata.page.locale); const contextValue = useMemo( - () => ({ ...data, resolveSectionTitle, rtl }), - [data, resolveSectionTitle, rtl], + () => ({ ...data, resolveSectionTitle, renderOptions, rtl }), + [data, resolveSectionTitle, renderOptions, rtl], ); return {children}; diff --git a/packages/pdf/src/document.tsx b/packages/pdf/src/document.tsx index b1e6a6b83..b420b3934 100644 --- a/packages/pdf/src/document.tsx +++ b/packages/pdf/src/document.tsx @@ -2,6 +2,7 @@ import type { LayoutPage, ResumeData, Typography } from "@reactive-resume/schema import type { Template } from "@reactive-resume/schema/templates"; import type { Locale } from "@reactive-resume/utils/locale"; import type { ComponentType } from "react"; +import type { ResumeRenderOptions } from "./context"; import type { SectionTitleResolver } from "./section-title"; import { useMemo } from "react"; import { Document } from "#react-pdf-renderer"; @@ -19,13 +20,14 @@ export type TemplatePage = ComponentType; type ResumeDocumentProps = { data: ResumeData; template: Template; + renderOptions?: ResumeRenderOptions | undefined; resolveSectionTitle?: SectionTitleResolver | undefined; }; const getLayoutPageKey = (page: LayoutPage, pageIndex: number) => `${page.fullWidth ? "full" : "split"}:${page.main.join(",")}:${page.sidebar.join(",")}:${pageIndex}`; -export const ResumeDocument = ({ data, template, resolveSectionTitle }: ResumeDocumentProps) => { +export const ResumeDocument = ({ data, template, renderOptions, resolveSectionTitle }: ResumeDocumentProps) => { const TemplatePageComponent = getTemplatePage(template); const creationDate = useMemo(() => new Date(), []); const hasCjkContent = useMemo(() => resumeContentContainsCJK(data), [data]); @@ -43,7 +45,7 @@ export const ResumeDocument = ({ data, template, resolveSectionTitle }: ResumeDo const resumeData = useMemo(() => ({ ...data, metadata: { ...data.metadata, typography } }), [data, typography]); return ( - + { expect(shouldShowResumeHeader(createCoverLetterOnlyData(), 0)).toBe(false); }); + it("can keep the first-page header for cover letter documents", () => { + const data = { ...createCoverLetterOnlyData(), renderOptions: { includeCoverLetterHeader: true } }; + + expect(shouldShowResumeHeader(data, 0)).toBe(true); + expect(shouldShowResumeHeader(data, 1)).toBe(false); + }); + it("keeps the first-page header for normal resume documents", () => { expect(shouldShowResumeHeader(sampleResumeData, 0)).toBe(true); expect(shouldShowResumeHeader(sampleResumeData, 1)).toBe(false); diff --git a/packages/pdf/src/templates/shared/cover-letter.ts b/packages/pdf/src/templates/shared/cover-letter.ts index 8d580a5fe..3331ebd54 100644 --- a/packages/pdf/src/templates/shared/cover-letter.ts +++ b/packages/pdf/src/templates/shared/cover-letter.ts @@ -1,6 +1,11 @@ import type { ResumeData } from "@reactive-resume/schema/resume/data"; +import type { ResumeRenderOptions } from "../../context"; import { filterSections } from "./filtering"; +type HeaderResumeData = ResumeData & { + renderOptions?: ResumeRenderOptions; +}; + const isCoverLetterSection = (data: ResumeData, sectionId: string) => data.customSections.some((section) => section.id === sectionId && section.type === "cover-letter"); @@ -12,5 +17,5 @@ const isCoverLetterOnlyDocument = (data: ResumeData) => { return visibleSections.length > 0 && visibleSections.every((sectionId) => isCoverLetterSection(data, sectionId)); }; -export const shouldShowResumeHeader = (data: ResumeData, pageIndex: number) => - pageIndex === 0 && !isCoverLetterOnlyDocument(data); +export const shouldShowResumeHeader = (data: HeaderResumeData, pageIndex: number) => + pageIndex === 0 && (data.renderOptions?.includeCoverLetterHeader || !isCoverLetterOnlyDocument(data)); diff --git a/packages/resume/package.json b/packages/resume/package.json index b8499d771..a786e628c 100644 --- a/packages/resume/package.json +++ b/packages/resume/package.json @@ -23,7 +23,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/packages/schema/package.json b/packages/schema/package.json index 136951e30..d34974e9f 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -22,7 +22,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/packages/ui/package.json b/packages/ui/package.json index 00adfe48d..73877d7c7 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -23,7 +23,7 @@ "@phosphor-icons/react": "^2.1.10", "@phosphor-icons/web": "^2.1.2", "@reactive-resume/utils": "workspace:*", - "@shadcn/react": "^0.2.0", + "@shadcn/react": "^0.2.1", "class-variance-authority": "^0.7.1", "cmdk": "^1.1.1", "next-themes": "^0.4.6", @@ -40,9 +40,9 @@ "@tailwindcss/typography": "^0.5.20", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", - "@typescript/native-preview": "7.0.0-dev.20260705.1", + "@typescript/native-preview": "7.0.0-dev.20260707.2", "postcss": "^8.5.16", "tailwindcss": "^4.3.2", - "typescript": "^6.0.3" + "typescript": "^7.0.2" } } diff --git a/packages/utils/package.json b/packages/utils/package.json index 42ee6444f..2e411275b 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -32,8 +32,8 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@types/node": "^26.1.0", - "@typescript/native-preview": "7.0.0-dev.20260705.1", - "typescript": "^6.0.3" + "@types/node": "^26.1.1", + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "typescript": "^7.0.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1fdf02d4c..33f0eff80 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,11 +19,11 @@ importers: .: devDependencies: '@biomejs/biome': - specifier: ^2.5.2 - version: 2.5.2 + specifier: ^2.5.3 + version: 2.5.3 '@commitlint/cli': - specifier: ^21.2.0 - version: 21.2.0(@types/node@26.1.0)(conventional-commits-parser@6.4.0)(typescript@6.0.3) + specifier: ^21.2.1 + version: 21.2.1(@types/node@26.1.1)(conventional-commits-parser@7.0.1)(typescript@7.0.2) '@commitlint/config-conventional': specifier: ^21.2.0 version: 21.2.0 @@ -46,14 +46,14 @@ importers: specifier: ^14.6.1 version: 14.6.1(@testing-library/dom@10.4.1) '@types/node': - specifier: ^26.1.0 - version: 26.1.0 + specifier: ^26.1.1 + version: 26.1.1 '@types/pg': specifier: ^8.20.0 version: 8.20.0 '@vitest/coverage-v8': - specifier: ^4.1.9 - version: 4.1.9(vitest@4.1.9) + specifier: ^4.1.10 + version: 4.1.10(vitest@4.1.10) github-actionlint: specifier: 1.7.12 version: 1.7.12 @@ -61,11 +61,11 @@ importers: specifier: ^20.10.6 version: 20.10.6 knip: - specifier: ^6.24.0 - version: 6.24.0 + specifier: ^6.25.0 + version: 6.25.0 lefthook: - specifier: ^2.1.9 - version: 2.1.9 + specifier: ^2.1.10 + version: 2.1.10 markdownlint-cli2: specifier: 0.23.0 version: 0.23.0 @@ -73,71 +73,98 @@ importers: specifier: ^8.22.0 version: 8.22.0 turbo: - specifier: ^2.10.3 - version: 2.10.3 + specifier: ^2.10.4 + version: 2.10.4 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 vitest: - specifier: ^4.1.9 - version: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@26.1.0)(@vitest/coverage-v8@4.1.9)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.0)(typescript@6.0.3))(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + specifier: ^4.1.10 + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) apps/server: dependencies: '@ai-sdk/anthropic': - specifier: ^4.0.8 - version: 4.0.8(zod@4.4.3) + specifier: ^4.0.10 + version: 4.0.10(zod@4.4.3) + '@ai-sdk/cerebras': + specifier: ^3.0.6 + version: 3.0.6(zod@4.4.3) + '@ai-sdk/cohere': + specifier: ^4.0.6 + version: 4.0.6(zod@4.4.3) + '@ai-sdk/deepseek': + specifier: ^3.0.6 + version: 3.0.6(zod@4.4.3) + '@ai-sdk/fireworks': + specifier: ^3.0.7 + version: 3.0.7(zod@4.4.3) '@ai-sdk/google': - specifier: ^4.0.8 - version: 4.0.8(zod@4.4.3) - '@ai-sdk/openai': + specifier: ^4.0.10 + version: 4.0.10(zod@4.4.3) + '@ai-sdk/groq': + specifier: ^4.0.6 + version: 4.0.6(zod@4.4.3) + '@ai-sdk/mistral': specifier: ^4.0.7 version: 4.0.7(zod@4.4.3) + '@ai-sdk/openai': + specifier: ^4.0.9 + version: 4.0.9(zod@4.4.3) '@ai-sdk/openai-compatible': - specifier: ^3.0.5 - version: 3.0.5(zod@4.4.3) + specifier: ^3.0.6 + version: 3.0.6(zod@4.4.3) + '@ai-sdk/perplexity': + specifier: ^4.0.7 + version: 4.0.7(zod@4.4.3) + '@ai-sdk/togetherai': + specifier: ^3.0.7 + version: 3.0.7(zod@4.4.3) + '@ai-sdk/xai': + specifier: ^4.0.9 + version: 4.0.9(zod@4.4.3) '@aws-sdk/client-s3': - specifier: ^3.1079.0 - version: 3.1079.0 + specifier: ^3.1081.0 + version: 3.1081.0 '@better-auth/api-key': specifier: ^1.6.23 - version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3)) + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3)) '@better-auth/drizzle-adapter': specifier: ^1.6.23 - version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3)) + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3)) '@better-auth/infra': - specifier: ^0.3.4 - version: 0.3.4(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(zod@4.4.3) + specifier: ^0.3.5 + version: 0.3.5(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(zod@4.4.3) '@better-auth/oauth-provider': specifier: ^1.6.23 - version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3)) + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3)) '@better-auth/passkey': specifier: ^1.6.23 - version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3))(nanostores@1.4.0) + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3))(nanostores@1.4.0) '@hono/node-server': specifier: ^2.0.8 - version: 2.0.8(hono@4.12.27) + version: 2.0.8(hono@4.12.28) '@modelcontextprotocol/sdk': specifier: ^1.29.0 version: 1.29.0(zod@4.4.3) '@orpc/client': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1) '@orpc/experimental-ratelimit': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) '@orpc/json-schema': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) '@orpc/openapi': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) '@orpc/server': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) '@orpc/zod': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1)(@orpc/contract@1.14.6(@opentelemetry/api@1.9.1))(@orpc/server@1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0))(ws@8.21.0)(zod@4.4.3) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1)(@orpc/contract@1.14.7(@opentelemetry/api@1.9.1))(@orpc/server@1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0))(ws@8.21.0)(zod@4.4.3) '@react-pdf/renderer': specifier: ^4.5.1 version: 4.5.1(react@19.2.7) @@ -167,19 +194,19 @@ importers: version: 3.0.0 '@t3-oss/env-core': specifier: ^0.13.11 - version: 0.13.11(typescript@6.0.3)(zod@4.4.3) + version: 0.13.11(typescript@7.0.2)(zod@4.4.3) '@uiw/color-convert': specifier: ^2.10.3 version: 2.10.3(@babel/runtime@7.29.7) ai: - specifier: ^7.0.15 - version: 7.0.15(zod@4.4.3) + specifier: ^7.0.18 + version: 7.0.18(zod@4.4.3) bcrypt: specifier: ^6.0.0 version: 6.0.0 better-auth: specifier: 1.6.23 - version: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9) + version: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10) cjk-regex: specifier: ^3.4.0 version: 3.4.0 @@ -199,20 +226,20 @@ importers: specifier: ^3.1.1 version: 3.1.1 hono: - specifier: ^4.12.27 - version: 4.12.27 + specifier: ^4.12.28 + version: 4.12.28 jsonrepair: specifier: ^3.15.0 version: 3.15.0 node-html-parser: - specifier: ^8.0.4 - version: 8.0.4 + specifier: ^9.0.0 + version: 9.0.0 nodemailer: specifier: ^9.0.3 version: 9.0.3 ollama-ai-provider-v2: - specifier: ^3.6.0 - version: 3.6.0(ai@7.0.15(zod@4.4.3))(zod@4.4.3) + specifier: ^4.0.1 + version: 4.0.1(ai@7.0.18(zod@4.4.3))(zod@4.4.3) pg: specifier: ^8.22.0 version: 8.22.0 @@ -223,8 +250,8 @@ importers: specifier: ^19.2.7 version: 19.2.7 react-email: - specifier: ^6.6.6 - version: 6.6.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: ^6.6.8 + version: 6.6.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react-pdf-html: specifier: ^2.1.5 version: 2.1.5(@react-pdf/renderer@4.5.1(react@19.2.7))(react@19.2.7) @@ -233,7 +260,7 @@ importers: version: 2.2.12 sharp: specifier: ^0.35.3 - version: 0.35.3(@types/node@26.1.0) + version: 0.35.3(@types/node@26.1.1) ts-pattern: specifier: ^5.9.0 version: 5.9.0 @@ -251,8 +278,8 @@ importers: specifier: workspace:* version: link:../../packages/config '@types/node': - specifier: ^26.1.0 - version: 26.1.0 + specifier: ^26.1.1 + version: 26.1.1 '@types/pg': specifier: ^8.20.0 version: 8.20.0 @@ -260,41 +287,41 @@ importers: specifier: ^19.2.17 version: 19.2.17 '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 tsdown: - specifier: ^0.22.3 - version: 0.22.3(@typescript/native-preview@7.0.0-dev.20260705.1)(oxc-resolver@11.21.3)(tsx@4.23.0)(typescript@6.0.3) + specifier: ^0.22.4 + version: 0.22.4(@typescript/native-preview@7.0.0-dev.20260707.2)(oxc-resolver@11.21.3)(tsx@4.23.0)(typescript@7.0.2) tsx: specifier: ^4.23.0 version: 4.23.0 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 vitest: - specifier: ^4.1.9 - version: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@26.1.0)(@vitest/coverage-v8@4.1.9)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.0)(typescript@6.0.3))(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + specifier: ^4.1.10 + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) apps/web: dependencies: '@ai-sdk/react': - specifier: ^4.0.16 - version: 4.0.16(react@19.2.7)(zod@4.4.3) + specifier: ^4.0.19 + version: 4.0.19(react@19.2.7)(zod@4.4.3) '@base-ui/react': specifier: ^1.6.0 version: 1.6.0(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@better-auth/api-key': specifier: ^1.6.23 - version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3)) + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3)) '@better-auth/infra': - specifier: ^0.3.4 - version: 0.3.4(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(zod@4.4.3) + specifier: ^0.3.5 + version: 0.3.5(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(zod@4.4.3) '@better-auth/oauth-provider': specifier: ^1.6.23 - version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3)) + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3)) '@better-auth/passkey': specifier: ^1.6.23 - version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3))(nanostores@1.4.0) + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3))(nanostores@1.4.0) '@dnd-kit/core': specifier: ^6.3.1 version: 6.3.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -305,20 +332,20 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.2.7) '@lingui/core': - specifier: ^6.4.0 - version: 6.4.0(babel-plugin-macros@3.1.0) + specifier: ^6.5.0 + version: 6.5.0(babel-plugin-macros@3.1.0) '@lingui/react': - specifier: ^6.4.0 - version: 6.4.0(babel-plugin-macros@3.1.0)(react@19.2.7) + specifier: ^6.5.0 + version: 6.5.0(babel-plugin-macros@3.1.0)(react@19.2.7) '@orpc/client': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1) '@orpc/server': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) '@orpc/tanstack-query': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1)(@orpc/client@1.14.6(@opentelemetry/api@1.9.1))(@tanstack/query-core@5.101.2) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1)(@orpc/client@1.14.7(@opentelemetry/api@1.9.1))(@tanstack/query-core@5.101.2) '@phosphor-icons/react': specifier: ^2.1.10 version: 2.1.10(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -360,7 +387,7 @@ importers: version: link:../../packages/utils '@tailwindcss/vite': specifier: ^4.3.2 - version: 4.3.2(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + version: 4.3.2(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) '@tanstack/react-form': specifier: ^1.33.0 version: 1.33.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -374,26 +401,26 @@ importers: specifier: ^1.170.17 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tiptap/extension-color': - specifier: ^3.27.1 - version: 3.27.1(@tiptap/extension-text-style@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))) + specifier: ^3.27.3 + version: 3.27.3(@tiptap/extension-text-style@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))) '@tiptap/extension-highlight': - specifier: ^3.27.1 - version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + specifier: ^3.27.3 + version: 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) '@tiptap/extension-text-align': - specifier: ^3.27.1 - version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + specifier: ^3.27.3 + version: 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) '@tiptap/extension-text-style': - specifier: ^3.27.1 - version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + specifier: ^3.27.3 + version: 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) '@tiptap/pm': - specifier: ^3.27.1 - version: 3.27.1 + specifier: ^3.27.3 + version: 3.27.3 '@tiptap/react': - specifier: ^3.27.1 - version: 3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: ^3.27.3 + version: 3.27.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tiptap/starter-kit': - specifier: ^3.27.1 - version: 3.27.1 + specifier: ^3.27.3 + version: 3.27.3 '@types/js-cookie': specifier: ^3.0.6 version: 3.0.6 @@ -404,11 +431,11 @@ importers: specifier: ^2.10.3 version: 2.10.3(@babel/runtime@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) ai: - specifier: ^7.0.15 - version: 7.0.15(zod@4.4.3) + specifier: ^7.0.18 + version: 7.0.18(zod@4.4.3) better-auth: specifier: 1.6.23 - version: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9) + version: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10) cmdk: specifier: ^1.1.1 version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -446,8 +473,8 @@ importers: specifier: ^19.2.7 version: 19.2.7(react@19.2.7) react-easy-crop: - specifier: ^6.1.0 - version: 6.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: ^6.2.2 + version: 6.2.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react-markdown: specifier: ^10.1.0 version: 10.1.0(@types/react@19.2.17)(react@19.2.7) @@ -483,26 +510,26 @@ importers: specifier: ^8.0.1 version: 8.0.1 '@lingui/babel-plugin-lingui-macro': - specifier: ^6.4.0 - version: 6.4.0 + specifier: ^6.5.0 + version: 6.5.0 '@lingui/cli': - specifier: ^6.4.0 - version: 6.4.0(babel-plugin-macros@3.1.0) + specifier: ^6.5.0 + version: 6.5.0(babel-plugin-macros@3.1.0)(esbuild@0.28.1)(rolldown@1.1.5) '@lingui/format-po': - specifier: ^6.4.0 - version: 6.4.0 + specifier: ^6.5.0 + version: 6.5.0 '@lingui/vite-plugin': - specifier: ^6.4.0 - version: 6.4.0(@babel/core@8.0.1)(@lingui/babel-plugin-lingui-macro@6.4.0)(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)))(babel-plugin-macros@3.1.0)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + specifier: ^6.5.0 + version: 6.5.0(@babel/core@8.0.1)(@lingui/babel-plugin-lingui-macro@6.5.0)(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)))(babel-plugin-macros@3.1.0)(esbuild@0.28.1)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) '@reactive-resume/config': specifier: workspace:* version: link:../../packages/config '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) '@tanstack/devtools-vite': specifier: ^0.8.1 - version: 0.8.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + version: 0.8.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) '@tanstack/react-devtools': specifier: ^0.10.8 version: 0.10.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(csstype@3.2.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14) @@ -514,7 +541,7 @@ importers: version: 1.167.0(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@tanstack/router-core@1.171.14)(csstype@3.2.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tanstack/router-plugin': specifier: ^1.168.19 - version: 1.168.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + version: 1.168.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) '@types/babel__core': specifier: ^7.20.5 version: 7.20.5 @@ -528,11 +555,11 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.17) '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 '@vitejs/plugin-react': specifier: ^6.0.3 - version: 6.0.3(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + version: 6.0.3(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) babel-plugin-macros: specifier: ^3.1.0 version: 3.1.0 @@ -543,11 +570,11 @@ importers: specifier: ^6.1.3 version: 6.1.3 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 vite: specifier: ^8.1.3 - version: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) + version: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) packages/ai: dependencies: @@ -574,38 +601,65 @@ importers: specifier: workspace:* version: link:../config '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/api: dependencies: '@ai-sdk/anthropic': - specifier: ^4.0.8 - version: 4.0.8(zod@4.4.3) + specifier: ^4.0.10 + version: 4.0.10(zod@4.4.3) + '@ai-sdk/cerebras': + specifier: ^3.0.6 + version: 3.0.6(zod@4.4.3) + '@ai-sdk/cohere': + specifier: ^4.0.6 + version: 4.0.6(zod@4.4.3) + '@ai-sdk/deepseek': + specifier: ^3.0.6 + version: 3.0.6(zod@4.4.3) + '@ai-sdk/fireworks': + specifier: ^3.0.7 + version: 3.0.7(zod@4.4.3) '@ai-sdk/google': - specifier: ^4.0.8 - version: 4.0.8(zod@4.4.3) - '@ai-sdk/openai': + specifier: ^4.0.10 + version: 4.0.10(zod@4.4.3) + '@ai-sdk/groq': + specifier: ^4.0.6 + version: 4.0.6(zod@4.4.3) + '@ai-sdk/mistral': specifier: ^4.0.7 version: 4.0.7(zod@4.4.3) + '@ai-sdk/openai': + specifier: ^4.0.9 + version: 4.0.9(zod@4.4.3) '@ai-sdk/openai-compatible': - specifier: ^3.0.5 - version: 3.0.5(zod@4.4.3) + specifier: ^3.0.6 + version: 3.0.6(zod@4.4.3) + '@ai-sdk/perplexity': + specifier: ^4.0.7 + version: 4.0.7(zod@4.4.3) + '@ai-sdk/togetherai': + specifier: ^3.0.7 + version: 3.0.7(zod@4.4.3) + '@ai-sdk/xai': + specifier: ^4.0.9 + version: 4.0.9(zod@4.4.3) '@aws-sdk/client-s3': - specifier: ^3.1079.0 - version: 3.1079.0 + specifier: ^3.1081.0 + version: 3.1081.0 '@orpc/client': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1) '@orpc/experimental-ratelimit': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) '@orpc/server': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) '@reactive-resume/ai': specifier: workspace:* version: link:../ai @@ -631,14 +685,14 @@ importers: specifier: workspace:* version: link:../utils ai: - specifier: ^7.0.15 - version: 7.0.15(zod@4.4.3) + specifier: ^7.0.18 + version: 7.0.18(zod@4.4.3) bcrypt: specifier: ^6.0.0 version: 6.0.0 better-auth: specifier: 1.6.23 - version: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9) + version: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10) drizzle-orm: specifier: 1.0.0-rc.4 version: 1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3) @@ -652,8 +706,8 @@ importers: specifier: ^5.11.1 version: 5.11.1 ollama-ai-provider-v2: - specifier: ^3.6.0 - version: 3.6.0(ai@7.0.15(zod@4.4.3))(zod@4.4.3) + specifier: ^4.0.1 + version: 4.0.1(ai@7.0.18(zod@4.4.3))(zod@4.4.3) react: specifier: ^19.2.7 version: 19.2.7 @@ -662,7 +716,7 @@ importers: version: 2.2.12 sharp: specifier: ^0.35.3 - version: 0.35.3(@types/node@26.1.0) + version: 0.35.3(@types/node@26.1.1) ts-pattern: specifier: ^5.9.0 version: 5.9.0 @@ -677,29 +731,29 @@ importers: specifier: ^6.0.0 version: 6.0.0 '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/auth: dependencies: '@better-auth/api-key': specifier: ^1.6.23 - version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3)) + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3)) '@better-auth/drizzle-adapter': specifier: ^1.6.23 - version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3)) + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3)) '@better-auth/infra': - specifier: ^0.3.4 - version: 0.3.4(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(zod@4.4.3) + specifier: ^0.3.5 + version: 0.3.5(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(zod@4.4.3) '@better-auth/oauth-provider': specifier: ^1.6.23 - version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3)) + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3)) '@better-auth/passkey': specifier: ^1.6.23 - version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3))(nanostores@1.4.0) + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3))(nanostores@1.4.0) '@reactive-resume/db': specifier: workspace:* version: link:../db @@ -717,7 +771,7 @@ importers: version: 6.0.0 better-auth: specifier: 1.6.23 - version: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9) + version: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10) drizzle-orm: specifier: 1.0.0-rc.4 version: 1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3) @@ -738,11 +792,11 @@ importers: specifier: ^19.2.17 version: 19.2.17 '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/config: {} @@ -771,14 +825,14 @@ importers: specifier: ^8.20.0 version: 8.20.0 '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 drizzle-kit: specifier: 1.0.0-rc.4 version: 1.0.0-rc.4 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/docx: dependencies: @@ -796,11 +850,11 @@ importers: specifier: workspace:* version: link:../config '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/email: dependencies: @@ -814,12 +868,12 @@ importers: specifier: ^19.2.7 version: 19.2.7 react-email: - specifier: ^6.6.6 - version: 6.6.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: ^6.6.8 + version: 6.6.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) devDependencies: '@react-email/ui': - specifier: ^6.6.6 - version: 6.6.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: ^6.6.8 + version: 6.6.8(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@reactive-resume/config': specifier: workspace:* version: link:../config @@ -830,11 +884,11 @@ importers: specifier: ^19.2.17 version: 19.2.17 '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/env: dependencies: @@ -843,7 +897,7 @@ importers: version: link:../utils '@t3-oss/env-core': specifier: ^0.13.11 - version: 0.13.11(typescript@6.0.3)(zod@4.4.3) + version: 0.13.11(typescript@7.0.2)(zod@4.4.3) zod: specifier: ^4.4.3 version: 4.4.3 @@ -852,14 +906,14 @@ importers: specifier: workspace:* version: link:../config '@types/node': - specifier: ^26.1.0 - version: 26.1.0 + specifier: ^26.1.1 + version: 26.1.1 '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/fonts: dependencies: @@ -871,11 +925,11 @@ importers: specifier: workspace:* version: link:../config '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/import: dependencies: @@ -896,11 +950,11 @@ importers: specifier: workspace:* version: link:../config '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/mcp: dependencies: @@ -908,8 +962,8 @@ importers: specifier: ^1.29.0 version: 1.29.0(zod@4.4.3) '@orpc/server': - specifier: ^1.14.6 - version: 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) + specifier: ^1.14.7 + version: 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) '@reactive-resume/ai': specifier: workspace:* version: link:../ai @@ -930,14 +984,14 @@ importers: specifier: workspace:* version: link:../config '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 vitest: - specifier: ^4.1.9 - version: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@26.1.0)(@vitest/coverage-v8@4.1.9)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.0)(typescript@6.0.3))(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + specifier: ^4.1.10 + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) packages/pdf: dependencies: @@ -957,8 +1011,8 @@ importers: specifier: ^3.4.0 version: 3.4.0 node-html-parser: - specifier: ^8.0.4 - version: 8.0.4 + specifier: ^9.0.0 + version: 9.0.0 phosphor-icons-react-pdf: specifier: ^0.1.3 version: 0.1.3(@react-pdf/renderer@4.5.1(react@19.2.7))(react@19.2.7) @@ -979,11 +1033,11 @@ importers: specifier: ^19.2.17 version: 19.2.17 '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/resume: dependencies: @@ -1001,11 +1055,11 @@ importers: specifier: workspace:* version: link:../config '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/schema: dependencies: @@ -1017,11 +1071,11 @@ importers: specifier: workspace:* version: link:../config '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/ui: dependencies: @@ -1041,8 +1095,8 @@ importers: specifier: workspace:* version: link:../utils '@shadcn/react': - specifier: ^0.2.0 - version: 0.2.0(@types/react@19.2.17)(react@19.2.7) + specifier: ^0.2.1 + version: 0.2.1(@types/react@19.2.17)(react@19.2.7) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -1063,7 +1117,7 @@ importers: version: 4.12.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) shadcn: specifier: ^4.13.0 - version: 4.13.0(babel-plugin-macros@3.1.0)(typescript@6.0.3) + version: 4.13.0(babel-plugin-macros@3.1.0)(typescript@7.0.2) sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -1087,8 +1141,8 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.17) '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 postcss: specifier: ^8.5.16 version: 8.5.16 @@ -1096,8 +1150,8 @@ importers: specifier: ^4.3.2 version: 4.3.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 packages/utils: dependencies: @@ -1127,14 +1181,14 @@ importers: specifier: workspace:* version: link:../config '@types/node': - specifier: ^26.1.0 - version: 26.1.0 + specifier: ^26.1.1 + version: 26.1.1 '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 tooling: devDependencies: @@ -1148,8 +1202,8 @@ importers: specifier: ^8.20.0 version: 8.20.0 '@typescript/native-preview': - specifier: 7.0.0-dev.20260705.1 - version: 7.0.0-dev.20260705.1 + specifier: 7.0.0-dev.20260707.2 + version: 7.0.0-dev.20260707.2 drizzle-orm: specifier: 1.0.0-rc.4 version: 1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3) @@ -1165,130 +1219,174 @@ packages: '@adobe/css-tools@4.5.0': resolution: {integrity: sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==} - '@ai-sdk/anthropic@4.0.8': - resolution: {integrity: sha512-ZqT9kLxS2Cbo/4juwtEGbYyP0jNQTnUUKy2nQ8Vn28xqNu50+TukO/oCEWCpm18YbQq7N+hr6ClJs/ATTFpBTg==} + '@ai-sdk/anthropic@4.0.10': + resolution: {integrity: sha512-L9GlJyL8stPyv5QTRONnVoRVw82b6iBuX4LTiRJMM++I2RfDe+yrBsPa6gz6Msll9GZ7JsX0MRNUP4G1afjDTw==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/gateway@4.0.12': - resolution: {integrity: sha512-Y7Fy8xJwPz7ZC0DhSQG3HIVk+drup42hrIj6yqKlib3CxwiR0F7nYyUI8+kPrEtbZEoyKoRstvT4/o0HEyFBHA==} + '@ai-sdk/cerebras@3.0.6': + resolution: {integrity: sha512-QI02IBxolbJ9Ohk2ZKCiTzXN/hE1p0M5G1YVUIUiN/G/qafDtyyGcbiymuZsFiCEOWqTx+k9gYDR4MO+ksTsew==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/google@4.0.8': - resolution: {integrity: sha512-GELd0RkltieuODzr6tfnEOIufeooctYpGUNxujeh+zrChbHUkX2K6Li4h2EAfizctkY4k3JvC93dU9eh2QxzoQ==} + '@ai-sdk/cohere@4.0.6': + resolution: {integrity: sha512-ieK271Znc1T2KApGWE9oz65wx/9MVyy93VsJuZiUj43J71lkVn1K5aX3sEG/tFDB+MxaMN/ofbhI8gWRzoOYfw==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/mcp@2.0.7': - resolution: {integrity: sha512-DX1v5M/R4RD2yi1KSH2ERLKcb6h2qJF0DKt0PGTTpNJNK+meXMmouwSRZS8Y+JocbyHk7U9p6PgqVmKU/e5XhQ==} + '@ai-sdk/deepseek@3.0.6': + resolution: {integrity: sha512-mPX5fqMN6flScSq5XvU/Oli4r6GXRx57I7h/NVQSAHChzpZAl4bGirV3eEKCCR9pS65WVEc9iNI4w+hqrFBecQ==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai-compatible@3.0.5': - resolution: {integrity: sha512-4UtDxT6Ga7U225o5fBEgtCFZHba4/iTDXRqMrU62yEfTrFks4o+F4jt0D3OWmUasR9LPFzLy0KnEITxFDtc89g==} + '@ai-sdk/fireworks@3.0.7': + resolution: {integrity: sha512-dZaTQldheNVMaAZgKi9ZtOtxOEUpPYOWIwcZbrHRRgZbrTbsnrN9dt6DOemetfcBPNNf82a0vCmjQJLEueTUzg==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@4.0.7': - resolution: {integrity: sha512-55K0j8RRjcKosUvIl8u/+SMaS1wedq77xN2iuhlOvB/USbIgSmjkWKV9lqGhhp+Qxhnm3qg5NzrqOI1jmra9fQ==} + '@ai-sdk/gateway@4.0.14': + resolution: {integrity: sha512-wbYqQKpASsuK7bdoa1fp+QA6oy3ddqqBOukN3IkyaR8PAp0pWoc66ch2td+ixeknoCcO4F6VTkSFKVC6MP3bTQ==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@4.0.35': - resolution: {integrity: sha512-bjYld/2KGPLt78kpqbya+fD4LYS7BqVQJyUjE3qAHrYB0FR2Q90BaWEVIBZaguTWXf/A8L6uG1zO1v9TxVlGWg==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - - '@ai-sdk/provider-utils@5.0.5': - resolution: {integrity: sha512-oI0t3dvCoqWNV1I8o1Rybi2DXDvHES5r/TrwtJW90tuFLVepgJlftPxrcjh8vaSvjqC2diTuA2vXyjKAyHJm4A==} + '@ai-sdk/google@4.0.10': + resolution: {integrity: sha512-+g629pKE4xhLB6LnskHlOkie30UENhiKpdYMGQoGYm09191kfRU8qAU7wgF01PmzGFe0h3JYpls6Ok2aCYmjzQ==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider@3.0.13': - resolution: {integrity: sha512-ZPtVYt5QIJzOta1kdUiDuCx4HhFkvNPv/rvmZ2b1iXwybYjJsCnNYR4PAw4kW7rgVfDARvHXcU64efWuqNp6bw==} - engines: {node: '>=18'} + '@ai-sdk/groq@4.0.6': + resolution: {integrity: sha512-8aKfwUElkmjvyMr7cCEGMO8Wbt9udvxeJtsTIgDan25jqhoT/GUqV1YcFXczwwveIjaRB2xR6m9hKfDuXcTrBA==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/mcp@2.0.9': + resolution: {integrity: sha512-Mokfd6Ff5QjpdftICnQ9jC9opJcUqfPE31oG9sTYiXEykj5InIt0FA+9acLtCrnM/hx3Tz2BgkNQCXibjSDhpA==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/mistral@4.0.7': + resolution: {integrity: sha512-HhXtQBZyQBUWvh3q4wtQoq99WUOjb7dgGnTgedkdISHiNRZ4OkSQ1kYVFlbNG4XRddvIUf4CJd2fKzq+sYedAQ==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/openai-compatible@3.0.6': + resolution: {integrity: sha512-1YB8Wt2l3X1gCLuF5bYoaQn04XXw+GKqxSvnHAnGEpK+xflJfnJ1l93KHbijLBObM6KAC7amKT9KjM9iu1B6zA==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/openai@4.0.9': + resolution: {integrity: sha512-j7x7FC6KQJMQaJoi6hFLzbB2aXMnR+IA8h0BQH8YCbQESppbM7SzmZ4VAPpobIvx0rqiVNJ1JjraElOLuA31Ag==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/perplexity@4.0.7': + resolution: {integrity: sha512-qrd8klmEo8XGRH2m5lXsj+Hc+CqkqeZuV2cdLlgttIm8HRQfe5dFna/DodNslCSxVJu9Erk2M6pN8VMkmNvOLg==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider-utils@5.0.6': + resolution: {integrity: sha512-i4mVayGtC+HrRmtfPFOxvKKQgFU+1dwTTsh4MY0jY1MaGuppOwDFrNYrJ3dDXWMkO3o6FDVAKY8ZDsy7hLsO9Q==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 '@ai-sdk/provider@4.0.2': resolution: {integrity: sha512-pfPoy9J1B1xV7cqJ8MYHOsDYrMv5tR3+EMNfI249OhkD2uRakvav3Fo7XpD2luuN/YNCBY7KfEQc7vEV7KEtyw==} engines: {node: '>=22'} - '@ai-sdk/react@4.0.16': - resolution: {integrity: sha512-VpJhn9ob7EC9g2Wn5m/FCCu8h6Uj4tE7u8BunK0kNo5kJasEl/f3oHV7f3r4tNtq4zW5wu0EjGs5sKkShErGew==} + '@ai-sdk/react@4.0.19': + resolution: {integrity: sha512-3n/UxiZZh727ROIjQMEyphyzsz3N8bKyBIcfFHicLq7fJjuydQ8owcGRmLXoU5jrhGBRTf4O1QhwmgYNU+vkJA==} engines: {node: '>=22'} peerDependencies: react: ^18 || ~19.0.1 || ~19.1.2 || ^19.2.1 + '@ai-sdk/togetherai@3.0.7': + resolution: {integrity: sha512-qcnRe0MxiMO6TjgZVfi/4hIuGUkBJqyq0BEOzGsoyV7bTdgYvcfQdv+6O96rtp1y9kammCKsjYcxZTbOZjdtug==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/xai@4.0.9': + resolution: {integrity: sha512-hwK3vplmnjylCPfTvugj+n41ueFfW6C5U5twXHpkVdldOSp05Uc4ZocW+XVykWDyv4HdBUL0ia1BwAGXkJQt7g==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - '@aws-sdk/checksums@3.1000.12': - resolution: {integrity: sha512-RgNDWfhNRIlNEzePIRrYTNi/6q+wwRMMapojn8YVzw4ZcJRa/gxVMtUbeZARR1gmopuv6oIhMbY7J66qIQ0ynw==} + '@aws-sdk/checksums@3.1000.14': + resolution: {integrity: sha512-9j0TSNmYVywV+shhBXXkIhaazZwZ+nDSGfG6V47nFLqXdk6mPYk/OJkV4+uRvIg2Ju5F6HTvgM/sfsuTsbAYwg==} engines: {node: '>=20.0.0'} - '@aws-sdk/client-s3@3.1079.0': - resolution: {integrity: sha512-di9U/7Po7qlVYb2dq58ULsbBAE1pBIk53rux+50LQCvH1X+/l1Ys+BIk/QLBtdaK1nADk0xRNEBbA1QWVnMccw==} + '@aws-sdk/client-s3@3.1081.0': + resolution: {integrity: sha512-mHAdLBibsbFwcW2YHrH5sIQlaXjB3zha7Nkooa2gqTlXxRpVJ+ba/v/mg19B6rJeZmOEteRHFz+INOlAbCbxJg==} engines: {node: '>=20.0.0'} - '@aws-sdk/core@3.974.27': - resolution: {integrity: sha512-WRWEgIq6vx+NU6ot3VrRu4Jovj9MIObitSi6of/GV5THDDPccBhivCRNkWJutMM+m3GvdeI3l/UbGNcoOobxOA==} + '@aws-sdk/core@3.974.29': + resolution: {integrity: sha512-yqKcltLbtRh1ubzhRSldIs8jFHNZlyMlgoIccCC0aDVbrB99nXaBdmfr89mK7obWX/NVg4rAMpCpZ6dCDiVBtA==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-env@3.972.53': - resolution: {integrity: sha512-+KDA3uc/HZ1vIneGu5QMQb0gAXDYrm2vOE60+BJ7lS0YinMQ5i2oV4PR1A16XkF6K1IbSwjEHd1hQIIgMsK48w==} + '@aws-sdk/credential-provider-env@3.972.55': + resolution: {integrity: sha512-Ah36tYkqyaVnaHkx7VseoTYrHUmwgBps3V+wnrC1idhIIMGlviH0FtrX9EIPdAlVHvXC7FQZLhmHBRz+pLaiWg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-http@3.972.55': - resolution: {integrity: sha512-1gBfkWY3RWeBlCoB9lIJjXMx45/54wxcgfzv6BY9otTmMrZPcNPi1v+MwZxxaCUg441NV3jsr1efnFNCXiW70g==} + '@aws-sdk/credential-provider-http@3.972.57': + resolution: {integrity: sha512-/vp6i5YEliJqRm5k/BDmYjAyRAMTdkjW6UciVRk9oh/0OfDCWeb/ih7hqte4lFvKXkIbsqe9AdK9LQK6NGardw==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-ini@3.972.60': - resolution: {integrity: sha512-CV2md+PXvABwRjApWGhQ0wACy9WSFIhnUGrovLcjnjBCd/46TbuivLADtkF8IWNjtCQmQ+2IagSaxqBYqXBNAQ==} + '@aws-sdk/credential-provider-ini@3.972.62': + resolution: {integrity: sha512-pQIRiQQs+MUlVnJdWJ7/6KS0WxcLRVfut57OFgwC3cnM1F8mXw3Kh4gAVwj6AtvD6CWx8x6+po4ENRcqe64XrQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-login@3.972.59': - resolution: {integrity: sha512-JG4S9yyA1GFzJdJXqLKrUzZbyK+VDp2QIsJD7YOicJHAhqymfHpDJIok2dLnhOdVB0I37RjdC53uOwCMVS00gw==} + '@aws-sdk/credential-provider-login@3.972.61': + resolution: {integrity: sha512-jtrxWwC7slqxh7DnAWHrwsA3UwCsnlypdYtavGT7EX5p791wxWQys7QzkCZ7JvOMAyylDtPoxyV+ic0zg3rV9g==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-node@3.972.62': - resolution: {integrity: sha512-S6Slq3Tx7bvFk5yc34XNADyZYTX2HUXvaFAnowGRQnhjBO8J/mP62Fn7lxvJwjaDyYm/7gh9h6HEHaltRyMFXw==} + '@aws-sdk/credential-provider-node@3.972.64': + resolution: {integrity: sha512-zyKVYDyMR9VQL/kPi03ygN2vtD9uLMuWRLoJ77KxgZZaS1VlJloI+SzleF9Zg4HWUI+AIu+ZRs8zsJFNqbrxsw==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-process@3.972.53': - resolution: {integrity: sha512-EhfH+MQlqOMCkXIVa8MMObPzAQqwTTtxA7KhEJiyPeuNVA8PLOOUpgK7nBrgaDaGiIDLN/9LpGdaHuDjomeRTw==} + '@aws-sdk/credential-provider-process@3.972.55': + resolution: {integrity: sha512-x0XjjF0l1WGRtK2vEhTZqCguQuAIZLep9l2+eeEmuxQQjjD3BlGQXY5xADR+l3t576UX+dxRkRtTjEu40l81Vw==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-sso@3.972.59': - resolution: {integrity: sha512-h8793pOjcImx0SB+VcLONcaQQ57VAvKVuqyewQMRKqqH+CSXsG2dwOeLMUJPMxLdNvL7dXOM0ueTukyNUnu5mA==} + '@aws-sdk/credential-provider-sso@3.972.61': + resolution: {integrity: sha512-d/V0VRsz73i+PHhbult/tx0Y1+de1SNQVsXkcQCmpfeBq7uODy/RTxNsOLpT9ZVHxcRNzbQFuywLKC33fUMIxA==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-web-identity@3.972.59': - resolution: {integrity: sha512-VoyO9+vl3XVmpZwn4obskrWIkrA/Jf3lSe1E3ZERlaN9u0D4YZ6+HywC3+L98QOXqZesEfedk67gRER8tK8+8w==} + '@aws-sdk/credential-provider-web-identity@3.972.61': + resolution: {integrity: sha512-Bv4n3NOI6hPy+rmr6Bw9R6LnBVRkcp3ncj2E2IKSYJG+0UkysSitWMvbgndNvMxDw7gE1pQ/ErwkNceuKwj7zQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-sdk-s3@3.972.58': - resolution: {integrity: sha512-6uaWRRYJGhOqc9EoTSbLDf9nI/doSAb5vAwGshs5/Hlv5Ce25b246lBkbRd/77fLAi+uMI1a70mJzVyLyCEufQ==} + '@aws-sdk/middleware-sdk-s3@3.972.60': + resolution: {integrity: sha512-f8SREKL6uQUYt8fwreiUgaAJQ31/M+UkWfJMDY/TBJC5FdHgNzxuvRFeZ9eMbnf2ydQ3p4pcKEhaLk35DDIPxw==} engines: {node: '>=20.0.0'} - '@aws-sdk/nested-clients@3.997.27': - resolution: {integrity: sha512-A8PIePF9NIIOJ/4Lg1rl9xm/+QaKkHGetq+Z9wb5B+3Da31YYXRo8n7IDMh5C+HQI5eyEmjrwkGWVdYtnLtbXQ==} + '@aws-sdk/nested-clients@3.997.29': + resolution: {integrity: sha512-ot6v8J5W8P0w6ryyuIkXP1bHZHTlvwtn83mVCYaBE0GJ6tJX4vPSBx7M98w9O4wmmDruFsDBUMjhEHA+OosUFQ==} engines: {node: '>=20.0.0'} '@aws-sdk/signature-v4-multi-region@3.996.38': resolution: {integrity: sha512-C379Sk+MiFZCfWZphKlMyLHKxV22OjoGM5KJjj5IJNJcOCWL4IGIpnEGzv1FQiRwhYXfq55SJMfxlqPE08JJ9g==} engines: {node: '>=20.0.0'} - '@aws-sdk/token-providers@3.1079.0': - resolution: {integrity: sha512-cbietrLlHPhhmbnMPTuDS4Zj/KNGhY+3vVhn6dwjO6Dqzrwothzg2srtcY34T9mlICsTXn34avDoWLHSntP54A==} + '@aws-sdk/token-providers@3.1081.0': + resolution: {integrity: sha512-kduAeI6cL+zqwj3gjPh9LhuX7kBZ83msYxutavaR+UPm5K8J7iThJBvNRAsFNyWTji92CSU8dogUgvi9T0BehA==} engines: {node: '>=20.0.0'} '@aws-sdk/types@3.973.15': @@ -1568,8 +1666,8 @@ packages: drizzle-orm: optional: true - '@better-auth/infra@0.3.4': - resolution: {integrity: sha512-Chak9ebnPBWsMdf/+9KHvEjLvJv9QaYgFHwGdGOvtCs8+2RYW+6b0bECEEpDNYJEro9EREOmSq+U7Umor/wFTQ==} + '@better-auth/infra@0.3.5': + resolution: {integrity: sha512-SpChq3cVOLur72SyNx0hTY1gawruaJChBL06NL84OoKPcdnAmJIjrbWc7gi6h1FhzQFrip7+F6vaJqf1v4eM5Q==} peerDependencies: '@better-auth/core': '>=1.4.0' '@react-native-async-storage/async-storage': '>=1.21.0' @@ -1662,59 +1760,59 @@ packages: '@better-fetch/fetch@1.3.1': resolution: {integrity: sha512-ABkD1WhyfPZprKRQI3bhATjeiFuNWC9PXhfGWqL+sg/gKrM977oFrYkdb4msM3hgUGonr7KlOsOFT5TU2rht9g==} - '@biomejs/biome@2.5.2': - resolution: {integrity: sha512-VQ3RCqr7JmDIX+w6stWYl+g/3bYofN3q2wDBHUKKc/c7i5QWrFKFBZYCYPWTE6agsUPMIZZe6/CMmVUfUAhkKA==} + '@biomejs/biome@2.5.3': + resolution: {integrity: sha512-MrJswFdei9EfDwwUy2tQrPDpK0AO+RmMFvBoaaJ6ayBc3sUbHdCE+XG5N8vp+5So41ZupZJQm0roHFFhMGVD7A==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.5.2': - resolution: {integrity: sha512-e7P3P7EkwFc/KiX2AHw4YDLIBOMfG9CPCAwy52k5Bp0dfhkozx9hf6wCmIr2QeXy2XeccJ3V/Sg+hDmzYEqxSg==} + '@biomejs/cli-darwin-arm64@2.5.3': + resolution: {integrity: sha512-QhYP9muVQ0nUO5zztFuPbEwi4+94sJWVjaZds9aMi1l/KNZBiUjdiSUrGHsTaMGDXrYl+r4AS2sUKfgH3w+V3g==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.5.2': - resolution: {integrity: sha512-ymzMvjC1Jg0b9K0D26ZdARqFQXs7MocfLC5FOCGfkC0Ss+ACUJkX5364ZM5nT4NLZanHRZNVrZEy+Ibwcvux/g==} + '@biomejs/cli-darwin-x64@2.5.3': + resolution: {integrity: sha512-NC1Ss13UaW7QZX+y8j44bF7AP0jSJdBl6iRhe0MAkvaSqZy+mWg3GaXsrb+eSoHoGDBtaXWEbMVV0iVN2cZ7cQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.5.2': - resolution: {integrity: sha512-w+ANG0ZvTu9IeEg9QnstoOnk6L0fpwJifW6aHR18+cb5Z39bkANItYjAfMrnvce5tmMK+IQ6nPX7/kQFdam5iw==} + '@biomejs/cli-linux-arm64-musl@2.5.3': + resolution: {integrity: sha512-fccix0w6xp6csCXgxeC0dU/3ecgRQal0y+cv2SP9ajNlhe7Yrk2Ug7UDe2j9AT9ZDYitkXpvUKgZjjuoYeP4Vg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [musl] - '@biomejs/cli-linux-arm64@2.5.2': - resolution: {integrity: sha512-t7sseOmqND57uUWTwlawU6BYj+J06T/9EkydzBhkrgw/FK3QVhjU2wsJR0frljrKZ0/I8A/rYw7284QgqjQfIQ==} + '@biomejs/cli-linux-arm64@2.5.3': + resolution: {integrity: sha512-ksx1KWeyYW18ILL04msF/J4ZBtBDN33znYK8Z/aNv/vlBVxL9/g3mGP+omgHJKy4+KWbK87vcmmpmurfNjSgiA==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [glibc] - '@biomejs/cli-linux-x64-musl@2.5.2': - resolution: {integrity: sha512-VArNLAzND063tF+XY0yPyM+DyahpzOMzOAvb7qs259nhjJWRjvjZdssuA+Rfl+l07+NOesKZ0Xu2yFrXyBMtzw==} + '@biomejs/cli-linux-x64-musl@2.5.3': + resolution: {integrity: sha512-O/yU9YKRUiHhmcjF2f38PSjseVk3G4VLWYc0G2HWpzdBVREV6G8IGWIVEFf7MFPfWIzNUIvPsEjeAZQIOgnLcQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [musl] - '@biomejs/cli-linux-x64@2.5.2': - resolution: {integrity: sha512-M/lOZrewzTCRDINbjhQ1gYYru37KlD3kJBQwwKCG0ckz5E9IZwIoJ3X0wBwRXA+yBDIwWUuPBHS67HzJY4dTfA==} + '@biomejs/cli-linux-x64@2.5.3': + resolution: {integrity: sha512-yMkJtilsgvILDcVkh187aVLTb64xYsrxYajx5kym+r1ULkO5HUOfu9AYKLGQbOVLwJtT2utNw7hhFNg+17mUYA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [glibc] - '@biomejs/cli-win32-arm64@2.5.2': - resolution: {integrity: sha512-kbjFFKyZlzYnAuw7sRy5qDoFG6zrP40UK08oPQsWK0ct3NMnGSt+Bs1iviEEyEIP57N5MrykGXdO/wRiaR4lww==} + '@biomejs/cli-win32-arm64@2.5.3': + resolution: {integrity: sha512-cX5z+GYwRcqEok0AH3KSfQGgqYd0Nomfp6Fbe1uiTtELE38hdH2k842wQ9wLNaF/JJ7r4rjJQ4VR+ce+fRmQbw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.5.2': - resolution: {integrity: sha512-4InchVpdVmdkkkgjQqKpgvyu+VPnoF/7RPSw5YATgEVpt2j72wcCAeV5TwaE9ZGJUZWZn7v2CwSAj6CrMJEx8A==} + '@biomejs/cli-win32-x64@2.5.3': + resolution: {integrity: sha512-ExSaJWi4/u6+GXCszlSKpWSjKNbDseAYqqkCznsCsZ/4uidZ/BEqsCc5/3ctlq6dfIubdIIRSVLC/PG9xPl70Q==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -1723,8 +1821,8 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} - '@commitlint/cli@21.2.0': - resolution: {integrity: sha512-4GLVIhUaT3c3GBlQ0GB80/5H3xXdn/Tgw4lrsuoOQVDu2wl4Xw0GuzSar8xZKSMv4H3xaKaQXmvH91GmdyYBZA==} + '@commitlint/cli@21.2.1': + resolution: {integrity: sha512-blsZGe29hJ72VGEFVl72IVYX+1vsfINpjA9yWQA6i7OKD/McGEOXg08sKIRKjFk4JvzhV/9n0l3i6NooPLTNfg==} engines: {node: '>=22.12.0'} hasBin: true @@ -1768,8 +1866,8 @@ packages: resolution: {integrity: sha512-QHWxG4d0PLTF634/AdyZ0MQS+CLn5YOuJlCFhMMlSGKFxzYGUetkHBj18xgBD+6fVzUrA2lrCdi/vlS2f/oYXg==} engines: {node: '>=22.12.0'} - '@commitlint/read@21.2.0': - resolution: {integrity: sha512-ELx8Ovh/JoAw5lpvDgxc6Y0We9skf2IPI2RFN+gnYgDGjRdMSF8zeodxhZmcclLWzfUIF7hXLOa8gOlllYcvBA==} + '@commitlint/read@21.2.1': + resolution: {integrity: sha512-hUW7EJQnNTL0vPOmVMNK4CrnrNBN0nN+JJHReFkdHO5y4iyHeEmTBwuC15OCqUTjxWo7idnH1LftfpWVIaPWIA==} engines: {node: '>=22.12.0'} '@commitlint/resolve-extends@21.2.0': @@ -1792,12 +1890,12 @@ packages: resolution: {integrity: sha512-7zVFCDB2reMvJH5dmbKnOQPjZEvjdJTH8jc0U/PIPU1r3/+vf5pD1HlfitV2MWsWXrvu7u39iY1lyLUPOaN0Gw==} engines: {node: '>=22.12.0'} - '@conventional-changelog/git-client@2.7.0': - resolution: {integrity: sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==} - engines: {node: '>=18'} + '@conventional-changelog/git-client@3.1.0': + resolution: {integrity: sha512-Tqa/gHco2WJWa740NRjOrfKVvzIqxkZpecb8bemaQ8sKM5PXb1UK4uTyTb/1wIqNuOVaDOFxyBdhTIQZn6gdjQ==} + engines: {node: '>=22'} peerDependencies: - conventional-commits-filter: ^5.0.0 - conventional-commits-parser: ^6.4.0 + conventional-commits-filter: ^6.0.1 + conventional-commits-parser: ^7.0.1 peerDependenciesMeta: conventional-commits-filter: optional: true @@ -2431,25 +2529,33 @@ packages: '@levischuck/tiny-cbor@0.2.11': resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==} - '@lingui/babel-plugin-extract-messages@6.4.0': - resolution: {integrity: sha512-b9NatQFU1h0muPCC0QGdSVKE/OEdR4w9FQrKAOFYwH0eF7pD2ArafqyqG6xsw2E+7w4PlZQjzOhihQMxI8a6sA==} + '@lingui/babel-plugin-extract-messages@6.5.0': + resolution: {integrity: sha512-ZvHG9eekHvfr+qErKgfPG/twfpXfMIiNSQk7iHKr/eSaeUP/c+Syuysx7s5I4WbkZlnzYjovp1K1iS7VHdX93Q==} engines: {node: '>=22.19.0'} - '@lingui/babel-plugin-lingui-macro@6.4.0': - resolution: {integrity: sha512-V15kARtjzWgLga/6LOTMMki5pv3F42m9BX8jdI1mBg4yCo1cS0B3szfoBqoveFs7x+nh0iuEPAKcM9lVdSYadw==} + '@lingui/babel-plugin-lingui-macro@6.5.0': + resolution: {integrity: sha512-p80TT6WMGXpFnAe9nP9ad/BJsADBxBvTa1QFy07tZqpg/5G5eOxUn641koQjHHr/EQ3yNstLohPV9aAVoKKsiA==} engines: {node: '>=22.19.0'} - '@lingui/cli@6.4.0': - resolution: {integrity: sha512-OqtEPHFmgQlyroQMmpnda6QRnfAqlAYnRVZpZSX3rZpwwaHI1pD7T1EQoK8n7kin9TGhitc1J33wFom7o/+yyg==} + '@lingui/cli@6.5.0': + resolution: {integrity: sha512-aTvggRa8yUHT6tNmkWuJfNehO/gkShiQA0UTn02hNSTIqqfh3y4avsHiJGFBAEmFx/zpvJ+XcHtZDhTtNMojhA==} engines: {node: '>=22.19.0'} hasBin: true + peerDependencies: + esbuild: ^0.28.1 + rolldown: ^1.0.0 + peerDependenciesMeta: + esbuild: + optional: true + rolldown: + optional: true - '@lingui/conf@6.4.0': - resolution: {integrity: sha512-C+THkLbda72//6dL7QAVyaxIxOnag8mGWKqrMsyIUHgZpStE05KiF8HDwTCMNiaeQmQPym/D8fVm7m8jCau3EA==} + '@lingui/conf@6.5.0': + resolution: {integrity: sha512-zfR4uuzev2mz9ayVB2AwEQlzodDKgMcq/OR3pdHiJFCl80UQRsFA5Oqe67TmxA7SSbTygK+U0nS0qrotmXjyrA==} engines: {node: '>=22.19.0'} - '@lingui/core@6.4.0': - resolution: {integrity: sha512-DVbgp9tn07t3iByH6snsn1WaM8PxjDacOqf45oLVXyIti98PmXadO2UkO+NgCybHSqm3+7GGV4zTr4777Cc9nA==} + '@lingui/core@6.5.0': + resolution: {integrity: sha512-zAoD/fIMNqtgvH15BJBtyHSMRssnMSumCEggj4c4kGYU0hh5rWn1JoOw/xLbA0Xe2iH4oBG9/SDnvVjJ4VvWrA==} engines: {node: '>=22.19.0'} peerDependencies: babel-plugin-macros: 2 || 3 @@ -2457,16 +2563,16 @@ packages: babel-plugin-macros: optional: true - '@lingui/format-po@6.4.0': - resolution: {integrity: sha512-tu5aNalW9u+xjmcAlNEjfw4ahzMHFeC4nKz+zYHcv44Drpy9/bWnrr5j7Pi4rc9u4PILtXikwAsLh28u284WiA==} + '@lingui/format-po@6.5.0': + resolution: {integrity: sha512-jK2JhYpKuDMG3VP8T0W6X5SL0GYRkeaTOlX3EiRggDWNJqc6wFxJP0vTZScMlyBXHC+v0OUxy+4Ja+9kVJwKsQ==} engines: {node: '>=22.19.0'} - '@lingui/message-utils@6.4.0': - resolution: {integrity: sha512-Bkt2V7vI57/CEVyJCO+93jssN2MhLJ07M6S0d16tHvigNftP5Ndl+2xX1HKWD6eozidc5lOeTZMtrEL9jzXEsg==} + '@lingui/message-utils@6.5.0': + resolution: {integrity: sha512-qZZijYERMADeWVJbpQGyFxicW3F17CjtR2hnzo0VgT4cICPE27e0zBieQHxuUD/pj4dmyOOldVhWhHs5CN6ABw==} engines: {node: '>=22.19.0'} - '@lingui/react@6.4.0': - resolution: {integrity: sha512-9ui7O/K/X+AXN7TdSEbKq//sNLAJ42dk1GftzAcHL58jKv3CnEyKOPJb2S0L/Ez6li8I0O4KKgRn1BK0Qk/Jqg==} + '@lingui/react@6.5.0': + resolution: {integrity: sha512-Q2jd82chqbCrQAPu8MNl+/PwSNumehWbH2AxXGFNq1/w1v0T3dgbfOXOtQ2sNd0Fq+a5gkuyul8RWbW1CDYw7Q==} engines: {node: '>=22.19.0'} peerDependencies: babel-plugin-macros: 2 || 3 @@ -2475,8 +2581,8 @@ packages: babel-plugin-macros: optional: true - '@lingui/vite-plugin@6.4.0': - resolution: {integrity: sha512-15ogZWydII5TbWwTJJGfJF9OpATxiIbJGearfBv+tj13uv3TlKwLGdmpn/GV8COY8v0irKr7dfdyfxYvxLxSZQ==} + '@lingui/vite-plugin@6.5.0': + resolution: {integrity: sha512-mWiMnG0dTXofzRDbi5KrAMQRQQCk70YtKebYSmkA1rmVaLLdmBuGKvvh1kJYCFyM8hxtpLvqaFDebJvG9MUjXQ==} engines: {node: '>=22.19.0'} peerDependencies: '@babel/core': ^7.29.0 || ^8.0.0-rc.1 @@ -2698,34 +2804,34 @@ packages: resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==} engines: {node: '>=14'} - '@orpc/client@1.14.6': - resolution: {integrity: sha512-Y03NcTtmEJdxcqkKBkdGxqe1IHVpD9IorshG4PaTnz9dQIW+RYI8anRo7o0IlbBlzBICN+Ubo1rnw6bpkhagCQ==} + '@orpc/client@1.14.7': + resolution: {integrity: sha512-/yloM96/6Z3qlmEgW4/VMYUnhxXbCr6lIJiKSHmsvhgKcwrUPOPJrL3p0ZpItz5SKVtQSwXIhT5KcT/3va/Aew==} - '@orpc/contract@1.14.6': - resolution: {integrity: sha512-o4i2ciYWtALidF969S8yj/VFk7ZUmHHKaYGRVitX5K2uMaSB8lJM6TMyBKzRC5Clo99VPjCb9mcl6jMLEAgmKw==} + '@orpc/contract@1.14.7': + resolution: {integrity: sha512-LVAzjOfwW+5L4z5hGOkGGsocFF4URLmQBujrvUr6/TLeDmiiY2kB89jyJ793U40ol9/Ba935g/b0pBajiQhPWA==} - '@orpc/experimental-ratelimit@1.14.6': - resolution: {integrity: sha512-cxX2ff/VLEIgxIAvFRtfpmDnMCbNLf/pL9dh1sBf2jG/g34A0V7mOQZYlp/s7ZrTD2qwzgYVAPu3LY80BucsoQ==} + '@orpc/experimental-ratelimit@1.14.7': + resolution: {integrity: sha512-uvOdJRdL/hAnpFO1+5xjfjYfpq5cgAwI2cD13LCXKyA0Bueh4UkgrL5F5wMLctokyp7Mdm5YbIYitbdwXzEoYQ==} peerDependencies: '@upstash/ratelimit': '>=2.0.7' peerDependenciesMeta: '@upstash/ratelimit': optional: true - '@orpc/interop@1.14.6': - resolution: {integrity: sha512-ZjNaHH9754uUkC98DHfm9HaGnniFnFRLdXXBWL2u+o1TVzEbiNX8dA5+oChxoSTUD3GiwpjLjAuTWXvrbhm4fA==} + '@orpc/interop@1.14.7': + resolution: {integrity: sha512-2evzgNl6CMh5MZ3xHLHYX01siGZCQu9E6mcuPTSM3G7wQKG9ozvtGjAiH6dBWKfNUQRAavjJpQVoEW9LJ5VICA==} - '@orpc/json-schema@1.14.6': - resolution: {integrity: sha512-p79GOJ88DpOTsOaAQ8Ef/2J5455Yh2qp3KjY9q6858RozHuPSXHu7MSgE/bilkzbiuGNoen3frw7GSiKfYpKSA==} + '@orpc/json-schema@1.14.7': + resolution: {integrity: sha512-N4yvqv6f3BXLh5VABXiwUqhrEJFQLE/c8arIwa0tGRhXqAFXFQqaeGHYD+POGVQT7muu7l4yvnJd8jBJOkcsfQ==} - '@orpc/openapi-client@1.14.6': - resolution: {integrity: sha512-Z0rdO+oVJTASat3fIQmLEjKnqRsjg4QsjRFwFamZ5W+Y076I3Lbp8XhVcMoHbKyfgm/TKnZu3y41b4NFfPBYiA==} + '@orpc/openapi-client@1.14.7': + resolution: {integrity: sha512-TRNFa1q/4OkhygvRqzlH7AVfSR52xbBNSWVIvEeJoYX4lZvFEXqlSvyiejQpoR5gjhqDvFMe3OAUMCpKvYP0Kw==} - '@orpc/openapi@1.14.6': - resolution: {integrity: sha512-MdQ0KKLdvqZlmpUgw/6W/6dOfwo1GdtW2kE0VL/AJxqaeM6i3sygtIGAzEr6/CfhIJnfGHqo1jMzdlELQjCqYg==} + '@orpc/openapi@1.14.7': + resolution: {integrity: sha512-elTxq+tWqQvUaU3nsGQclsJ5qkxUJe3lZxKQyCqmrt7r3oG3NMa0W8efWzXVrxJ6zMIav1l5lTKHaU/QIv6NOw==} - '@orpc/server@1.14.6': - resolution: {integrity: sha512-aHn8dW2clr/fRZzMLbRsZ1Pe4AYxg7YmM3tSZSAkPjn5/3UaHnpuwWeY7LYPok23CGYUmjidTmJQjm0zm+vgoA==} + '@orpc/server@1.14.7': + resolution: {integrity: sha512-bN38rwVELPx/AEHnOIKlJz0Vo2OnuzGpCMdMtspqKoiposkpB4jqx2CMFZCMzj4ew43m+sUSUmbQZ001Q4fgTA==} peerDependencies: crossws: '>=0.3.4' ws: '>=8.18.1' @@ -2735,48 +2841,48 @@ packages: ws: optional: true - '@orpc/shared@1.14.6': - resolution: {integrity: sha512-P2W+DdrUq18kUiF7nIw5wDOA0SR41mM/NsVKDVRsdyhdHk9V9KDuW1JRymyMl+7Wo5SDeSr1Rm/VjA5v08+PHw==} + '@orpc/shared@1.14.7': + resolution: {integrity: sha512-uEvbm+IGxUyQMpVYufU5mEPflyZoF1Nh2yFBqHgmu5QycXZ5GGb5GdwtMa+IE8WXZSHQ4wOgftBNtzGfX/rBIg==} peerDependencies: '@opentelemetry/api': '>=1.9.0' peerDependenciesMeta: '@opentelemetry/api': optional: true - '@orpc/standard-server-aws-lambda@1.14.6': - resolution: {integrity: sha512-8FQX0uBQ2OKkIrF0u5qpd9EH2uqaM1n37NJSw9bvQqLnqoSfzk0xzVkP5s+c8N0Gec6M9mnrLvB7aqQSlpPukw==} + '@orpc/standard-server-aws-lambda@1.14.7': + resolution: {integrity: sha512-Ov+xeJqga0S6346mxZ8xAyZVHudXDSnl9sKgZKYa1jmp8KV221Q9yYV7c2fmNE5NmDr+uNZS9nmUtB38Fz08mA==} - '@orpc/standard-server-fastify@1.14.6': - resolution: {integrity: sha512-cwS7jRfc+yM8bFyEFVzVcXfgYLfy96KpdPBPUlIQLpInwYvMxePpENM3rEAJ3MHOfMHx1PT5LidrlbR7Npb1Cg==} + '@orpc/standard-server-fastify@1.14.7': + resolution: {integrity: sha512-f5TXZ/qU/L0mMpJ4sz3/YvBrXqKj4d5cgfx8uriA1sSqMTyuadYXp75pywnW6WQ8tuJ9rARVj35l7mx7K6VvpQ==} peerDependencies: fastify: '>=5.6.1' peerDependenciesMeta: fastify: optional: true - '@orpc/standard-server-fetch@1.14.6': - resolution: {integrity: sha512-XnwEnHaKMMBoilK0QVwgMsUvDbCXyz6CDoLgMN51v+p3VSnwjIkrMdOwbc/sj43z6T4irQDu9Zm8T1pxxh1L8w==} + '@orpc/standard-server-fetch@1.14.7': + resolution: {integrity: sha512-bkp9pDDX36enqVC5Q2+o4fofPFR9COI9FpdhLI3mGlQuV6NT9ZBjrscXv57hUPTc7g0aKDOzjiAo0NHoCfZc+g==} - '@orpc/standard-server-node@1.14.6': - resolution: {integrity: sha512-CmW/EPu1dxoppYMRmsK+F3Z22wMx74RLUtjRokXyRKu4XEX/Ja6nwD+xauQcAMiAQYkp39aCMofAW7BvA46Qcg==} + '@orpc/standard-server-node@1.14.7': + resolution: {integrity: sha512-5ESH31uBbIkW3FyVmTz6cbdTAxm+y8gDhE7lXC3B6+SuZrNBetaPZmv9FjhyGHm2tIKUCjZfcf1bzXmCUV0vEw==} - '@orpc/standard-server-peer@1.14.6': - resolution: {integrity: sha512-jwVGc5yRA5hk1F/W4yw45P2H4fbu4Tfsk62XijJBXRvtlSNKvvPAuwAd6jFv/fxnq2SH/uskgi91Ja9wgfnYDQ==} + '@orpc/standard-server-peer@1.14.7': + resolution: {integrity: sha512-5YzX7goqeg5cZv+R58SCZHKo0Jk9CiHgepzJYM5oQYoLbdqoxGC4yZG12sqwN/CTX7nZkE2nnbfk6l3+YD/reg==} - '@orpc/standard-server@1.14.6': - resolution: {integrity: sha512-75Oh4rAZb8K7P46d6v7R2JhjqjLLEo7Qs4+ABdF+f0m0uKM1oaykJWy7leqTJ+WaYm+uDbsZl/3nyWie9aeJTg==} + '@orpc/standard-server@1.14.7': + resolution: {integrity: sha512-N+7I4SzYoSVyf5lRbANGz9oBVmZSM/nm2JlxAP+UPSbWnqrjltSFFHVlSdp4wXSb39LVjT74uSLZ9Da1wOyLeg==} - '@orpc/tanstack-query@1.14.6': - resolution: {integrity: sha512-uCu6iTT0MDyk+ihba65N2CT56XYMny2N389l8pC+NIOQ7dG46RF98MhaQEvFUQo3atZb6pkKNWkg7BaA1Z9o7g==} + '@orpc/tanstack-query@1.14.7': + resolution: {integrity: sha512-cNOdHwxg6+CHOE9QqVtaWEPMMQLvYzs19xZIs5X69UgmEehWy/zrtmErbxDdzd7a2pTCcZXDcFV7kkl/12ke0Q==} peerDependencies: - '@orpc/client': 1.14.6 + '@orpc/client': 1.14.7 '@tanstack/query-core': '>=5.80.2' - '@orpc/zod@1.14.6': - resolution: {integrity: sha512-skGc5Qj6BLy3ir+VgYZZBJFlxDVAYoJPVymVPEOLawEVSf2mje0/oMPiaQJE4+CyVRSIXUHG8MoQnW0X1OoQ5w==} + '@orpc/zod@1.14.7': + resolution: {integrity: sha512-t4JCHF70QrV9apYKuJE4dUl0AwoHcjenPbSPfP7j76u50qDlean3E5XGQkxTS4FHWbwlOVY5bhSQzKcegN/MBg==} peerDependencies: - '@orpc/contract': 1.14.6 - '@orpc/server': 1.14.6 + '@orpc/contract': 1.14.7 + '@orpc/server': 1.14.7 zod: '>=3.25.0' '@oxc-parser/binding-android-arm-eabi@0.120.0': @@ -3039,8 +3145,8 @@ packages: '@oxc-project/types@0.137.0': resolution: {integrity: sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==} - '@oxc-project/types@0.138.0': - resolution: {integrity: sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA==} + '@oxc-project/types@0.139.0': + resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} '@oxc-resolver/binding-android-arm-eabi@11.21.3': resolution: {integrity: sha512-eNU11A2WNizh04v3uyaJCootrHIaS0B9aHYXvAvVnPNk4xYSjMUjHnhQ6dewPN2MRYDskV85d1N0Aw0WNWhcyg==} @@ -3203,8 +3309,8 @@ packages: '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} - '@radix-ui/primitive@1.1.4': - resolution: {integrity: sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==} + '@radix-ui/primitive@1.1.5': + resolution: {integrity: sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg==} '@radix-ui/react-compose-refs@1.1.3': resolution: {integrity: sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==} @@ -3215,8 +3321,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-context@1.1.4': - resolution: {integrity: sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==} + '@radix-ui/react-context@1.2.0': + resolution: {integrity: sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -3224,8 +3330,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-dialog@1.1.18': - resolution: {integrity: sha512-apa28mldjMgORmE6g/w3sCcA0Y9UAVeeDVoozN4i7kOw12mLl9RBchfzK3Nn6qxOWjrZhK1Lfy7f07kyzxtnBw==} + '@radix-ui/react-dialog@1.1.19': + resolution: {integrity: sha512-+HhbN2+YtkRgVirjZ2afMeutQRuGOrdkWR5+EFC58SJojGmtyNQwYzgi6tHBpOxvFHefMtPeHdgtjz0BOGxFQg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -3237,8 +3343,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-dismissable-layer@1.1.14': - resolution: {integrity: sha512-4lUhWTWAjbDIqFrAPWJ3WqBOpO5YchVZ88X3nh6H9Lu5AFi5nCUeTPj3D8FSDmabmFeRe9ME0BDA4MwKTha5GQ==} + '@radix-ui/react-dismissable-layer@1.1.15': + resolution: {integrity: sha512-b0XaRlzn2QKuo10XyNgi2DAJDf5XC9d1nD3FJcuvCjbR7+4Ad28zmZsLsqx+hvDEzMnRuZaZxZm9gYObV6RmRA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -3259,8 +3365,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-focus-scope@1.1.11': - resolution: {integrity: sha512-Mn88Vg2whaRocGJNOH+DKFqYm6ySFPQaiwHNxZPyjn99B52KAEJWWY9NP83+nWdk2HM3rdov+STu9AG471Rt9w==} + '@radix-ui/react-focus-scope@1.1.12': + resolution: {integrity: sha512-jjk/lqTeNL0azUx5ZYzVrl4NgaDIrdzTNE4mABV9yBFI7FQqN7pIgzV1bTleUezP2QiTGA1BFTqY8MegDgWX9A==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -3294,8 +3400,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-presence@1.1.6': - resolution: {integrity: sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==} + '@radix-ui/react-presence@1.1.7': + resolution: {integrity: sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -3372,8 +3478,8 @@ packages: react: ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/ui@6.6.6': - resolution: {integrity: sha512-mupCOgV0sC94ODcYGwqj7CD0RAonBgaeeMxnu8DYA9JPFH8hx1061X87itIKL1OVxoBW3IftjvsECuMfqUilwg==} + '@react-email/ui@6.6.8': + resolution: {integrity: sha512-BmE00nhGfXyd2W8JZhri+p3578j/TYhukJwkAhQAGMorBWYIPenESYgifFXjey3cNVhKd466/D8tmOThlNrKtA==} '@react-pdf/fns@3.1.3': resolution: {integrity: sha512-0I7pApDr1/RLAKbizuLy/IHTEa93LSPy/bEwYniboC3Xqnp6Od8xFJKbKEzGw2wh/5zKFFwl00g4t9RwgIMc3w==} @@ -3418,97 +3524,97 @@ packages: '@react-pdf/types@2.11.1': resolution: {integrity: sha512-i9xQgfaDU9QoeNnbp6rltXCWg1huEh195rpOuN8cE4BZ2FuLdQrsIcb2dhFF9aOxXf+XBA6LOSpIW051MDD/bw==} - '@rolldown/binding-android-arm64@1.1.4': - resolution: {integrity: sha512-EZLpf/8y7GXkkra90ML47kzik/GMP3EMcE9bPyHmRfxLC6z9+aW5A8poCsoxjrT5GfEcNAAvWwUHjvP1pUQkfw==} + '@rolldown/binding-android-arm64@1.1.5': + resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.1.4': - resolution: {integrity: sha512-aUi+HBvmYb7j8krl1+qJgkG8C17fO79gk3c+jPw4S8glRFc1DTija9S3EyaTSQUm5GJXYKDAsugBEhFHH2vYiQ==} + '@rolldown/binding-darwin-arm64@1.1.5': + resolution: {integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.1.4': - resolution: {integrity: sha512-F7hHC3gwY11+vByKPRWqwGbeXWVgKmL+pTGCinaEhdihzBV2aQ0fvZOch9cXYUOKuKKq429HeYXOqQLc7wFCEg==} + '@rolldown/binding-darwin-x64@1.1.5': + resolution: {integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.1.4': - resolution: {integrity: sha512-sI5yw+7s92SK6odiEhD5lKCBlWcpjHS5qyqpVQbZAJ0fIzEUXrmbl3DH2ybR3PZogulNJF+COLtmA8hUfvkCCQ==} + '@rolldown/binding-freebsd-x64@1.1.5': + resolution: {integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.1.4': - resolution: {integrity: sha512-mCi0OKgEieFircrtVYmQAFGszRtMnZ6fpZAXrxanXAu7lqZcsK1E1RAaZNG0uKAnxox3B1f4EyQNnoyMfN1vAA==} + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': + resolution: {integrity: sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.1.4': - resolution: {integrity: sha512-B9Ial3Kv5sh0SHnB1g/QWcUQCEvCF6QKGAl4zXypYj65mVI+B4AhFBwPtSN7pDrJeIx8Z7zdy4ntx+wQABom7w==} + '@rolldown/binding-linux-arm64-gnu@1.1.5': + resolution: {integrity: sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.1.4': - resolution: {integrity: sha512-lZVym0PuHE1KZ22gmFTC15lAkrg9iTszR617oYRB/iPY1A56ywoJzVKOJBKaot5RiikCObmur6pogpse3gRcng==} + '@rolldown/binding-linux-arm64-musl@1.1.5': + resolution: {integrity: sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.1.4': - resolution: {integrity: sha512-t2DNiLJWNTbnEHyUzTumldML6ET4/g16467LZoDDJ3tSxGvguL5/NyC2lCsNKuyRycg9XeDQF5SSv+TNOhQEXg==} + '@rolldown/binding-linux-ppc64-gnu@1.1.5': + resolution: {integrity: sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.1.4': - resolution: {integrity: sha512-0WIRnL1Uw4BvTZRLQt+PVgo6ZKTJadlC2btP+/EOXv2f/DWbY0rEgl+y834mIVwP1FkTlWVTrGGJXf12lru7EQ==} + '@rolldown/binding-linux-s390x-gnu@1.1.5': + resolution: {integrity: sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.1.4': - resolution: {integrity: sha512-JWtGshGfX+oENAKonoNkqEJX+7hC8yfhi9GUyPX1VX4mdh1y5r+ZiJLR5XzAB0aoP6s/PcILsGjKq8O0mm24bw==} + '@rolldown/binding-linux-x64-gnu@1.1.5': + resolution: {integrity: sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.1.4': - resolution: {integrity: sha512-rT6yQcxUuXs4CnbofqwHRRV0iem349rLMYpTjkgQGLjrY4ado/eDzwPZPTCgTOlF6Nkp8NEv70yLMTn6qkWxsQ==} + '@rolldown/binding-linux-x64-musl@1.1.5': + resolution: {integrity: sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.1.4': - resolution: {integrity: sha512-KXMGoboq5cyaCQjDA4GLuRiOwBQ0EyFnJoVViLeZ45/3rFItRODEr+NdsBcVpll40hhNArlm/speWGRvj08LzA==} + '@rolldown/binding-openharmony-arm64@1.1.5': + resolution: {integrity: sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.1.4': - resolution: {integrity: sha512-5K83rb36oJiY7BCyE9zLZtGcPV4g5wvq+xwdO0XPIwDVZI8cyB/AUjkNXGb92/rnmezEkjMOpgY61rtwjQtFwg==} + '@rolldown/binding-wasm32-wasi@1.1.5': + resolution: {integrity: sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.1.4': - resolution: {integrity: sha512-PnWBtw3TV5KOg69HQQDR0mnQuyCmSGR2pAB4DC1rPF808fgKeTUMj2EOEyKATpgiuxuR5APQmiDO7PDgEjTFSA==} + '@rolldown/binding-win32-arm64-msvc@1.1.5': + resolution: {integrity: sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.1.4': - resolution: {integrity: sha512-M1lpniBePobTfsa7Ks9a199e1akxsXn+GYBUKsEzv3YFzOm1HJAMNwKI3qr0Zq+mxwx9gOZoTdP1yXRYsZUocQ==} + '@rolldown/binding-win32-x64-msvc@1.1.5': + resolution: {integrity: sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -3539,8 +3645,8 @@ packages: '@selderee/plugin-htmlparser2@0.11.0': resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} - '@shadcn/react@0.2.0': - resolution: {integrity: sha512-g/LMtyL0eiHCHkOCelhYf32RC5nTMdtUNag1ZQRhSDCW+jnHxDY1Dajk7P6zJosOg8z2N4wzfKOY5sh54QTDYA==} + '@shadcn/react@0.2.1': + resolution: {integrity: sha512-5krgi3dRMKb5jH6a+qPzVJUy/54s0kKE4Rw4LjDfLqOdVQTWKUgxWf1kW8r912I0jX/Lzxqc+pgjkjWxUIK5BQ==} peerDependencies: '@types/react': '>=19' react: '>=19' @@ -3550,13 +3656,9 @@ packages: react: optional: true - '@simple-libs/child-process-utils@1.0.2': - resolution: {integrity: sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==} - engines: {node: '>=18'} - - '@simple-libs/stream-utils@1.2.0': - resolution: {integrity: sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==} - engines: {node: '>=18'} + '@simple-libs/child-process-utils@2.0.0': + resolution: {integrity: sha512-dvNoRKLijXnD0XoJAz94pbNuB5GQgDr55UhpSPhffDkTT0Cmcqh9jSCOtwfT2d4H6MI9E7c4SgtMuJXZ6F3c6A==} + engines: {node: '>=22'} '@simple-libs/stream-utils@2.0.0': resolution: {integrity: sha512-fCTuZK4QBa+39Oz9l4OGfJfz+GpwCp3AqO7Zch3to99xHPgstVsRFpeQ8LNd2o1Gv8raL2mCFwiaHh7bFSp5DQ==} @@ -3584,28 +3686,28 @@ packages: resolution: {integrity: sha512-gVaaGtKYMYAMmI8buULVH3A2TXVJ98QiwGwI7ddrWGuGidGC2uRt4FHs22+8iROJ0QTzju9CuMjlVsrvpqsdhA==} engines: {node: '>=20'} - '@smithy/core@3.29.1': - resolution: {integrity: sha512-qoiY4nrk5OCu1+eIR1VB8l5DmON/oKiqrd5zZFAhXJXjJlLWQusKEW/SkBDAtGDcPaz86m9kfcE1lngU0GlM6A==} + '@smithy/core@3.29.2': + resolution: {integrity: sha512-DXUk6yU0C1Q1tYvJh1VCtl8QOBcSoZpKwjTPkxT6A4MUQYHvgeKGByL8mrEdxnvhdf9nq5GyzmRb5n/vPgu3Lw==} engines: {node: '>=18.0.0'} - '@smithy/credential-provider-imds@4.4.6': - resolution: {integrity: sha512-B2WQ/PV/H6Jeg3lrIq6bKUfa6Hy01mtK7CGs6lhjzHA6k4aagldH6T6eEjnzKl4HI0cJnAsxfJ19pgb5PV+CVQ==} + '@smithy/credential-provider-imds@4.4.7': + resolution: {integrity: sha512-UEMLOoA0Fl4uYBxh6l0uN0H6EJe/A89OGeDNTteQeXpJ20BcpfIr4wlCY9pel1jEAUHAxaYwuqrYlrKdXE1GKQ==} engines: {node: '>=18.0.0'} - '@smithy/fetch-http-handler@5.6.3': - resolution: {integrity: sha512-CwCc/7SMTj45y97MUnDTbTaxvtAsiNNRm81z3abROIuMbMsC2Iy5EKfkkVdsKrz8WExQAAMx1EJapq+9j4fFTQ==} + '@smithy/fetch-http-handler@5.6.4': + resolution: {integrity: sha512-psnst7NZWdAEvJvyW8YZEE7xNVMyLrQFfHtyrVFrxNyy+dKWkQ+rqC6oI5ZhxThpUy9RSfEshgm34zqbOxzsRw==} engines: {node: '>=18.0.0'} - '@smithy/node-http-handler@4.9.3': - resolution: {integrity: sha512-qZTa4gQFUo8RM02rk6q5UVTDLNrQ1oS20LsepBzqq1QBVc/EHJ03OOUADcqMZiXHArW+Y7+OGY0BpdTwZRq/Yg==} + '@smithy/node-http-handler@4.9.4': + resolution: {integrity: sha512-BNTop/fSOptmoVk8g+efwHCofFh37g70OWGAFES1TeAAJja1K5aAI8rTE26ETSc5k8IQuWY2kAIoPla01NgYrA==} engines: {node: '>=18.0.0'} - '@smithy/signature-v4@5.6.2': - resolution: {integrity: sha512-QgHflghMoPxCJ9axiCVh8KZfbC9fuP6vkXXyK//E3cq7nLaSSyyLj0GAoqVWezYeDQmXIZhmlRvLE16jsqDK6g==} + '@smithy/signature-v4@5.6.3': + resolution: {integrity: sha512-8qVKKzqh7naF27ePmx0SkUfnGP/wBI9dyaeAmhHvopnbIlItUAmB/e6PkPCU3rRb2v9BY8D4EZXSoydSibatvw==} engines: {node: '>=18.0.0'} - '@smithy/types@4.15.1': - resolution: {integrity: sha512-x3L0XSACF6UYzKpa9biqiRMgvH5+wnFFew9Tm/grFYqgaupPwx/+ojDPpPJM8dZON3S9tjz5U+PQYsCBd1Mw5Q==} + '@smithy/types@4.16.0': + resolution: {integrity: sha512-aVUabzlBBmY0PfvVgLKQSOGFIL5/7R54JE3uD9a5Ay/jSED61SkuAcCYENNXJzYUvJ1NPrWO0P+rAXHCkbBUKw==} engines: {node: '>=18.0.0'} '@socket.io/component-emitter@3.1.2': @@ -3621,8 +3723,8 @@ packages: peerDependencies: solid-js: ^1.6.12 - '@solid-primitives/resize-observer@2.1.6': - resolution: {integrity: sha512-GFj6b81KIahl5SBf35VlyClHshDhVEREeZz2WYkHHKBvam66mE5H5f1g3EralabAAjmcU1bBd18YYYETPv0Knw==} + '@solid-primitives/resize-observer@2.2.0': + resolution: {integrity: sha512-9Fuu/EWBeGj+atGHRJp70HKhdfalmpjwxY8a32NZixdLNmfCJ45AfhLQNr6uOzETbbiMx4iCKlTrJ8KZCHC2Ww==} peerDependencies: solid-js: ^1.6.12 @@ -3977,205 +4079,205 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' - '@tiptap/core@3.27.1': - resolution: {integrity: sha512-rV6Qn4wmC6BxfF+4mu6bqGWj9vA4oXXhsrpXaJL2uhjxeHAGofjwcHof2X84VYzeyXgdlsGmqKie4TAppVXZUQ==} + '@tiptap/core@3.27.3': + resolution: {integrity: sha512-TJj5929M96C1KlH796wS8MywfHDh49RhmakOyzyMMc9pFmRj9UXi1gj0TCXgsZtjEOG7B+m/DRvNOvnuvR9kmg==} peerDependencies: - '@tiptap/pm': 3.27.1 + '@tiptap/pm': 3.27.3 - '@tiptap/extension-blockquote@3.27.1': - resolution: {integrity: sha512-VMF7xJx6qEGiX6DTKNiL31NLqypOcd/4sNjFSe8rb41PwejBJh/nOqVIbBvWkiT6NMGFLxMhj7zJ8/zPo1hXeg==} + '@tiptap/extension-blockquote@3.27.3': + resolution: {integrity: sha512-VGoVMcqcGkkoduzEqQ70ZK5OOHBDn5iYeHJSgkvNoSHzYHl0CaKoWxoDKJjSWC5DAM4mBU+tXTlsiUp3evRMfA==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-bold@3.27.1': - resolution: {integrity: sha512-TlC5bsS+pqETTrlz4CZz9RO/cKBYtELGIxwtKeivUn3eNfnOxQbbu4WDsiwIfzRFyd0OMnKl6BPM2KnYEehoEQ==} + '@tiptap/extension-bold@3.27.3': + resolution: {integrity: sha512-pchbycFppBqBmvk+OxrQLIPZLNd3rNbcm7zOa+OTjluphpAcsJ6AmHBmiRhJUYWitV6/SA+0nujcaWxBp5hNcQ==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-bubble-menu@3.27.1': - resolution: {integrity: sha512-j/j8Qp9Z5nViade2m7zjrO/CYH/Ca80Qj7aqo0eUaei6FZQ5izlF9o4XQU5EFMAutV6mwynsPUp8FVo5sCuYfw==} + '@tiptap/extension-bubble-menu@3.27.3': + resolution: {integrity: sha512-PKSM9g8BXzO0Lxm2gOin7FAFvxO6T0QvlXTXVke/GJn/sR1tEz7w5ybsvweytUPmSliUc601pfIUOHKEhIVC2Q==} peerDependencies: - '@tiptap/core': 3.27.1 - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3 + '@tiptap/pm': 3.27.3 - '@tiptap/extension-bullet-list@3.27.1': - resolution: {integrity: sha512-faCUHnRP47o9Zh9VZZX6EX/569udw9Vopm2PgEKPWuKLE2qaS5WBuUVU0iItdJmKUqaWiOZkpoW4jvnDmj0dfg==} + '@tiptap/extension-bullet-list@3.27.3': + resolution: {integrity: sha512-owQW6mcgnYgQU1z5BqmslcjZFBUm1SGM/Ax++4R6XelIt/7ol6uSTjzjAzum+ASW7UlBbuJHuSgRjl8cA+RGkg==} peerDependencies: - '@tiptap/extension-list': 3.27.1 + '@tiptap/extension-list': 3.27.3 - '@tiptap/extension-code-block@3.27.1': - resolution: {integrity: sha512-pHlzmZx2OlHfyQ0yRlT5UL4mGokz947DthZuYefN1OleVqOkHpWBG+2JQwqoNq6bmzMne92zbH32rhcJUEYSjA==} + '@tiptap/extension-code-block@3.27.3': + resolution: {integrity: sha512-3CVnzkpGoqqI5KaXI9l9PMwLkx34SYY63tpeo0I0QjDk4LU+JTAQDTPJFSwB4zTsHZ7ZFMU0jjasFOZ1kZRVgw==} peerDependencies: - '@tiptap/core': 3.27.1 - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3 + '@tiptap/pm': 3.27.3 - '@tiptap/extension-code@3.27.1': - resolution: {integrity: sha512-epOUpFfEmBzjvnqvjv2qHX7NAuLo5dlOGV690lWu+sAYMjibuJBeVvAiKPyFCfRCCTUxdbDB3jbaOA1yEcEJ7w==} + '@tiptap/extension-code@3.27.3': + resolution: {integrity: sha512-T7JF10Y3k7fyVujXXLVubdUh7fctgBUoiuxbvjotpltg1U/mPbOcT0UW/uif9j3H8TFvAwNApVw3x8bwwFUakA==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-color@3.27.1': - resolution: {integrity: sha512-9R/vW4dDTce0E0HU+AyfSkKhz08Hlrx7noRRj3CKrTwsCTR86wReTKFHlzxhLKZiDrJuV2Y7CtNG7KGrAArf+A==} + '@tiptap/extension-color@3.27.3': + resolution: {integrity: sha512-tNXyK3VXPGygJP+vq1+YyPmrxLabx4vs+rYiVhGtmhIapTQeMVYcHbFH4s4v3h5m8JGVlTWnpI8n7cb5ExIhSQ==} peerDependencies: - '@tiptap/extension-text-style': 3.27.1 + '@tiptap/extension-text-style': 3.27.3 - '@tiptap/extension-document@3.27.1': - resolution: {integrity: sha512-8FbBTkfnRP4iVaoj+2h3iWa+H0eGDD3yTyVCwrmue/sQTkqUNUoSuAZa3GDG4Sd41xdPwTJxl9nUWGgM1qDCnw==} + '@tiptap/extension-document@3.27.3': + resolution: {integrity: sha512-PR25MRv56Nm4ETVLwA8nAh/0RrVdvD4D2nxnAC8kUkxz1WOYDaqTfPqqEeSWDoUUTUp1I1xzDkD4x0gEnAlmZA==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-dropcursor@3.27.1': - resolution: {integrity: sha512-blFf9x9RG0Qr7P3FoAH/033ffa+mMLZn34trVs8Vi0Ppk6FmJAg5HpYFOtmYoeREdNDJ5rHJKV7SoACbOHgskQ==} + '@tiptap/extension-dropcursor@3.27.3': + resolution: {integrity: sha512-XsL0Ziual+ynXyx5JgLb0KIOShlMN3MW7+GQvf9PGRb1vOB7IOTRFDxMPrxDWcFIZ6WWMWSrbkCLOKHStt1BWg==} peerDependencies: - '@tiptap/extensions': 3.27.1 + '@tiptap/extensions': 3.27.3 - '@tiptap/extension-floating-menu@3.27.1': - resolution: {integrity: sha512-BmJF1VqB7dSJkgAalrpVFj88WLhxKjcWPuWHOqf2ITrUU2832BhKLXKmxjWUy1gqV8PfNNVWtGfIERy7I0y0+Q==} + '@tiptap/extension-floating-menu@3.27.3': + resolution: {integrity: sha512-qL+g1Z6MqZvYG4mHTPwub9II2fWZY+2I5VFfV8fzqy1HchBOyY6Df0mRKDNb0bmjBdFabIXnswz3iqLx3mDTbw==} peerDependencies: '@floating-ui/dom': ^1.0.0 - '@tiptap/core': 3.27.1 - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3 + '@tiptap/pm': 3.27.3 - '@tiptap/extension-gapcursor@3.27.1': - resolution: {integrity: sha512-QoezN0wdvXIwLQ4ee2ccWDaX3RG0lzgQpIMpMz55oPDhpUVax1+19ApsS53LkcktpS4EbnPL4xO4DaJk0Vp7PQ==} + '@tiptap/extension-gapcursor@3.27.3': + resolution: {integrity: sha512-MVBqzwYrDOttkn2GOrvvKTDCymfSS2VGSKpahcKKhge5mweSDiqko2X1vBDnMF8aVW3WxIFfDMmO4VMmh8HDZA==} peerDependencies: - '@tiptap/extensions': 3.27.1 + '@tiptap/extensions': 3.27.3 - '@tiptap/extension-hard-break@3.27.1': - resolution: {integrity: sha512-iv/m9hzl6jfSj9Q8UEjAxONvCoUDaP7M9SRCPx3PaLNxA230TTD6RE0Ye4zFJ8ze7ZVoJJMAqg9Qpq1iYg2JOQ==} + '@tiptap/extension-hard-break@3.27.3': + resolution: {integrity: sha512-cySObJITR2CRrWII87mI2LJ12wEETTnxt2p1vvC6ZtUmKnB50fOu+ux8ZEt6KYNocIOtrEZthNFzTOx7R7UtrQ==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-heading@3.27.1': - resolution: {integrity: sha512-SrC4l1kEIyv9ZXFaI/8LQqU2MyMmjczw7XXsWUQOTN4YXv0JyVgMNR3cI/wz0d2xsTfBdZ1N85Tdng+Ga1t0Sg==} + '@tiptap/extension-heading@3.27.3': + resolution: {integrity: sha512-QHXnsNic6iId8pnsFZ8z4PkX5L+HCHa/D7rAi3nNWtPlSIAOxo4nKrALcB5/tHmY+XL8kEXKH3nsNLNEDLCYPg==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-highlight@3.27.1': - resolution: {integrity: sha512-IeMIUKbW4oyRkgn92BPYQ0fifkbTwVigKwa107nGDHMokz+pHQPFHy8xG3U7gtUOra/8OUo57bFgNGuP0TaH4A==} + '@tiptap/extension-highlight@3.27.3': + resolution: {integrity: sha512-99QYxMx8F/NhdvznM8/Zhm4XiCdMU0OEiLwPvLNObJiKV8UBqjdA68cJLX6FRuOi2nqD7xfJq2KuSsFKBldi2A==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-horizontal-rule@3.27.1': - resolution: {integrity: sha512-QlKE7qn5qMnIGVGhXQlvYedvLtNJ9z0dmit5w8vPb8tKzW4Spk6M7N2kruprrDA8GBwHfeR5wmF+njfUm34qxg==} + '@tiptap/extension-horizontal-rule@3.27.3': + resolution: {integrity: sha512-sNCuo0+Q001B5XTVWY+ULpWXQqtBNRmAqXxAexZl44bx3rDqHG8OzjwT4EM0LIj2+BYVbdqwaJ1vfQbZVEEbig==} peerDependencies: - '@tiptap/core': 3.27.1 - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3 + '@tiptap/pm': 3.27.3 - '@tiptap/extension-italic@3.27.1': - resolution: {integrity: sha512-jGGeyn9uRUnNjSTHpbqhiGsp6KaYTSbV09jDXPJI9cDwfV9hpugLvpaCZd0BMBbhU1B1W6kOfX0BE15qX/HQfA==} + '@tiptap/extension-italic@3.27.3': + resolution: {integrity: sha512-7VpVi2vn8kGFAc/HLrt96J/E6+LXOGKn8xLhJS863t150yLIG3EPQLA1h+G5O6eo+/w+9YokvJAAJoeDihj1Jg==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-link@3.27.1': - resolution: {integrity: sha512-/2jBfsxBZUDGJmpZifqRQPz7f1E5qpS1BckTZ39TADzUJX+feKy7RJ3DtQ02+8y6SSMzvP9loGVjrk6zEMTk4g==} + '@tiptap/extension-link@3.27.3': + resolution: {integrity: sha512-iXmu1tJ/3vP60c9d+zfO3+X64vod2EyBrM1qeufecAtWA6t0bT9tYeka0Zq6qDRGsZK5zViO9F2lsY7eHXiYuA==} peerDependencies: - '@tiptap/core': 3.27.1 - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3 + '@tiptap/pm': 3.27.3 - '@tiptap/extension-list-item@3.27.1': - resolution: {integrity: sha512-zwRl01ETfCkWUvtvK5fw9bXtAajMPkvlkE3Cq6JvH3LF7XXJwDtNj5Tj7exacMpCaSZmlNc43vFb2rAYnrnwMA==} + '@tiptap/extension-list-item@3.27.3': + resolution: {integrity: sha512-UddhVaQ7+V9IfQVVE8AJLNzSmyaaNpZPQsoPQxFNlJyOFxD6RwSTT8L4rb/TwbUctxSFWpyd1J7exzf33Ony/g==} peerDependencies: - '@tiptap/extension-list': 3.27.1 + '@tiptap/extension-list': 3.27.3 - '@tiptap/extension-list-keymap@3.27.1': - resolution: {integrity: sha512-OIMZNlzPSO8WRd4ic73Fxckzl4N1tesjjLL2XApaNA/uMpO0LoF6WSRPAWv+Z24Wp92ARRJAnRP7iZoI5+Jxig==} + '@tiptap/extension-list-keymap@3.27.3': + resolution: {integrity: sha512-GZPVg4QCFm41yTMPEPeTlH2odNeQwRuWHY/pt3pI5LsfipQ4kDBv6h9we928vJQUnU2Gg9Y3cL5iRbmXIWWTUA==} peerDependencies: - '@tiptap/extension-list': 3.27.1 + '@tiptap/extension-list': 3.27.3 - '@tiptap/extension-list@3.27.1': - resolution: {integrity: sha512-c2Upru7lj0/ZV/Ibww6cNz6sUS8m6Dp/9uygFhYcZOd3X8M0xBIEk42c6m6SQehkPziVA8QOgNJz7sMqsbz1OQ==} + '@tiptap/extension-list@3.27.3': + resolution: {integrity: sha512-52rcaSzYjtVGUrNkdB8k1Bw/rId2lBirrWMvmnBLsieoeFd8zo8ow5zkwV057BYSgWXfnMAV7GOpDyq2IoSD9A==} peerDependencies: - '@tiptap/core': 3.27.1 - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3 + '@tiptap/pm': 3.27.3 - '@tiptap/extension-ordered-list@3.27.1': - resolution: {integrity: sha512-GYrKqD//9nHJ2r80uXqbDMzRnFpGzbaEQRTSGaO/SH7DvXWFMow8evkOdjQ7PCQO07jNjJo75+A85Jwu3Ov3AA==} + '@tiptap/extension-ordered-list@3.27.3': + resolution: {integrity: sha512-oHYoE65WfRSM5tCcXi8MtQmzPxz83E2qw0pa2yHBKwr9xCCQUu8vJHJE+EJGduWdaNImv43+6/6kVMeYYbXRKg==} peerDependencies: - '@tiptap/extension-list': 3.27.1 + '@tiptap/extension-list': 3.27.3 - '@tiptap/extension-paragraph@3.27.1': - resolution: {integrity: sha512-7K7eo1gruOgAsnbK+GCV23AUVUI0cL1bTig8HaPneoFMVbig7vddk8jNLKBWO8TXVbG7TuHdnDN4F98vdtwh5Q==} + '@tiptap/extension-paragraph@3.27.3': + resolution: {integrity: sha512-G5XPCN7lm0nULYPelJC2eUbKbt1q97j67e/HSWxwMYEXhceec5eNAtVfpDCRyXNO9osyBi2kXqLv/IQtxbch9A==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-strike@3.27.1': - resolution: {integrity: sha512-Y3DW1jlSlCNCyMGHP3+3qBNNPS83wuFz4RTYGjZtvRRTCRh7apZme9XRWMq1rN5mJ2Cr7fKocA2/5Bs13KgN6Q==} + '@tiptap/extension-strike@3.27.3': + resolution: {integrity: sha512-dp6Rs3I4zLVJPvAw2Q9yrNuYKcX5LTONH3/oyULvGsrqq5DKz7pqscfwhwnDSzrgm/3aCz6B9r1BVHlYI/DXlA==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-text-align@3.27.1': - resolution: {integrity: sha512-EXawuJBO55wd8WcTbHTMoPhv0CGQxza4yCCPB5Hqz4ZPQwahIr3ej+8yp/kimIl0xokabwZ0/Fu8STQ4AkZv5g==} + '@tiptap/extension-text-align@3.27.3': + resolution: {integrity: sha512-yyhlwRz0Eh6xQCn+GtTDWUGqxGajT02Qf8zBN/3eZQtl3EZ2xrI8lvfLmcV9SAW0srgMd+5hX0CVV+zKeXuxeg==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-text-style@3.27.1': - resolution: {integrity: sha512-J48WIl+6YDYTFPhWXUBQk+u7+AKVUqTdvrZOQyPYCGuQMgHrYzgWrI5+HeEifUgXJ5rMIWWP3qytp7KhVVqpDQ==} + '@tiptap/extension-text-style@3.27.3': + resolution: {integrity: sha512-oim4RqFtMBCA4N+J8f8dTFFYZrwyfmXLxLL5SvQkn+kkpfGLv8PqJCnJ4uHxsnHXDNsWHBtVVhfTGUABZsTEHg==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-text@3.27.1': - resolution: {integrity: sha512-6ZwaZwSrDh+KFFv6V1J79oO37yPs7y1bFxvk1/9Ih2rn3Xr5AWz+eMS+n8RpH3djBVVAQpdIAeYQgcn+VCSsTg==} + '@tiptap/extension-text@3.27.3': + resolution: {integrity: sha512-wSatZ/bop0pleeC18nF90zvWWEoRe/ewZncvm8LjcMrXwq41kTEs3j7nZflMYAh7X8fZvu00UIMeEyCNJl+5Yg==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extension-underline@3.27.1': - resolution: {integrity: sha512-N889J4nXN/TPfVt8uF9N1A0SY82E90zwc1y26lqOcw6KWNLmQrlhMh/9OD4ikLDbekmFpOBq/UicpHf/6S8hbQ==} + '@tiptap/extension-underline@3.27.3': + resolution: {integrity: sha512-YH7ka/Rp7ZwlzTuQCcs0OZ4CMSx/P/MzbseQKxKebEIZreWaKMZAaED97Fnu0dA66VlreD4/1C7xHJy84ovamg==} peerDependencies: - '@tiptap/core': 3.27.1 + '@tiptap/core': 3.27.3 - '@tiptap/extensions@3.27.1': - resolution: {integrity: sha512-1Tdx9faw8k0/83V6X+xCDVhV8yElGt95JxeW3YMkKQJI56QdlPz0xOdJPlMiSGJKinPyVier+x9LJD/YZUZIaw==} + '@tiptap/extensions@3.27.3': + resolution: {integrity: sha512-IA2QKUVJgzUPEhhkUfr6P5u5GFVfhiApiEaaHXBz07saL2c4HNoVs2RC18QlZDCtLNKrPR1mUScr72u7uYs+YQ==} peerDependencies: - '@tiptap/core': 3.27.1 - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3 + '@tiptap/pm': 3.27.3 - '@tiptap/pm@3.27.1': - resolution: {integrity: sha512-Ffjx+vimmBU7zH/KrpXzJid3+pziCe/VL2aexSTP63cyQwKQ65LkFkCKaIsSpFdQQuakVZBGWjCA5RoBV852pw==} + '@tiptap/pm@3.27.3': + resolution: {integrity: sha512-ppiG57RxM3HSHHgcHT0hP6Ib4P56Sd5itxdV4w0hIGHKPGyLLKiAkYp+htIHa9T7IvjMdaqxIlsfyV3ZKsS1sw==} - '@tiptap/react@3.27.1': - resolution: {integrity: sha512-/Wn2fc9zMtX08MXYScDFsm4wJ8lzfhfPEdbtls7WCDlbtrop48PWlkHDBBJrywARfAQTB2mFs9KiFy9yrQm5Lg==} + '@tiptap/react@3.27.3': + resolution: {integrity: sha512-lanXxMScw/LevbRFuFw5MoQJ1grmHUDszwph2VIk4l2U5e/EDIw3rr4CeDME6Z4isVReD6zccMFVShkHqsv+jg==} peerDependencies: - '@tiptap/core': 3.27.1 - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3 + '@tiptap/pm': 3.27.3 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 '@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tiptap/starter-kit@3.27.1': - resolution: {integrity: sha512-vfxRsqW8rCc0k4pzo0ilU3wobVi2wqVj88VZI2SlgZlNnUAkrDGDIAph7CTa9k9fshV+O1ivpEgPC5yC046jow==} + '@tiptap/starter-kit@3.27.3': + resolution: {integrity: sha512-xX3baFqiC30skntdhxUUvyJo755ON9c1pE83+2Wiq2g+Qnffg9knUuLCZStHoZZ318yB0aBsKAMvHWLtYDo8AA==} '@ts-morph/common@0.27.0': resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} - '@turbo/darwin-64@2.10.3': - resolution: {integrity: sha512-guuiO2kKc7yUQFU2jhWyM/BrYGD/brqb0+JvJIXTQ/QI1NlWfHZ1id50kkkOWqxmBiDc8DgW2orfY85pQIc7gw==} + '@turbo/darwin-64@2.10.4': + resolution: {integrity: sha512-m1MUEI4MJ69r5CwfMYxmHi0H0rrgiYCBOp0tgBZ9x/YVvOb5uu/lRIDyDwdtH054R2yWeQaIigUGu6aCX9f8cA==} cpu: [x64] os: [darwin] - '@turbo/darwin-arm64@2.10.3': - resolution: {integrity: sha512-UglEDl/r1/h5Vw6oS6cEE29Jugz2sDLxHCSupNznKatj1fDMRXFqYKFcbvm8RTFhtYPI45NxkrPNo9BqNychBg==} + '@turbo/darwin-arm64@2.10.4': + resolution: {integrity: sha512-VQ1Yxs5zkPT+2z7t1P4mvn6JmcKLkOCAsPuK9XbOvuVj0DlTlETfIXNisX0771v/vTWHOQqiwoGi+TtAUq8efw==} cpu: [arm64] os: [darwin] - '@turbo/linux-64@2.10.3': - resolution: {integrity: sha512-KuQxaPWD7OBmwEZqO0sgijwcuXR5eMWbo7BEt2m1D2Q3RylJDj7WMcJ0Btv2VJA0QC+khzAaTAm1yWowJ0CWAw==} + '@turbo/linux-64@2.10.4': + resolution: {integrity: sha512-IzV1QovmwX7mfGnVinmE++2IB8tbeo38weltiuH5zNqwCTBjLs/DytyRKx+bmnhHdXIq9SheR8p0Nip/LBUPHg==} cpu: [x64] os: [linux] - '@turbo/linux-arm64@2.10.3': - resolution: {integrity: sha512-DPkIKQ+6p0sho3Cx/e/A3F+AKgXQJA+z//cHsTcyyM1YWRGSYA0UTP8NUpb4iS2tVBSniGwmjRUr73hpq8kcDg==} + '@turbo/linux-arm64@2.10.4': + resolution: {integrity: sha512-rfujSQkP5aYiRn0PgTM7F00WkJCP/bKDVZbOx3WmrZwa/vHA0bplhCl328kpX7VI9HH2vI90ISGwuSVgJgoqTw==} cpu: [arm64] os: [linux] - '@turbo/windows-64@2.10.3': - resolution: {integrity: sha512-8NvFAze9D4PsosZAnK3aGqHz2vLzREz9lNIxLgfE0jRchq2sZQE190cwFm7WX17yg3ftPvwCvWH3rhLbG1UHCQ==} + '@turbo/windows-64@2.10.4': + resolution: {integrity: sha512-NnspP7Wd5fa3Wwnqv9bKfhegqZzuHBgbPxdZU/idTLQcazx/vgKu95JlCx2YHY0hdvKCnPcARrDwM+KEUmaO7A==} cpu: [x64] os: [win32] - '@turbo/windows-arm64@2.10.3': - resolution: {integrity: sha512-AqjqV5cHbFa0YRaQ+Dyw6lSm6as4h/Uf8LcZ7VN8i+Odr23ShFD5SUvVAR1d3rZqibFVs9c0VdtXdfQfkdcs3A==} + '@turbo/windows-arm64@2.10.4': + resolution: {integrity: sha512-Iv02YgOpaEShc2OkG7mgCJ2pEw1RUKiKbs0h8W5wAf4jZ5vpmraTEjuGTgHRuOORQnC1GN3KHo5WB+hu1abRMA==} cpu: [arm64] os: [win32] @@ -4248,11 +4350,11 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@25.9.4': - resolution: {integrity: sha512-dszCsrKb5U7ZsVZBWiHFklTloVl0mSEnWH/iZXfZUlI4rzCUnsvGmgqfuVRHL54ugE7/wRuxEIXRa2iMZ+BG6g==} + '@types/node@25.9.5': + resolution: {integrity: sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==} - '@types/node@26.1.0': - resolution: {integrity: sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw==} + '@types/node@26.1.1': + resolution: {integrity: sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==} '@types/nodemailer@8.0.1': resolution: {integrity: sha512-PxpaInm8V1JQDd4j0ds5HfvWQk8JupS1C0Picb96QJsrrRDjBH+DlK7L4ZdNSqNULhiZRQHc40nLVShaGxXAMw==} @@ -4301,53 +4403,173 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260705.1': - resolution: {integrity: sha512-OemjoGm+5nLCaUyL0zwWcSDhyQYQnO6/DcOidm2EzOqK7dYXgaCerDFUAz6iOGjOFtTAQFU50CV+ZbtUxodk9A==} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-wny2pgKjGbiZtnOIHVa3tXC1UfDqxNEFzyPGmiqybedG8hipG2Nfp0l5UxbaKCjkLacUpH/W5bP2hBOMVhCOzg==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [darwin] - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260705.1': - resolution: {integrity: sha512-jYEsBtcVOin3ARa2xAkwM21KOlmr9s3FGxcY28gESigXPJOGooRaxZlJ45tFM3TczCMEGmML88XCXuQaH2z1kw==} + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-Afc7M5zOwo+GpfcYwz5Z8HMB2tPVsui7nNIqEuuFB73MPdVqNn/Wmpe4tP4MRri0AtJnJknoHBaTJ/VDAp/Jhw==} engines: {node: '>=16.20.0'} cpu: [x64] os: [darwin] - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260705.1': - resolution: {integrity: sha512-kmWaZkuqb5RGTHt4AFIdPJ53/wO8vuZbmjSizNFNpvx1owYgQ8QZNu51zKfLQZbMs2FR7NAzVuQT14mhBaQW5Q==} + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-iITBa2WjjTI5N9t5l7Z4KoOSI+2zBlhbvFzsD/f8qX8QoKjz/Y4DPyBDgezYi8nkqjjksbgSOJ3/ykzhwrB9cg==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [linux] - '@typescript/native-preview-linux-arm@7.0.0-dev.20260705.1': - resolution: {integrity: sha512-abTOyfyx5SW5szf1YeZf5K9vUWEE7nbbqUUthl8OgRrFrJzlZnDIRf/FV0h6QGqQIN7XTf8lgKjdFe4piNFLww==} + '@typescript/native-preview-linux-arm@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-hJm/UOqZTr9FHmR7uNm8VGX4oKtfWk0Jem0zPeJFNC8ckGUfSBueyiEYMZB+XmRc1aG4x1E46y3CplP4CLHvGQ==} engines: {node: '>=16.20.0'} cpu: [arm] os: [linux] - '@typescript/native-preview-linux-x64@7.0.0-dev.20260705.1': - resolution: {integrity: sha512-oNA9I3MFLqdFVbwolnsFObjrQ1AsBXc4WXPcNyKcoaauAmFTwjxOBPKtiaqFKj4j4Abum7KvjVj0fgBaO5gRPA==} + '@typescript/native-preview-linux-x64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-du0dzi6y97Po5vDNdPJTyyijHCpaS22JLRnKZEJXBDaO9gCIymOv/5QQokFRuOlQm0bWl3i9PF4OVdGP6uAOQA==} engines: {node: '>=16.20.0'} cpu: [x64] os: [linux] - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260705.1': - resolution: {integrity: sha512-K6hTgnqAEBbrIGH6feXM//FHbk0ilSAQDpLct+3IHfd+tg2sKop5lK2rTZkl/ptHM7Vlh0CF77m0RL73an+oAw==} + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-SsAwfhyHJ1akgBc+99z4+hwdbHsdWaKB8EwCNIMA6JfSLMeUjffrYvxu+vfMyxVtOVOz7RrRXRoiDiu4a2sCtg==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [win32] - '@typescript/native-preview-win32-x64@7.0.0-dev.20260705.1': - resolution: {integrity: sha512-gAwPJgfQWtJnZlMrJ8NCA+vdI42N+XLev+jqZnpcMqt+Jd2zMtoNpppHB0I6URMVys+R2WpMiOOSlHcnvOMyTQ==} + '@typescript/native-preview-win32-x64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-DL4u27stv0fo71sVhOzHSwE+YMZsbBijVI+kg5dLDLilSH79WFTJ8RSQ46vJrCMt+Gjlv/JOZP1PuLJDfioYeQ==} engines: {node: '>=16.20.0'} cpu: [x64] os: [win32] - '@typescript/native-preview@7.0.0-dev.20260705.1': - resolution: {integrity: sha512-mXc3tDkRCe8UinMcl5yqUfLAP5Vk5MFuZNNaNsrwRehu1d+lnL+Zu+K7g6kSMOV8NOY9bn9tGFN4/cqhlK4VwA==} + '@typescript/native-preview@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-oUGp+Rep/hqMhPunyinsALUwSlzHINSxitifPiSaeqoKOKD2OlR9NE3TaPqwsl4NlGslsOSUXI1JotWQzpYCPg==} engines: {node: '>=16.20.0'} hasBin: true + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] + + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] + + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] + + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] + + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] + + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + '@uiw/color-convert@2.10.3': resolution: {integrity: sha512-5tIjb4CZzGR7K3Sshswsuuc6FOAFNFwjtF0hkhKH3f+CMauC4Akv7LPq6o9v68S7dIAeKvfj8qWg5Tc2I1TVSA==} peerDependencies: @@ -4408,20 +4630,20 @@ packages: babel-plugin-react-compiler: optional: true - '@vitest/coverage-v8@4.1.9': - resolution: {integrity: sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==} + '@vitest/coverage-v8@4.1.10': + resolution: {integrity: sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==} peerDependencies: - '@vitest/browser': 4.1.9 - vitest: 4.1.9 + '@vitest/browser': 4.1.10 + vitest: 4.1.10 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.1.9': - resolution: {integrity: sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==} + '@vitest/expect@4.1.10': + resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} - '@vitest/mocker@4.1.9': - resolution: {integrity: sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==} + '@vitest/mocker@4.1.10': + resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -4431,24 +4653,149 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.9': - resolution: {integrity: sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==} + '@vitest/pretty-format@4.1.10': + resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} - '@vitest/runner@4.1.9': - resolution: {integrity: sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==} + '@vitest/runner@4.1.10': + resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} - '@vitest/snapshot@4.1.9': - resolution: {integrity: sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==} + '@vitest/snapshot@4.1.10': + resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} - '@vitest/spy@4.1.9': - resolution: {integrity: sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==} + '@vitest/spy@4.1.10': + resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} - '@vitest/utils@4.1.9': - resolution: {integrity: sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==} + '@vitest/utils@4.1.10': + resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} '@workflow/serde@4.1.0': resolution: {integrity: sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ==} + '@yuku-codegen/binding-darwin-arm64@0.5.44': + resolution: {integrity: sha512-mpZc7hrjl/qxcbEMS6vVLE0lO4DjiXCvrp3gYbZ58bbmsSxSGCTlOCA0lpeLXAKOZxe0ZrVoqKteaewFF2Vbuw==} + cpu: [arm64] + os: [darwin] + + '@yuku-codegen/binding-darwin-x64@0.5.44': + resolution: {integrity: sha512-PCt776PnGtnQYimxk18IyvPf/BQ6CNU95W+6eaoQfeME8ra+7v3pNNoTAmLfSveUC9KZPaoajR9NqkKfEVjA2Q==} + cpu: [x64] + os: [darwin] + + '@yuku-codegen/binding-freebsd-x64@0.5.44': + resolution: {integrity: sha512-5MNu1R4ysytPLMdl1UlGyjgAbUdT8fguW/QRo+pyEymbuWRN5n8JEHCFpm4AsWdP61fStagSpPDJcwN+mwC9Lg==} + cpu: [x64] + os: [freebsd] + + '@yuku-codegen/binding-linux-arm-gnu@0.5.44': + resolution: {integrity: sha512-xbP2qQ7/h6ZZKeckCiI2osB5SE5PBfLb4uzIfO1BSTX+9rlBKTqomxDaCib7aPf2X1CXMiIq+i7AK1EhBa5a7A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@yuku-codegen/binding-linux-arm-musl@0.5.44': + resolution: {integrity: sha512-gmXKMCpgkUm5PllGMKBMoBmqgbTQkx+S85eE46LctuwTSKS/K7u65NE6t4zk6cLDvZpV67enycKXBORWn6q7xA==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@yuku-codegen/binding-linux-arm64-gnu@0.5.44': + resolution: {integrity: sha512-eOoejNUtnHs1/TMn4wryOAG/TarvlOqSZtRPeS56liBKp/GVQSirqTM9AITSGPLSdK1u7fZWMdj5IOEoJp3ruw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@yuku-codegen/binding-linux-arm64-musl@0.5.44': + resolution: {integrity: sha512-xTzrhEMy1mdv5+SbJPPlwqlMrhXGPntE2f12TLi+dNPXhif4iXCGJpoh8pV9nwZFE/cq1ITuTnjIfTFj/PifzA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@yuku-codegen/binding-linux-x64-gnu@0.5.44': + resolution: {integrity: sha512-2bvgIU4P+f4q18grdHoGnt9L6XlAciq/8GWpM06fmwj8qqruS8qwwwZXBk3/0U2+IHGv9pXRR8GtSXzl5n/blg==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@yuku-codegen/binding-linux-x64-musl@0.5.44': + resolution: {integrity: sha512-EzX5hWK0MmU4fbqY9coc5PJ0y0LYjrBdAF7mjSyetdK/yWRGBfHi9nh0dUJ0lqb47653hxB8/r9byfYgg6ecbA==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@yuku-codegen/binding-win32-arm64@0.5.44': + resolution: {integrity: sha512-/ajGFWcOLGtmVUdxWKXDW6Ixtez68xxtmd2l95xNg8Lzs4aqbV2cy0Ns2Bzg9vjHsgDIooQlLXHpWh6HsHcy6w==} + cpu: [arm64] + os: [win32] + + '@yuku-codegen/binding-win32-x64@0.5.44': + resolution: {integrity: sha512-geuJQ7FKI8YUtBgW8w72ChMfMvYy3gSytACxB4HOkylsoutrhH6lUNYHk1ny/p8u8t47NGxktpnzVJzI8IzJkA==} + cpu: [x64] + os: [win32] + + '@yuku-parser/binding-darwin-arm64@0.5.44': + resolution: {integrity: sha512-EXSW5w1YOIMyxu53MFxP43gTDeHlQueOjk8AEI9tuLF5976bDq3MXuIgzQvZKPVAirxGZu8+ANVXH1WcAH1G6A==} + cpu: [arm64] + os: [darwin] + + '@yuku-parser/binding-darwin-x64@0.5.44': + resolution: {integrity: sha512-pJBHsKxqR/nPwwaXgkkYTVo3G9dJ/AXhWsYyKyadU1zLg9gGfVwVTMehqwwutMCONDsLqOmEv/UqItmhpVsQJw==} + cpu: [x64] + os: [darwin] + + '@yuku-parser/binding-freebsd-x64@0.5.44': + resolution: {integrity: sha512-fOqYX5BQML94uj9hd3a+LlBNz54OoDm6l+wgUIZ8UUkOBfPV+w2lux1jj9FKXT85wwjDOFhgZ/XQYSEDK/N9mA==} + cpu: [x64] + os: [freebsd] + + '@yuku-parser/binding-linux-arm-gnu@0.5.44': + resolution: {integrity: sha512-kA2jRNh2cbbHDbhBN9IR8CnYI4UZHNQg0OVz6+V16Ph5VlLYpfv/6GdCmvQQoTGAnhFlbQiRoQys03ey91FTew==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@yuku-parser/binding-linux-arm-musl@0.5.44': + resolution: {integrity: sha512-TQ82L8c5Lxl3HBOmw0uGfCcsyw0mp7DVGwCuW24OdDWak6BKaumvB8/Ep1llPOvhk5xgSFB7fsqgh6sIwkNRew==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@yuku-parser/binding-linux-arm64-gnu@0.5.44': + resolution: {integrity: sha512-o6up+m/MsoMEtq6h4JTzmzKOvH9o3o41vK8oiok0LOZoPOFOqOSqC+N5V2ArD1O54m5LUq6ErghAbGWiPsMsqg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@yuku-parser/binding-linux-arm64-musl@0.5.44': + resolution: {integrity: sha512-3XZoiHhtrjWKgk7CJC/sGzk1TE57SDPYzOFXUg6CZrigRZ+c0Q5ItzJpyAvhzlxv5ruNRYiuGvFbaRSIDnp2BA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@yuku-parser/binding-linux-x64-gnu@0.5.44': + resolution: {integrity: sha512-7KYCySZI6cjsdeiiIwvviDfJFd4Xj5gjNBzm9akUpwxRXNwaHHuEq2yGkVdGqj3BT6dJsiNhJIhtS6k7/HJdFA==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@yuku-parser/binding-linux-x64-musl@0.5.44': + resolution: {integrity: sha512-SLU/nXwOjET2XlOiO984sAzCloiWw0+JdcWpGzXLz3JQWbdiblxWC9cIvB0fCtKdDhX1mIutKNEH+RRRJADYcQ==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@yuku-parser/binding-win32-arm64@0.5.44': + resolution: {integrity: sha512-LGmaJtB2mVqPD7Gu/RKAu9aIVxlaKPOgKB8RPHeFFD5Tf/apCiWZix1tkBjdOAo9cVEAoR9qnVHE6zJ+OG0drQ==} + cpu: [arm64] + os: [win32] + + '@yuku-parser/binding-win32-x64@0.5.44': + resolution: {integrity: sha512-2i0FTklLuhBIgILvtEQ3IN3J4qaTMKlxptseWNrz4F5mimL9UpQFUniVju9OOInwP2O1vgLdZn8EBjEXGNCHmg==} + cpu: [x64] + os: [win32] + + '@yuku-toolchain/types@0.5.43': + resolution: {integrity: sha512-kSpvPntnXw5+lYjO71ffBEnQ5ycQ74KGIYknh0TS4xeyCuBkOqxyJumxZkMhLBBUCLjDAbx2+Icnr3Zh4ftjpQ==} + abs-svg-path@0.1.1: resolution: {integrity: sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==} @@ -4464,8 +4811,8 @@ packages: resolution: {integrity: sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==} engines: {node: '>=12.0'} - ai@7.0.15: - resolution: {integrity: sha512-7406MUy9O5sIhwOgxEWuoj+td3XUGgG96SBt6pmBU4t4sQ2fpnDx5UnHaXT2HUTXl5GorbWz/MfCrSPRz0QJqw==} + ai@7.0.18: + resolution: {integrity: sha512-/DsiRfbLPtoHf9C47Hy+LK+HkjNowX1DQo3id4zWegfU6z1WjVDRAHYJAiX7SXhGp0mWX4tcenUhfIFessDWnw==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -4539,10 +4886,6 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-kit@3.0.0: - resolution: {integrity: sha512-8OG92q3R35qjC/4i6BLBMg8IB+fClWu/1PEwg2Z9Rn+BuNaiEgJzpzn+pxWOdHJWDCAwu2JP0wCDTozAM4QirQ==} - engines: {node: ^22.18.0 || >=24.11.0} - ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} @@ -4667,9 +5010,6 @@ packages: bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - birpc@4.0.0: - resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} - body-parser@2.3.0: resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} engines: {node: '>=18'} @@ -4694,8 +5034,8 @@ packages: browserify-zlib@0.2.0: resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} - browserslist@4.28.4: - resolution: {integrity: sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==} + browserslist@4.28.5: + resolution: {integrity: sha512-Cu2E6QejHWzuDMTkuwgpABFgDfZrXLQq5V13YOACZx4mFAG4IwGTbTfHPMr4WtxlHoXSM8FIuRwYYCz5XiabaQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -4731,8 +5071,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001800: - resolution: {integrity: sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==} + caniuse-lite@1.0.30001803: + resolution: {integrity: sha512-g/uHREV2ZpK9qMalCsWaxmA6ol+DX8GYhuf3T40RKoP+oL7vhRJh8LNt73PCjpnR6l14FzfPrB5Yux4PKm2meg==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -4901,11 +5241,6 @@ packages: resolution: {integrity: sha512-n4Kr1HFMTf3iMbES0TMxKIcYtUUv4rKqyQQp2JwfOEfFCOfGT3Tq4mCyJ8S9/YPyWhydjfKrrvnyl+gCjA+mJQ==} engines: {node: '>=22'} - conventional-commits-parser@6.4.0: - resolution: {integrity: sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==} - engines: {node: '>=18'} - hasBin: true - conventional-commits-parser@7.0.1: resolution: {integrity: sha512-6VtskFpPsNkGVk/TY2RnV/MEdKfvCPBtQZN9x8jh9+k5RWBQ+tiaWn5UFCzTr0Dd88iKx7xghxbjBRp5uIzp3g==} engines: {node: '>=22'} @@ -5285,8 +5620,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.387: - resolution: {integrity: sha512-TaxwufTFDufvPEoXdhwVrA3UdFWBeWGkYoJ1K8ldF1xe6gKfth6iRNS5lTQ5JPNOHdGQm8PT1QYKUqFLCiUefQ==} + electron-to-chromium@1.5.389: + resolution: {integrity: sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg==} emoji-regex-xs@1.0.0: resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} @@ -5587,12 +5922,6 @@ packages: resolution: {integrity: sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==} engines: {node: '>=20.20.0'} - git-raw-commits@5.0.1: - resolution: {integrity: sha512-Y+csSm2GD/PCSh6Isd/WiMjNAydu0VBiG9J7EdQsNA5P9uXvLayqjmTsNlK5Gs9IhblFZqOU0yid5Il5JPoLiQ==} - engines: {node: '>=18'} - deprecated: Deprecated and no longer maintained. Use @conventional-changelog/git-client instead. - hasBin: true - github-actionlint@1.7.12: resolution: {integrity: sha512-kSVz5clt9voatp2Tdh1BETKNooT358/nPChYseaDC4M6f9Hc/sBRMbhagx2FTu2F/WHzDoxlNPh2EqwBngTYQg==} engines: {node: '>=18.0.0'} @@ -5666,8 +5995,8 @@ packages: headers-polyfill@5.0.1: resolution: {integrity: sha512-1TJ6Fih/b8h5TIcv+1+Hw0PDQWJTKDKzFZzcKOiW1wJza3XoAQlkCuXLbymPYB8+ZQyw8mHvdw560e8zVFIWyA==} - hono@4.12.27: - resolution: {integrity: sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q==} + hono@4.12.28: + resolution: {integrity: sha512-YwUvVpSF7m1yOblFPrU3Hbo8XhPheBoiyfGuII6z19LnOr6JpDnyyp7LFNrfV56wS8tpvtBFGRISHN02pDdLOA==} engines: {node: '>=16.9.0'} hookable@6.1.1: @@ -5876,8 +6205,8 @@ packages: isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isbot@5.1.44: - resolution: {integrity: sha512-PGEHtwMnKbZpeSEXW2Utx+/JWed7dp6DiH0WWg33vGSDA7RUvpUeJSVlLrVkQ1RCpvDOUc/eH9ql7VsdbBZ8pA==} + isbot@5.2.0: + resolution: {integrity: sha512-gbZiGCb4B5xaoxg9mS7koAyRdvJnArk10VLSHOgz6rtBG93/pi1xOFaVvXMKZ7JXgyZ8zAbNRK5uIBdIUTFSqw==} engines: {node: '>=18'} isexe@2.0.0: @@ -6005,13 +6334,13 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - knip@6.24.0: - resolution: {integrity: sha512-PokLlgeEjLh1rAsB7ts+52wZ37HBr1nDhE6NNONwEaXdeZGCJOkP7ZlIAI2Gtu8xohquzTWy75bc/1diI9shQw==} + knip@6.25.0: + resolution: {integrity: sha512-Q3n41VjOOB/aqsbxb8kallAcFKrUz3b2S5fD5pTODljVpP01t+rvAgy2x3j0Cq8yEpRRHNdar1vHuqFfGuIakQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - kysely@0.29.2: - resolution: {integrity: sha512-s6WVJyEZrbm6jhBpiKHsGHyePMrVQKJ85wZCFCr9W4QHv6WTjWIrdvTmO9hDEA3bNK0xkrE2DqrHsXMLWuZpQg==} + kysely@0.29.3: + resolution: {integrity: sha512-VHtBdW6XB/pgoTSqraM3UAa2rYoYdNXqnNPpX+8XXP+cwYbVEFuAp3HyPt1vpNfU9l7Y2kpUrA9QDPsy8uUqOQ==} engines: {node: '>=22.0.0'} launch-editor@2.14.1: @@ -6020,58 +6349,58 @@ packages: leac@0.6.0: resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} - lefthook-darwin-arm64@2.1.9: - resolution: {integrity: sha512-119HryNcvr4nqn0wUIrNPgpMEPn9yMQzEcW/lezRsnb56PCJriJB92+MCySPVcWDxJnZef7o0T3jdnPNiSH7Qg==} + lefthook-darwin-arm64@2.1.10: + resolution: {integrity: sha512-nw+X8wRNDoUUV6WSteyKBbcLySq+fsmZt5WV/s50ZJpysmsDKJOUMln6SllNfP+60dzUahAO7REco/2633BsLg==} cpu: [arm64] os: [darwin] - lefthook-darwin-x64@2.1.9: - resolution: {integrity: sha512-dwo5Tke2XcQCM56DGHgFKBfRbJIL6xs2wZ0zG1TUVZgl4t4mQUt6LiZ4V/ZQfYHTZF9qywvXoIlR5N35qOaiVQ==} + lefthook-darwin-x64@2.1.10: + resolution: {integrity: sha512-KQ/bHmvpkFdHMn4pZnUdTf+GuSC+aBBgBTxZT4GW+6cSf+qbErKZBhK7cH6BmILsvx43+VzEArvHYY7YOfRFOQ==} cpu: [x64] os: [darwin] - lefthook-freebsd-arm64@2.1.9: - resolution: {integrity: sha512-+09PVap6nl6xsaHch5JLtq7WvIR++U1Q2MzA2ai0M4uB/VP3AqrvKqHw6+9hjyKnIH+HHL83uqi77EAY+LaxLA==} + lefthook-freebsd-arm64@2.1.10: + resolution: {integrity: sha512-8su6DwydP7+pv7kG0zCtjphqsw4ouOnfexRUErapy5GTxYBoUOhYz3RSHTSWNRsK6W4jva7FPUh2Lp5/PSn30w==} cpu: [arm64] os: [freebsd] - lefthook-freebsd-x64@2.1.9: - resolution: {integrity: sha512-8XresjKIYpkE9ARgCtBEZgJZxAU3T4MIqzj4zNy15XRT59I1Us+QdqXTNm+pkZ41Yd2X/nxs2Pkvbq3NWWlIGw==} + lefthook-freebsd-x64@2.1.10: + resolution: {integrity: sha512-GeAJEFxko3Lk+AsnS3NleAFrpyMLFUKOlgJvPKuU0xHwVEI/z+ZoCcmuO0BX+4CS0NLbZhC/YQAvBASqDvvVdQ==} cpu: [x64] os: [freebsd] - lefthook-linux-arm64@2.1.9: - resolution: {integrity: sha512-1oNIQfwrPe6rgU2KcDM3aF6+hpZDCKx1TmawQKpXUY5gVsbZ7MqX0Sk/1lnnWxqPm+kQQ5f6J2dpFWd+4xH8jg==} + lefthook-linux-arm64@2.1.10: + resolution: {integrity: sha512-1sHTCmpTWjVMs+yKPBLRNT1kuuIr1yjietlk7rCB6wFPVOS6Ph3o2zPFH2AvW1UymHlqwyHXzBr9EtDpQ7j1mQ==} cpu: [arm64] os: [linux] - lefthook-linux-x64@2.1.9: - resolution: {integrity: sha512-fT+7Q+BJyGp+CslFQkNXmdFRgyVXsPHPi9NAsDX0a6QOyNnoORByAsvx6zeAKuF5rL3BBgNfho1/v2RuGxGy9w==} + lefthook-linux-x64@2.1.10: + resolution: {integrity: sha512-z/VlRB3bh6mBvW3r1rwnJ5vP8z+Krx5gJzkZ4veDXh+6FlRTx8wtd3g3fllOv/yZMxkgmL3fQoFXv05Esa7vBQ==} cpu: [x64] os: [linux] - lefthook-openbsd-arm64@2.1.9: - resolution: {integrity: sha512-4bVuafBk3dddVNo0+3hMbjcJs4mqYAstxpPMmX2ufkudSTYFNIhWoqwuGVQV/SS/xdcOKJAldW4qayAzed2ysw==} + lefthook-openbsd-arm64@2.1.10: + resolution: {integrity: sha512-430zL8sSIKw5P0YXGG6PB+eAhHa06n0PXuaERaAQE4Ss3odfqwnl5Mq9hQmkEnOS1EGiQEKkd0UHv/i4PtMNIQ==} cpu: [arm64] os: [openbsd] - lefthook-openbsd-x64@2.1.9: - resolution: {integrity: sha512-PmPoMmLP/wQQWcQ9u2YH86bTZ3UCfBsxuEmVTEyPU2U8R1qSTp5r/Gs3G8cN5Mxo91XB9oBERtF1n+xD3W6aVA==} + lefthook-openbsd-x64@2.1.10: + resolution: {integrity: sha512-bgkO8PphGZVDhQgCJ524aYYPI5491pVmCiLPGjBIo1AvOSlIyw4N1Y+1C3QfqwEmechzw+Aq16SNc8pqv6UuXg==} cpu: [x64] os: [openbsd] - lefthook-windows-arm64@2.1.9: - resolution: {integrity: sha512-KphfkBKmwBnmolyrdhIl3lrBaOyTcCgXBT2AB/9OHnEXhOLvv5uTCUkrD4YRAxXPtFKq6UvnapIeoL3GZq0bdA==} + lefthook-windows-arm64@2.1.10: + resolution: {integrity: sha512-5Q6etF0Fla2DDA4ilDySrdNgiR5+W7cJZwnZ69Je3kvWCaWm4wnkuc8FEdjp3kiL2x3ZXipdI00f5vpO8aWmog==} cpu: [arm64] os: [win32] - lefthook-windows-x64@2.1.9: - resolution: {integrity: sha512-2qlUtkJHZ3MyUxgV5XTEmcrIoNZA07iwaquoswAcqv/1MeBFXlD+O+koFRfrzWng2O5WYEbpJnd8tvaYnV8fTA==} + lefthook-windows-x64@2.1.10: + resolution: {integrity: sha512-c/XH8YZtylG4XaxzqFfXluvq2LXq2W/p54Bnzn3+Z7E5X2Fk3JlFJAibulMbIt2+w8T7UI/r97ok5GqE4kGaeA==} cpu: [x64] os: [win32] - lefthook@2.1.9: - resolution: {integrity: sha512-bwDaIOViTktE8kJLf9jP0p+H2/RDTlFFlc43Am2YgUsX22hI6Sq4RbzsrecwzY5y+MHTipOH7WsmWSEniePHWQ==} + lefthook@2.1.10: + resolution: {integrity: sha512-K7mM4WoqMwqfXYK11EHy+lSH1uW8XHni3Yn/bSqyerPkUPygGdf3xn18JoV5HyA06xuQL3ofGAOjG01QX9oJ4w==} hasBin: true leven@3.1.0: @@ -6196,8 +6525,8 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - lru-cache@11.5.1: - resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -6308,10 +6637,6 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} - meow@13.2.0: - resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} - engines: {node: '>=18'} - meow@14.1.0: resolution: {integrity: sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==} engines: {node: '>=20'} @@ -6571,8 +6896,8 @@ packages: node-html-parser@6.1.13: resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} - node-html-parser@8.0.4: - resolution: {integrity: sha512-w2YxujN/TqrSIWGVNW/fVgKKfAyQeHMXCvnKZI0owLnfP0tfjdLecUoy9zhOMZGoEFk6eP5qSDyvUarjPl3bwQ==} + node-html-parser@9.0.0: + resolution: {integrity: sha512-MhdaHPyxnyYu/sf0TpiRvDnTrkum0UKHC7FdbDGIUQNlx3I7xzwXoyV0eMUMv/XU+lkJT1glOUzpDPq7b2p1Ew==} node-releases@2.0.50: resolution: {integrity: sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==} @@ -6624,11 +6949,11 @@ packages: resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} engines: {node: '>=12.20.0'} - ollama-ai-provider-v2@3.6.0: - resolution: {integrity: sha512-1Om3FVJYhBwkAr5kQ+BX1s/tdVdtVdoFQWrX4PBQHDHPISyGt24CjhtggEjUYpy5ait0YeVfZwEpIYjgD8Ih7Q==} - engines: {node: '>=20'} + ollama-ai-provider-v2@4.0.1: + resolution: {integrity: sha512-JHw/Knt4kOTSwQ0oqorbdgzukK6iE73U3MPUyOuCEBpAQGAzm80CQDwyaXMwF80yFjY21RY9qfzkoLyPFFts/w==} + engines: {node: '>=22'} peerDependencies: - ai: ^5.0.0 || ^6.0.0 + ai: ^7.0.0 zod: ^4.0.16 on-finished@2.4.1: @@ -6925,8 +7250,8 @@ packages: prosemirror-commands@1.7.1: resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==} - prosemirror-dropcursor@1.8.2: - resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==} + prosemirror-dropcursor@1.8.3: + resolution: {integrity: sha512-FoYbsJR8gK+DGlqhNoE29Loa38eIZPzQRIb1VMaDNBoo4OLP6vVof/jR8qFY/6XvUd6Dhug8MDCHl2a/h8RTfQ==} prosemirror-gapcursor@1.4.1: resolution: {integrity: sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==} @@ -6940,8 +7265,8 @@ packages: prosemirror-keymap@1.2.3: resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} - prosemirror-model@1.25.9: - resolution: {integrity: sha512-pRTklkDDMMRopyoAcrr9wV/8g/RYgrLHBuJAb5hlEuYZRdm5yqmPjWId83fpBwPpSFqEdja0H7Dfd7z1X/npcA==} + prosemirror-model@1.25.10: + resolution: {integrity: sha512-9n6rH4DbJU1eH4SxLt6Y0HhJIo6cZsb7DJ/30uob1hOKPeO6TAaMWI2tc7kwR92BjfPOU2fFHWbZLovLi3XQfA==} prosemirror-schema-list@1.5.1: resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} @@ -7013,14 +7338,14 @@ packages: peerDependencies: react: ^19.2.7 - react-easy-crop@6.1.0: - resolution: {integrity: sha512-zimsbH7DLuajy2hA4UpQpTVoisV8EpeE0/CFmph8tFS3EUbr83iL5TXMVYS0xli990VN6hVepmLNVRZ3SyD05A==} + react-easy-crop@6.2.2: + resolution: {integrity: sha512-b0HOicSvLYoNk1yvZTwjH8sNjF5uD9xLtWrSDnv+fx1dXTbwd8bNLQaP6gjXw//A+tni9Mw5KDmPNOEjKF55NQ==} peerDependencies: react: '>=16.4.0' react-dom: '>=16.4.0' - react-email@6.6.6: - resolution: {integrity: sha512-4eYmISIQbmEzibkl8pW+ZQHIFMwUVqZQRpTDYj6Ow7kk/gpUjtA95ggxoXji8pRq/y76tOhe7D3vNUJkZWO58g==} + react-email@6.6.8: + resolution: {integrity: sha512-AMGO67n9jrntQc7+cz/KjFzDO0IoQmpxC/yEZwLszTD7cTX/mwjITu8+dFatZMVkAU5Pd+VSp39e1IgHSP4cFg==} engines: {node: '>=20.0.0'} hasBin: true peerDependencies: @@ -7197,8 +7522,8 @@ packages: engines: {node: 20 || >=22} hasBin: true - rolldown-plugin-dts@0.26.0: - resolution: {integrity: sha512-e+kEPtUiDES0htk5iqkSeF4EzAV7R+vugGB44iPDuw1Kw9E+WyL1VG7PaV0IIjGHLiacztMBcMTyrr8ON9CT1Q==} + rolldown-plugin-dts@0.27.1: + resolution: {integrity: sha512-s1HLtZfsXcLsBrcqW6nmIcTqkBZd7Y9srgL9SMS2hNvl37US5jFl193d5ki2w9Ei5myP7ERLVlQX2o6ZTL/AQQ==} engines: {node: ^22.18.0 || >=24.11.0} peerDependencies: '@ts-macro/tsc': ^0.3.6 @@ -7216,8 +7541,8 @@ packages: vue-tsc: optional: true - rolldown@1.1.4: - resolution: {integrity: sha512-IjZYiLxZwpnhwhdBH2ugdTGVSdhCQUmLxLoqyjiL0JxYjyRst+5a0P3xfrTxJ5F638j4Mvvw5FAX5XE6eHpXbA==} + rolldown@1.1.5: + resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -7412,8 +7737,8 @@ packages: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} - std-env@4.1.0: - resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + std-env@4.2.0: + resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} stdin-discarder@0.2.2: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} @@ -7520,8 +7845,8 @@ packages: peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - systeminformation@5.31.13: - resolution: {integrity: sha512-iUJXJoKzm4vtLSeT3nwe2s9QjoJAxHg7wYJ0KaQ54Xy2u9jsTq0ULWQQ0+T72FXjX2XnGqubazNx9lUfng7ELw==} + systeminformation@5.31.15: + resolution: {integrity: sha512-7mqCtD28TK5dVdLAQONVa/Do/NBgMH2dxqf49nh6DIKoEWuDg6tkgGBP+dN22VEJVPZa/QqiHomhWNRn4WUNTQ==} engines: {node: '>=8.0.0'} os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] hasBin: true @@ -7612,14 +7937,14 @@ packages: resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} engines: {node: '>=6'} - tsdown@0.22.3: - resolution: {integrity: sha512-louqbfA8Qf//B9jTTL0FPtXTNpjCWv1VPkbcmQMph2pTpzs+LnB1tbe4tDDRVpo2BjF5SgUXaTZe45SxB8pWHg==} + tsdown@0.22.4: + resolution: {integrity: sha512-3a5FsNL2fH2jw3ozvFUuPMBgS0xXjX9wpZShHyB4klXelVhyaNw5Q5WA9TPCNeoGYpRZEc4OZdMx5wT4Fkma3A==} engines: {node: ^22.18.0 || >=24.11.0} hasBin: true peerDependencies: '@arethetypeswrong/core': ^0.18.1 - '@tsdown/css': 0.22.3 - '@tsdown/exe': 0.22.3 + '@tsdown/css': 0.22.4 + '@tsdown/exe': 0.22.4 '@vitejs/devtools': '*' publint: ^0.3.8 tsx: '*' @@ -7661,8 +7986,8 @@ packages: resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} engines: {node: '>= 6.0.0'} - turbo@2.10.3: - resolution: {integrity: sha512-uZIqzfgtWbyqu1Tqwdd0giRnPGgL0ejbcdF8eZLJhtTTVSrOgArZGzYeXTD6XNcc7ANgdhqex11Y9bHBeyiQLQ==} + turbo@2.10.4: + resolution: {integrity: sha512-GQpduILaKjoaGljw097ScsSyKTtZSY7cZ3bJktzfTkPMyCf3ShKLuXK2IaOEN2Plziml+ArR7WJ1m+V4VbnaKQ==} hasBin: true tw-animate-css@1.4.0: @@ -7676,9 +8001,9 @@ packages: resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} engines: {node: '>= 18'} - typescript@6.0.3: - resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} - engines: {node: '>=14.17'} + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} + engines: {node: '>=16.20.0'} hasBin: true uc.micro@2.1.0: @@ -7894,20 +8219,20 @@ packages: yaml: optional: true - vitest@4.1.9: - resolution: {integrity: sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==} + vitest@4.1.10: + resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.9 - '@vitest/browser-preview': 4.1.9 - '@vitest/browser-webdriverio': 4.1.9 - '@vitest/coverage-istanbul': 4.1.9 - '@vitest/coverage-v8': 4.1.9 - '@vitest/ui': 4.1.9 + '@vitest/browser-playwright': 4.1.10 + '@vitest/browser-preview': 4.1.10 + '@vitest/browser-webdriverio': 4.1.10 + '@vitest/coverage-istanbul': 4.1.10 + '@vitest/coverage-v8': 4.1.10 + '@vitest/ui': 4.1.10 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -8044,8 +8369,8 @@ packages: resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} engines: {node: ^20.19.0 || ^22.12.0 || >=23} - yocto-spinner@1.2.0: - resolution: {integrity: sha512-Yw0hUB6UA3o4YUgKy3oSe9a4cxoaZ9sBfYDw+JSxo6Id0KoJGoxzPA24qqUXYKBWABs/zDSGTz9kww7t3F0XGw==} + yocto-spinner@1.2.1: + resolution: {integrity: sha512-9cbFWLhbiZp+820O4pkHGNncI7+MrUGzBOjw8NMG+ewsY+aG0DdEXnr19Smxao32YOjLZRMdn1UtaxcrXOYOIg==} engines: {node: '>=18.19'} yoctocolors@2.1.2: @@ -8055,6 +8380,15 @@ packages: yoga-layout@3.2.1: resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==} + yuku-ast@0.1.7: + resolution: {integrity: sha512-2RiMEWv500TixY5rJy6OZd4fSy9WYZKWh6gGbIJ7y7vAGcuCugWOWwOLGaQcRZrXcPUfqtLtvpaJ3SdXtWlhKA==} + + yuku-codegen@0.5.44: + resolution: {integrity: sha512-0rhtgWGz+bR3Pe7xqJ5E4VqxI1vqNtkeJRkeXM0Qd3tgldYClQipxa9bRZyuNOOfk0Ri02scrjnkoAHM16/f2g==} + + yuku-parser@0.5.44: + resolution: {integrity: sha512-mAhpQZ/bXjxZmKiGUqEWskC9mZTcTBv6/fdzVdzdjM6XuD1DP3IavdLVWdM39L9ewK9vS9OtJmaKNeWgRzpy0w==} + zod-to-json-schema@3.25.2: resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} peerDependencies: @@ -8091,52 +8425,89 @@ snapshots: '@adobe/css-tools@4.5.0': {} - '@ai-sdk/anthropic@4.0.8(zod@4.4.3)': + '@ai-sdk/anthropic@4.0.10(zod@4.4.3)': dependencies: '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) zod: 4.4.3 - '@ai-sdk/gateway@4.0.12(zod@4.4.3)': + '@ai-sdk/cerebras@3.0.6(zod@4.4.3)': + dependencies: + '@ai-sdk/openai-compatible': 3.0.6(zod@4.4.3) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) + zod: 4.4.3 + + '@ai-sdk/cohere@4.0.6(zod@4.4.3)': dependencies: '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) + zod: 4.4.3 + + '@ai-sdk/deepseek@3.0.6(zod@4.4.3)': + dependencies: + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) + zod: 4.4.3 + + '@ai-sdk/fireworks@3.0.7(zod@4.4.3)': + dependencies: + '@ai-sdk/openai-compatible': 3.0.6(zod@4.4.3) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) + zod: 4.4.3 + + '@ai-sdk/gateway@4.0.14(zod@4.4.3)': + dependencies: + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) '@vercel/oidc': 3.2.0 zod: 4.4.3 - '@ai-sdk/google@4.0.8(zod@4.4.3)': + '@ai-sdk/google@4.0.10(zod@4.4.3)': dependencies: '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) zod: 4.4.3 - '@ai-sdk/mcp@2.0.7(zod@4.4.3)': + '@ai-sdk/groq@4.0.6(zod@4.4.3)': dependencies: '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) + zod: 4.4.3 + + '@ai-sdk/mcp@2.0.9(zod@4.4.3)': + dependencies: + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) pkce-challenge: 5.0.1 zod: 4.4.3 - '@ai-sdk/openai-compatible@3.0.5(zod@4.4.3)': + '@ai-sdk/mistral@4.0.7(zod@4.4.3)': dependencies: '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) zod: 4.4.3 - '@ai-sdk/openai@4.0.7(zod@4.4.3)': + '@ai-sdk/openai-compatible@3.0.6(zod@4.4.3)': dependencies: '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) zod: 4.4.3 - '@ai-sdk/provider-utils@4.0.35(zod@4.4.3)': + '@ai-sdk/openai@4.0.9(zod@4.4.3)': dependencies: - '@ai-sdk/provider': 3.0.13 - '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.1.0 + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) zod: 4.4.3 - '@ai-sdk/provider-utils@5.0.5(zod@4.4.3)': + '@ai-sdk/perplexity@4.0.7(zod@4.4.3)': + dependencies: + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) + zod: 4.4.3 + + '@ai-sdk/provider-utils@5.0.6(zod@4.4.3)': dependencies: '@ai-sdk/provider': 4.0.2 '@standard-schema/spec': 1.1.0 @@ -8144,189 +8515,199 @@ snapshots: eventsource-parser: 3.1.0 zod: 4.4.3 - '@ai-sdk/provider@3.0.13': - dependencies: - json-schema: 0.4.0 - '@ai-sdk/provider@4.0.2': dependencies: json-schema: 0.4.0 - '@ai-sdk/react@4.0.16(react@19.2.7)(zod@4.4.3)': + '@ai-sdk/react@4.0.19(react@19.2.7)(zod@4.4.3)': dependencies: - '@ai-sdk/mcp': 2.0.7(zod@4.4.3) + '@ai-sdk/mcp': 2.0.9(zod@4.4.3) '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) - ai: 7.0.15(zod@4.4.3) + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) + ai: 7.0.18(zod@4.4.3) react: 19.2.7 swr: 2.4.2(react@19.2.7) throttleit: 2.1.0 transitivePeerDependencies: - zod + '@ai-sdk/togetherai@3.0.7(zod@4.4.3)': + dependencies: + '@ai-sdk/openai-compatible': 3.0.6(zod@4.4.3) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) + zod: 4.4.3 + + '@ai-sdk/xai@4.0.9(zod@4.4.3)': + dependencies: + '@ai-sdk/openai-compatible': 3.0.6(zod@4.4.3) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) + zod: 4.4.3 + '@alloc/quick-lru@5.2.0': {} - '@aws-sdk/checksums@3.1000.12': + '@aws-sdk/checksums@3.1000.14': dependencies: - '@aws-sdk/core': 3.974.27 + '@aws-sdk/core': 3.974.29 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/client-s3@3.1079.0': + '@aws-sdk/client-s3@3.1081.0': dependencies: - '@aws-sdk/checksums': 3.1000.12 - '@aws-sdk/core': 3.974.27 - '@aws-sdk/credential-provider-node': 3.972.62 - '@aws-sdk/middleware-sdk-s3': 3.972.58 + '@aws-sdk/checksums': 3.1000.14 + '@aws-sdk/core': 3.974.29 + '@aws-sdk/credential-provider-node': 3.972.64 + '@aws-sdk/middleware-sdk-s3': 3.972.60 '@aws-sdk/signature-v4-multi-region': 3.996.38 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/fetch-http-handler': 5.6.3 - '@smithy/node-http-handler': 4.9.3 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/fetch-http-handler': 5.6.4 + '@smithy/node-http-handler': 4.9.4 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/core@3.974.27': + '@aws-sdk/core@3.974.29': dependencies: '@aws-sdk/types': 3.973.15 '@aws-sdk/xml-builder': 3.972.33 '@aws/lambda-invoke-store': 0.3.0 - '@smithy/core': 3.29.1 - '@smithy/signature-v4': 5.6.2 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/signature-v4': 5.6.3 + '@smithy/types': 4.16.0 bowser: 2.14.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.972.53': + '@aws-sdk/credential-provider-env@3.972.55': dependencies: - '@aws-sdk/core': 3.974.27 + '@aws-sdk/core': 3.974.29 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.972.55': + '@aws-sdk/credential-provider-http@3.972.57': dependencies: - '@aws-sdk/core': 3.974.27 + '@aws-sdk/core': 3.974.29 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/fetch-http-handler': 5.6.3 - '@smithy/node-http-handler': 4.9.3 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/fetch-http-handler': 5.6.4 + '@smithy/node-http-handler': 4.9.4 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.972.60': + '@aws-sdk/credential-provider-ini@3.972.62': dependencies: - '@aws-sdk/core': 3.974.27 - '@aws-sdk/credential-provider-env': 3.972.53 - '@aws-sdk/credential-provider-http': 3.972.55 - '@aws-sdk/credential-provider-login': 3.972.59 - '@aws-sdk/credential-provider-process': 3.972.53 - '@aws-sdk/credential-provider-sso': 3.972.59 - '@aws-sdk/credential-provider-web-identity': 3.972.59 - '@aws-sdk/nested-clients': 3.997.27 + '@aws-sdk/core': 3.974.29 + '@aws-sdk/credential-provider-env': 3.972.55 + '@aws-sdk/credential-provider-http': 3.972.57 + '@aws-sdk/credential-provider-login': 3.972.61 + '@aws-sdk/credential-provider-process': 3.972.55 + '@aws-sdk/credential-provider-sso': 3.972.61 + '@aws-sdk/credential-provider-web-identity': 3.972.61 + '@aws-sdk/nested-clients': 3.997.29 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/credential-provider-imds': 4.4.6 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/credential-provider-imds': 4.4.7 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-login@3.972.59': + '@aws-sdk/credential-provider-login@3.972.61': dependencies: - '@aws-sdk/core': 3.974.27 - '@aws-sdk/nested-clients': 3.997.27 + '@aws-sdk/core': 3.974.29 + '@aws-sdk/nested-clients': 3.997.29 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-node@3.972.62': + '@aws-sdk/credential-provider-node@3.972.64': dependencies: - '@aws-sdk/credential-provider-env': 3.972.53 - '@aws-sdk/credential-provider-http': 3.972.55 - '@aws-sdk/credential-provider-ini': 3.972.60 - '@aws-sdk/credential-provider-process': 3.972.53 - '@aws-sdk/credential-provider-sso': 3.972.59 - '@aws-sdk/credential-provider-web-identity': 3.972.59 + '@aws-sdk/credential-provider-env': 3.972.55 + '@aws-sdk/credential-provider-http': 3.972.57 + '@aws-sdk/credential-provider-ini': 3.972.62 + '@aws-sdk/credential-provider-process': 3.972.55 + '@aws-sdk/credential-provider-sso': 3.972.61 + '@aws-sdk/credential-provider-web-identity': 3.972.61 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/credential-provider-imds': 4.4.6 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/credential-provider-imds': 4.4.7 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-process@3.972.53': + '@aws-sdk/credential-provider-process@3.972.55': dependencies: - '@aws-sdk/core': 3.974.27 + '@aws-sdk/core': 3.974.29 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.972.59': + '@aws-sdk/credential-provider-sso@3.972.61': dependencies: - '@aws-sdk/core': 3.974.27 - '@aws-sdk/nested-clients': 3.997.27 - '@aws-sdk/token-providers': 3.1079.0 + '@aws-sdk/core': 3.974.29 + '@aws-sdk/nested-clients': 3.997.29 + '@aws-sdk/token-providers': 3.1081.0 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-web-identity@3.972.59': + '@aws-sdk/credential-provider-web-identity@3.972.61': dependencies: - '@aws-sdk/core': 3.974.27 - '@aws-sdk/nested-clients': 3.997.27 + '@aws-sdk/core': 3.974.29 + '@aws-sdk/nested-clients': 3.997.29 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-s3@3.972.58': + '@aws-sdk/middleware-sdk-s3@3.972.60': dependencies: - '@aws-sdk/core': 3.974.27 + '@aws-sdk/core': 3.974.29 '@aws-sdk/signature-v4-multi-region': 3.996.38 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/nested-clients@3.997.27': + '@aws-sdk/nested-clients@3.997.29': dependencies: - '@aws-sdk/core': 3.974.27 + '@aws-sdk/core': 3.974.29 '@aws-sdk/signature-v4-multi-region': 3.996.38 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/fetch-http-handler': 5.6.3 - '@smithy/node-http-handler': 4.9.3 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/fetch-http-handler': 5.6.4 + '@smithy/node-http-handler': 4.9.4 + '@smithy/types': 4.16.0 tslib: 2.8.1 '@aws-sdk/signature-v4-multi-region@3.996.38': dependencies: '@aws-sdk/types': 3.973.15 - '@smithy/signature-v4': 5.6.2 - '@smithy/types': 4.15.1 + '@smithy/signature-v4': 5.6.3 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@aws-sdk/token-providers@3.1079.0': + '@aws-sdk/token-providers@3.1081.0': dependencies: - '@aws-sdk/core': 3.974.27 - '@aws-sdk/nested-clients': 3.997.27 + '@aws-sdk/core': 3.974.29 + '@aws-sdk/nested-clients': 3.997.29 '@aws-sdk/types': 3.973.15 - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 '@aws-sdk/types@3.973.15': dependencies: - '@smithy/types': 4.15.1 + '@smithy/types': 4.16.0 tslib: 2.8.1 '@aws-sdk/xml-builder@3.972.33': dependencies: - '@smithy/types': 4.15.1 + '@smithy/types': 4.16.0 tslib: 2.8.1 '@aws/lambda-invoke-store@0.3.0': {} @@ -8410,7 +8791,7 @@ snapshots: dependencies: '@babel/compat-data': 7.29.7 '@babel/helper-validator-option': 7.29.7 - browserslist: 4.28.4 + browserslist: 4.28.5 lru-cache: 5.1.1 semver: 6.3.1 @@ -8418,8 +8799,8 @@ snapshots: dependencies: '@babel/compat-data': 8.0.0 '@babel/helper-validator-option': 8.0.0 - browserslist: 4.28.4 - lru-cache: 11.5.1 + browserslist: 4.28.5 + lru-cache: 11.5.2 semver: 7.8.5 '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': @@ -8641,15 +9022,15 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@better-auth/api-key@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3))': + '@better-auth/api-key@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3))': dependencies: - '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) '@better-auth/utils': 0.4.2 - better-auth: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9) + better-auth: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10) better-call: 1.3.7(zod@4.4.3) zod: 4.4.3 - '@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0)': + '@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0)': dependencies: '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.1 @@ -8657,77 +9038,77 @@ snapshots: '@standard-schema/spec': 1.1.0 better-call: 1.3.7(zod@4.4.3) jose: 6.2.3 - kysely: 0.29.2 + kysely: 0.29.3 nanostores: 1.4.0 zod: 4.4.3 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@better-auth/drizzle-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))': + '@better-auth/drizzle-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))': dependencies: - '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) '@better-auth/utils': 0.4.2 optionalDependencies: drizzle-orm: 1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3) - '@better-auth/infra@0.3.4(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(zod@4.4.3)': + '@better-auth/infra@0.3.5(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(zod@4.4.3)': dependencies: - '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.1 - better-auth: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9) + better-auth: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10) better-call: 1.3.7(zod@4.4.3) jose: 6.2.3 libphonenumber-js: 1.13.8 zod: 4.4.3 - '@better-auth/kysely-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(kysely@0.29.2)': + '@better-auth/kysely-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(kysely@0.29.3)': dependencies: - '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) '@better-auth/utils': 0.4.2 optionalDependencies: - kysely: 0.29.2 + kysely: 0.29.3 - '@better-auth/memory-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)': + '@better-auth/memory-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)': dependencies: - '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) '@better-auth/utils': 0.4.2 - '@better-auth/mongo-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)': + '@better-auth/mongo-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)': dependencies: - '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) '@better-auth/utils': 0.4.2 - '@better-auth/oauth-provider@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3))': + '@better-auth/oauth-provider@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3))': dependencies: - '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.1 - better-auth: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9) + better-auth: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10) better-call: 1.3.7(zod@4.4.3) jose: 6.2.3 zod: 4.4.3 - '@better-auth/passkey@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9))(better-call@1.3.7(zod@4.4.3))(nanostores@1.4.0)': + '@better-auth/passkey@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10))(better-call@1.3.7(zod@4.4.3))(nanostores@1.4.0)': dependencies: - '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.1 '@simplewebauthn/browser': 13.3.0 '@simplewebauthn/server': 13.3.2 - better-auth: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9) + better-auth: 1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10) better-call: 1.3.7(zod@4.4.3) nanostores: 1.4.0 zod: 4.4.3 - '@better-auth/prisma-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)': + '@better-auth/prisma-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)': dependencies: - '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) '@better-auth/utils': 0.4.2 - '@better-auth/telemetry@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)': + '@better-auth/telemetry@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)': dependencies: - '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.1 @@ -8737,51 +9118,51 @@ snapshots: '@better-fetch/fetch@1.3.1': {} - '@biomejs/biome@2.5.2': + '@biomejs/biome@2.5.3': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.5.2 - '@biomejs/cli-darwin-x64': 2.5.2 - '@biomejs/cli-linux-arm64': 2.5.2 - '@biomejs/cli-linux-arm64-musl': 2.5.2 - '@biomejs/cli-linux-x64': 2.5.2 - '@biomejs/cli-linux-x64-musl': 2.5.2 - '@biomejs/cli-win32-arm64': 2.5.2 - '@biomejs/cli-win32-x64': 2.5.2 + '@biomejs/cli-darwin-arm64': 2.5.3 + '@biomejs/cli-darwin-x64': 2.5.3 + '@biomejs/cli-linux-arm64': 2.5.3 + '@biomejs/cli-linux-arm64-musl': 2.5.3 + '@biomejs/cli-linux-x64': 2.5.3 + '@biomejs/cli-linux-x64-musl': 2.5.3 + '@biomejs/cli-win32-arm64': 2.5.3 + '@biomejs/cli-win32-x64': 2.5.3 - '@biomejs/cli-darwin-arm64@2.5.2': + '@biomejs/cli-darwin-arm64@2.5.3': optional: true - '@biomejs/cli-darwin-x64@2.5.2': + '@biomejs/cli-darwin-x64@2.5.3': optional: true - '@biomejs/cli-linux-arm64-musl@2.5.2': + '@biomejs/cli-linux-arm64-musl@2.5.3': optional: true - '@biomejs/cli-linux-arm64@2.5.2': + '@biomejs/cli-linux-arm64@2.5.3': optional: true - '@biomejs/cli-linux-x64-musl@2.5.2': + '@biomejs/cli-linux-x64-musl@2.5.3': optional: true - '@biomejs/cli-linux-x64@2.5.2': + '@biomejs/cli-linux-x64@2.5.3': optional: true - '@biomejs/cli-win32-arm64@2.5.2': + '@biomejs/cli-win32-arm64@2.5.3': optional: true - '@biomejs/cli-win32-x64@2.5.2': + '@biomejs/cli-win32-x64@2.5.3': optional: true '@colors/colors@1.5.0': optional: true - '@commitlint/cli@21.2.0(@types/node@26.1.0)(conventional-commits-parser@6.4.0)(typescript@6.0.3)': + '@commitlint/cli@21.2.1(@types/node@26.1.1)(conventional-commits-parser@7.0.1)(typescript@7.0.2)': dependencies: '@commitlint/config-conventional': 21.2.0 '@commitlint/format': 21.2.0 '@commitlint/lint': 21.2.0 - '@commitlint/load': 21.2.0(@types/node@26.1.0)(typescript@6.0.3) - '@commitlint/read': 21.2.0(conventional-commits-parser@6.4.0) + '@commitlint/load': 21.2.0(@types/node@26.1.1)(typescript@7.0.2) + '@commitlint/read': 21.2.1(conventional-commits-parser@7.0.1) '@commitlint/types': 21.2.0 tinyexec: 1.2.4 yargs: 18.0.0 @@ -8825,14 +9206,14 @@ snapshots: '@commitlint/rules': 21.2.0 '@commitlint/types': 21.2.0 - '@commitlint/load@21.2.0(@types/node@26.1.0)(typescript@6.0.3)': + '@commitlint/load@21.2.0(@types/node@26.1.1)(typescript@7.0.2)': dependencies: '@commitlint/config-validator': 21.2.0 '@commitlint/execute-rule': 21.0.1 '@commitlint/resolve-extends': 21.2.0 '@commitlint/types': 21.2.0 - cosmiconfig: 9.0.2(typescript@6.0.3) - cosmiconfig-typescript-loader: 6.3.0(@types/node@26.1.0)(cosmiconfig@9.0.2(typescript@6.0.3))(typescript@6.0.3) + cosmiconfig: 9.0.2(typescript@7.0.2) + cosmiconfig-typescript-loader: 6.3.0(@types/node@26.1.1)(cosmiconfig@9.0.2(typescript@7.0.2))(typescript@7.0.2) es-toolkit: 1.49.0 is-plain-obj: 4.1.0 picocolors: 1.1.1 @@ -8848,11 +9229,11 @@ snapshots: conventional-changelog-angular: 9.2.1 conventional-commits-parser: 7.0.1 - '@commitlint/read@21.2.0(conventional-commits-parser@6.4.0)': + '@commitlint/read@21.2.1(conventional-commits-parser@7.0.1)': dependencies: '@commitlint/top-level': 21.2.0 '@commitlint/types': 21.2.0 - git-raw-commits: 5.0.1(conventional-commits-parser@6.4.0) + '@conventional-changelog/git-client': 3.1.0(conventional-commits-parser@7.0.1) tinyexec: 1.2.4 transitivePeerDependencies: - conventional-commits-filter @@ -8884,13 +9265,13 @@ snapshots: conventional-commits-parser: 7.0.1 picocolors: 1.1.1 - '@conventional-changelog/git-client@2.7.0(conventional-commits-parser@6.4.0)': + '@conventional-changelog/git-client@3.1.0(conventional-commits-parser@7.0.1)': dependencies: - '@simple-libs/child-process-utils': 1.0.2 - '@simple-libs/stream-utils': 1.2.0 + '@simple-libs/child-process-utils': 2.0.0 + '@simple-libs/stream-utils': 2.0.0 semver: 7.8.5 optionalDependencies: - conventional-commits-parser: 6.4.0 + conventional-commits-parser: 7.0.1 '@conventional-changelog/template@1.2.1': {} @@ -8933,10 +9314,10 @@ snapshots: object-treeify: 1.1.33 open: 8.4.2 picomatch: 4.0.5 - systeminformation: 5.31.13 + systeminformation: 5.31.15 undici: 7.28.0 which: 4.0.0 - yocto-spinner: 1.2.0 + yocto-spinner: 1.2.1 '@dotenvx/primitives@0.8.0': {} @@ -9073,13 +9454,13 @@ snapshots: '@hexagon/base64@1.1.28': {} - '@hono/node-server@1.19.14(hono@4.12.27)': + '@hono/node-server@1.19.14(hono@4.12.28)': dependencies: - hono: 4.12.27 + hono: 4.12.28 - '@hono/node-server@2.0.8(hono@4.12.27)': + '@hono/node-server@2.0.8(hono@4.12.28)': dependencies: - hono: 4.12.27 + hono: 4.12.28 '@img/colour@1.1.0': {} @@ -9284,33 +9665,33 @@ snapshots: '@inquirer/ansi@2.0.7': optional: true - '@inquirer/confirm@6.1.1(@types/node@26.1.0)': + '@inquirer/confirm@6.1.1(@types/node@26.1.1)': dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.0) - '@inquirer/type': 4.0.7(@types/node@26.1.0) + '@inquirer/core': 11.2.1(@types/node@26.1.1) + '@inquirer/type': 4.0.7(@types/node@26.1.1) optionalDependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.1 optional: true - '@inquirer/core@11.2.1(@types/node@26.1.0)': + '@inquirer/core@11.2.1(@types/node@26.1.1)': dependencies: '@inquirer/ansi': 2.0.7 '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@26.1.0) + '@inquirer/type': 4.0.7(@types/node@26.1.1) 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.1.0 + '@types/node': 26.1.1 optional: true '@inquirer/figures@2.0.7': optional: true - '@inquirer/type@4.0.7(@types/node@26.1.0)': + '@inquirer/type@4.0.7(@types/node@26.1.1)': optionalDependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.1 optional: true '@ioredis/commands@1.10.0': {} @@ -9328,7 +9709,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 26.1.0 + '@types/node': 26.1.1 '@types/yargs': 17.0.35 chalk: 4.1.2 @@ -9357,35 +9738,34 @@ snapshots: '@levischuck/tiny-cbor@0.2.11': {} - '@lingui/babel-plugin-extract-messages@6.4.0': + '@lingui/babel-plugin-extract-messages@6.5.0': dependencies: - '@lingui/conf': 6.4.0 + '@lingui/conf': 6.5.0 - '@lingui/babel-plugin-lingui-macro@6.4.0': + '@lingui/babel-plugin-lingui-macro@6.5.0': dependencies: '@babel/core': 7.29.7 '@babel/types': 7.29.7 - '@lingui/conf': 6.4.0 - '@lingui/message-utils': 6.4.0 + '@lingui/conf': 6.5.0 + '@lingui/message-utils': 6.5.0 transitivePeerDependencies: - supports-color - '@lingui/cli@6.4.0(babel-plugin-macros@3.1.0)': + '@lingui/cli@6.5.0(babel-plugin-macros@3.1.0)(esbuild@0.28.1)(rolldown@1.1.5)': dependencies: '@babel/core': 7.29.7 '@babel/generator': 7.29.7 '@babel/parser': 7.29.7 '@babel/types': 7.29.7 - '@lingui/babel-plugin-extract-messages': 6.4.0 - '@lingui/babel-plugin-lingui-macro': 6.4.0 - '@lingui/conf': 6.4.0 - '@lingui/core': 6.4.0(babel-plugin-macros@3.1.0) - '@lingui/format-po': 6.4.0 - '@lingui/message-utils': 6.4.0 + '@lingui/babel-plugin-extract-messages': 6.5.0 + '@lingui/babel-plugin-lingui-macro': 6.5.0 + '@lingui/conf': 6.5.0 + '@lingui/core': 6.5.0(babel-plugin-macros@3.1.0) + '@lingui/format-po': 6.5.0 + '@lingui/message-utils': 6.5.0 chokidar: 5.0.0 cli-table3: 0.6.5 commander: 14.0.3 - esbuild: 0.28.1 jiti: 2.7.0 micromatch: 4.0.8 ms: 2.1.3 @@ -9394,60 +9774,64 @@ snapshots: pseudolocale: 2.2.0 source-map: 0.7.6 tinypool: 2.1.0 + optionalDependencies: + esbuild: 0.28.1 + rolldown: 1.1.5 transitivePeerDependencies: - babel-plugin-macros - supports-color - '@lingui/conf@6.4.0': + '@lingui/conf@6.5.0': dependencies: jest-validate: 29.7.0 jiti: 2.7.0 lilconfig: 3.1.3 normalize-path: 3.0.0 - '@lingui/core@6.4.0(babel-plugin-macros@3.1.0)': + '@lingui/core@6.5.0(babel-plugin-macros@3.1.0)': dependencies: - '@lingui/babel-plugin-lingui-macro': 6.4.0 - '@lingui/message-utils': 6.4.0 + '@lingui/babel-plugin-lingui-macro': 6.5.0 + '@lingui/message-utils': 6.5.0 optionalDependencies: babel-plugin-macros: 3.1.0 transitivePeerDependencies: - supports-color - '@lingui/format-po@6.4.0': + '@lingui/format-po@6.5.0': dependencies: - '@lingui/conf': 6.4.0 - '@lingui/message-utils': 6.4.0 + '@lingui/conf': 6.5.0 + '@lingui/message-utils': 6.5.0 pofile-ts: 4.0.3 - '@lingui/message-utils@6.4.0': + '@lingui/message-utils@6.5.0': dependencies: '@messageformat/date-skeleton': 1.1.0 '@messageformat/parser': 5.1.1 js-sha256: 0.10.1 - '@lingui/react@6.4.0(babel-plugin-macros@3.1.0)(react@19.2.7)': + '@lingui/react@6.5.0(babel-plugin-macros@3.1.0)(react@19.2.7)': dependencies: - '@lingui/babel-plugin-lingui-macro': 6.4.0 - '@lingui/core': 6.4.0(babel-plugin-macros@3.1.0) + '@lingui/babel-plugin-lingui-macro': 6.5.0 + '@lingui/core': 6.5.0(babel-plugin-macros@3.1.0) react: 19.2.7 optionalDependencies: babel-plugin-macros: 3.1.0 transitivePeerDependencies: - supports-color - '@lingui/vite-plugin@6.4.0(@babel/core@8.0.1)(@lingui/babel-plugin-lingui-macro@6.4.0)(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)))(babel-plugin-macros@3.1.0)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': + '@lingui/vite-plugin@6.5.0(@babel/core@8.0.1)(@lingui/babel-plugin-lingui-macro@6.5.0)(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)))(babel-plugin-macros@3.1.0)(esbuild@0.28.1)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': dependencies: - '@lingui/cli': 6.4.0(babel-plugin-macros@3.1.0) - '@lingui/conf': 6.4.0 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) + '@lingui/cli': 6.5.0(babel-plugin-macros@3.1.0)(esbuild@0.28.1)(rolldown@1.1.5) + '@lingui/conf': 6.5.0 + vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) optionalDependencies: '@babel/core': 8.0.1 - '@lingui/babel-plugin-lingui-macro': 6.4.0 - '@rolldown/plugin-babel': 0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) - rolldown: 1.1.4 + '@lingui/babel-plugin-lingui-macro': 6.5.0 + '@rolldown/plugin-babel': 0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + rolldown: 1.1.5 transitivePeerDependencies: - babel-plugin-macros + - esbuild - supports-color '@messageformat/date-skeleton@1.1.0': {} @@ -9458,7 +9842,7 @@ snapshots: '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': dependencies: - '@hono/node-server': 1.19.14(hono@4.12.27) + '@hono/node-server': 1.19.14(hono@4.12.28) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 @@ -9468,7 +9852,7 @@ snapshots: eventsource-parser: 3.1.0 express: 5.2.1 express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.27 + hono: 4.12.28 jose: 6.2.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -9480,7 +9864,7 @@ snapshots: '@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)': dependencies: - '@hono/node-server': 1.19.14(hono@4.12.27) + '@hono/node-server': 1.19.14(hono@4.12.28) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 @@ -9490,7 +9874,7 @@ snapshots: eventsource-parser: 3.1.0 express: 5.2.1 express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.27 + hono: 4.12.28 jose: 6.2.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -9645,45 +10029,45 @@ snapshots: '@opentelemetry/semantic-conventions@1.41.1': {} - '@orpc/client@1.14.6(@opentelemetry/api@1.9.1)': + '@orpc/client@1.14.7(@opentelemetry/api@1.9.1)': dependencies: - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server-fetch': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server-peer': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server-fetch': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server-peer': 1.14.7(@opentelemetry/api@1.9.1) transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/contract@1.14.6(@opentelemetry/api@1.9.1)': + '@orpc/contract@1.14.7(@opentelemetry/api@1.9.1)': dependencies: - '@orpc/client': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/client': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) '@standard-schema/spec': 1.1.0 openapi-types: 12.1.3 transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/experimental-ratelimit@1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0)': + '@orpc/experimental-ratelimit@1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0)': dependencies: - '@orpc/client': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/server': 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/client': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/server': 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server': 1.14.7(@opentelemetry/api@1.9.1) transitivePeerDependencies: - '@opentelemetry/api' - crossws - fastify - ws - '@orpc/interop@1.14.6': {} + '@orpc/interop@1.14.7': {} - '@orpc/json-schema@1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0)': + '@orpc/json-schema@1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0)': dependencies: - '@orpc/contract': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/interop': 1.14.6 - '@orpc/openapi': 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) - '@orpc/server': 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/contract': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/interop': 1.14.7 + '@orpc/openapi': 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) + '@orpc/server': 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) json-schema-typed: 8.0.2 transitivePeerDependencies: - '@opentelemetry/api' @@ -9691,24 +10075,24 @@ snapshots: - fastify - ws - '@orpc/openapi-client@1.14.6(@opentelemetry/api@1.9.1)': + '@orpc/openapi-client@1.14.7(@opentelemetry/api@1.9.1)': dependencies: - '@orpc/client': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/contract': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/client': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/contract': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server': 1.14.7(@opentelemetry/api@1.9.1) transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/openapi@1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0)': + '@orpc/openapi@1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0)': dependencies: - '@orpc/client': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/contract': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/interop': 1.14.6 - '@orpc/openapi-client': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/server': 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/client': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/contract': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/interop': 1.14.7 + '@orpc/openapi-client': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/server': 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server': 1.14.7(@opentelemetry/api@1.9.1) json-schema-typed: 8.0.2 rou3: 0.7.12 transitivePeerDependencies: @@ -9717,18 +10101,18 @@ snapshots: - fastify - ws - '@orpc/server@1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0)': + '@orpc/server@1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0)': dependencies: - '@orpc/client': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/contract': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/interop': 1.14.6 - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server-aws-lambda': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server-fastify': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server-fetch': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server-node': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server-peer': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/client': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/contract': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/interop': 1.14.7 + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server-aws-lambda': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server-fastify': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server-fetch': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server-node': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server-peer': 1.14.7(@opentelemetry/api@1.9.1) cookie: 1.1.1 optionalDependencies: ws: 8.21.0 @@ -9736,73 +10120,73 @@ snapshots: - '@opentelemetry/api' - fastify - '@orpc/shared@1.14.6(@opentelemetry/api@1.9.1)': + '@orpc/shared@1.14.7(@opentelemetry/api@1.9.1)': dependencies: radash: 12.1.1 type-fest: 5.8.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@orpc/standard-server-aws-lambda@1.14.6(@opentelemetry/api@1.9.1)': + '@orpc/standard-server-aws-lambda@1.14.7(@opentelemetry/api@1.9.1)': dependencies: - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server-fetch': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server-node': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server-fetch': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server-node': 1.14.7(@opentelemetry/api@1.9.1) transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/standard-server-fastify@1.14.6(@opentelemetry/api@1.9.1)': + '@orpc/standard-server-fastify@1.14.7(@opentelemetry/api@1.9.1)': dependencies: - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server-node': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server-node': 1.14.7(@opentelemetry/api@1.9.1) transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/standard-server-fetch@1.14.6(@opentelemetry/api@1.9.1)': + '@orpc/standard-server-fetch@1.14.7(@opentelemetry/api@1.9.1)': dependencies: - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server': 1.14.7(@opentelemetry/api@1.9.1) transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/standard-server-node@1.14.6(@opentelemetry/api@1.9.1)': + '@orpc/standard-server-node@1.14.7(@opentelemetry/api@1.9.1)': dependencies: - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server-fetch': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server-fetch': 1.14.7(@opentelemetry/api@1.9.1) transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/standard-server-peer@1.14.6(@opentelemetry/api@1.9.1)': + '@orpc/standard-server-peer@1.14.7(@opentelemetry/api@1.9.1)': dependencies: - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/standard-server': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/standard-server': 1.14.7(@opentelemetry/api@1.9.1) transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/standard-server@1.14.6(@opentelemetry/api@1.9.1)': + '@orpc/standard-server@1.14.7(@opentelemetry/api@1.9.1)': dependencies: - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/tanstack-query@1.14.6(@opentelemetry/api@1.9.1)(@orpc/client@1.14.6(@opentelemetry/api@1.9.1))(@tanstack/query-core@5.101.2)': + '@orpc/tanstack-query@1.14.7(@opentelemetry/api@1.9.1)(@orpc/client@1.14.7(@opentelemetry/api@1.9.1))(@tanstack/query-core@5.101.2)': dependencies: - '@orpc/client': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/client': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) '@tanstack/query-core': 5.101.2 transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/zod@1.14.6(@opentelemetry/api@1.9.1)(@orpc/contract@1.14.6(@opentelemetry/api@1.9.1))(@orpc/server@1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0))(ws@8.21.0)(zod@4.4.3)': + '@orpc/zod@1.14.7(@opentelemetry/api@1.9.1)(@orpc/contract@1.14.7(@opentelemetry/api@1.9.1))(@orpc/server@1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0))(ws@8.21.0)(zod@4.4.3)': dependencies: - '@orpc/contract': 1.14.6(@opentelemetry/api@1.9.1) - '@orpc/json-schema': 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) - '@orpc/openapi': 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) - '@orpc/server': 1.14.6(@opentelemetry/api@1.9.1)(ws@8.21.0) - '@orpc/shared': 1.14.6(@opentelemetry/api@1.9.1) + '@orpc/contract': 1.14.7(@opentelemetry/api@1.9.1) + '@orpc/json-schema': 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) + '@orpc/openapi': 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) + '@orpc/server': 1.14.7(@opentelemetry/api@1.9.1)(ws@8.21.0) + '@orpc/shared': 1.14.7(@opentelemetry/api@1.9.1) escape-string-regexp: 5.0.0 wildcard-match: 5.1.4 zod: 4.4.3 @@ -9945,7 +10329,7 @@ snapshots: '@oxc-project/types@0.137.0': {} - '@oxc-project/types@0.138.0': {} + '@oxc-project/types@0.139.0': {} '@oxc-resolver/binding-android-arm-eabi@11.21.3': optional: true @@ -10123,7 +10507,7 @@ snapshots: dependencies: quansync: 1.0.0 - '@radix-ui/primitive@1.1.4': {} + '@radix-ui/primitive@1.1.5': {} '@radix-ui/react-compose-refs@1.1.3(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -10131,23 +10515,23 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-context@1.1.4(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-context@1.2.0(@types/react@19.2.17)(react@19.2.7)': dependencies: react: 19.2.7 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-dialog@1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-dialog@1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/primitive': 1.1.4 + '@radix-ui/primitive': 1.1.5 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) @@ -10159,9 +10543,9 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-dismissable-layer@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-dismissable-layer@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/primitive': 1.1.4 + '@radix-ui/primitive': 1.1.5 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -10178,7 +10562,7 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-focus-scope@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-focus-scope@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -10206,7 +10590,7 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-presence@1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-presence@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 @@ -10265,7 +10649,7 @@ snapshots: react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - '@react-email/ui@6.6.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@react-email/ui@6.6.8(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: esbuild: 0.28.1 next: 16.2.6(@babel/core@8.0.1)(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -10383,63 +10767,63 @@ snapshots: '@react-pdf/primitives': 4.3.0 '@react-pdf/stylesheet': 6.2.1 - '@rolldown/binding-android-arm64@1.1.4': + '@rolldown/binding-android-arm64@1.1.5': optional: true - '@rolldown/binding-darwin-arm64@1.1.4': + '@rolldown/binding-darwin-arm64@1.1.5': optional: true - '@rolldown/binding-darwin-x64@1.1.4': + '@rolldown/binding-darwin-x64@1.1.5': optional: true - '@rolldown/binding-freebsd-x64@1.1.4': + '@rolldown/binding-freebsd-x64@1.1.5': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.1.4': + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': optional: true - '@rolldown/binding-linux-arm64-gnu@1.1.4': + '@rolldown/binding-linux-arm64-gnu@1.1.5': optional: true - '@rolldown/binding-linux-arm64-musl@1.1.4': + '@rolldown/binding-linux-arm64-musl@1.1.5': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.1.4': + '@rolldown/binding-linux-ppc64-gnu@1.1.5': optional: true - '@rolldown/binding-linux-s390x-gnu@1.1.4': + '@rolldown/binding-linux-s390x-gnu@1.1.5': optional: true - '@rolldown/binding-linux-x64-gnu@1.1.4': + '@rolldown/binding-linux-x64-gnu@1.1.5': optional: true - '@rolldown/binding-linux-x64-musl@1.1.4': + '@rolldown/binding-linux-x64-musl@1.1.5': optional: true - '@rolldown/binding-openharmony-arm64@1.1.4': + '@rolldown/binding-openharmony-arm64@1.1.5': optional: true - '@rolldown/binding-wasm32-wasi@1.1.4': + '@rolldown/binding-wasm32-wasi@1.1.5': dependencies: '@emnapi/core': 1.11.1 '@emnapi/runtime': 1.11.1 '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) optional: true - '@rolldown/binding-win32-arm64-msvc@1.1.4': + '@rolldown/binding-win32-arm64-msvc@1.1.5': optional: true - '@rolldown/binding-win32-x64-msvc@1.1.4': + '@rolldown/binding-win32-x64-msvc@1.1.5': optional: true - '@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': + '@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': dependencies: '@babel/core': 8.0.1 picomatch: 4.0.5 - rolldown: 1.1.4 + rolldown: 1.1.5 optionalDependencies: '@babel/runtime': 7.29.7 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) '@rolldown/pluginutils@1.0.1': {} @@ -10450,16 +10834,14 @@ snapshots: domhandler: 5.0.3 selderee: 0.11.0 - '@shadcn/react@0.2.0(@types/react@19.2.17)(react@19.2.7)': + '@shadcn/react@0.2.1(@types/react@19.2.17)(react@19.2.7)': optionalDependencies: '@types/react': 19.2.17 react: 19.2.7 - '@simple-libs/child-process-utils@1.0.2': + '@simple-libs/child-process-utils@2.0.0': dependencies: - '@simple-libs/stream-utils': 1.2.0 - - '@simple-libs/stream-utils@1.2.0': {} + '@simple-libs/stream-utils': 2.0.0 '@simple-libs/stream-utils@2.0.0': {} @@ -10487,36 +10869,36 @@ snapshots: '@sindresorhus/transliterate@2.3.1': {} - '@smithy/core@3.29.1': + '@smithy/core@3.29.2': dependencies: - '@smithy/types': 4.15.1 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@smithy/credential-provider-imds@4.4.6': + '@smithy/credential-provider-imds@4.4.7': dependencies: - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@smithy/fetch-http-handler@5.6.3': + '@smithy/fetch-http-handler@5.6.4': dependencies: - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@smithy/node-http-handler@4.9.3': + '@smithy/node-http-handler@4.9.4': dependencies: - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@smithy/signature-v4@5.6.2': + '@smithy/signature-v4@5.6.3': dependencies: - '@smithy/core': 3.29.1 - '@smithy/types': 4.15.1 + '@smithy/core': 3.29.2 + '@smithy/types': 4.16.0 tslib: 2.8.1 - '@smithy/types@4.15.1': + '@smithy/types@4.16.0': dependencies: tslib: 2.8.1 @@ -10534,7 +10916,7 @@ snapshots: '@solid-primitives/utils': 6.4.1(solid-js@1.9.14) solid-js: 1.9.14 - '@solid-primitives/resize-observer@2.1.6(solid-js@1.9.14)': + '@solid-primitives/resize-observer@2.2.0(solid-js@1.9.14)': dependencies: '@solid-primitives/event-listener': 2.4.6(solid-js@1.9.14) '@solid-primitives/rootless': 1.5.4(solid-js@1.9.14) @@ -10566,9 +10948,9 @@ snapshots: dependencies: tslib: 2.8.1 - '@t3-oss/env-core@0.13.11(typescript@6.0.3)(zod@4.4.3)': + '@t3-oss/env-core@0.13.11(typescript@7.0.2)(zod@4.4.3)': optionalDependencies: - typescript: 6.0.3 + typescript: 7.0.2 zod: 4.4.3 '@tailwindcss/node@4.3.2': @@ -10645,12 +11027,12 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 4.3.2 - '@tailwindcss/vite@4.3.2(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': + '@tailwindcss/vite@4.3.2(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.2 '@tailwindcss/oxide': 4.3.2 tailwindcss: 4.3.2 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) '@tanstack/devtools-client@0.0.8': dependencies: @@ -10676,7 +11058,7 @@ snapshots: transitivePeerDependencies: - csstype - '@tanstack/devtools-vite@0.8.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': + '@tanstack/devtools-vite@0.8.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': dependencies: '@tanstack/devtools-client': 0.0.8 '@tanstack/devtools-event-bus': 0.4.2 @@ -10685,7 +11067,7 @@ snapshots: magic-string: 0.30.21 oxc-parser: 0.120.0(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2) picomatch: 4.0.5 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -10696,7 +11078,7 @@ snapshots: dependencies: '@solid-primitives/event-listener': 2.4.6(solid-js@1.9.14) '@solid-primitives/keyboard': 1.3.7(solid-js@1.9.14) - '@solid-primitives/resize-observer': 2.1.6(solid-js@1.9.14) + '@solid-primitives/resize-observer': 2.2.0(solid-js@1.9.14) '@tanstack/devtools-client': 0.0.8 '@tanstack/devtools-event-bus': 0.4.2 '@tanstack/devtools-ui': 0.6.0(csstype@3.2.3)(solid-js@1.9.14) @@ -10781,7 +11163,7 @@ snapshots: '@tanstack/history': 1.162.0 '@tanstack/react-store': 0.9.3(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tanstack/router-core': 1.171.14 - isbot: 5.1.44 + isbot: 5.2.0 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -10827,7 +11209,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.168.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': + '@tanstack/router-plugin@1.168.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7 '@babel/template': 7.29.7 @@ -10836,11 +11218,11 @@ snapshots: '@tanstack/router-generator': 1.167.18 '@tanstack/router-utils': 1.162.2 chokidar: 5.0.0 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) zod: 4.4.3 optionalDependencies: '@tanstack/react-router': 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -10904,154 +11286,154 @@ snapshots: dependencies: '@testing-library/dom': 10.4.1 - '@tiptap/core@3.27.1(@tiptap/pm@3.27.1)': + '@tiptap/core@3.27.3(@tiptap/pm@3.27.3)': dependencies: - '@tiptap/pm': 3.27.1 + '@tiptap/pm': 3.27.3 - '@tiptap/extension-blockquote@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-blockquote@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-bold@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-bold@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-bubble-menu@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': + '@tiptap/extension-bubble-menu@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)': dependencies: '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) + '@tiptap/pm': 3.27.3 optional: true - '@tiptap/extension-bullet-list@3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': + '@tiptap/extension-bullet-list@3.27.3(@tiptap/extension-list@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extension-list': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) - '@tiptap/extension-code-block@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': + '@tiptap/extension-code-block@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) + '@tiptap/pm': 3.27.3 - '@tiptap/extension-code@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-code@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-color@3.27.1(@tiptap/extension-text-style@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)))': + '@tiptap/extension-color@3.27.3(@tiptap/extension-text-style@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)))': dependencies: - '@tiptap/extension-text-style': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extension-text-style': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) - '@tiptap/extension-document@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-document@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-dropcursor@3.27.1(@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': + '@tiptap/extension-dropcursor@3.27.3(@tiptap/extensions@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/extensions': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extensions': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) - '@tiptap/extension-floating-menu@3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': + '@tiptap/extension-floating-menu@3.27.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)': dependencies: '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) + '@tiptap/pm': 3.27.3 optional: true - '@tiptap/extension-gapcursor@3.27.1(@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': + '@tiptap/extension-gapcursor@3.27.3(@tiptap/extensions@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/extensions': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extensions': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) - '@tiptap/extension-hard-break@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-hard-break@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-heading@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-heading@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-highlight@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-highlight@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-horizontal-rule@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': + '@tiptap/extension-horizontal-rule@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) + '@tiptap/pm': 3.27.3 - '@tiptap/extension-italic@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-italic@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-link@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': + '@tiptap/extension-link@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) + '@tiptap/pm': 3.27.3 linkifyjs: 4.3.3 - '@tiptap/extension-list-item@3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': + '@tiptap/extension-list-item@3.27.3(@tiptap/extension-list@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extension-list': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) - '@tiptap/extension-list-keymap@3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': + '@tiptap/extension-list-keymap@3.27.3(@tiptap/extension-list@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extension-list': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) - '@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': + '@tiptap/extension-list@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) + '@tiptap/pm': 3.27.3 - '@tiptap/extension-ordered-list@3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': + '@tiptap/extension-ordered-list@3.27.3(@tiptap/extension-list@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extension-list': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) - '@tiptap/extension-paragraph@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-paragraph@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-strike@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-strike@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-text-align@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-text-align@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-text-style@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-text-style@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-text@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-text@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extension-underline@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': + '@tiptap/extension-underline@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) - '@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': + '@tiptap/extensions@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) + '@tiptap/pm': 3.27.3 - '@tiptap/pm@3.27.1': + '@tiptap/pm@3.27.3': dependencies: prosemirror-changeset: 2.4.1 prosemirror-commands: 1.7.1 - prosemirror-dropcursor: 1.8.2 + prosemirror-dropcursor: 1.8.3 prosemirror-gapcursor: 1.4.1 prosemirror-history: 1.5.0 prosemirror-inputrules: 1.5.1 prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.9 + prosemirror-model: 1.25.10 prosemirror-schema-list: 1.5.1 prosemirror-state: 1.4.4 prosemirror-tables: 1.8.5 prosemirror-transform: 1.12.0 prosemirror-view: 1.42.0 - '@tiptap/react@3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@tiptap/react@3.27.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) + '@tiptap/pm': 3.27.3 '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) '@types/use-sync-external-store': 0.0.6 @@ -11060,37 +11442,37 @@ snapshots: react-dom: 19.2.7(react@19.2.7) use-sync-external-store: 1.6.0(react@19.2.7) optionalDependencies: - '@tiptap/extension-bubble-menu': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-floating-menu': 3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extension-bubble-menu': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) + '@tiptap/extension-floating-menu': 3.27.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) transitivePeerDependencies: - '@floating-ui/dom' - '@tiptap/starter-kit@3.27.1': + '@tiptap/starter-kit@3.27.3': dependencies: - '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-blockquote': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extension-bold': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extension-bullet-list': 3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) - '@tiptap/extension-code': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extension-code-block': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-document': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extension-dropcursor': 3.27.1(@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) - '@tiptap/extension-gapcursor': 3.27.1(@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) - '@tiptap/extension-hard-break': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extension-heading': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extension-horizontal-rule': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-italic': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extension-link': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-list-item': 3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) - '@tiptap/extension-list-keymap': 3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) - '@tiptap/extension-ordered-list': 3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) - '@tiptap/extension-paragraph': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extension-strike': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extension-text': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extension-underline': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extensions': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/pm': 3.27.1 + '@tiptap/core': 3.27.3(@tiptap/pm@3.27.3) + '@tiptap/extension-blockquote': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) + '@tiptap/extension-bold': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) + '@tiptap/extension-bullet-list': 3.27.3(@tiptap/extension-list@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)) + '@tiptap/extension-code': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) + '@tiptap/extension-code-block': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) + '@tiptap/extension-document': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) + '@tiptap/extension-dropcursor': 3.27.3(@tiptap/extensions@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)) + '@tiptap/extension-gapcursor': 3.27.3(@tiptap/extensions@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)) + '@tiptap/extension-hard-break': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) + '@tiptap/extension-heading': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) + '@tiptap/extension-horizontal-rule': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) + '@tiptap/extension-italic': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) + '@tiptap/extension-link': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) + '@tiptap/extension-list': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) + '@tiptap/extension-list-item': 3.27.3(@tiptap/extension-list@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)) + '@tiptap/extension-list-keymap': 3.27.3(@tiptap/extension-list@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)) + '@tiptap/extension-ordered-list': 3.27.3(@tiptap/extension-list@3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3)) + '@tiptap/extension-paragraph': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) + '@tiptap/extension-strike': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) + '@tiptap/extension-text': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) + '@tiptap/extension-underline': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3)) + '@tiptap/extensions': 3.27.3(@tiptap/core@3.27.3(@tiptap/pm@3.27.3))(@tiptap/pm@3.27.3) + '@tiptap/pm': 3.27.3 '@ts-morph/common@0.27.0': dependencies: @@ -11098,22 +11480,22 @@ snapshots: minimatch: 10.2.5 path-browserify: 1.0.1 - '@turbo/darwin-64@2.10.3': + '@turbo/darwin-64@2.10.4': optional: true - '@turbo/darwin-arm64@2.10.3': + '@turbo/darwin-arm64@2.10.4': optional: true - '@turbo/linux-64@2.10.3': + '@turbo/linux-64@2.10.4': optional: true - '@turbo/linux-arm64@2.10.3': + '@turbo/linux-arm64@2.10.4': optional: true - '@turbo/windows-64@2.10.3': + '@turbo/windows-64@2.10.4': optional: true - '@turbo/windows-arm64@2.10.3': + '@turbo/windows-arm64@2.10.4': optional: true '@tybys/wasm-util@0.10.3': @@ -11146,7 +11528,7 @@ snapshots: '@types/bcrypt@6.0.0': dependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.1 '@types/chai@5.2.3': dependencies: @@ -11155,7 +11537,7 @@ snapshots: '@types/cors@2.8.19': dependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.1 '@types/debug@4.1.13': dependencies: @@ -11197,23 +11579,23 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@25.9.4': + '@types/node@25.9.5': dependencies: undici-types: 7.24.6 - '@types/node@26.1.0': + '@types/node@26.1.1': dependencies: undici-types: 8.3.0 '@types/nodemailer@8.0.1': dependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.1 '@types/parse-json@4.0.2': {} '@types/pg@8.20.0': dependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.1 pg-protocol: 1.15.0 pg-types: 2.2.0 @@ -11227,7 +11609,7 @@ snapshots: '@types/set-cookie-parser@2.4.10': dependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.1 optional: true '@types/statuses@2.0.6': @@ -11245,7 +11627,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.1 '@types/yargs-parser@21.0.3': {} @@ -11253,36 +11635,96 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260705.1': + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260707.2': optional: true - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260705.1': + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260707.2': optional: true - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260705.1': + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260707.2': optional: true - '@typescript/native-preview-linux-arm@7.0.0-dev.20260705.1': + '@typescript/native-preview-linux-arm@7.0.0-dev.20260707.2': optional: true - '@typescript/native-preview-linux-x64@7.0.0-dev.20260705.1': + '@typescript/native-preview-linux-x64@7.0.0-dev.20260707.2': optional: true - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260705.1': + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260707.2': optional: true - '@typescript/native-preview-win32-x64@7.0.0-dev.20260705.1': + '@typescript/native-preview-win32-x64@7.0.0-dev.20260707.2': optional: true - '@typescript/native-preview@7.0.0-dev.20260705.1': + '@typescript/native-preview@7.0.0-dev.20260707.2': optionalDependencies: - '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260705.1 - '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260705.1 - '@typescript/native-preview-linux-arm': 7.0.0-dev.20260705.1 - '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260705.1 - '@typescript/native-preview-linux-x64': 7.0.0-dev.20260705.1 - '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260705.1 - '@typescript/native-preview-win32-x64': 7.0.0-dev.20260705.1 + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260707.2 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260707.2 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260707.2 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260707.2 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260707.2 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260707.2 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260707.2 + + '@typescript/typescript-aix-ppc64@7.0.2': + optional: true + + '@typescript/typescript-darwin-arm64@7.0.2': + optional: true + + '@typescript/typescript-darwin-x64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-x64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm@7.0.2': + optional: true + + '@typescript/typescript-linux-loong64@7.0.2': + optional: true + + '@typescript/typescript-linux-mips64el@7.0.2': + optional: true + + '@typescript/typescript-linux-ppc64@7.0.2': + optional: true + + '@typescript/typescript-linux-riscv64@7.0.2': + optional: true + + '@typescript/typescript-linux-s390x@7.0.2': + optional: true + + '@typescript/typescript-linux-x64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-sunos-x64@7.0.2': + optional: true + + '@typescript/typescript-win32-arm64@7.0.2': + optional: true + + '@typescript/typescript-win32-x64@7.0.2': + optional: true '@uiw/color-convert@2.10.3(@babel/runtime@7.29.7)': dependencies: @@ -11332,72 +11774,140 @@ snapshots: '@vercel/oidc@3.2.0': {} - '@vitejs/plugin-react@6.0.3(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': + '@vitejs/plugin-react@6.0.3(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) optionalDependencies: - '@rolldown/plugin-babel': 0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + '@rolldown/plugin-babel': 0.2.3(@babel/core@8.0.1)(@babel/runtime@7.29.7)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) babel-plugin-react-compiler: 1.0.0 - '@vitest/coverage-v8@4.1.9(vitest@4.1.9)': + '@vitest/coverage-v8@4.1.10(vitest@4.1.10)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.9 + '@vitest/utils': 4.1.10 ast-v8-to-istanbul: 1.0.4 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-reports: 3.2.0 magicast: 0.5.3 obug: 2.1.3 - std-env: 4.1.0 + std-env: 4.2.0 tinyrainbow: 3.1.0 - vitest: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@26.1.0)(@vitest/coverage-v8@4.1.9)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.0)(typescript@6.0.3))(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) - '@vitest/expect@4.1.9': + '@vitest/expect@4.1.10': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.9 - '@vitest/utils': 4.1.9 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.9(msw@2.14.6(@types/node@26.1.0)(typescript@6.0.3))(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.10(msw@2.14.6(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.9 + '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.14.6(@types/node@26.1.0)(typescript@6.0.3) - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) + msw: 2.14.6(@types/node@26.1.1)(typescript@7.0.2) + vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) - '@vitest/pretty-format@4.1.9': + '@vitest/pretty-format@4.1.10': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.9': + '@vitest/runner@4.1.10': dependencies: - '@vitest/utils': 4.1.9 + '@vitest/utils': 4.1.10 pathe: 2.0.3 - '@vitest/snapshot@4.1.9': + '@vitest/snapshot@4.1.10': dependencies: - '@vitest/pretty-format': 4.1.9 - '@vitest/utils': 4.1.9 + '@vitest/pretty-format': 4.1.10 + '@vitest/utils': 4.1.10 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.9': {} + '@vitest/spy@4.1.10': {} - '@vitest/utils@4.1.9': + '@vitest/utils@4.1.10': dependencies: - '@vitest/pretty-format': 4.1.9 + '@vitest/pretty-format': 4.1.10 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 '@workflow/serde@4.1.0': {} + '@yuku-codegen/binding-darwin-arm64@0.5.44': + optional: true + + '@yuku-codegen/binding-darwin-x64@0.5.44': + optional: true + + '@yuku-codegen/binding-freebsd-x64@0.5.44': + optional: true + + '@yuku-codegen/binding-linux-arm-gnu@0.5.44': + optional: true + + '@yuku-codegen/binding-linux-arm-musl@0.5.44': + optional: true + + '@yuku-codegen/binding-linux-arm64-gnu@0.5.44': + optional: true + + '@yuku-codegen/binding-linux-arm64-musl@0.5.44': + optional: true + + '@yuku-codegen/binding-linux-x64-gnu@0.5.44': + optional: true + + '@yuku-codegen/binding-linux-x64-musl@0.5.44': + optional: true + + '@yuku-codegen/binding-win32-arm64@0.5.44': + optional: true + + '@yuku-codegen/binding-win32-x64@0.5.44': + optional: true + + '@yuku-parser/binding-darwin-arm64@0.5.44': + optional: true + + '@yuku-parser/binding-darwin-x64@0.5.44': + optional: true + + '@yuku-parser/binding-freebsd-x64@0.5.44': + optional: true + + '@yuku-parser/binding-linux-arm-gnu@0.5.44': + optional: true + + '@yuku-parser/binding-linux-arm-musl@0.5.44': + optional: true + + '@yuku-parser/binding-linux-arm64-gnu@0.5.44': + optional: true + + '@yuku-parser/binding-linux-arm64-musl@0.5.44': + optional: true + + '@yuku-parser/binding-linux-x64-gnu@0.5.44': + optional: true + + '@yuku-parser/binding-linux-x64-musl@0.5.44': + optional: true + + '@yuku-parser/binding-win32-arm64@0.5.44': + optional: true + + '@yuku-parser/binding-win32-x64@0.5.44': + optional: true + + '@yuku-toolchain/types@0.5.43': {} + abs-svg-path@0.1.1: {} accepts@1.3.8: @@ -11412,11 +11922,11 @@ snapshots: adm-zip@0.5.18: {} - ai@7.0.15(zod@4.4.3): + ai@7.0.18(zod@4.4.3): dependencies: - '@ai-sdk/gateway': 4.0.12(zod@4.4.3) + '@ai-sdk/gateway': 4.0.14(zod@4.4.3) '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) zod: 4.4.3 ajv-formats@2.1.1(ajv@8.20.0): @@ -11470,12 +11980,6 @@ snapshots: assertion-error@2.0.1: {} - ast-kit@3.0.0: - dependencies: - '@babel/parser': 8.0.0 - estree-walker: 3.0.3 - pathe: 2.0.3 - ast-types@0.16.1: dependencies: tslib: 2.8.1 @@ -11529,15 +12033,15 @@ snapshots: node-addon-api: 8.9.0 node-gyp-build: 4.8.4 - better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.9): + better-auth@1.6.23(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.61.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(solid-js@1.9.14)(vitest@4.1.10): dependencies: - '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0) - '@better-auth/drizzle-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3)) - '@better-auth/kysely-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(kysely@0.29.2) - '@better-auth/memory-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2) - '@better-auth/mongo-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2) - '@better-auth/prisma-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2) - '@better-auth/telemetry': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) + '@better-auth/drizzle-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(drizzle-orm@1.0.0-rc.4(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.22.0)(zod@4.4.3)) + '@better-auth/kysely-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(kysely@0.29.3) + '@better-auth/memory-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2) + '@better-auth/prisma-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2) + '@better-auth/telemetry': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.1 '@noble/ciphers': 2.2.0 @@ -11545,7 +12049,7 @@ snapshots: better-call: 1.3.7(zod@4.4.3) defu: 6.1.7 jose: 6.2.3 - kysely: 0.29.2 + kysely: 0.29.3 nanostores: 1.4.0 zod: 4.4.3 optionalDependencies: @@ -11555,7 +12059,7 @@ snapshots: react: 19.2.7 react-dom: 19.2.7(react@19.2.7) solid-js: 1.9.14 - vitest: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@26.1.0)(@vitest/coverage-v8@4.1.9)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.0)(typescript@6.0.3))(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) transitivePeerDependencies: - '@cloudflare/workers-types' - '@opentelemetry/api' @@ -11573,8 +12077,6 @@ snapshots: dependencies: require-from-string: 2.0.2 - birpc@4.0.0: {} - body-parser@2.3.0: dependencies: bytes: 3.1.2 @@ -11609,17 +12111,17 @@ snapshots: dependencies: pako: 1.0.11 - browserslist@4.28.4: + browserslist@4.28.5: dependencies: baseline-browser-mapping: 2.10.42 - caniuse-lite: 1.0.30001800 - electron-to-chromium: 1.5.387 + caniuse-lite: 1.0.30001803 + electron-to-chromium: 1.5.389 node-releases: 2.0.50 - update-browserslist-db: 1.2.3(browserslist@4.28.4) + update-browserslist-db: 1.2.3(browserslist@4.28.5) buffer-image-size@0.6.4: dependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.1 bundle-name@4.1.0: dependencies: @@ -11643,7 +12145,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001800: {} + caniuse-lite@1.0.30001803: {} ccount@2.0.1: {} @@ -11726,7 +12228,7 @@ snapshots: cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dialog': 1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dialog': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 @@ -11800,12 +12302,6 @@ snapshots: dependencies: '@conventional-changelog/template': 1.2.1 - conventional-commits-parser@6.4.0: - dependencies: - '@simple-libs/stream-utils': 1.2.0 - meow: 13.2.0 - optional: true - conventional-commits-parser@7.0.1: dependencies: '@simple-libs/stream-utils': 2.0.0 @@ -11828,12 +12324,12 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - cosmiconfig-typescript-loader@6.3.0(@types/node@26.1.0)(cosmiconfig@9.0.2(typescript@6.0.3))(typescript@6.0.3): + cosmiconfig-typescript-loader@6.3.0(@types/node@26.1.1)(cosmiconfig@9.0.2(typescript@7.0.2))(typescript@7.0.2): dependencies: - '@types/node': 26.1.0 - cosmiconfig: 9.0.2(typescript@6.0.3) + '@types/node': 26.1.1 + cosmiconfig: 9.0.2(typescript@7.0.2) jiti: 2.6.1 - typescript: 6.0.3 + typescript: 7.0.2 cosmiconfig@7.1.0: dependencies: @@ -11843,14 +12339,14 @@ snapshots: path-type: 4.0.0 yaml: 1.10.3 - cosmiconfig@9.0.2(typescript@6.0.3): + cosmiconfig@9.0.2(typescript@7.0.2): dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 js-yaml: 4.3.0 parse-json: 5.2.0 optionalDependencies: - typescript: 6.0.3 + typescript: 7.0.2 cross-spawn@7.0.6: dependencies: @@ -11945,7 +12441,7 @@ snapshots: docx@9.7.1: dependencies: - '@types/node': 25.9.4 + '@types/node': 25.9.5 hash.js: 1.1.7 jszip: 3.10.1 nanoid: 5.1.16 @@ -12016,7 +12512,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.387: {} + electron-to-chromium@1.5.389: {} emoji-regex-xs@1.0.0: {} @@ -12033,7 +12529,7 @@ snapshots: engine.io@6.6.9: dependencies: '@types/cors': 2.8.19 - '@types/node': 26.1.0 + '@types/node': 26.1.1 '@types/ws': 8.18.1 accepts: 1.3.8 base64id: 2.0.0 @@ -12361,14 +12857,6 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - git-raw-commits@5.0.1(conventional-commits-parser@6.4.0): - dependencies: - '@conventional-changelog/git-client': 2.7.0(conventional-commits-parser@6.4.0) - meow: 13.2.0 - transitivePeerDependencies: - - conventional-commits-filter - - conventional-commits-parser - github-actionlint@1.7.12: dependencies: adm-zip: 0.5.18 @@ -12412,7 +12900,7 @@ snapshots: happy-dom@20.10.6: dependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.1 '@types/whatwg-mimetype': 3.0.2 '@types/ws': 8.18.1 buffer-image-size: 0.6.4 @@ -12468,7 +12956,7 @@ snapshots: set-cookie-parser: 3.1.1 optional: true - hono@4.12.27: {} + hono@4.12.28: {} hookable@6.1.1: {} @@ -12630,7 +13118,7 @@ snapshots: isarray@1.0.0: {} - isbot@5.1.44: {} + isbot@5.2.0: {} isexe@2.0.0: {} @@ -12733,7 +13221,7 @@ snapshots: kleur@4.1.5: {} - knip@6.24.0: + knip@6.25.0: dependencies: fdir: 6.5.0(picomatch@4.0.5) formatly: 0.3.0 @@ -12749,7 +13237,7 @@ snapshots: yaml: 2.9.0 zod: 4.4.3 - kysely@0.29.2: {} + kysely@0.29.3: {} launch-editor@2.14.1: dependencies: @@ -12758,48 +13246,48 @@ snapshots: leac@0.6.0: {} - lefthook-darwin-arm64@2.1.9: + lefthook-darwin-arm64@2.1.10: optional: true - lefthook-darwin-x64@2.1.9: + lefthook-darwin-x64@2.1.10: optional: true - lefthook-freebsd-arm64@2.1.9: + lefthook-freebsd-arm64@2.1.10: optional: true - lefthook-freebsd-x64@2.1.9: + lefthook-freebsd-x64@2.1.10: optional: true - lefthook-linux-arm64@2.1.9: + lefthook-linux-arm64@2.1.10: optional: true - lefthook-linux-x64@2.1.9: + lefthook-linux-x64@2.1.10: optional: true - lefthook-openbsd-arm64@2.1.9: + lefthook-openbsd-arm64@2.1.10: optional: true - lefthook-openbsd-x64@2.1.9: + lefthook-openbsd-x64@2.1.10: optional: true - lefthook-windows-arm64@2.1.9: + lefthook-windows-arm64@2.1.10: optional: true - lefthook-windows-x64@2.1.9: + lefthook-windows-x64@2.1.10: optional: true - lefthook@2.1.9: + lefthook@2.1.10: optionalDependencies: - lefthook-darwin-arm64: 2.1.9 - lefthook-darwin-x64: 2.1.9 - lefthook-freebsd-arm64: 2.1.9 - lefthook-freebsd-x64: 2.1.9 - lefthook-linux-arm64: 2.1.9 - lefthook-linux-x64: 2.1.9 - lefthook-openbsd-arm64: 2.1.9 - lefthook-openbsd-x64: 2.1.9 - lefthook-windows-arm64: 2.1.9 - lefthook-windows-x64: 2.1.9 + lefthook-darwin-arm64: 2.1.10 + lefthook-darwin-x64: 2.1.10 + lefthook-freebsd-arm64: 2.1.10 + lefthook-freebsd-x64: 2.1.10 + lefthook-linux-arm64: 2.1.10 + lefthook-linux-x64: 2.1.10 + lefthook-openbsd-arm64: 2.1.10 + lefthook-openbsd-x64: 2.1.10 + lefthook-windows-arm64: 2.1.10 + lefthook-windows-x64: 2.1.10 leven@3.1.0: {} @@ -12896,7 +13384,7 @@ snapshots: dependencies: js-tokens: 4.0.0 - lru-cache@11.5.1: {} + lru-cache@11.5.2: {} lru-cache@5.1.1: dependencies: @@ -13128,8 +13616,6 @@ snapshots: media-typer@1.1.0: {} - meow@13.2.0: {} - meow@14.1.0: {} merge-descriptors@2.0.0: {} @@ -13406,9 +13892,9 @@ snapshots: ms@2.1.3: {} - msw@2.14.6(@types/node@26.1.0)(typescript@6.0.3): + msw@2.14.6(@types/node@26.1.1)(typescript@7.0.2): dependencies: - '@inquirer/confirm': 6.1.1(@types/node@26.1.0) + '@inquirer/confirm': 6.1.1(@types/node@26.1.1) '@mswjs/interceptors': 0.41.9 '@open-draft/deferred-promise': 3.0.0 '@types/statuses': 2.0.6 @@ -13427,7 +13913,7 @@ snapshots: until-async: 3.0.2 yargs: 17.7.3 optionalDependencies: - typescript: 6.0.3 + typescript: 7.0.2 transitivePeerDependencies: - '@types/node' optional: true @@ -13455,7 +13941,7 @@ snapshots: '@next/env': 16.2.6 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.10.42 - caniuse-lite: 1.0.30001800 + caniuse-lite: 1.0.30001803 postcss: 8.5.16 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -13486,7 +13972,7 @@ snapshots: css-select: 5.2.2 he: 1.2.0 - node-html-parser@8.0.4: + node-html-parser@9.0.0: dependencies: css-select: 5.2.2 entities: 8.0.0 @@ -13530,11 +14016,11 @@ snapshots: obug@2.1.3: {} - ollama-ai-provider-v2@3.6.0(ai@7.0.15(zod@4.4.3))(zod@4.4.3): + ollama-ai-provider-v2@4.0.1(ai@7.0.18(zod@4.4.3))(zod@4.4.3): dependencies: - '@ai-sdk/provider': 3.0.13 - '@ai-sdk/provider-utils': 4.0.35(zod@4.4.3) - ai: 7.0.15(zod@4.4.3) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.4.3) + ai: 7.0.18(zod@4.4.3) zod: 4.4.3 on-finished@2.4.1: @@ -13733,7 +14219,7 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.5.1 + lru-cache: 11.5.2 minipass: 7.1.3 path-to-regexp@6.3.0: @@ -13890,11 +14376,11 @@ snapshots: prosemirror-commands@1.7.1: dependencies: - prosemirror-model: 1.25.9 + prosemirror-model: 1.25.10 prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 - prosemirror-dropcursor@1.8.2: + prosemirror-dropcursor@1.8.3: dependencies: prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 @@ -13903,7 +14389,7 @@ snapshots: prosemirror-gapcursor@1.4.1: dependencies: prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.9 + prosemirror-model: 1.25.10 prosemirror-state: 1.4.4 prosemirror-view: 1.42.0 @@ -13924,37 +14410,37 @@ snapshots: prosemirror-state: 1.4.4 w3c-keyname: 2.2.8 - prosemirror-model@1.25.9: + prosemirror-model@1.25.10: dependencies: orderedmap: 2.1.1 prosemirror-schema-list@1.5.1: dependencies: - prosemirror-model: 1.25.9 + prosemirror-model: 1.25.10 prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 prosemirror-state@1.4.4: dependencies: - prosemirror-model: 1.25.9 + prosemirror-model: 1.25.10 prosemirror-transform: 1.12.0 prosemirror-view: 1.42.0 prosemirror-tables@1.8.5: dependencies: prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.9 + prosemirror-model: 1.25.10 prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 prosemirror-view: 1.42.0 prosemirror-transform@1.12.0: dependencies: - prosemirror-model: 1.25.9 + prosemirror-model: 1.25.10 prosemirror-view@1.42.0: dependencies: - prosemirror-model: 1.25.9 + prosemirror-model: 1.25.10 prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 @@ -14008,13 +14494,13 @@ snapshots: react: 19.2.7 scheduler: 0.27.0 - react-easy-crop@6.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + react-easy-crop@6.2.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: normalize-wheel: 1.0.1 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - react-email@6.6.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + react-email@6.6.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: '@babel/parser': 7.27.0 '@babel/traverse': 7.27.0 @@ -14230,43 +14716,41 @@ snapshots: glob: 13.0.6 package-json-from-dist: 1.0.1 - rolldown-plugin-dts@0.26.0(@typescript/native-preview@7.0.0-dev.20260705.1)(oxc-resolver@11.21.3)(rolldown@1.1.4)(typescript@6.0.3): + rolldown-plugin-dts@0.27.1(@typescript/native-preview@7.0.0-dev.20260707.2)(oxc-resolver@11.21.3)(rolldown@1.1.5)(typescript@7.0.2): dependencies: - '@babel/generator': 8.0.0 - '@babel/helper-validator-identifier': 8.0.2 - '@babel/parser': 8.0.0 - ast-kit: 3.0.0 - birpc: 4.0.0 dts-resolver: 3.0.0(oxc-resolver@11.21.3) get-tsconfig: 5.0.0-beta.5 obug: 2.1.3 - rolldown: 1.1.4 + rolldown: 1.1.5 + yuku-ast: 0.1.7 + yuku-codegen: 0.5.44 + yuku-parser: 0.5.44 optionalDependencies: - '@typescript/native-preview': 7.0.0-dev.20260705.1 - typescript: 6.0.3 + '@typescript/native-preview': 7.0.0-dev.20260707.2 + typescript: 7.0.2 transitivePeerDependencies: - oxc-resolver - rolldown@1.1.4: + rolldown@1.1.5: dependencies: - '@oxc-project/types': 0.138.0 + '@oxc-project/types': 0.139.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.1.4 - '@rolldown/binding-darwin-arm64': 1.1.4 - '@rolldown/binding-darwin-x64': 1.1.4 - '@rolldown/binding-freebsd-x64': 1.1.4 - '@rolldown/binding-linux-arm-gnueabihf': 1.1.4 - '@rolldown/binding-linux-arm64-gnu': 1.1.4 - '@rolldown/binding-linux-arm64-musl': 1.1.4 - '@rolldown/binding-linux-ppc64-gnu': 1.1.4 - '@rolldown/binding-linux-s390x-gnu': 1.1.4 - '@rolldown/binding-linux-x64-gnu': 1.1.4 - '@rolldown/binding-linux-x64-musl': 1.1.4 - '@rolldown/binding-openharmony-arm64': 1.1.4 - '@rolldown/binding-wasm32-wasi': 1.1.4 - '@rolldown/binding-win32-arm64-msvc': 1.1.4 - '@rolldown/binding-win32-x64-msvc': 1.1.4 + '@rolldown/binding-android-arm64': 1.1.5 + '@rolldown/binding-darwin-arm64': 1.1.5 + '@rolldown/binding-darwin-x64': 1.1.5 + '@rolldown/binding-freebsd-x64': 1.1.5 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.5 + '@rolldown/binding-linux-arm64-gnu': 1.1.5 + '@rolldown/binding-linux-arm64-musl': 1.1.5 + '@rolldown/binding-linux-ppc64-gnu': 1.1.5 + '@rolldown/binding-linux-s390x-gnu': 1.1.5 + '@rolldown/binding-linux-x64-gnu': 1.1.5 + '@rolldown/binding-linux-x64-musl': 1.1.5 + '@rolldown/binding-openharmony-arm64': 1.1.5 + '@rolldown/binding-wasm32-wasi': 1.1.5 + '@rolldown/binding-win32-arm64-msvc': 1.1.5 + '@rolldown/binding-win32-x64-msvc': 1.1.5 rope-sequence@1.3.4: {} @@ -14345,7 +14829,7 @@ snapshots: setprototypeof@1.2.0: {} - shadcn@4.13.0(babel-plugin-macros@3.1.0)(typescript@6.0.3): + shadcn@4.13.0(babel-plugin-macros@3.1.0)(typescript@7.0.2): dependencies: '@babel/core': 7.29.7 '@babel/parser': 7.29.7 @@ -14354,9 +14838,9 @@ snapshots: '@dotenvx/dotenvx': 1.75.1 '@modelcontextprotocol/sdk': 1.29.0(zod@3.25.76) '@types/validate-npm-package-name': 4.0.2 - browserslist: 4.28.4 + browserslist: 4.28.5 commander: 14.0.3 - cosmiconfig: 9.0.2(typescript@6.0.3) + cosmiconfig: 9.0.2(typescript@7.0.2) dedent: 1.7.2(babel-plugin-macros@3.1.0) deepmerge: 4.3.1 diff: 8.0.4 @@ -14417,7 +14901,7 @@ snapshots: '@img/sharp-win32-x64': 0.34.5 optional: true - sharp@0.35.3(@types/node@26.1.0): + sharp@0.35.3(@types/node@26.1.1): dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 @@ -14448,7 +14932,7 @@ snapshots: '@img/sharp-win32-arm64': 0.35.3 '@img/sharp-win32-ia32': 0.35.3 '@img/sharp-win32-x64': 0.35.3 - '@types/node': 26.1.0 + '@types/node': 26.1.1 shebang-command@2.0.0: dependencies: @@ -14555,7 +15039,7 @@ snapshots: statuses@2.0.2: {} - std-env@4.1.0: {} + std-env@4.2.0: {} stdin-discarder@0.2.2: {} @@ -14656,7 +15140,7 @@ snapshots: react: 19.2.7 use-sync-external-store: 1.6.0(react@19.2.7) - systeminformation@5.31.13: {} + systeminformation@5.31.15: {} tagged-tag@1.0.0: {} @@ -14731,7 +15215,7 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tsdown@0.22.3(@typescript/native-preview@7.0.0-dev.20260705.1)(oxc-resolver@11.21.3)(tsx@4.23.0)(typescript@6.0.3): + tsdown@0.22.4(@typescript/native-preview@7.0.0-dev.20260707.2)(oxc-resolver@11.21.3)(tsx@4.23.0)(typescript@7.0.2): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -14741,8 +15225,8 @@ snapshots: import-without-cache: 0.4.0 obug: 2.1.3 picomatch: 4.0.5 - rolldown: 1.1.4 - rolldown-plugin-dts: 0.26.0(@typescript/native-preview@7.0.0-dev.20260705.1)(oxc-resolver@11.21.3)(rolldown@1.1.4)(typescript@6.0.3) + rolldown: 1.1.5 + rolldown-plugin-dts: 0.27.1(@typescript/native-preview@7.0.0-dev.20260707.2)(oxc-resolver@11.21.3)(rolldown@1.1.5)(typescript@7.0.2) semver: 7.8.5 tinyexec: 1.2.4 tinyglobby: 0.2.17 @@ -14750,7 +15234,7 @@ snapshots: unconfig-core: 7.5.0 optionalDependencies: tsx: 4.23.0 - typescript: 6.0.3 + typescript: 7.0.2 transitivePeerDependencies: - '@ts-macro/tsc' - '@typescript/native-preview' @@ -14771,14 +15255,14 @@ snapshots: dependencies: tslib: 1.14.1 - turbo@2.10.3: + turbo@2.10.4: optionalDependencies: - '@turbo/darwin-64': 2.10.3 - '@turbo/darwin-arm64': 2.10.3 - '@turbo/linux-64': 2.10.3 - '@turbo/linux-arm64': 2.10.3 - '@turbo/windows-64': 2.10.3 - '@turbo/windows-arm64': 2.10.3 + '@turbo/darwin-64': 2.10.4 + '@turbo/darwin-arm64': 2.10.4 + '@turbo/linux-64': 2.10.4 + '@turbo/linux-arm64': 2.10.4 + '@turbo/windows-64': 2.10.4 + '@turbo/windows-arm64': 2.10.4 tw-animate-css@1.4.0: {} @@ -14792,7 +15276,28 @@ snapshots: media-typer: 1.1.0 mime-types: 3.0.2 - typescript@6.0.3: {} + typescript@7.0.2: + optionalDependencies: + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 uc.micro@2.1.0: {} @@ -14868,22 +15373,22 @@ snapshots: unpipe@1.0.0: {} - unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.1.4)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)): + unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.1.5)(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)): dependencies: '@jridgewell/remapping': 2.3.5 picomatch: 4.0.5 webpack-virtual-modules: 0.6.2 optionalDependencies: esbuild: 0.28.1 - rolldown: 1.1.4 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) + rolldown: 1.1.5 + vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) until-async@3.0.2: optional: true - update-browserslist-db@1.2.3(browserslist@4.28.4): + update-browserslist-db@1.2.3(browserslist@4.28.5): dependencies: - browserslist: 4.28.4 + browserslist: 4.28.5 escalade: 3.2.0 picocolors: 1.1.1 @@ -14935,47 +15440,47 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0): + vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.5 postcss: 8.5.16 - rolldown: 1.1.4 + rolldown: 1.1.5 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.1 esbuild: 0.28.1 fsevents: 2.3.3 jiti: 2.7.0 tsx: 4.23.0 yaml: 2.9.0 - vitest@4.1.9(@opentelemetry/api@1.9.1)(@types/node@26.1.0)(@vitest/coverage-v8@4.1.9)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.0)(typescript@6.0.3))(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)): + vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6)(msw@2.14.6(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.9 - '@vitest/mocker': 4.1.9(msw@2.14.6(@types/node@26.1.0)(typescript@6.0.3))(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.9 - '@vitest/runner': 4.1.9 - '@vitest/snapshot': 4.1.9 - '@vitest/spy': 4.1.9 - '@vitest/utils': 4.1.9 + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(msw@2.14.6(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 es-module-lexer: 2.3.0 expect-type: 1.4.0 magic-string: 0.30.21 obug: 2.1.3 pathe: 2.0.3 picomatch: 4.0.5 - std-env: 4.1.0 + std-env: 4.2.0 tinybench: 2.9.0 tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 26.1.0 - '@vitest/coverage-v8': 4.1.9(vitest@4.1.9) + '@types/node': 26.1.1 + '@vitest/coverage-v8': 4.1.10(vitest@4.1.10) happy-dom: 20.10.6 transitivePeerDependencies: - msw @@ -15070,7 +15575,7 @@ snapshots: y18n: 5.0.8 yargs-parser: 22.0.0 - yocto-spinner@1.2.0: + yocto-spinner@1.2.1: dependencies: yoctocolors: 2.1.2 @@ -15078,6 +15583,42 @@ snapshots: yoga-layout@3.2.1: {} + yuku-ast@0.1.7: + dependencies: + '@yuku-toolchain/types': 0.5.43 + + yuku-codegen@0.5.44: + dependencies: + '@yuku-toolchain/types': 0.5.43 + optionalDependencies: + '@yuku-codegen/binding-darwin-arm64': 0.5.44 + '@yuku-codegen/binding-darwin-x64': 0.5.44 + '@yuku-codegen/binding-freebsd-x64': 0.5.44 + '@yuku-codegen/binding-linux-arm-gnu': 0.5.44 + '@yuku-codegen/binding-linux-arm-musl': 0.5.44 + '@yuku-codegen/binding-linux-arm64-gnu': 0.5.44 + '@yuku-codegen/binding-linux-arm64-musl': 0.5.44 + '@yuku-codegen/binding-linux-x64-gnu': 0.5.44 + '@yuku-codegen/binding-linux-x64-musl': 0.5.44 + '@yuku-codegen/binding-win32-arm64': 0.5.44 + '@yuku-codegen/binding-win32-x64': 0.5.44 + + yuku-parser@0.5.44: + dependencies: + '@yuku-toolchain/types': 0.5.43 + optionalDependencies: + '@yuku-parser/binding-darwin-arm64': 0.5.44 + '@yuku-parser/binding-darwin-x64': 0.5.44 + '@yuku-parser/binding-freebsd-x64': 0.5.44 + '@yuku-parser/binding-linux-arm-gnu': 0.5.44 + '@yuku-parser/binding-linux-arm-musl': 0.5.44 + '@yuku-parser/binding-linux-arm64-gnu': 0.5.44 + '@yuku-parser/binding-linux-arm64-musl': 0.5.44 + '@yuku-parser/binding-linux-x64-gnu': 0.5.44 + '@yuku-parser/binding-linux-x64-musl': 0.5.44 + '@yuku-parser/binding-win32-arm64': 0.5.44 + '@yuku-parser/binding-win32-x64': 0.5.44 + zod-to-json-schema@3.25.2(zod@3.25.76): dependencies: zod: 3.25.76 diff --git a/tests/e2e/fixtures/resume.ts b/tests/e2e/fixtures/resume.ts index f9f75d2dd..24e352621 100644 --- a/tests/e2e/fixtures/resume.ts +++ b/tests/e2e/fixtures/resume.ts @@ -29,8 +29,8 @@ export async function openSidebarSection(page: Page, title: string) { await expect(page.getByRole("heading", { name: title, exact: true }).filter({ visible: true }).first()).toBeVisible(); } -export async function openResumeCardMenu(page: Page, resumeName: string) { - await page.goto("/dashboard/resumes"); +export async function openResumeCardMenu(page: Page, resumeName: string, { reload = true } = {}) { + if (reload) await page.goto("/dashboard/resumes"); const resumeLink = page.getByRole("link", { name: new RegExp(resumeName) }); await expect(resumeLink).toBeVisible(); await resumeLink.click({ button: "right" }); diff --git a/tests/e2e/specs/dashboard-lifecycle.spec.ts b/tests/e2e/specs/dashboard-lifecycle.spec.ts index 3ffe684ee..10a5c9068 100644 --- a/tests/e2e/specs/dashboard-lifecycle.spec.ts +++ b/tests/e2e/specs/dashboard-lifecycle.spec.ts @@ -14,7 +14,7 @@ test("renames, duplicates and deletes a resume from the dashboard", async ({ aut await expect(page.getByRole("link", { name: new RegExp(renamedTo) })).toBeVisible(); // Duplicate — the copy defaults to " (Copy)" - await openResumeCardMenu(page, renamedTo); + await openResumeCardMenu(page, renamedTo, { reload: false }); await page.getByRole("menuitem", { name: "Duplicate" }).click(); const duplicateDialog = page.getByRole("dialog", { name: "Duplicate Resume" }); await duplicateDialog.getByRole("button", { name: "Duplicate" }).click(); @@ -22,7 +22,7 @@ test("renames, duplicates and deletes a resume from the dashboard", async ({ aut await expect(copyLink).toBeVisible(); // Delete the copy and verify it disappears while the original stays - await openResumeCardMenu(page, `${renamedTo} \\(Copy\\)`); + await openResumeCardMenu(page, `${renamedTo} \\(Copy\\)`, { reload: false }); await page.getByRole("menuitem", { name: "Delete" }).click(); await page.getByRole("alertdialog").getByRole("button", { name: "Confirm" }).click(); await expect(copyLink).toBeHidden(); diff --git a/tooling/package.json b/tooling/package.json index 699fb0ec1..7aa088ddb 100644 --- a/tooling/package.json +++ b/tooling/package.json @@ -12,7 +12,7 @@ "@reactive-resume/config": "workspace:*", "@reactive-resume/env": "workspace:*", "@types/pg": "^8.20.0", - "@typescript/native-preview": "7.0.0-dev.20260705.1", + "@typescript/native-preview": "7.0.0-dev.20260707.2", "drizzle-orm": "1.0.0-rc.4", "pg": "^8.22.0", "tsx": "^4.23.0"