diff --git a/.ncurc.cjs b/.ncurc.cjs index c6547081c..f4c09972b 100644 --- a/.ncurc.cjs +++ b/.ncurc.cjs @@ -2,7 +2,7 @@ const nextPackages = ["@monaco-editor/react"]; -const betaPackages = ["drizzle-orm", "drizzle-kit", "@better-auth/core", "@better-auth/passkey", "better-auth"]; +const betaPackages = ["vite", "drizzle-orm", "drizzle-kit", "@better-auth/core", "@better-auth/passkey", "better-auth"]; /** @type {import('npm-check-updates').RunOptions} */ module.exports = { diff --git a/.vscode/settings.json b/.vscode/settings.json index da924b97a..9249c2180 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,19 +10,19 @@ "*.css": "tailwindcss" }, "files.readonlyInclude": { - "pnpm-lock.yaml": true, - "**/routeTree.gen.ts": true + "**/routeTree.gen.ts": true, + "pnpm-lock.yaml": true }, "files.watcherExclude": { - "pnpm-lock.yaml": true, - "**/routeTree.gen.ts": true + "**/routeTree.gen.ts": true, + "pnpm-lock.yaml": true }, "i18n-ally.enabledParsers": ["po"], "i18n-ally.localesPaths": ["locales"], "i18n-ally.sourceLanguage": "en-US", "search.exclude": { - "pnpm-lock.yaml": true, - "**/routeTree.gen.ts": true + "**/routeTree.gen.ts": true, + "pnpm-lock.yaml": true }, "tailwindCSS.classFunctions": ["cn", "cva"], "tailwindCSS.experimental.classRegex": [ @@ -31,5 +31,5 @@ ["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] ], "tailwindCSS.experimental.configFile": "src/styles/globals.css", - "typescript.tsdk": "node_modules/typescript/lib" + "typescript.experimental.useTsgo": true } diff --git a/biome.json b/biome.json index ec5dcec60..d29a83034 100644 --- a/biome.json +++ b/biome.json @@ -10,9 +10,9 @@ "ignoreUnknown": true, "includes": [ "**", + "!**/docs/spec.json", "!**/webfontlist.json", "!**/schema/schema.json", - "!**/docs/spec.json", "!**/src/routeTree.gen.ts" ] }, @@ -24,8 +24,7 @@ "actions": { "recommended": true, "source": { - "organizeImports": "on", - "useSortedProperties": "on" + "organizeImports": "on" } } }, diff --git a/docs/changelog/index.mdx b/docs/changelog/index.mdx index d6f54f464..c9d760171 100644 --- a/docs/changelog/index.mdx +++ b/docs/changelog/index.mdx @@ -4,6 +4,19 @@ description: "List of all notable changes and updates to Reactive Resume" rss: true --- + + - Introduce a new **MCP (Model Context Protocol) server** that lets you manage and edit resumes from any MCP-compatible AI tool — Claude Desktop, Cursor, Codex, and more. Supports listing, reading, creating, deleting, locking/unlocking, and patching resumes via natural language. [(guide)](/guides/using-the-mcp-server) + - Add an **AI Chat** panel to the resume builder, allowing you to modify your resume through conversational AI directly within the editor. The chat uses tool-calling to apply JSON Patch operations to your resume in real-time, with visual feedback for each change. + - Add a system prompt and `patch_resume` tool for the AI chat, enabling structured, minimal-diff resume edits following RFC 6902 JSON Patch operations. + - Chat history is now persisted per resume in localStorage, so conversations are preserved across sessions. + - Fix rendering issues in the Lapras and Onyx resume templates. + - Improvements to the Combobox and ScrollArea UI components. + - Fix an issue with skills item rendering in the shared resume components. + - Update authentication configuration and auth route handling. + - Update the JSON Schema to reflect the latest resume data model. + - Update dependencies to the latest versions. + + - Implement Atomic Resume Patching API for fine-grained resume updates, allowing partial, atomic updates to resumes via a new PATCH endpoint. [#2692](https://github.com/amruthpillai/reactive-resume/pull/2692) - The API endpoint `PUT /resume/{id}` now returns the updated resume object instead of void. Also, resume routing/services now use explicit DTOs for input and output schemas. [#2688](https://github.com/amruthpillai/reactive-resume/pull/2688) diff --git a/docs/docs.json b/docs/docs.json index 2d4a526c9..707140a47 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -72,6 +72,7 @@ "pages": [ "guides/using-the-api", "guides/using-the-patch-api", + "guides/using-the-mcp-server", "guides/using-ai", "guides/json-resume-schema" ] diff --git a/docs/guides/using-the-mcp-server.mdx b/docs/guides/using-the-mcp-server.mdx new file mode 100644 index 000000000..86317221d --- /dev/null +++ b/docs/guides/using-the-mcp-server.mdx @@ -0,0 +1,165 @@ +--- +title: "Using the MCP Server" +description: "Connect Reactive Resume to AI tools like Claude Desktop, Cursor, and Codex using the Model Context Protocol" +--- + +The Reactive Resume MCP server lets you manage and modify your resumes through any MCP-compatible AI tool — Claude Desktop, Cursor, Codex, and more. It connects to the Reactive Resume API and exposes tools for listing, reading, and patching resumes using natural language. + +## What is MCP? + +The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) is a standard that lets LLM-powered tools connect to external services. Instead of being limited to the built-in chat UI, you can use any MCP client to interact with your resumes. + +## Prerequisites + + + + Follow the [Using the API](/guides/using-the-api) guide to create an API key in your Reactive Resume dashboard. + + + + The MCP server requires [Node.js](https://nodejs.org) version 18 or later. + + + + From the Reactive Resume repository root, install dependencies (the MCP server uses the main project's dependencies): + + ```bash + cd /path/to/reactive-resume + pnpm install + ``` + + + +## Running the MCP server + +The server is a single TypeScript entry point and is run with **tsx** (no build step). From the repository root: + +```bash +npx tsx /path/to/reactive-resume/mcp/index.ts +``` + +The working directory must be the **repository root** so that `node_modules` (and thus `@modelcontextprotocol/sdk`) is resolved. Configure your MCP client with `cwd` set to the repo path. + +## Configuration + +### Claude Desktop + +Add the following to your `claude_desktop_config.json`: + +```json +{ + "mcpServers": { + "reactive-resume": { + "command": "npx", + "args": ["tsx", "/path/to/reactive-resume/mcp/index.ts"], + "cwd": "/path/to/reactive-resume", + "env": { + "REACTIVE_RESUME_API_KEY": "your-api-key", + "REACTIVE_RESUME_URL": "https://rxresu.me" + } + } + } +} +``` + + + Replace `/path/to/reactive-resume` with the actual path to your cloned repository, and `your-api-key` with the API key you created. + + +### Cursor + +Add the following to `.cursor/mcp.json` in your project or home directory: + +```json +{ + "mcpServers": { + "reactive-resume": { + "command": "npx", + "args": ["tsx", "/path/to/reactive-resume/mcp/index.ts"], + "cwd": "/path/to/reactive-resume", + "env": { + "REACTIVE_RESUME_API_KEY": "your-api-key", + "REACTIVE_RESUME_URL": "https://rxresu.me" + } + } + } +} +``` + +## Available Tools + +The MCP server exposes three tools: + +| Tool | Description | +| --- | --- | +| `list_resumes` | List all your resumes with their IDs, names, tags, and status | +| `get_resume` | Get the full data of a specific resume by ID | +| `patch_resume` | Apply JSON Patch operations to modify a resume | + +## Available Resources + +| Resource | Description | +| --- | --- | +| `resume://{id}` | The full resume data as a readable JSON resource | +| `resume://schema` | The ResumeData JSON schema for understanding the data structure | + +## Usage Examples + +Once your MCP client is connected, you can use natural language to interact with your resumes: + +### Browsing + +- "List my resumes" +- "Show me my resume named 'Software Engineer'" +- "What skills are listed on my resume?" + +### Editing + +- "Update my name to Jane Doe" +- "Change my headline to Senior Software Engineer" +- "Add TypeScript to my skills with an Advanced proficiency level" +- "Add a new experience entry for my role as Staff Engineer at Acme Corp from Jan 2024 to Present" +- "Remove the third item from my skills section" + +### Styling + +- "Change the template to bronzor" +- "Set the primary color to blue" +- "Hide the interests section" + + + The AI will use `get_resume` to inspect your current resume before making changes with `patch_resume`. This ensures the correct JSON paths are used. + + +## Self-Hosting + +If you're running a self-hosted Reactive Resume instance, set `REACTIVE_RESUME_URL` to your instance URL: + +```json +{ + "env": { + "REACTIVE_RESUME_API_KEY": "your-api-key", + "REACTIVE_RESUME_URL": "https://resume.example.com" + } +} +``` + +## Environment Variables + +| Variable | Required | Default | Description | +| --- | --- | --- | --- | +| `REACTIVE_RESUME_API_KEY` | Yes | — | API key from Reactive Resume settings | +| `REACTIVE_RESUME_URL` | No | `https://rxresu.me` | Base URL of the Reactive Resume instance | +| `TRANSPORT` | No | `stdio` | Transport mode: `stdio` or `http` | +| `PORT` | No | `3100` | Port for streamable HTTP transport | + +## Troubleshooting + +| Issue | Solution | +| --- | --- | +| "REACTIVE_RESUME_API_KEY is required" | Set the `REACTIVE_RESUME_API_KEY` environment variable in your MCP client configuration | +| "API error (401)" | Your API key is invalid or expired. Create a new one in the dashboard | +| "API error (404)" | The resume ID doesn't exist. Use `list_resumes` to find valid IDs | +| "API error (403)" | The resume is locked. Unlock it in the Reactive Resume dashboard | +| Connection refused | Check that `REACTIVE_RESUME_URL` is correct and the instance is running | +| Module not found / Cannot find package | Ensure `cwd` is the repository root so the main project's `node_modules` is used | diff --git a/docs/spec.json b/docs/spec.json index 572498b3c..154a9f04d 100644 --- a/docs/spec.json +++ b/docs/spec.json @@ -1 +1 @@ -{"info":{"title":"Reactive Resume","version":"5.0.0","description":"Reactive Resume API","license":{"name":"MIT","url":"https://github.com/amruthpillai/reactive-resume/blob/main/LICENSE"},"contact":{"name":"Amruth Pillai","email":"hello@amruthpillai.com","url":"https://amruthpillai.com"}},"servers":[{"url":"http://localhost:3000/api/openapi"}],"externalDocs":{"url":"https://docs.rxresu.me","description":"Reactive Resume Documentation"},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","name":"x-api-key","in":"header","description":"The API key to authenticate requests."}}},"security":[{"apiKey":[]}],"openapi":"3.1.1","paths":{"/auth/providers/list":{"get":{"operationId":"auth.providers.list","summary":"List all auth providers","description":"A list of all authentication providers, and their display names, supported by the instance of Reactive Resume.","tags":["Authentication"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"anyOf":[{},{"not":{}}]}}}}}}},"/auth/verify-resume-password":{"post":{"operationId":"auth.verifyResumePassword","summary":"Verify resume password","description":"Verify a resume password, to grant access to the locked resume.","tags":["Authentication","Resume"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1},"username":{"type":"string","minLength":1},"password":{"type":"string","minLength":1}},"required":["slug","username","password"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"boolean"}}}}}}},"/auth/delete-account":{"delete":{"operationId":"auth.deleteAccount","summary":"Delete user account","description":"Delete the authenticated user's account and all associated data.","tags":["Authentication"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"anyOf":[{},{"not":{}}]}}}}}}},"/resume/tags/list":{"get":{"operationId":"resume.tags.list","summary":"List all resume tags","description":"List all tags for the authenticated user's resumes. Used to populate the filter in the dashboard.","tags":["Resume"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}}}},"/resume/statistics/{id}":{"get":{"operationId":"resume.statistics.getById","summary":"Get resume statistics","description":"Get the statistics for a resume, such as number of views and downloads.","tags":["Resume"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"isPublic":{"type":"boolean"},"views":{"type":"number"},"downloads":{"type":"number"},"lastViewedAt":{"anyOf":[{"type":"string","format":"date-time","x-native-type":"date"},{"type":"null"}]},"lastDownloadedAt":{"anyOf":[{"type":"string","format":"date-time","x-native-type":"date"},{"type":"null"}]}},"required":["isPublic","views","downloads","lastViewedAt","lastDownloadedAt"]}}}}}}},"/resume/list":{"get":{"operationId":"resume.list","summary":"List all resumes","description":"List of all the resumes for the authenticated user.","tags":["Resume"],"parameters":[{"name":"tags","in":"query","schema":{"type":"array","items":{"type":"string"},"default":[]},"style":"deepObject","explode":true,"allowEmptyValue":true,"allowReserved":true},{"name":"sort","in":"query","schema":{"enum":["lastUpdatedAt","createdAt","name"],"default":"lastUpdatedAt"},"style":"deepObject","explode":true,"allowEmptyValue":true,"allowReserved":true}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"isPublic":{"type":"boolean"},"isLocked":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","x-native-type":"date"},"updatedAt":{"type":"string","format":"date-time","x-native-type":"date"}},"required":["id","name","slug","tags","isPublic","isLocked","createdAt","updatedAt"]}}}}}}}},"/resume/{id}":{"get":{"operationId":"resume.getById","summary":"Get resume by ID","description":"Get a resume, along with its data, by its ID.","tags":["Resume"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"data":{"type":"object","properties":{"picture":{"type":"object","properties":{"hidden":{"type":"boolean","description":"Whether to hide the picture from the resume."},"url":{"type":"string","description":"The URL to the picture to display on the resume. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"size":{"type":"number","minimum":32,"maximum":512,"description":"The size of the picture to display on the resume, defined in points (pt)."},"rotation":{"type":"number","minimum":0,"maximum":360,"description":"The rotation of the picture to display on the resume, defined in degrees (°)."},"aspectRatio":{"type":"number","minimum":0.5,"maximum":2.5,"description":"The aspect ratio of the picture to display on the resume, defined as width / height (e.g. 1.5 for 1.5:1 or 0.5 for 1:2)."},"borderRadius":{"type":"number","minimum":0,"maximum":100,"description":"The border radius of the picture to display on the resume, defined in points (pt)."},"borderColor":{"type":"string","description":"The color of the border of the picture to display on the resume, defined as rgba(r, g, b, a)."},"borderWidth":{"type":"number","minimum":0,"description":"The width of the border of the picture to display on the resume, defined in points (pt)."},"shadowColor":{"type":"string","description":"The color of the shadow of the picture to display on the resume, defined as rgba(r, g, b, a)."},"shadowWidth":{"type":"number","minimum":0,"description":"The width of the shadow of the picture to display on the resume, defined in points (pt)."}},"required":["hidden","url","size","rotation","aspectRatio","borderRadius","borderColor","borderWidth","shadowColor","shadowWidth"],"description":"Configuration for photograph displayed on the resume"},"basics":{"type":"object","properties":{"name":{"type":"string","description":"The full name of the author of the resume."},"headline":{"type":"string","description":"The headline of the author of the resume."},"email":{"anyOf":[{"type":"string","format":"email"},{"const":""}],"description":"The email address of the author of the resume. Leave blank to hide."},"phone":{"type":"string","description":"The phone number of the author of the resume. Leave blank to hide."},"location":{"type":"string","description":"The location of the author of the resume."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the author of the resume."},"customFields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the custom field. Usually generated as a UUID."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"text":{"type":"string","description":"The text to display for the custom field."}},"required":["id","icon","text"]},"description":"The custom fields to display on the resume."}},"required":["name","headline","email","phone","location","website","customFields"],"description":"Basic information about the author, such as name, email, phone, location, and website"},"summary":{"type":"object","properties":{"title":{"type":"string","description":"The title of the summary of the resume."},"columns":{"type":"number","description":"The number of columns the summary should span across."},"hidden":{"type":"boolean","description":"Whether to hide the summary from the resume."},"content":{"type":"string","description":"The content of the summary of the resume. This should be a HTML-formatted string. Leave blank to hide."}},"required":["title","columns","hidden","content"],"description":"Summary section of the resume, useful for a short bio or introduction"},"sections":{"type":"object","properties":{"profiles":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"network":{"type":"string","minLength":1,"description":"The name of the network or platform."},"username":{"type":"string","description":"The username of the author on the network or platform."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the profile of the author on the network or platform, if any."}},"required":["id","hidden","icon","network","username","website"]},"description":"The items to display in the profiles section."}},"required":["title","columns","hidden","items"],"description":"The section to display the profiles of the author."},"experience":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"company":{"type":"string","minLength":1,"description":"The name of the company or organization."},"position":{"type":"string","description":"The position held at the company or organization."},"location":{"type":"string","description":"The location of the company or organization."},"period":{"type":"string","description":"The period of time the author was employed at the company or organization."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the company or organization, if any."},"description":{"type":"string","description":"The description of the experience. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","company","position","location","period","website","description"]},"description":"The items to display in the experience section."}},"required":["title","columns","hidden","items"],"description":"The section to display the experience of the author."},"education":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"school":{"type":"string","minLength":1,"description":"The name of the school or institution."},"degree":{"type":"string","description":"The degree or qualification obtained."},"area":{"type":"string","description":"The area of study or specialization."},"grade":{"type":"string","description":"The grade or score achieved."},"location":{"type":"string","description":"The location of the school or institution."},"period":{"type":"string","description":"The period of time the education was obtained over."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the school or institution, if any."},"description":{"type":"string","description":"The description of the education. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","school","degree","area","grade","location","period","website","description"]},"description":"The items to display in the education section."}},"required":["title","columns","hidden","items"],"description":"The section to display the education of the author."},"projects":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"name":{"type":"string","minLength":1,"description":"The name of the project."},"period":{"type":"string","description":"The period of time the project was worked on."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the project, if any."},"description":{"type":"string","description":"The description of the project. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","name","period","website","description"]},"description":"The items to display in the projects section."}},"required":["title","columns","hidden","items"],"description":"The section to display the projects of the author."},"skills":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the skill."},"proficiency":{"type":"string","description":"The proficiency level of the skill. Can be any text, such as 'Beginner', 'Intermediate', 'Advanced', etc."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the skill, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the skill, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","proficiency","level","keywords"]},"description":"The items to display in the skills section."}},"required":["title","columns","hidden","items"],"description":"The section to display the skills of the author."},"languages":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"language":{"type":"string","minLength":1,"description":"The name of the language the author knows."},"fluency":{"type":"string","description":"The fluency level of the language. Can be any text, such as 'Native', 'Fluent', 'Conversational', etc. or can also be a CEFR level (A1, A2, B1, B2, C1, C2)."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the language, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."}},"required":["id","hidden","language","fluency","level"]},"description":"The items to display in the languages section."}},"required":["title","columns","hidden","items"],"description":"The section to display the languages of the author."},"interests":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the interest/hobby."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the interest/hobby, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","keywords"]},"description":"The items to display in the interests section."}},"required":["title","columns","hidden","items"],"description":"The section to display the interests of the author."},"awards":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the award."},"awarder":{"type":"string","description":"The awarder of the award."},"date":{"type":"string","description":"The date when the award was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the award, if any."},"description":{"type":"string","description":"The description of the award. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","awarder","date","website","description"]},"description":"The items to display in the awards section."}},"required":["title","columns","hidden","items"],"description":"The section to display the awards of the author."},"certifications":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the certification."},"issuer":{"type":"string","description":"The issuer of the certification."},"date":{"type":"string","description":"The date when the certification was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the certification, if any."},"description":{"type":"string","description":"The description of the certification. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","issuer","date","website","description"]},"description":"The items to display in the certifications section."}},"required":["title","columns","hidden","items"],"description":"The section to display the certifications of the author."},"publications":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the publication."},"publisher":{"type":"string","description":"The publisher of the publication."},"date":{"type":"string","description":"The date when the publication was published."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the publication, if any."},"description":{"type":"string","description":"The description of the publication. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","publisher","date","website","description"]},"description":"The items to display in the publications section."}},"required":["title","columns","hidden","items"],"description":"The section to display the publications of the author."},"volunteer":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"organization":{"type":"string","minLength":1,"description":"The name of the organization or company."},"location":{"type":"string","description":"The location of the organization or company."},"period":{"type":"string","description":"The period of time the author was volunteered at the organization or company."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the organization or company, if any."},"description":{"type":"string","description":"The description of the volunteer experience. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","organization","location","period","website","description"]},"description":"The items to display in the volunteer section."}},"required":["title","columns","hidden","items"],"description":"The section to display the volunteer experience of the author."},"references":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"name":{"type":"string","minLength":1,"description":"The name of the reference, or a note such as 'Available upon request'."},"description":{"type":"string","description":"The description of the reference. Can be used to display a quote, a testimonial, etc. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","name","description"]},"description":"The items to display in the references section."}},"required":["title","columns","hidden","items"],"description":"The section to display the references of the author."}},"required":["profiles","experience","education","projects","skills","languages","interests","awards","certifications","publications","volunteer","references"],"description":"Various sections of the resume, such as experience, education, projects, etc."},"customSections":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"id":{"type":"string","description":"The unique identifier for the custom section. Usually generated as a UUID."},"content":{"type":"string","description":"The content of the custom section. This should be a HTML-formatted string. Leave blank to hide."}},"required":["title","columns","hidden","id","content"]},"description":"Custom sections of the resume, such as a custom section for notes, etc."},"metadata":{"type":"object","properties":{"template":{"enum":["azurill","bronzor","chikorita","ditto","gengar","glalie","kakuna","lapras","leafish","onyx","pikachu","rhyhorn"],"description":"The template to use for the resume. Determines the overall design and appearance of the resume."},"layout":{"type":"object","properties":{"sidebarWidth":{"type":"number","minimum":10,"maximum":50,"description":"The width of the sidebar column, defined as a percentage of the page width."},"pages":{"type":"array","items":{"type":"object","properties":{"fullWidth":{"type":"boolean","description":"Whether the layout of the page should be full width. If true, the main column will span the entire width of the page. This means that there should be no items in the sidebar column."},"main":{"type":"array","items":{"type":"string"},"description":"The items to display in the main column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)."},"sidebar":{"type":"array","items":{"type":"string"},"description":"The items to display in the sidebar column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)."}},"required":["fullWidth","main","sidebar"]},"description":"The pages to display in the layout."}},"required":["sidebarWidth","pages"],"description":"The layout of the resume. Determines the structure and arrangement of the sections on the resume."},"css":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether to enable custom CSS for the resume."},"value":{"type":"string","description":"The custom CSS to apply to the resume. This should be a valid CSS string."}},"required":["enabled","value"],"description":"Custom CSS to apply to the resume. Can be used to override the default styles of the template."},"page":{"type":"object","properties":{"gapX":{"type":"number","minimum":0,"description":"The horizontal gap between the sections of the page, defined in points (pt)."},"gapY":{"type":"number","minimum":0,"description":"The vertical gap between the sections of the page, defined in points (pt)."},"marginX":{"type":"number","minimum":0,"description":"The horizontal margin of the page, defined in points (pt)."},"marginY":{"type":"number","minimum":0,"description":"The vertical margin of the page, defined in points (pt)."},"format":{"enum":["a4","letter"],"description":"The format of the page. Can be 'a4' or 'letter'."},"locale":{"anyOf":[{"const":"af-ZA"},{"const":"am-ET"},{"const":"ar-SA"},{"const":"az-AZ"},{"const":"bg-BG"},{"const":"bn-BD"},{"const":"ca-ES"},{"const":"cs-CZ"},{"const":"da-DK"},{"const":"de-DE"},{"const":"el-GR"},{"const":"en-US"},{"const":"es-ES"},{"const":"fa-IR"},{"const":"fi-FI"},{"const":"fr-FR"},{"const":"he-IL"},{"const":"hi-IN"},{"const":"hu-HU"},{"const":"id-ID"},{"const":"it-IT"},{"const":"ja-JP"},{"const":"km-KH"},{"const":"kn-IN"},{"const":"ko-KR"},{"const":"lt-LT"},{"const":"lv-LV"},{"const":"ml-IN"},{"const":"mr-IN"},{"const":"ms-MY"},{"const":"ne-NP"},{"const":"nl-NL"},{"const":"no-NO"},{"const":"or-IN"},{"const":"pl-PL"},{"const":"pt-BR"},{"const":"pt-PT"},{"const":"ro-RO"},{"const":"ru-RU"},{"const":"sk-SK"},{"const":"sq-AL"},{"const":"sr-SP"},{"const":"sv-SE"},{"const":"ta-IN"},{"const":"te-IN"},{"const":"th-TH"},{"const":"tr-TR"},{"const":"uk-UA"},{"const":"uz-UZ"},{"const":"vi-VN"},{"const":"zh-CN"},{"const":"zh-TW"},{"const":"zu-ZA"}],"description":"The language used in the resume, used for displaying pre-translated section headings, if not overridden."}},"required":["gapX","gapY","marginX","marginY","format","locale"],"description":"The page settings of the resume. Determines the margins, format, and locale of the resume."},"design":{"type":"object","properties":{"level":{"type":"object","properties":{"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"type":{"enum":["hidden","circle","square","rectangle","rectangle-full","progress-bar","icon"],"description":"The type of the level design. 'hidden' will hide the level design, 'circle' will display a circle, 'square' will display a square, 'rectangle' will display a rectangle, 'rectangle-full' will display a full rectangle, 'progress-bar' will display a progress bar, and 'icon' will display an icon. If 'icon' is selected, the icon to display should be specified in the 'icon' field."}},"required":["icon","type"]},"colors":{"type":"object","properties":{"primary":{"type":"string","description":"The primary color of the design, defined as rgba(r, g, b, a)."},"text":{"type":"string","description":"The text color of the design, defined as rgba(r, g, b, a). Usually set to black: rgba(0, 0, 0, 1)."},"background":{"type":"string","description":"The background color of the design, defined as rgba(r, g, b, a). Usually set to white: rgba(255, 255, 255, 1)."}},"required":["primary","text","background"]}},"required":["level","colors"],"description":"The design settings of the resume. Determines the colors, level designs, and typography of the resume."},"typography":{"type":"object","properties":{"body":{"type":"object","properties":{"fontFamily":{"type":"string","description":"The family of the font to use. Must be a font that is available on Google Fonts."},"fontWeights":{"type":"array","items":{"enum":["100","200","300","400","500","600","700","800","900"]},"description":"The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font."},"fontSize":{"type":"number","minimum":6,"maximum":24,"description":"The size of the font to use, defined in points (pt)."},"lineHeight":{"type":"number","minimum":0.5,"maximum":4,"description":"The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x)."}},"required":["fontFamily","fontWeights","fontSize","lineHeight"],"description":"The typography for the body of the resume."},"heading":{"type":"object","properties":{"fontFamily":{"type":"string","description":"The family of the font to use. Must be a font that is available on Google Fonts."},"fontWeights":{"type":"array","items":{"enum":["100","200","300","400","500","600","700","800","900"]},"description":"The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font."},"fontSize":{"type":"number","minimum":6,"maximum":24,"description":"The size of the font to use, defined in points (pt)."},"lineHeight":{"type":"number","minimum":0.5,"maximum":4,"description":"The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x)."}},"required":["fontFamily","fontWeights","fontSize","lineHeight"],"description":"The typography for the headings of the resume."}},"required":["body","heading"],"description":"The typography settings of the resume. Determines the fonts and sizes of the body and headings of the resume."},"notes":{"type":"string","description":"Personal notes for the resume. Can be used to add any additional information or instructions for the resume. These notes are not displayed on the resume, they are only visible to the author of the resume when editing the resume. This should be a HTML-formatted string."}},"required":["template","layout","css","page","design","typography","notes"],"description":"Metadata for the resume, such as template, layout, typography, etc. This section describes the overall design and appearance of the resume."}},"required":["picture","basics","summary","sections","customSections","metadata"]},"isPublic":{"type":"boolean"},"isLocked":{"type":"boolean"},"hasPassword":{"type":"boolean"}},"required":["id","name","slug","tags","data","isPublic","isLocked","hasPassword"]}}}}}},"put":{"operationId":"resume.update","summary":"Update a resume","description":"Update a resume, along with its data, by its ID.","tags":["Resume"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"data":{"type":"object","properties":{"picture":{"type":"object","properties":{"hidden":{"type":"boolean","description":"Whether to hide the picture from the resume."},"url":{"type":"string","description":"The URL to the picture to display on the resume. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"size":{"type":"number","minimum":32,"maximum":512,"description":"The size of the picture to display on the resume, defined in points (pt)."},"rotation":{"type":"number","minimum":0,"maximum":360,"description":"The rotation of the picture to display on the resume, defined in degrees (°)."},"aspectRatio":{"type":"number","minimum":0.5,"maximum":2.5,"description":"The aspect ratio of the picture to display on the resume, defined as width / height (e.g. 1.5 for 1.5:1 or 0.5 for 1:2)."},"borderRadius":{"type":"number","minimum":0,"maximum":100,"description":"The border radius of the picture to display on the resume, defined in points (pt)."},"borderColor":{"type":"string","description":"The color of the border of the picture to display on the resume, defined as rgba(r, g, b, a)."},"borderWidth":{"type":"number","minimum":0,"description":"The width of the border of the picture to display on the resume, defined in points (pt)."},"shadowColor":{"type":"string","description":"The color of the shadow of the picture to display on the resume, defined as rgba(r, g, b, a)."},"shadowWidth":{"type":"number","minimum":0,"description":"The width of the shadow of the picture to display on the resume, defined in points (pt)."}},"required":["hidden","url","size","rotation","aspectRatio","borderRadius","borderColor","borderWidth","shadowColor","shadowWidth"],"description":"Configuration for photograph displayed on the resume"},"basics":{"type":"object","properties":{"name":{"type":"string","description":"The full name of the author of the resume."},"headline":{"type":"string","description":"The headline of the author of the resume."},"email":{"anyOf":[{"type":"string","format":"email"},{"const":""}],"description":"The email address of the author of the resume. Leave blank to hide."},"phone":{"type":"string","description":"The phone number of the author of the resume. Leave blank to hide."},"location":{"type":"string","description":"The location of the author of the resume."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the author of the resume."},"customFields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the custom field. Usually generated as a UUID."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"text":{"type":"string","description":"The text to display for the custom field."}},"required":["id","icon","text"]},"description":"The custom fields to display on the resume."}},"required":["name","headline","email","phone","location","website","customFields"],"description":"Basic information about the author, such as name, email, phone, location, and website"},"summary":{"type":"object","properties":{"title":{"type":"string","description":"The title of the summary of the resume."},"columns":{"type":"number","description":"The number of columns the summary should span across."},"hidden":{"type":"boolean","description":"Whether to hide the summary from the resume."},"content":{"type":"string","description":"The content of the summary of the resume. This should be a HTML-formatted string. Leave blank to hide."}},"required":["title","columns","hidden","content"],"description":"Summary section of the resume, useful for a short bio or introduction"},"sections":{"type":"object","properties":{"profiles":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"network":{"type":"string","minLength":1,"description":"The name of the network or platform."},"username":{"type":"string","description":"The username of the author on the network or platform."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the profile of the author on the network or platform, if any."}},"required":["id","hidden","icon","network","username","website"]},"description":"The items to display in the profiles section."}},"required":["title","columns","hidden","items"],"description":"The section to display the profiles of the author."},"experience":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"company":{"type":"string","minLength":1,"description":"The name of the company or organization."},"position":{"type":"string","description":"The position held at the company or organization."},"location":{"type":"string","description":"The location of the company or organization."},"period":{"type":"string","description":"The period of time the author was employed at the company or organization."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the company or organization, if any."},"description":{"type":"string","description":"The description of the experience. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","company","position","location","period","website","description"]},"description":"The items to display in the experience section."}},"required":["title","columns","hidden","items"],"description":"The section to display the experience of the author."},"education":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"school":{"type":"string","minLength":1,"description":"The name of the school or institution."},"degree":{"type":"string","description":"The degree or qualification obtained."},"area":{"type":"string","description":"The area of study or specialization."},"grade":{"type":"string","description":"The grade or score achieved."},"location":{"type":"string","description":"The location of the school or institution."},"period":{"type":"string","description":"The period of time the education was obtained over."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the school or institution, if any."},"description":{"type":"string","description":"The description of the education. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","school","degree","area","grade","location","period","website","description"]},"description":"The items to display in the education section."}},"required":["title","columns","hidden","items"],"description":"The section to display the education of the author."},"projects":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"name":{"type":"string","minLength":1,"description":"The name of the project."},"period":{"type":"string","description":"The period of time the project was worked on."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the project, if any."},"description":{"type":"string","description":"The description of the project. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","name","period","website","description"]},"description":"The items to display in the projects section."}},"required":["title","columns","hidden","items"],"description":"The section to display the projects of the author."},"skills":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the skill."},"proficiency":{"type":"string","description":"The proficiency level of the skill. Can be any text, such as 'Beginner', 'Intermediate', 'Advanced', etc."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the skill, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the skill, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","proficiency","level","keywords"]},"description":"The items to display in the skills section."}},"required":["title","columns","hidden","items"],"description":"The section to display the skills of the author."},"languages":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"language":{"type":"string","minLength":1,"description":"The name of the language the author knows."},"fluency":{"type":"string","description":"The fluency level of the language. Can be any text, such as 'Native', 'Fluent', 'Conversational', etc. or can also be a CEFR level (A1, A2, B1, B2, C1, C2)."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the language, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."}},"required":["id","hidden","language","fluency","level"]},"description":"The items to display in the languages section."}},"required":["title","columns","hidden","items"],"description":"The section to display the languages of the author."},"interests":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the interest/hobby."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the interest/hobby, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","keywords"]},"description":"The items to display in the interests section."}},"required":["title","columns","hidden","items"],"description":"The section to display the interests of the author."},"awards":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the award."},"awarder":{"type":"string","description":"The awarder of the award."},"date":{"type":"string","description":"The date when the award was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the award, if any."},"description":{"type":"string","description":"The description of the award. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","awarder","date","website","description"]},"description":"The items to display in the awards section."}},"required":["title","columns","hidden","items"],"description":"The section to display the awards of the author."},"certifications":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the certification."},"issuer":{"type":"string","description":"The issuer of the certification."},"date":{"type":"string","description":"The date when the certification was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the certification, if any."},"description":{"type":"string","description":"The description of the certification. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","issuer","date","website","description"]},"description":"The items to display in the certifications section."}},"required":["title","columns","hidden","items"],"description":"The section to display the certifications of the author."},"publications":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the publication."},"publisher":{"type":"string","description":"The publisher of the publication."},"date":{"type":"string","description":"The date when the publication was published."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the publication, if any."},"description":{"type":"string","description":"The description of the publication. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","publisher","date","website","description"]},"description":"The items to display in the publications section."}},"required":["title","columns","hidden","items"],"description":"The section to display the publications of the author."},"volunteer":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"organization":{"type":"string","minLength":1,"description":"The name of the organization or company."},"location":{"type":"string","description":"The location of the organization or company."},"period":{"type":"string","description":"The period of time the author was volunteered at the organization or company."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the organization or company, if any."},"description":{"type":"string","description":"The description of the volunteer experience. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","organization","location","period","website","description"]},"description":"The items to display in the volunteer section."}},"required":["title","columns","hidden","items"],"description":"The section to display the volunteer experience of the author."},"references":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"name":{"type":"string","minLength":1,"description":"The name of the reference, or a note such as 'Available upon request'."},"description":{"type":"string","description":"The description of the reference. Can be used to display a quote, a testimonial, etc. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","name","description"]},"description":"The items to display in the references section."}},"required":["title","columns","hidden","items"],"description":"The section to display the references of the author."}},"required":["profiles","experience","education","projects","skills","languages","interests","awards","certifications","publications","volunteer","references"],"description":"Various sections of the resume, such as experience, education, projects, etc."},"customSections":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"id":{"type":"string","description":"The unique identifier for the custom section. Usually generated as a UUID."},"content":{"type":"string","description":"The content of the custom section. This should be a HTML-formatted string. Leave blank to hide."}},"required":["title","columns","hidden","id","content"]},"description":"Custom sections of the resume, such as a custom section for notes, etc."},"metadata":{"type":"object","properties":{"template":{"enum":["azurill","bronzor","chikorita","ditto","gengar","glalie","kakuna","lapras","leafish","onyx","pikachu","rhyhorn"],"description":"The template to use for the resume. Determines the overall design and appearance of the resume."},"layout":{"type":"object","properties":{"sidebarWidth":{"type":"number","minimum":10,"maximum":50,"description":"The width of the sidebar column, defined as a percentage of the page width."},"pages":{"type":"array","items":{"type":"object","properties":{"fullWidth":{"type":"boolean","description":"Whether the layout of the page should be full width. If true, the main column will span the entire width of the page. This means that there should be no items in the sidebar column."},"main":{"type":"array","items":{"type":"string"},"description":"The items to display in the main column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)."},"sidebar":{"type":"array","items":{"type":"string"},"description":"The items to display in the sidebar column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)."}},"required":["fullWidth","main","sidebar"]},"description":"The pages to display in the layout."}},"required":["sidebarWidth","pages"],"description":"The layout of the resume. Determines the structure and arrangement of the sections on the resume."},"css":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether to enable custom CSS for the resume."},"value":{"type":"string","description":"The custom CSS to apply to the resume. This should be a valid CSS string."}},"required":["enabled","value"],"description":"Custom CSS to apply to the resume. Can be used to override the default styles of the template."},"page":{"type":"object","properties":{"gapX":{"type":"number","minimum":0,"description":"The horizontal gap between the sections of the page, defined in points (pt)."},"gapY":{"type":"number","minimum":0,"description":"The vertical gap between the sections of the page, defined in points (pt)."},"marginX":{"type":"number","minimum":0,"description":"The horizontal margin of the page, defined in points (pt)."},"marginY":{"type":"number","minimum":0,"description":"The vertical margin of the page, defined in points (pt)."},"format":{"enum":["a4","letter"],"description":"The format of the page. Can be 'a4' or 'letter'."},"locale":{"anyOf":[{"const":"af-ZA"},{"const":"am-ET"},{"const":"ar-SA"},{"const":"az-AZ"},{"const":"bg-BG"},{"const":"bn-BD"},{"const":"ca-ES"},{"const":"cs-CZ"},{"const":"da-DK"},{"const":"de-DE"},{"const":"el-GR"},{"const":"en-US"},{"const":"es-ES"},{"const":"fa-IR"},{"const":"fi-FI"},{"const":"fr-FR"},{"const":"he-IL"},{"const":"hi-IN"},{"const":"hu-HU"},{"const":"id-ID"},{"const":"it-IT"},{"const":"ja-JP"},{"const":"km-KH"},{"const":"kn-IN"},{"const":"ko-KR"},{"const":"lt-LT"},{"const":"lv-LV"},{"const":"ml-IN"},{"const":"mr-IN"},{"const":"ms-MY"},{"const":"ne-NP"},{"const":"nl-NL"},{"const":"no-NO"},{"const":"or-IN"},{"const":"pl-PL"},{"const":"pt-BR"},{"const":"pt-PT"},{"const":"ro-RO"},{"const":"ru-RU"},{"const":"sk-SK"},{"const":"sq-AL"},{"const":"sr-SP"},{"const":"sv-SE"},{"const":"ta-IN"},{"const":"te-IN"},{"const":"th-TH"},{"const":"tr-TR"},{"const":"uk-UA"},{"const":"uz-UZ"},{"const":"vi-VN"},{"const":"zh-CN"},{"const":"zh-TW"},{"const":"zu-ZA"}],"description":"The language used in the resume, used for displaying pre-translated section headings, if not overridden."}},"required":["gapX","gapY","marginX","marginY","format","locale"],"description":"The page settings of the resume. Determines the margins, format, and locale of the resume."},"design":{"type":"object","properties":{"level":{"type":"object","properties":{"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"type":{"enum":["hidden","circle","square","rectangle","rectangle-full","progress-bar","icon"],"description":"The type of the level design. 'hidden' will hide the level design, 'circle' will display a circle, 'square' will display a square, 'rectangle' will display a rectangle, 'rectangle-full' will display a full rectangle, 'progress-bar' will display a progress bar, and 'icon' will display an icon. If 'icon' is selected, the icon to display should be specified in the 'icon' field."}},"required":["icon","type"]},"colors":{"type":"object","properties":{"primary":{"type":"string","description":"The primary color of the design, defined as rgba(r, g, b, a)."},"text":{"type":"string","description":"The text color of the design, defined as rgba(r, g, b, a). Usually set to black: rgba(0, 0, 0, 1)."},"background":{"type":"string","description":"The background color of the design, defined as rgba(r, g, b, a). Usually set to white: rgba(255, 255, 255, 1)."}},"required":["primary","text","background"]}},"required":["level","colors"],"description":"The design settings of the resume. Determines the colors, level designs, and typography of the resume."},"typography":{"type":"object","properties":{"body":{"type":"object","properties":{"fontFamily":{"type":"string","description":"The family of the font to use. Must be a font that is available on Google Fonts."},"fontWeights":{"type":"array","items":{"enum":["100","200","300","400","500","600","700","800","900"]},"description":"The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font."},"fontSize":{"type":"number","minimum":6,"maximum":24,"description":"The size of the font to use, defined in points (pt)."},"lineHeight":{"type":"number","minimum":0.5,"maximum":4,"description":"The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x)."}},"required":["fontFamily","fontWeights","fontSize","lineHeight"],"description":"The typography for the body of the resume."},"heading":{"type":"object","properties":{"fontFamily":{"type":"string","description":"The family of the font to use. Must be a font that is available on Google Fonts."},"fontWeights":{"type":"array","items":{"enum":["100","200","300","400","500","600","700","800","900"]},"description":"The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font."},"fontSize":{"type":"number","minimum":6,"maximum":24,"description":"The size of the font to use, defined in points (pt)."},"lineHeight":{"type":"number","minimum":0.5,"maximum":4,"description":"The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x)."}},"required":["fontFamily","fontWeights","fontSize","lineHeight"],"description":"The typography for the headings of the resume."}},"required":["body","heading"],"description":"The typography settings of the resume. Determines the fonts and sizes of the body and headings of the resume."},"notes":{"type":"string","description":"Personal notes for the resume. Can be used to add any additional information or instructions for the resume. These notes are not displayed on the resume, they are only visible to the author of the resume when editing the resume. This should be a HTML-formatted string."}},"required":["template","layout","css","page","design","typography","notes"],"description":"Metadata for the resume, such as template, layout, typography, etc. This section describes the overall design and appearance of the resume."}},"required":["picture","basics","summary","sections","customSections","metadata"]},"isPublic":{"type":"boolean"}},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"anyOf":[{"not":{}},{"not":{}}]}}}}}},"delete":{"operationId":"resume.delete","summary":"Delete a resume","description":"Delete a resume, by its ID.","tags":["Resume"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"anyOf":[{"not":{}},{"not":{}}]}}}}}}},"/resume/{username}/{slug}":{"get":{"operationId":"resume.getBySlug","summary":"Get resume by username and slug","description":"Get a resume, along with its data, by its username and slug.","tags":["Resume"],"parameters":[{"name":"username","in":"path","required":true,"schema":{"type":"string"}},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"data":{"type":"object","properties":{"picture":{"type":"object","properties":{"hidden":{"type":"boolean","description":"Whether to hide the picture from the resume."},"url":{"type":"string","description":"The URL to the picture to display on the resume. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"size":{"type":"number","minimum":32,"maximum":512,"description":"The size of the picture to display on the resume, defined in points (pt)."},"rotation":{"type":"number","minimum":0,"maximum":360,"description":"The rotation of the picture to display on the resume, defined in degrees (°)."},"aspectRatio":{"type":"number","minimum":0.5,"maximum":2.5,"description":"The aspect ratio of the picture to display on the resume, defined as width / height (e.g. 1.5 for 1.5:1 or 0.5 for 1:2)."},"borderRadius":{"type":"number","minimum":0,"maximum":100,"description":"The border radius of the picture to display on the resume, defined in points (pt)."},"borderColor":{"type":"string","description":"The color of the border of the picture to display on the resume, defined as rgba(r, g, b, a)."},"borderWidth":{"type":"number","minimum":0,"description":"The width of the border of the picture to display on the resume, defined in points (pt)."},"shadowColor":{"type":"string","description":"The color of the shadow of the picture to display on the resume, defined as rgba(r, g, b, a)."},"shadowWidth":{"type":"number","minimum":0,"description":"The width of the shadow of the picture to display on the resume, defined in points (pt)."}},"required":["hidden","url","size","rotation","aspectRatio","borderRadius","borderColor","borderWidth","shadowColor","shadowWidth"],"description":"Configuration for photograph displayed on the resume"},"basics":{"type":"object","properties":{"name":{"type":"string","description":"The full name of the author of the resume."},"headline":{"type":"string","description":"The headline of the author of the resume."},"email":{"anyOf":[{"type":"string","format":"email"},{"const":""}],"description":"The email address of the author of the resume. Leave blank to hide."},"phone":{"type":"string","description":"The phone number of the author of the resume. Leave blank to hide."},"location":{"type":"string","description":"The location of the author of the resume."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the author of the resume."},"customFields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the custom field. Usually generated as a UUID."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"text":{"type":"string","description":"The text to display for the custom field."}},"required":["id","icon","text"]},"description":"The custom fields to display on the resume."}},"required":["name","headline","email","phone","location","website","customFields"],"description":"Basic information about the author, such as name, email, phone, location, and website"},"summary":{"type":"object","properties":{"title":{"type":"string","description":"The title of the summary of the resume."},"columns":{"type":"number","description":"The number of columns the summary should span across."},"hidden":{"type":"boolean","description":"Whether to hide the summary from the resume."},"content":{"type":"string","description":"The content of the summary of the resume. This should be a HTML-formatted string. Leave blank to hide."}},"required":["title","columns","hidden","content"],"description":"Summary section of the resume, useful for a short bio or introduction"},"sections":{"type":"object","properties":{"profiles":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"network":{"type":"string","minLength":1,"description":"The name of the network or platform."},"username":{"type":"string","description":"The username of the author on the network or platform."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the profile of the author on the network or platform, if any."}},"required":["id","hidden","icon","network","username","website"]},"description":"The items to display in the profiles section."}},"required":["title","columns","hidden","items"],"description":"The section to display the profiles of the author."},"experience":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"company":{"type":"string","minLength":1,"description":"The name of the company or organization."},"position":{"type":"string","description":"The position held at the company or organization."},"location":{"type":"string","description":"The location of the company or organization."},"period":{"type":"string","description":"The period of time the author was employed at the company or organization."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the company or organization, if any."},"description":{"type":"string","description":"The description of the experience. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","company","position","location","period","website","description"]},"description":"The items to display in the experience section."}},"required":["title","columns","hidden","items"],"description":"The section to display the experience of the author."},"education":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"school":{"type":"string","minLength":1,"description":"The name of the school or institution."},"degree":{"type":"string","description":"The degree or qualification obtained."},"area":{"type":"string","description":"The area of study or specialization."},"grade":{"type":"string","description":"The grade or score achieved."},"location":{"type":"string","description":"The location of the school or institution."},"period":{"type":"string","description":"The period of time the education was obtained over."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the school or institution, if any."},"description":{"type":"string","description":"The description of the education. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","school","degree","area","grade","location","period","website","description"]},"description":"The items to display in the education section."}},"required":["title","columns","hidden","items"],"description":"The section to display the education of the author."},"projects":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"name":{"type":"string","minLength":1,"description":"The name of the project."},"period":{"type":"string","description":"The period of time the project was worked on."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the project, if any."},"description":{"type":"string","description":"The description of the project. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","name","period","website","description"]},"description":"The items to display in the projects section."}},"required":["title","columns","hidden","items"],"description":"The section to display the projects of the author."},"skills":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the skill."},"proficiency":{"type":"string","description":"The proficiency level of the skill. Can be any text, such as 'Beginner', 'Intermediate', 'Advanced', etc."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the skill, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the skill, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","proficiency","level","keywords"]},"description":"The items to display in the skills section."}},"required":["title","columns","hidden","items"],"description":"The section to display the skills of the author."},"languages":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"language":{"type":"string","minLength":1,"description":"The name of the language the author knows."},"fluency":{"type":"string","description":"The fluency level of the language. Can be any text, such as 'Native', 'Fluent', 'Conversational', etc. or can also be a CEFR level (A1, A2, B1, B2, C1, C2)."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the language, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."}},"required":["id","hidden","language","fluency","level"]},"description":"The items to display in the languages section."}},"required":["title","columns","hidden","items"],"description":"The section to display the languages of the author."},"interests":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the interest/hobby."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the interest/hobby, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","keywords"]},"description":"The items to display in the interests section."}},"required":["title","columns","hidden","items"],"description":"The section to display the interests of the author."},"awards":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the award."},"awarder":{"type":"string","description":"The awarder of the award."},"date":{"type":"string","description":"The date when the award was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the award, if any."},"description":{"type":"string","description":"The description of the award. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","awarder","date","website","description"]},"description":"The items to display in the awards section."}},"required":["title","columns","hidden","items"],"description":"The section to display the awards of the author."},"certifications":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the certification."},"issuer":{"type":"string","description":"The issuer of the certification."},"date":{"type":"string","description":"The date when the certification was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the certification, if any."},"description":{"type":"string","description":"The description of the certification. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","issuer","date","website","description"]},"description":"The items to display in the certifications section."}},"required":["title","columns","hidden","items"],"description":"The section to display the certifications of the author."},"publications":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the publication."},"publisher":{"type":"string","description":"The publisher of the publication."},"date":{"type":"string","description":"The date when the publication was published."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the publication, if any."},"description":{"type":"string","description":"The description of the publication. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","publisher","date","website","description"]},"description":"The items to display in the publications section."}},"required":["title","columns","hidden","items"],"description":"The section to display the publications of the author."},"volunteer":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"organization":{"type":"string","minLength":1,"description":"The name of the organization or company."},"location":{"type":"string","description":"The location of the organization or company."},"period":{"type":"string","description":"The period of time the author was volunteered at the organization or company."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the organization or company, if any."},"description":{"type":"string","description":"The description of the volunteer experience. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","organization","location","period","website","description"]},"description":"The items to display in the volunteer section."}},"required":["title","columns","hidden","items"],"description":"The section to display the volunteer experience of the author."},"references":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"name":{"type":"string","minLength":1,"description":"The name of the reference, or a note such as 'Available upon request'."},"description":{"type":"string","description":"The description of the reference. Can be used to display a quote, a testimonial, etc. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","name","description"]},"description":"The items to display in the references section."}},"required":["title","columns","hidden","items"],"description":"The section to display the references of the author."}},"required":["profiles","experience","education","projects","skills","languages","interests","awards","certifications","publications","volunteer","references"],"description":"Various sections of the resume, such as experience, education, projects, etc."},"customSections":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"id":{"type":"string","description":"The unique identifier for the custom section. Usually generated as a UUID."},"content":{"type":"string","description":"The content of the custom section. This should be a HTML-formatted string. Leave blank to hide."}},"required":["title","columns","hidden","id","content"]},"description":"Custom sections of the resume, such as a custom section for notes, etc."},"metadata":{"type":"object","properties":{"template":{"enum":["azurill","bronzor","chikorita","ditto","gengar","glalie","kakuna","lapras","leafish","onyx","pikachu","rhyhorn"],"description":"The template to use for the resume. Determines the overall design and appearance of the resume."},"layout":{"type":"object","properties":{"sidebarWidth":{"type":"number","minimum":10,"maximum":50,"description":"The width of the sidebar column, defined as a percentage of the page width."},"pages":{"type":"array","items":{"type":"object","properties":{"fullWidth":{"type":"boolean","description":"Whether the layout of the page should be full width. If true, the main column will span the entire width of the page. This means that there should be no items in the sidebar column."},"main":{"type":"array","items":{"type":"string"},"description":"The items to display in the main column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)."},"sidebar":{"type":"array","items":{"type":"string"},"description":"The items to display in the sidebar column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)."}},"required":["fullWidth","main","sidebar"]},"description":"The pages to display in the layout."}},"required":["sidebarWidth","pages"],"description":"The layout of the resume. Determines the structure and arrangement of the sections on the resume."},"css":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether to enable custom CSS for the resume."},"value":{"type":"string","description":"The custom CSS to apply to the resume. This should be a valid CSS string."}},"required":["enabled","value"],"description":"Custom CSS to apply to the resume. Can be used to override the default styles of the template."},"page":{"type":"object","properties":{"gapX":{"type":"number","minimum":0,"description":"The horizontal gap between the sections of the page, defined in points (pt)."},"gapY":{"type":"number","minimum":0,"description":"The vertical gap between the sections of the page, defined in points (pt)."},"marginX":{"type":"number","minimum":0,"description":"The horizontal margin of the page, defined in points (pt)."},"marginY":{"type":"number","minimum":0,"description":"The vertical margin of the page, defined in points (pt)."},"format":{"enum":["a4","letter"],"description":"The format of the page. Can be 'a4' or 'letter'."},"locale":{"anyOf":[{"const":"af-ZA"},{"const":"am-ET"},{"const":"ar-SA"},{"const":"az-AZ"},{"const":"bg-BG"},{"const":"bn-BD"},{"const":"ca-ES"},{"const":"cs-CZ"},{"const":"da-DK"},{"const":"de-DE"},{"const":"el-GR"},{"const":"en-US"},{"const":"es-ES"},{"const":"fa-IR"},{"const":"fi-FI"},{"const":"fr-FR"},{"const":"he-IL"},{"const":"hi-IN"},{"const":"hu-HU"},{"const":"id-ID"},{"const":"it-IT"},{"const":"ja-JP"},{"const":"km-KH"},{"const":"kn-IN"},{"const":"ko-KR"},{"const":"lt-LT"},{"const":"lv-LV"},{"const":"ml-IN"},{"const":"mr-IN"},{"const":"ms-MY"},{"const":"ne-NP"},{"const":"nl-NL"},{"const":"no-NO"},{"const":"or-IN"},{"const":"pl-PL"},{"const":"pt-BR"},{"const":"pt-PT"},{"const":"ro-RO"},{"const":"ru-RU"},{"const":"sk-SK"},{"const":"sq-AL"},{"const":"sr-SP"},{"const":"sv-SE"},{"const":"ta-IN"},{"const":"te-IN"},{"const":"th-TH"},{"const":"tr-TR"},{"const":"uk-UA"},{"const":"uz-UZ"},{"const":"vi-VN"},{"const":"zh-CN"},{"const":"zh-TW"},{"const":"zu-ZA"}],"description":"The language used in the resume, used for displaying pre-translated section headings, if not overridden."}},"required":["gapX","gapY","marginX","marginY","format","locale"],"description":"The page settings of the resume. Determines the margins, format, and locale of the resume."},"design":{"type":"object","properties":{"level":{"type":"object","properties":{"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"type":{"enum":["hidden","circle","square","rectangle","rectangle-full","progress-bar","icon"],"description":"The type of the level design. 'hidden' will hide the level design, 'circle' will display a circle, 'square' will display a square, 'rectangle' will display a rectangle, 'rectangle-full' will display a full rectangle, 'progress-bar' will display a progress bar, and 'icon' will display an icon. If 'icon' is selected, the icon to display should be specified in the 'icon' field."}},"required":["icon","type"]},"colors":{"type":"object","properties":{"primary":{"type":"string","description":"The primary color of the design, defined as rgba(r, g, b, a)."},"text":{"type":"string","description":"The text color of the design, defined as rgba(r, g, b, a). Usually set to black: rgba(0, 0, 0, 1)."},"background":{"type":"string","description":"The background color of the design, defined as rgba(r, g, b, a). Usually set to white: rgba(255, 255, 255, 1)."}},"required":["primary","text","background"]}},"required":["level","colors"],"description":"The design settings of the resume. Determines the colors, level designs, and typography of the resume."},"typography":{"type":"object","properties":{"body":{"type":"object","properties":{"fontFamily":{"type":"string","description":"The family of the font to use. Must be a font that is available on Google Fonts."},"fontWeights":{"type":"array","items":{"enum":["100","200","300","400","500","600","700","800","900"]},"description":"The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font."},"fontSize":{"type":"number","minimum":6,"maximum":24,"description":"The size of the font to use, defined in points (pt)."},"lineHeight":{"type":"number","minimum":0.5,"maximum":4,"description":"The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x)."}},"required":["fontFamily","fontWeights","fontSize","lineHeight"],"description":"The typography for the body of the resume."},"heading":{"type":"object","properties":{"fontFamily":{"type":"string","description":"The family of the font to use. Must be a font that is available on Google Fonts."},"fontWeights":{"type":"array","items":{"enum":["100","200","300","400","500","600","700","800","900"]},"description":"The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font."},"fontSize":{"type":"number","minimum":6,"maximum":24,"description":"The size of the font to use, defined in points (pt)."},"lineHeight":{"type":"number","minimum":0.5,"maximum":4,"description":"The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x)."}},"required":["fontFamily","fontWeights","fontSize","lineHeight"],"description":"The typography for the headings of the resume."}},"required":["body","heading"],"description":"The typography settings of the resume. Determines the fonts and sizes of the body and headings of the resume."},"notes":{"type":"string","description":"Personal notes for the resume. Can be used to add any additional information or instructions for the resume. These notes are not displayed on the resume, they are only visible to the author of the resume when editing the resume. This should be a HTML-formatted string."}},"required":["template","layout","css","page","design","typography","notes"],"description":"Metadata for the resume, such as template, layout, typography, etc. This section describes the overall design and appearance of the resume."}},"required":["picture","basics","summary","sections","customSections","metadata"]},"isPublic":{"type":"boolean"},"isLocked":{"type":"boolean"}},"required":["id","name","slug","tags","data","isPublic","isLocked"]}}}}}}},"/resume/create":{"post":{"operationId":"resume.create","summary":"Create a new resume","description":"Create a new resume, with the ability to initialize it with sample data.","tags":["Resume"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":64},"slug":{"type":"string","minLength":1,"maxLength":64},"tags":{"type":"array","items":{"type":"string"}},"withSampleData":{"type":"boolean","default":false}},"required":["name","slug","tags"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"string","description":"The ID of the created resume."}}}}}}},"/resume/import":{"post":{"operationId":"resume.import","summary":"Import a resume","description":"Import a resume from a file.","tags":["Resume"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"picture":{"type":"object","properties":{"hidden":{"type":"boolean","description":"Whether to hide the picture from the resume."},"url":{"type":"string","description":"The URL to the picture to display on the resume. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"size":{"type":"number","minimum":32,"maximum":512,"description":"The size of the picture to display on the resume, defined in points (pt)."},"rotation":{"type":"number","minimum":0,"maximum":360,"description":"The rotation of the picture to display on the resume, defined in degrees (°)."},"aspectRatio":{"type":"number","minimum":0.5,"maximum":2.5,"description":"The aspect ratio of the picture to display on the resume, defined as width / height (e.g. 1.5 for 1.5:1 or 0.5 for 1:2)."},"borderRadius":{"type":"number","minimum":0,"maximum":100,"description":"The border radius of the picture to display on the resume, defined in points (pt)."},"borderColor":{"type":"string","description":"The color of the border of the picture to display on the resume, defined as rgba(r, g, b, a)."},"borderWidth":{"type":"number","minimum":0,"description":"The width of the border of the picture to display on the resume, defined in points (pt)."},"shadowColor":{"type":"string","description":"The color of the shadow of the picture to display on the resume, defined as rgba(r, g, b, a)."},"shadowWidth":{"type":"number","minimum":0,"description":"The width of the shadow of the picture to display on the resume, defined in points (pt)."}},"required":["hidden","url","size","rotation","aspectRatio","borderRadius","borderColor","borderWidth","shadowColor","shadowWidth"],"description":"Configuration for photograph displayed on the resume"},"basics":{"type":"object","properties":{"name":{"type":"string","description":"The full name of the author of the resume."},"headline":{"type":"string","description":"The headline of the author of the resume."},"email":{"anyOf":[{"type":"string","format":"email"},{"const":""}],"description":"The email address of the author of the resume. Leave blank to hide."},"phone":{"type":"string","description":"The phone number of the author of the resume. Leave blank to hide."},"location":{"type":"string","description":"The location of the author of the resume."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the author of the resume."},"customFields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the custom field. Usually generated as a UUID."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"text":{"type":"string","description":"The text to display for the custom field."}},"required":["id","icon","text"]},"description":"The custom fields to display on the resume."}},"required":["name","headline","email","phone","location","website","customFields"],"description":"Basic information about the author, such as name, email, phone, location, and website"},"summary":{"type":"object","properties":{"title":{"type":"string","description":"The title of the summary of the resume."},"columns":{"type":"number","description":"The number of columns the summary should span across."},"hidden":{"type":"boolean","description":"Whether to hide the summary from the resume."},"content":{"type":"string","description":"The content of the summary of the resume. This should be a HTML-formatted string. Leave blank to hide."}},"required":["title","columns","hidden","content"],"description":"Summary section of the resume, useful for a short bio or introduction"},"sections":{"type":"object","properties":{"profiles":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"network":{"type":"string","minLength":1,"description":"The name of the network or platform."},"username":{"type":"string","description":"The username of the author on the network or platform."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the profile of the author on the network or platform, if any."}},"required":["id","hidden","icon","network","username","website"]},"description":"The items to display in the profiles section."}},"required":["title","columns","hidden","items"],"description":"The section to display the profiles of the author."},"experience":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"company":{"type":"string","minLength":1,"description":"The name of the company or organization."},"position":{"type":"string","description":"The position held at the company or organization."},"location":{"type":"string","description":"The location of the company or organization."},"period":{"type":"string","description":"The period of time the author was employed at the company or organization."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the company or organization, if any."},"description":{"type":"string","description":"The description of the experience. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","company","position","location","period","website","description"]},"description":"The items to display in the experience section."}},"required":["title","columns","hidden","items"],"description":"The section to display the experience of the author."},"education":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"school":{"type":"string","minLength":1,"description":"The name of the school or institution."},"degree":{"type":"string","description":"The degree or qualification obtained."},"area":{"type":"string","description":"The area of study or specialization."},"grade":{"type":"string","description":"The grade or score achieved."},"location":{"type":"string","description":"The location of the school or institution."},"period":{"type":"string","description":"The period of time the education was obtained over."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the school or institution, if any."},"description":{"type":"string","description":"The description of the education. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","school","degree","area","grade","location","period","website","description"]},"description":"The items to display in the education section."}},"required":["title","columns","hidden","items"],"description":"The section to display the education of the author."},"projects":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"name":{"type":"string","minLength":1,"description":"The name of the project."},"period":{"type":"string","description":"The period of time the project was worked on."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the project, if any."},"description":{"type":"string","description":"The description of the project. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","name","period","website","description"]},"description":"The items to display in the projects section."}},"required":["title","columns","hidden","items"],"description":"The section to display the projects of the author."},"skills":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the skill."},"proficiency":{"type":"string","description":"The proficiency level of the skill. Can be any text, such as 'Beginner', 'Intermediate', 'Advanced', etc."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the skill, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the skill, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","proficiency","level","keywords"]},"description":"The items to display in the skills section."}},"required":["title","columns","hidden","items"],"description":"The section to display the skills of the author."},"languages":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"language":{"type":"string","minLength":1,"description":"The name of the language the author knows."},"fluency":{"type":"string","description":"The fluency level of the language. Can be any text, such as 'Native', 'Fluent', 'Conversational', etc. or can also be a CEFR level (A1, A2, B1, B2, C1, C2)."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the language, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."}},"required":["id","hidden","language","fluency","level"]},"description":"The items to display in the languages section."}},"required":["title","columns","hidden","items"],"description":"The section to display the languages of the author."},"interests":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the interest/hobby."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the interest/hobby, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","keywords"]},"description":"The items to display in the interests section."}},"required":["title","columns","hidden","items"],"description":"The section to display the interests of the author."},"awards":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the award."},"awarder":{"type":"string","description":"The awarder of the award."},"date":{"type":"string","description":"The date when the award was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the award, if any."},"description":{"type":"string","description":"The description of the award. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","awarder","date","website","description"]},"description":"The items to display in the awards section."}},"required":["title","columns","hidden","items"],"description":"The section to display the awards of the author."},"certifications":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the certification."},"issuer":{"type":"string","description":"The issuer of the certification."},"date":{"type":"string","description":"The date when the certification was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the certification, if any."},"description":{"type":"string","description":"The description of the certification. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","issuer","date","website","description"]},"description":"The items to display in the certifications section."}},"required":["title","columns","hidden","items"],"description":"The section to display the certifications of the author."},"publications":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"title":{"type":"string","minLength":1,"description":"The title of the publication."},"publisher":{"type":"string","description":"The publisher of the publication."},"date":{"type":"string","description":"The date when the publication was published."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the publication, if any."},"description":{"type":"string","description":"The description of the publication. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","title","publisher","date","website","description"]},"description":"The items to display in the publications section."}},"required":["title","columns","hidden","items"],"description":"The section to display the publications of the author."},"volunteer":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"organization":{"type":"string","minLength":1,"description":"The name of the organization or company."},"location":{"type":"string","description":"The location of the organization or company."},"period":{"type":"string","description":"The period of time the author was volunteered at the organization or company."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://). Leave blank to hide."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the organization or company, if any."},"description":{"type":"string","description":"The description of the volunteer experience. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","organization","location","period","website","description"]},"description":"The items to display in the volunteer section."}},"required":["title","columns","hidden","items"],"description":"The section to display the volunteer experience of the author."},"references":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"name":{"type":"string","minLength":1,"description":"The name of the reference, or a note such as 'Available upon request'."},"description":{"type":"string","description":"The description of the reference. Can be used to display a quote, a testimonial, etc. This should be a HTML-formatted string. Leave blank to hide."}},"required":["id","hidden","name","description"]},"description":"The items to display in the references section."}},"required":["title","columns","hidden","items"],"description":"The section to display the references of the author."}},"required":["profiles","experience","education","projects","skills","languages","interests","awards","certifications","publications","volunteer","references"],"description":"Various sections of the resume, such as experience, education, projects, etc."},"customSections":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"id":{"type":"string","description":"The unique identifier for the custom section. Usually generated as a UUID."},"content":{"type":"string","description":"The content of the custom section. This should be a HTML-formatted string. Leave blank to hide."}},"required":["title","columns","hidden","id","content"]},"description":"Custom sections of the resume, such as a custom section for notes, etc."},"metadata":{"type":"object","properties":{"template":{"enum":["azurill","bronzor","chikorita","ditto","gengar","glalie","kakuna","lapras","leafish","onyx","pikachu","rhyhorn"],"description":"The template to use for the resume. Determines the overall design and appearance of the resume."},"layout":{"type":"object","properties":{"sidebarWidth":{"type":"number","minimum":10,"maximum":50,"description":"The width of the sidebar column, defined as a percentage of the page width."},"pages":{"type":"array","items":{"type":"object","properties":{"fullWidth":{"type":"boolean","description":"Whether the layout of the page should be full width. If true, the main column will span the entire width of the page. This means that there should be no items in the sidebar column."},"main":{"type":"array","items":{"type":"string"},"description":"The items to display in the main column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)."},"sidebar":{"type":"array","items":{"type":"string"},"description":"The items to display in the sidebar column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)."}},"required":["fullWidth","main","sidebar"]},"description":"The pages to display in the layout."}},"required":["sidebarWidth","pages"],"description":"The layout of the resume. Determines the structure and arrangement of the sections on the resume."},"css":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether to enable custom CSS for the resume."},"value":{"type":"string","description":"The custom CSS to apply to the resume. This should be a valid CSS string."}},"required":["enabled","value"],"description":"Custom CSS to apply to the resume. Can be used to override the default styles of the template."},"page":{"type":"object","properties":{"gapX":{"type":"number","minimum":0,"description":"The horizontal gap between the sections of the page, defined in points (pt)."},"gapY":{"type":"number","minimum":0,"description":"The vertical gap between the sections of the page, defined in points (pt)."},"marginX":{"type":"number","minimum":0,"description":"The horizontal margin of the page, defined in points (pt)."},"marginY":{"type":"number","minimum":0,"description":"The vertical margin of the page, defined in points (pt)."},"format":{"enum":["a4","letter"],"description":"The format of the page. Can be 'a4' or 'letter'."},"locale":{"anyOf":[{"const":"af-ZA"},{"const":"am-ET"},{"const":"ar-SA"},{"const":"az-AZ"},{"const":"bg-BG"},{"const":"bn-BD"},{"const":"ca-ES"},{"const":"cs-CZ"},{"const":"da-DK"},{"const":"de-DE"},{"const":"el-GR"},{"const":"en-US"},{"const":"es-ES"},{"const":"fa-IR"},{"const":"fi-FI"},{"const":"fr-FR"},{"const":"he-IL"},{"const":"hi-IN"},{"const":"hu-HU"},{"const":"id-ID"},{"const":"it-IT"},{"const":"ja-JP"},{"const":"km-KH"},{"const":"kn-IN"},{"const":"ko-KR"},{"const":"lt-LT"},{"const":"lv-LV"},{"const":"ml-IN"},{"const":"mr-IN"},{"const":"ms-MY"},{"const":"ne-NP"},{"const":"nl-NL"},{"const":"no-NO"},{"const":"or-IN"},{"const":"pl-PL"},{"const":"pt-BR"},{"const":"pt-PT"},{"const":"ro-RO"},{"const":"ru-RU"},{"const":"sk-SK"},{"const":"sq-AL"},{"const":"sr-SP"},{"const":"sv-SE"},{"const":"ta-IN"},{"const":"te-IN"},{"const":"th-TH"},{"const":"tr-TR"},{"const":"uk-UA"},{"const":"uz-UZ"},{"const":"vi-VN"},{"const":"zh-CN"},{"const":"zh-TW"},{"const":"zu-ZA"}],"description":"The language used in the resume, used for displaying pre-translated section headings, if not overridden."}},"required":["gapX","gapY","marginX","marginY","format","locale"],"description":"The page settings of the resume. Determines the margins, format, and locale of the resume."},"design":{"type":"object","properties":{"level":{"type":"object","properties":{"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"type":{"enum":["hidden","circle","square","rectangle","rectangle-full","progress-bar","icon"],"description":"The type of the level design. 'hidden' will hide the level design, 'circle' will display a circle, 'square' will display a square, 'rectangle' will display a rectangle, 'rectangle-full' will display a full rectangle, 'progress-bar' will display a progress bar, and 'icon' will display an icon. If 'icon' is selected, the icon to display should be specified in the 'icon' field."}},"required":["icon","type"]},"colors":{"type":"object","properties":{"primary":{"type":"string","description":"The primary color of the design, defined as rgba(r, g, b, a)."},"text":{"type":"string","description":"The text color of the design, defined as rgba(r, g, b, a). Usually set to black: rgba(0, 0, 0, 1)."},"background":{"type":"string","description":"The background color of the design, defined as rgba(r, g, b, a). Usually set to white: rgba(255, 255, 255, 1)."}},"required":["primary","text","background"]}},"required":["level","colors"],"description":"The design settings of the resume. Determines the colors, level designs, and typography of the resume."},"typography":{"type":"object","properties":{"body":{"type":"object","properties":{"fontFamily":{"type":"string","description":"The family of the font to use. Must be a font that is available on Google Fonts."},"fontWeights":{"type":"array","items":{"enum":["100","200","300","400","500","600","700","800","900"]},"description":"The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font."},"fontSize":{"type":"number","minimum":6,"maximum":24,"description":"The size of the font to use, defined in points (pt)."},"lineHeight":{"type":"number","minimum":0.5,"maximum":4,"description":"The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x)."}},"required":["fontFamily","fontWeights","fontSize","lineHeight"],"description":"The typography for the body of the resume."},"heading":{"type":"object","properties":{"fontFamily":{"type":"string","description":"The family of the font to use. Must be a font that is available on Google Fonts."},"fontWeights":{"type":"array","items":{"enum":["100","200","300","400","500","600","700","800","900"]},"description":"The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font."},"fontSize":{"type":"number","minimum":6,"maximum":24,"description":"The size of the font to use, defined in points (pt)."},"lineHeight":{"type":"number","minimum":0.5,"maximum":4,"description":"The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x)."}},"required":["fontFamily","fontWeights","fontSize","lineHeight"],"description":"The typography for the headings of the resume."}},"required":["body","heading"],"description":"The typography settings of the resume. Determines the fonts and sizes of the body and headings of the resume."},"notes":{"type":"string","description":"Personal notes for the resume. Can be used to add any additional information or instructions for the resume. These notes are not displayed on the resume, they are only visible to the author of the resume when editing the resume. This should be a HTML-formatted string."}},"required":["template","layout","css","page","design","typography","notes"],"description":"Metadata for the resume, such as template, layout, typography, etc. This section describes the overall design and appearance of the resume."}},"required":["picture","basics","summary","sections","customSections","metadata"]}},"required":["data"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"string","description":"The ID of the imported resume."}}}}}}},"/resume/{id}/set-locked":{"post":{"operationId":"resume.setLocked","summary":"Set resume locked status","description":"Toggle the locked status of a resume, by its ID.","tags":["Resume"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"isLocked":{"type":"boolean"}},"required":["isLocked"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"anyOf":[{"not":{}},{"not":{}}]}}}}}}},"/resume/{id}/set-password":{"post":{"operationId":"resume.setPassword","summary":"Set password on a resume","description":"Set a password on a resume to protect it from unauthorized access when shared publicly.","tags":["Resume"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string","minLength":6,"maxLength":64}},"required":["password"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"anyOf":[{"not":{}},{"not":{}}]}}}}}}},"/resume/{id}/remove-password":{"post":{"operationId":"resume.removePassword","summary":"Remove password from a resume","description":"Remove password protection from a resume.","tags":["Resume"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"anyOf":[{"not":{}},{"not":{}}]}}}}}}},"/resume/{id}/duplicate":{"post":{"operationId":"resume.duplicate","summary":"Duplicate a resume","description":"Duplicate a resume, by its ID.","tags":["Resume"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"string","description":"The ID of the duplicated resume."}}}}}}},"/printer/resume/{id}/pdf":{"get":{"operationId":"printer.printResumeAsPDF","summary":"Export resume as PDF","description":"Export a resume as a PDF. Returns a URL to download the PDF.","tags":["Resume","Printer"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}},"required":["url"]}}}}}}},"/printer/resume/{id}/screenshot":{"get":{"operationId":"printer.getResumeScreenshot","summary":"Get resume screenshot","description":"Get a screenshot of a resume. Returns a URL to the screenshot image.","tags":["Resume","Printer"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}},"required":["url"]}}}}}}},"/statistics/user/count":{"get":{"operationId":"statistics.user.getCount","summary":"Get total number of users","description":"Get the total number of users for the Reactive Resume.","tags":["Statistics"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"number"}}}}}}},"/statistics/resume/count":{"get":{"operationId":"statistics.resume.getCount","summary":"Get total number of resumes","description":"Get the total number of resumes for the Reactive Resume.","tags":["Statistics"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"number"}}}}}}},"/statistics/github/stars":{"get":{"operationId":"statistics.github.getStarCount","summary":"Get GitHub Repository stargazers count","description":"Get the stargazers count for the Reactive Resume GitHub repository, at the time of writing.","tags":["Statistics"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"number"}}}}}}}}} \ No newline at end of file +{"info":{"title":"Reactive Resume","version":"5.0.6","description":"Reactive Resume API","license":{"name":"MIT","url":"https://github.com/amruthpillai/reactive-resume/blob/main/LICENSE"},"contact":{"name":"Amruth Pillai","email":"hello@amruthpillai.com","url":"https://amruthpillai.com"}},"servers":[{"url":"http://localhost:3000/api/openapi"}],"externalDocs":{"url":"https://docs.rxresu.me","description":"Reactive Resume Documentation"},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","name":"x-api-key","in":"header","description":"The API key to authenticate requests."}},"schemas":{"ResumeData":{"type":"object","properties":{"picture":{"type":"object","properties":{"hidden":{"type":"boolean","description":"Whether to hide the picture from the resume."},"url":{"type":"string","description":"The URL to the picture to display on the resume. Must be a valid URL with a protocol (http:// or https://)."},"size":{"type":"number","minimum":32,"maximum":512,"description":"The size of the picture to display on the resume, defined in points (pt)."},"rotation":{"type":"number","minimum":0,"maximum":360,"description":"The rotation of the picture to display on the resume, defined in degrees (°)."},"aspectRatio":{"type":"number","minimum":0.5,"maximum":2.5,"description":"The aspect ratio of the picture to display on the resume, defined as width / height (e.g. 1.5 for 1.5:1 or 0.5 for 1:2)."},"borderRadius":{"type":"number","minimum":0,"maximum":100,"description":"The border radius of the picture to display on the resume, defined in points (pt)."},"borderColor":{"type":"string","description":"The color of the border of the picture to display on the resume, defined as rgba(r, g, b, a)."},"borderWidth":{"type":"number","minimum":0,"description":"The width of the border of the picture to display on the resume, defined in points (pt)."},"shadowColor":{"type":"string","description":"The color of the shadow of the picture to display on the resume, defined as rgba(r, g, b, a)."},"shadowWidth":{"type":"number","minimum":0,"description":"The width of the shadow of the picture to display on the resume, defined in points (pt)."}},"required":["hidden","url","size","rotation","aspectRatio","borderRadius","borderColor","borderWidth","shadowColor","shadowWidth"],"description":"Configuration for photograph displayed on the resume"},"basics":{"type":"object","properties":{"name":{"type":"string","description":"The full name of the author of the resume."},"headline":{"type":"string","description":"The headline of the author of the resume."},"email":{"type":"string","description":"The email address of the author of the resume."},"phone":{"type":"string","description":"The phone number of the author of the resume."},"location":{"type":"string","description":"The location of the author of the resume."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the author of the resume."},"customFields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the custom field. Usually generated as a UUID."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"text":{"type":"string","description":"The text to display for the custom field."},"link":{"type":"string","description":"If the custom field should be a link, the URL to link to."}},"required":["id","icon","text","link"]},"description":"The custom fields to display on the resume."}},"required":["name","headline","email","phone","location","website","customFields"],"description":"Basic information about the author, such as name, email, phone, location, and website"},"summary":{"type":"object","properties":{"title":{"type":"string","description":"The title of the summary of the resume."},"columns":{"type":"number","description":"The number of columns the summary should span across."},"hidden":{"type":"boolean","description":"Whether to hide the summary from the resume."},"content":{"type":"string","description":"The content of the summary of the resume. This should be a HTML-formatted string."}},"required":["title","columns","hidden","content"],"description":"Summary section of the resume, useful for a short bio or introduction"},"sections":{"type":"object","properties":{"profiles":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"network":{"type":"string","minLength":1,"description":"The name of the network or platform."},"username":{"type":"string","description":"The username of the author on the network or platform."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the profile of the author on the network or platform, if any."}},"required":["id","hidden","icon","network","username","website"]},"description":"The items to display in the profiles section."}},"required":["title","columns","hidden","items"],"description":"The section to display the profiles of the author."},"experience":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"company":{"type":"string","minLength":1,"description":"The name of the company or organization."},"position":{"type":"string","description":"The position held at the company or organization."},"location":{"type":"string","description":"The location of the company or organization."},"period":{"type":"string","description":"The period of time the author was employed at the company or organization."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the company or organization, if any."},"description":{"type":"string","description":"The description of the experience. This should be a HTML-formatted string."}},"required":["id","hidden","company","position","location","period","website","description"]},"description":"The items to display in the experience section."}},"required":["title","columns","hidden","items"],"description":"The section to display the experience of the author."},"education":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"school":{"type":"string","minLength":1,"description":"The name of the school or institution."},"degree":{"type":"string","description":"The degree or qualification obtained."},"area":{"type":"string","description":"The area of study or specialization."},"grade":{"type":"string","description":"The grade or score achieved."},"location":{"type":"string","description":"The location of the school or institution."},"period":{"type":"string","description":"The period of time the education was obtained over."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the school or institution, if any."},"description":{"type":"string","description":"The description of the education. This should be a HTML-formatted string."}},"required":["id","hidden","school","degree","area","grade","location","period","website","description"]},"description":"The items to display in the education section."}},"required":["title","columns","hidden","items"],"description":"The section to display the education of the author."},"projects":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"name":{"type":"string","minLength":1,"description":"The name of the project."},"period":{"type":"string","description":"The period of time the project was worked on."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the project, if any."},"description":{"type":"string","description":"The description of the project. This should be a HTML-formatted string."}},"required":["id","hidden","name","period","website","description"]},"description":"The items to display in the projects section."}},"required":["title","columns","hidden","items"],"description":"The section to display the projects of the author."},"skills":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the skill."},"proficiency":{"type":"string","description":"The proficiency level of the skill. Can be any text, such as 'Beginner', 'Intermediate', 'Advanced', etc."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the skill, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the skill, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","proficiency","level","keywords"]},"description":"The items to display in the skills section."}},"required":["title","columns","hidden","items"],"description":"The section to display the skills of the author."},"languages":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"language":{"type":"string","minLength":1,"description":"The name of the language the author knows."},"fluency":{"type":"string","description":"The fluency level of the language. Can be any text, such as 'Native', 'Fluent', 'Conversational', etc. or can also be a CEFR level (A1, A2, B1, B2, C1, C2)."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the language, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."}},"required":["id","hidden","language","fluency","level"]},"description":"The items to display in the languages section."}},"required":["title","columns","hidden","items"],"description":"The section to display the languages of the author."},"interests":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the interest/hobby."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the interest/hobby, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","keywords"]},"description":"The items to display in the interests section."}},"required":["title","columns","hidden","items"],"description":"The section to display the interests of the author."},"awards":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"title":{"type":"string","minLength":1,"description":"The title of the award."},"awarder":{"type":"string","description":"The awarder of the award."},"date":{"type":"string","description":"The date when the award was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the award, if any."},"description":{"type":"string","description":"The description of the award. This should be a HTML-formatted string."}},"required":["id","hidden","title","awarder","date","website","description"]},"description":"The items to display in the awards section."}},"required":["title","columns","hidden","items"],"description":"The section to display the awards of the author."},"certifications":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"title":{"type":"string","minLength":1,"description":"The title of the certification."},"issuer":{"type":"string","description":"The issuer of the certification."},"date":{"type":"string","description":"The date when the certification was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the certification, if any."},"description":{"type":"string","description":"The description of the certification. This should be a HTML-formatted string."}},"required":["id","hidden","title","issuer","date","website","description"]},"description":"The items to display in the certifications section."}},"required":["title","columns","hidden","items"],"description":"The section to display the certifications of the author."},"publications":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"title":{"type":"string","minLength":1,"description":"The title of the publication."},"publisher":{"type":"string","description":"The publisher of the publication."},"date":{"type":"string","description":"The date when the publication was published."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the publication, if any."},"description":{"type":"string","description":"The description of the publication. This should be a HTML-formatted string."}},"required":["id","hidden","title","publisher","date","website","description"]},"description":"The items to display in the publications section."}},"required":["title","columns","hidden","items"],"description":"The section to display the publications of the author."},"volunteer":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"organization":{"type":"string","minLength":1,"description":"The name of the organization or company."},"location":{"type":"string","description":"The location of the organization or company."},"period":{"type":"string","description":"The period of time the author was volunteered at the organization or company."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the organization or company, if any."},"description":{"type":"string","description":"The description of the volunteer experience. This should be a HTML-formatted string."}},"required":["id","hidden","organization","location","period","website","description"]},"description":"The items to display in the volunteer section."}},"required":["title","columns","hidden","items"],"description":"The section to display the volunteer experience of the author."},"references":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"name":{"type":"string","minLength":1,"description":"The name of the reference, or a note such as 'Available upon request'."},"position":{"type":"string","description":"The position or job title of the reference."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website or LinkedIn profile of the reference, if any."},"phone":{"type":"string","description":"The phone number of the reference."},"description":{"type":"string","description":"The description of the reference. Can be used to display a quote, a testimonial, etc. This should be a HTML-formatted string."}},"required":["id","hidden","name","position","website","phone","description"]},"description":"The items to display in the references section."}},"required":["title","columns","hidden","items"],"description":"The section to display the references of the author."}},"required":["profiles","experience","education","projects","skills","languages","interests","awards","certifications","publications","volunteer","references"],"description":"Various sections of the resume, such as experience, education, projects, etc."},"customSections":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the section."},"columns":{"type":"number","description":"The number of columns the section should span across."},"hidden":{"type":"boolean","description":"Whether to hide the section from the resume."},"id":{"type":"string","description":"The unique identifier for the custom section. Usually generated as a UUID."},"type":{"enum":["summary","profiles","experience","education","projects","skills","languages","interests","awards","certifications","publications","volunteer","references","cover-letter"],"description":"The type of items this custom section contains. Determines which item schema and form fields to use."},"items":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"recipient":{"type":"string","description":"The recipient's address block as HTML (name, title, company, address, email)."},"content":{"type":"string","description":"The cover letter body as HTML (salutation, paragraphs, closing, signature)."}},"required":["id","hidden","recipient","content"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"content":{"type":"string","description":"The rich text content of the summary item. This should be a HTML-formatted string."}},"required":["id","hidden","content"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"network":{"type":"string","minLength":1,"description":"The name of the network or platform."},"username":{"type":"string","description":"The username of the author on the network or platform."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the profile of the author on the network or platform, if any."}},"required":["id","hidden","icon","network","username","website"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"company":{"type":"string","minLength":1,"description":"The name of the company or organization."},"position":{"type":"string","description":"The position held at the company or organization."},"location":{"type":"string","description":"The location of the company or organization."},"period":{"type":"string","description":"The period of time the author was employed at the company or organization."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the company or organization, if any."},"description":{"type":"string","description":"The description of the experience. This should be a HTML-formatted string."}},"required":["id","hidden","company","position","location","period","website","description"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"school":{"type":"string","minLength":1,"description":"The name of the school or institution."},"degree":{"type":"string","description":"The degree or qualification obtained."},"area":{"type":"string","description":"The area of study or specialization."},"grade":{"type":"string","description":"The grade or score achieved."},"location":{"type":"string","description":"The location of the school or institution."},"period":{"type":"string","description":"The period of time the education was obtained over."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the school or institution, if any."},"description":{"type":"string","description":"The description of the education. This should be a HTML-formatted string."}},"required":["id","hidden","school","degree","area","grade","location","period","website","description"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"name":{"type":"string","minLength":1,"description":"The name of the project."},"period":{"type":"string","description":"The period of time the project was worked on."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the project, if any."},"description":{"type":"string","description":"The description of the project. This should be a HTML-formatted string."}},"required":["id","hidden","name","period","website","description"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the skill."},"proficiency":{"type":"string","description":"The proficiency level of the skill. Can be any text, such as 'Beginner', 'Intermediate', 'Advanced', etc."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the skill, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the skill, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","proficiency","level","keywords"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"language":{"type":"string","minLength":1,"description":"The name of the language the author knows."},"fluency":{"type":"string","description":"The fluency level of the language. Can be any text, such as 'Native', 'Fluent', 'Conversational', etc. or can also be a CEFR level (A1, A2, B1, B2, C1, C2)."},"level":{"type":"number","minimum":0,"maximum":5,"description":"The proficiency level of the language, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden."}},"required":["id","hidden","language","fluency","level"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"name":{"type":"string","minLength":1,"description":"The name of the interest/hobby."},"keywords":{"type":"array","items":{"type":"string"},"description":"The keywords associated with the interest/hobby, if any. These are displayed as tags below the name."}},"required":["id","hidden","icon","name","keywords"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"title":{"type":"string","minLength":1,"description":"The title of the award."},"awarder":{"type":"string","description":"The awarder of the award."},"date":{"type":"string","description":"The date when the award was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the award, if any."},"description":{"type":"string","description":"The description of the award. This should be a HTML-formatted string."}},"required":["id","hidden","title","awarder","date","website","description"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"title":{"type":"string","minLength":1,"description":"The title of the certification."},"issuer":{"type":"string","description":"The issuer of the certification."},"date":{"type":"string","description":"The date when the certification was received."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website of the certification, if any."},"description":{"type":"string","description":"The description of the certification. This should be a HTML-formatted string."}},"required":["id","hidden","title","issuer","date","website","description"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"title":{"type":"string","minLength":1,"description":"The title of the publication."},"publisher":{"type":"string","description":"The publisher of the publication."},"date":{"type":"string","description":"The date when the publication was published."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the publication, if any."},"description":{"type":"string","description":"The description of the publication. This should be a HTML-formatted string."}},"required":["id","hidden","title","publisher","date","website","description"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"organization":{"type":"string","minLength":1,"description":"The name of the organization or company."},"location":{"type":"string","description":"The location of the organization or company."},"period":{"type":"string","description":"The period of time the author was volunteered at the organization or company."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The link to the organization or company, if any."},"description":{"type":"string","description":"The description of the volunteer experience. This should be a HTML-formatted string."}},"required":["id","hidden","organization","location","period","website","description"]},{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the item. Usually generated as a UUID."},"hidden":{"type":"boolean","description":"Whether to hide the item from the resume."},"options":{"type":"object","properties":{"showLinkInTitle":{"type":"boolean","description":"If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom."}},"required":["showLinkInTitle"],"description":"Display options for this item."},"name":{"type":"string","minLength":1,"description":"The name of the reference, or a note such as 'Available upon request'."},"position":{"type":"string","description":"The position or job title of the reference."},"website":{"type":"object","properties":{"url":{"type":"string","description":"The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)."},"label":{"type":"string","description":"The label to display for the URL. Leave blank to display the URL as-is."}},"required":["url","label"],"description":"The website or LinkedIn profile of the reference, if any."},"phone":{"type":"string","description":"The phone number of the reference."},"description":{"type":"string","description":"The description of the reference. Can be used to display a quote, a testimonial, etc. This should be a HTML-formatted string."}},"required":["id","hidden","name","position","website","phone","description"]}]},"description":"The items to display in the custom section. Items follow the schema of the section type."}},"required":["title","columns","hidden","id","type","items"]},"description":"Custom sections of the resume, such as a custom section for notes, etc."},"metadata":{"type":"object","properties":{"template":{"enum":["azurill","bronzor","chikorita","ditgar","ditto","gengar","glalie","kakuna","lapras","leafish","onyx","pikachu","rhyhorn"],"description":"The template to use for the resume. Determines the overall design and appearance of the resume."},"layout":{"type":"object","properties":{"sidebarWidth":{"type":"number","minimum":10,"maximum":50,"description":"The width of the sidebar column, defined as a percentage of the page width."},"pages":{"type":"array","items":{"type":"object","properties":{"fullWidth":{"type":"boolean","description":"Whether the layout of the page should be full width. If true, the main column will span the entire width of the page. This means that there should be no items in the sidebar column."},"main":{"type":"array","items":{"type":"string"},"description":"The items to display in the main column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)."},"sidebar":{"type":"array","items":{"type":"string"},"description":"The items to display in the sidebar column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)."}},"required":["fullWidth","main","sidebar"]},"description":"The pages to display in the layout."}},"required":["sidebarWidth","pages"],"description":"The layout of the resume. Determines the structure and arrangement of the sections on the resume."},"css":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether to enable custom CSS for the resume."},"value":{"type":"string","description":"The custom CSS to apply to the resume. This should be a valid CSS string."}},"required":["enabled","value"],"description":"Custom CSS to apply to the resume. Can be used to override the default styles of the template."},"page":{"type":"object","properties":{"gapX":{"type":"number","minimum":0,"description":"The horizontal gap between the sections of the page, defined in points (pt)."},"gapY":{"type":"number","minimum":0,"description":"The vertical gap between the sections of the page, defined in points (pt)."},"marginX":{"type":"number","minimum":0,"description":"The horizontal margin of the page, defined in points (pt)."},"marginY":{"type":"number","minimum":0,"description":"The vertical margin of the page, defined in points (pt)."},"format":{"enum":["a4","letter","free-form"],"description":"The format of the page. Can be 'a4', 'letter' or 'free-form'."},"locale":{"type":"string","description":"The locale of the page. Used for displaying pre-translated section headings, if not overridden."},"hideIcons":{"type":"boolean","description":"Whether to hide the icons of the sections."}},"required":["gapX","gapY","marginX","marginY","format","locale","hideIcons"],"description":"The page settings of the resume. Determines the margins, format, and locale of the resume."},"design":{"type":"object","properties":{"level":{"type":"object","properties":{"icon":{"type":"string","description":"The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available."},"type":{"enum":["hidden","circle","square","rectangle","rectangle-full","progress-bar","icon"],"description":"The type of the level design. 'hidden' will hide the level design, 'circle' will display a circle, 'square' will display a square, 'rectangle' will display a rectangle, 'rectangle-full' will display a full rectangle, 'progress-bar' will display a progress bar, and 'icon' will display an icon. If 'icon' is selected, the icon to display should be specified in the 'icon' field."}},"required":["icon","type"]},"colors":{"type":"object","properties":{"primary":{"type":"string","description":"The primary color of the design, defined as rgba(r, g, b, a)."},"text":{"type":"string","description":"The text color of the design, defined as rgba(r, g, b, a). Usually set to black: rgba(0, 0, 0, 1)."},"background":{"type":"string","description":"The background color of the design, defined as rgba(r, g, b, a). Usually set to white: rgba(255, 255, 255, 1)."}},"required":["primary","text","background"]}},"required":["level","colors"],"description":"The design settings of the resume. Determines the colors, level designs, and typography of the resume."},"typography":{"type":"object","properties":{"body":{"type":"object","properties":{"fontFamily":{"type":"string","description":"The family of the font to use. Must be a font that is available on Google Fonts."},"fontWeights":{"type":"array","items":{"enum":["100","200","300","400","500","600","700","800","900"]},"description":"The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font."},"fontSize":{"type":"number","minimum":6,"maximum":24,"description":"The size of the font to use, defined in points (pt)."},"lineHeight":{"type":"number","minimum":0.5,"maximum":4,"description":"The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x)."}},"required":["fontFamily","fontWeights","fontSize","lineHeight"],"description":"The typography for the body of the resume."},"heading":{"type":"object","properties":{"fontFamily":{"type":"string","description":"The family of the font to use. Must be a font that is available on Google Fonts."},"fontWeights":{"type":"array","items":{"enum":["100","200","300","400","500","600","700","800","900"]},"description":"The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font."},"fontSize":{"type":"number","minimum":6,"maximum":24,"description":"The size of the font to use, defined in points (pt)."},"lineHeight":{"type":"number","minimum":0.5,"maximum":4,"description":"The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x)."}},"required":["fontFamily","fontWeights","fontSize","lineHeight"],"description":"The typography for the headings of the resume."}},"required":["body","heading"],"description":"The typography settings of the resume. Determines the fonts and sizes of the body and headings of the resume."},"notes":{"type":"string","description":"Personal notes for the resume. Can be used to add any additional information or instructions for the resume. These notes are not displayed on the resume, they are only visible to the author of the resume when editing the resume. This should be a HTML-formatted string."}},"required":["template","layout","css","page","design","typography","notes"],"description":"Metadata for the resume, such as template, layout, typography, etc. This section describes the overall design and appearance of the resume."}},"required":["picture","basics","summary","sections","customSections","metadata"]}}},"security":[{"apiKey":[]}],"openapi":"3.1.1","paths":{"/ai/test-connection":{"post":{"operationId":"testAiConnection","summary":"Test AI provider connection","description":"Validates the connection to an AI provider by sending a simple test prompt. Requires the provider type, model name, API key, and an optional base URL. Supported providers: OpenAI, Anthropic, Google Gemini, Ollama, and Vercel AI Gateway. Requires authentication.","tags":["AI"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"enum":["ollama","openai","gemini","anthropic","vercel-ai-gateway"]},"model":{"type":"string"},"apiKey":{"type":"string"},"baseURL":{"type":"string"}},"required":["provider","model","apiKey","baseURL"]}}}},"responses":{"200":{"description":"The AI provider connection was successful.","content":{"application/json":{"schema":{"anyOf":[{},{"not":{}}]}}}},"502":{"description":"502","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"defined":{"const":true},"code":{"const":"BAD_GATEWAY"},"status":{"const":502},"message":{"type":"string","default":"The AI provider returned an error or is unreachable."},"data":{}},"required":["defined","code","status","message"]},{"type":"object","properties":{"defined":{"const":false},"code":{"type":"string"},"status":{"type":"number"},"message":{"type":"string"},"data":{}},"required":["defined","code","status","message"]}]}}}}}}},"/ai/parse-pdf":{"post":{"operationId":"parseResumePdf","summary":"Parse a PDF file into resume data","description":"Extracts structured resume data from a PDF file using the specified AI provider. The file should be sent as a base64-encoded string along with AI provider credentials. Returns a complete ResumeData object. Requires authentication.","tags":["AI"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"enum":["ollama","openai","gemini","anthropic","vercel-ai-gateway"]},"model":{"type":"string"},"apiKey":{"type":"string"},"baseURL":{"type":"string"},"file":{"type":"object","properties":{"name":{"type":"string"},"data":{"type":"string"}},"required":["name","data"]}},"required":["provider","model","apiKey","baseURL","file"]}}}},"responses":{"200":{"description":"The PDF was successfully parsed into structured resume data.","content":{"application/json":{"schema":{"anyOf":[{},{"not":{}}]}}}},"502":{"description":"502","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"defined":{"const":true},"code":{"const":"BAD_GATEWAY"},"status":{"const":502},"message":{"type":"string","default":"The AI provider returned an error or is unreachable."},"data":{}},"required":["defined","code","status","message"]},{"type":"object","properties":{"defined":{"const":false},"code":{"type":"string"},"status":{"type":"number"},"message":{"type":"string"},"data":{}},"required":["defined","code","status","message"]}]}}}}}}},"/ai/parse-docx":{"post":{"operationId":"parseResumeDocx","summary":"Parse a DOCX file into resume data","description":"Extracts structured resume data from a DOCX or DOC file using the specified AI provider. The file should be sent as a base64-encoded string along with AI provider credentials and the document's media type. Returns a complete ResumeData object. Requires authentication.","tags":["AI"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"enum":["ollama","openai","gemini","anthropic","vercel-ai-gateway"]},"model":{"type":"string"},"apiKey":{"type":"string"},"baseURL":{"type":"string"},"file":{"type":"object","properties":{"name":{"type":"string"},"data":{"type":"string"}},"required":["name","data"]},"mediaType":{"enum":["application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document"]}},"required":["provider","model","apiKey","baseURL","file","mediaType"]}}}},"responses":{"200":{"description":"The DOCX was successfully parsed into structured resume data.","content":{"application/json":{"schema":{"anyOf":[{},{"not":{}}]}}}},"502":{"description":"502","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"defined":{"const":true},"code":{"const":"BAD_GATEWAY"},"status":{"const":502},"message":{"type":"string","default":"The AI provider returned an error or is unreachable."},"data":{}},"required":["defined","code","status","message"]},{"type":"object","properties":{"defined":{"const":false},"code":{"type":"string"},"status":{"type":"number"},"message":{"type":"string"},"data":{}},"required":["defined","code","status","message"]}]}}}}}}},"/auth/providers":{"get":{"operationId":"listAuthProviders","summary":"List authentication providers","description":"Returns a list of all authentication providers enabled on this Reactive Resume instance, along with their display names. Possible providers include password-based credentials, Google, GitHub, and custom OAuth. No authentication required.","tags":["Authentication"],"responses":{"200":{"description":"A map of enabled authentication provider identifiers to their display names.","content":{"application/json":{"schema":{"anyOf":[{},{"not":{}}]}}}}}}},"/auth/account":{"delete":{"operationId":"deleteAccount","summary":"Delete user account","description":"Permanently deletes the authenticated user's account, including all resumes, uploaded files (profile pictures, screenshots, PDFs), and associated data. This action is irreversible. Requires authentication.","tags":["Authentication"],"responses":{"200":{"description":"The user account and all associated data have been successfully deleted.","content":{"application/json":{"schema":{"anyOf":[{},{"not":{}}]}}}}}}},"/flags":{"get":{"operationId":"getFeatureFlags","summary":"Get feature flags","description":"Returns the current feature flags for this Reactive Resume instance. Feature flags control instance-wide settings such as whether new user signups or email-based authentication are disabled. No authentication required.","tags":["Feature Flags"],"responses":{"200":{"description":"The current feature flags for this instance.","content":{"application/json":{"schema":{"type":"object","properties":{"disableSignups":{"type":"boolean","description":"Whether new user signups are disabled on this instance."},"disableEmailAuth":{"type":"boolean","description":"Whether email-based authentication is disabled on this instance."}},"required":["disableSignups","disableEmailAuth"]}}}}}}},"/resumes/tags":{"get":{"operationId":"listResumeTags","summary":"List all resume tags","description":"Returns a sorted list of all unique tags across the authenticated user's resumes. Useful for populating tag filters in the dashboard. Requires authentication.","tags":["Resumes"],"responses":{"200":{"description":"A sorted array of unique tag strings.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}}}},"/resumes/{id}/statistics":{"get":{"operationId":"getResumeStatistics","summary":"Get resume statistics","description":"Returns view and download statistics for the specified resume, including total counts and the timestamps of the last view and download. Requires authentication.","tags":["Resume Statistics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The unique identifier of the resume."}}],"responses":{"200":{"description":"The resume's view and download statistics.","content":{"application/json":{"schema":{"type":"object","properties":{"isPublic":{"type":"boolean","description":"Whether the resume is currently public."},"views":{"type":"number","description":"Total number of times the resume has been viewed."},"downloads":{"type":"number","description":"Total number of times the resume has been downloaded."},"lastViewedAt":{"anyOf":[{"type":"string","format":"date-time","x-native-type":"date"},{"type":"null"}],"description":"Timestamp of the last view, or null if never viewed."},"lastDownloadedAt":{"anyOf":[{"type":"string","format":"date-time","x-native-type":"date"},{"type":"null"}],"description":"Timestamp of the last download, or null if never downloaded."}},"required":["isPublic","views","downloads","lastViewedAt","lastDownloadedAt"]}}}}}}},"/resumes":{"get":{"operationId":"listResumes","summary":"List all resumes","description":"Returns a list of all resumes belonging to the authenticated user. Results can be filtered by tags and sorted by last updated date, creation date, or name. Resume data is not included in the response for performance; use the get endpoint to fetch full resume data. Requires authentication.","tags":["Resumes"],"parameters":[{"name":"tags","in":"query","schema":{"type":"array","items":{"type":"string"},"default":[]},"style":"deepObject","explode":true,"allowEmptyValue":true,"allowReserved":true},{"name":"sort","in":"query","schema":{"enum":["lastUpdatedAt","createdAt","name"],"default":"lastUpdatedAt"},"style":"deepObject","explode":true,"allowEmptyValue":true,"allowReserved":true}],"responses":{"200":{"description":"A list of resumes with their metadata (without full resume data).","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The ID of the resume."},"name":{"type":"string","minLength":1,"maxLength":64,"description":"The name of the resume."},"slug":{"type":"string","minLength":1,"maxLength":64,"description":"The slug of the resume."},"tags":{"type":"array","items":{"type":"string"},"description":"The tags of the resume."},"isPublic":{"type":"boolean","description":"Whether the resume is public."},"isLocked":{"type":"boolean","description":"Whether the resume is locked."},"createdAt":{"type":"string","format":"date-time","x-native-type":"date","description":"The date and time the resume was created."},"updatedAt":{"type":"string","format":"date-time","x-native-type":"date","description":"The date and time the resume was last updated."}},"required":["id","name","slug","tags","isPublic","isLocked","createdAt","updatedAt"]}}}}}}},"post":{"operationId":"createResume","summary":"Create a new resume","description":"Creates a new resume with the given name, slug, and tags. Optionally initializes the resume with sample data by setting withSampleData to true. The slug must be unique across the user's resumes. Returns the ID of the newly created resume. Requires authentication.","tags":["Resumes"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":64,"description":"The name of the resume."},"slug":{"type":"string","minLength":1,"maxLength":64,"description":"The slug of the resume."},"tags":{"type":"array","items":{"type":"string"},"description":"The tags of the resume."},"withSampleData":{"type":"boolean","default":false}},"required":["name","slug","tags"]}}}},"responses":{"200":{"description":"The ID of the newly created resume.","content":{"application/json":{"schema":{"type":"string","description":"The ID of the created resume."}}}},"400":{"description":"400","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"defined":{"const":true},"code":{"const":"RESUME_SLUG_ALREADY_EXISTS"},"status":{"const":400},"message":{"type":"string","default":"A resume with this slug already exists."},"data":{}},"required":["defined","code","status","message"]},{"type":"object","properties":{"defined":{"const":false},"code":{"type":"string"},"status":{"type":"number"},"message":{"type":"string"},"data":{}},"required":["defined","code","status","message"]}]}}}}}}},"/resumes/{id}":{"get":{"operationId":"getResume","summary":"Get resume by ID","description":"Returns a single resume with its full data, identified by its unique ID. Only resumes belonging to the authenticated user can be retrieved. Requires authentication.","tags":["Resumes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the resume."}}],"responses":{"200":{"description":"The resume with its full data.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The ID of the resume."},"name":{"type":"string","minLength":1,"maxLength":64,"description":"The name of the resume."},"slug":{"type":"string","minLength":1,"maxLength":64,"description":"The slug of the resume."},"tags":{"type":"array","items":{"type":"string"},"description":"The tags of the resume."},"isPublic":{"type":"boolean","description":"Whether the resume is public."},"isLocked":{"type":"boolean","description":"Whether the resume is locked."},"data":{"$ref":"#/components/schemas/ResumeData"},"hasPassword":{"type":"boolean"}},"required":["id","name","slug","tags","isPublic","isLocked","data","hasPassword"]}}}}}},"put":{"operationId":"updateResume","summary":"Update a resume","description":"Updates one or more fields of a resume identified by its ID. All fields are optional; only provided fields will be updated. Locked resumes cannot be updated. Requires authentication.","tags":["Resumes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":64,"description":"The name of the resume."},"slug":{"type":"string","minLength":1,"maxLength":64,"description":"The slug of the resume."},"tags":{"type":"array","items":{"type":"string"},"description":"The tags of the resume."},"data":{"$ref":"#/components/schemas/ResumeData"},"isPublic":{"type":"boolean","description":"Whether the resume is public."}},"required":[]}}}},"responses":{"200":{"description":"The updated resume with its full data.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The ID of the resume."},"name":{"type":"string","minLength":1,"maxLength":64,"description":"The name of the resume."},"slug":{"type":"string","minLength":1,"maxLength":64,"description":"The slug of the resume."},"tags":{"type":"array","items":{"type":"string"},"description":"The tags of the resume."},"isPublic":{"type":"boolean","description":"Whether the resume is public."},"isLocked":{"type":"boolean","description":"Whether the resume is locked."},"data":{"$ref":"#/components/schemas/ResumeData"}},"required":["id","name","slug","tags","isPublic","isLocked","data"]}}}},"400":{"description":"400","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"defined":{"const":true},"code":{"const":"RESUME_SLUG_ALREADY_EXISTS"},"status":{"const":400},"message":{"type":"string","default":"A resume with this slug already exists."},"data":{}},"required":["defined","code","status","message"]},{"type":"object","properties":{"defined":{"const":false},"code":{"type":"string"},"status":{"type":"number"},"message":{"type":"string"},"data":{}},"required":["defined","code","status","message"]}]}}}}}},"patch":{"operationId":"patchResume","summary":"Patch resume data","description":"Applies JSON Patch (RFC 6902) operations to partially update a resume's data. This allows small, targeted changes (e.g. updating a single field) without sending the entire resume object. Locked resumes cannot be patched. Requires authentication.","tags":["Resumes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the resume to patch."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"operations":{"type":"array","minItems":1,"items":{"anyOf":[{"type":"object","properties":{"op":{"const":"add"},"path":{"type":"string"},"value":{}},"required":["op","path"]},{"type":"object","properties":{"op":{"const":"remove"},"path":{"type":"string"}},"required":["op","path"]},{"type":"object","properties":{"op":{"const":"replace"},"path":{"type":"string"},"value":{}},"required":["op","path"]},{"type":"object","properties":{"op":{"const":"move"},"path":{"type":"string"},"from":{"type":"string"}},"required":["op","path","from"]},{"type":"object","properties":{"op":{"const":"copy"},"path":{"type":"string"},"from":{"type":"string"}},"required":["op","path","from"]},{"type":"object","properties":{"op":{"const":"test"},"path":{"type":"string"},"value":{}},"required":["op","path"]}]},"description":"An array of JSON Patch (RFC 6902) operations to apply to the resume data."}},"required":["operations"]}}}},"responses":{"200":{"description":"The patched resume with its full data.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The ID of the resume."},"name":{"type":"string","minLength":1,"maxLength":64,"description":"The name of the resume."},"slug":{"type":"string","minLength":1,"maxLength":64,"description":"The slug of the resume."},"tags":{"type":"array","items":{"type":"string"},"description":"The tags of the resume."},"isPublic":{"type":"boolean","description":"Whether the resume is public."},"isLocked":{"type":"boolean","description":"Whether the resume is locked."},"data":{"$ref":"#/components/schemas/ResumeData"},"hasPassword":{"type":"boolean"}},"required":["id","name","slug","tags","isPublic","isLocked","data","hasPassword"]}}}},"400":{"description":"400","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"defined":{"const":true},"code":{"const":"INVALID_PATCH_OPERATIONS"},"status":{"const":400},"message":{"type":"string","default":"The patch operations are invalid or produced an invalid resume."},"data":{}},"required":["defined","code","status","message"]},{"type":"object","properties":{"defined":{"const":false},"code":{"type":"string"},"status":{"type":"number"},"message":{"type":"string"},"data":{}},"required":["defined","code","status","message"]}]}}}}}},"delete":{"operationId":"deleteResume","summary":"Delete a resume","description":"Permanently deletes a resume and its associated files (screenshots, PDFs) from storage. Locked resumes cannot be deleted; unlock the resume first. Requires authentication.","tags":["Resumes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the resume."}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}},"responses":{"200":{"description":"The resume and its associated files were deleted successfully.","content":{"application/json":{"schema":{"anyOf":[{"not":{}},{"not":{}}]}}}}}}},"/resumes/{username}/{slug}":{"get":{"operationId":"getResumeBySlug","summary":"Get public resume by username and slug","description":"Returns a publicly shared resume identified by the owner's username and the resume's slug. If the resume is password-protected and the viewer has not yet verified the password, a 401 error with code NEED_PASSWORD is returned. No authentication required for public resumes; if authenticated as the owner, private resumes are also accessible.","tags":["Resume Sharing"],"parameters":[{"name":"username","in":"path","required":true,"schema":{"type":"string"}},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The public resume with its full data.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The ID of the resume."},"name":{"type":"string","minLength":1,"maxLength":64,"description":"The name of the resume."},"slug":{"type":"string","minLength":1,"maxLength":64,"description":"The slug of the resume."},"tags":{"type":"array","items":{"type":"string"},"description":"The tags of the resume."},"isPublic":{"type":"boolean","description":"Whether the resume is public."},"isLocked":{"type":"boolean","description":"Whether the resume is locked."},"data":{"$ref":"#/components/schemas/ResumeData"}},"required":["id","name","slug","tags","isPublic","isLocked","data"]}}}}}}},"/resumes/import":{"post":{"operationId":"importResume","summary":"Import a resume","description":"Creates a new resume from an existing ResumeData object (e.g. from a previously exported JSON file). A random name and slug are generated automatically. Returns the ID of the imported resume. Requires authentication.","tags":["Resumes"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ResumeData"}},"required":["data"]}}}},"responses":{"200":{"description":"The ID of the imported resume.","content":{"application/json":{"schema":{"type":"string","description":"The ID of the imported resume."}}}},"400":{"description":"400","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"defined":{"const":true},"code":{"const":"RESUME_SLUG_ALREADY_EXISTS"},"status":{"const":400},"message":{"type":"string","default":"A resume with this slug already exists."},"data":{}},"required":["defined","code","status","message"]},{"type":"object","properties":{"defined":{"const":false},"code":{"type":"string"},"status":{"type":"number"},"message":{"type":"string"},"data":{}},"required":["defined","code","status","message"]}]}}}}}}},"/resumes/{id}/lock":{"post":{"operationId":"setResumeLocked","summary":"Set resume lock status","description":"Toggles the locked status of a resume. When locked, a resume cannot be updated, patched, or deleted. Useful for protecting finalized resumes from accidental edits. Requires authentication.","tags":["Resumes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the resume."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"isLocked":{"type":"boolean","description":"Whether the resume is locked."}},"required":["isLocked"]}}}},"responses":{"200":{"description":"The resume lock status was updated successfully.","content":{"application/json":{"schema":{"anyOf":[{"not":{}},{"not":{}}]}}}}}}},"/resumes/{id}/password":{"put":{"operationId":"setResumePassword","summary":"Set resume password","description":"Sets or updates a password on a resume. When a password is set, viewers of the public resume must enter the password before the resume data is revealed. The password must be between 6 and 64 characters. Requires authentication.","tags":["Resume Sharing"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the resume."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string","minLength":6,"maxLength":64}},"required":["password"]}}}},"responses":{"200":{"description":"The resume password was set successfully.","content":{"application/json":{"schema":{"anyOf":[{"not":{}},{"not":{}}]}}}}}},"delete":{"operationId":"removeResumePassword","summary":"Remove resume password","description":"Removes password protection from a resume. After removal, the resume (if public) can be viewed without entering a password. Requires authentication.","tags":["Resume Sharing"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the resume."}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}},"responses":{"200":{"description":"The resume password was removed successfully.","content":{"application/json":{"schema":{"anyOf":[{"not":{}},{"not":{}}]}}}}}}},"/resumes/{username}/{slug}/password/verify":{"post":{"operationId":"verifyResumePassword","summary":"Verify resume password","description":"Verifies a password for a password-protected public resume. On success, the viewer is granted access to view the resume data for the duration of their session. No authentication required.","tags":["Resume Sharing"],"parameters":[{"name":"username","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The username of the resume owner."}},{"name":"slug","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The slug of the resume."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string","minLength":1,"description":"The password to verify."}},"required":["password"]}}}},"responses":{"200":{"description":"The password was verified successfully and access has been granted.","content":{"application/json":{"schema":{"type":"boolean"}}}}}}},"/resumes/{id}/duplicate":{"post":{"operationId":"duplicateResume","summary":"Duplicate a resume","description":"Creates a copy of an existing resume with the same data. Optionally override the name, slug, and tags for the duplicate. If not provided, the original resume's name, slug, and tags are used. Returns the ID of the duplicated resume. Requires authentication.","tags":["Resumes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the resume."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":64,"description":"The name of the resume."},"slug":{"type":"string","minLength":1,"maxLength":64,"description":"The slug of the resume."},"tags":{"type":"array","items":{"type":"string"},"description":"The tags of the resume."}},"required":["name","slug","tags"]}}}},"responses":{"200":{"description":"The ID of the duplicated resume.","content":{"application/json":{"schema":{"type":"string","description":"The ID of the duplicated resume."}}}}}}},"/resumes/{id}/pdf":{"get":{"operationId":"exportResumePdf","summary":"Export resume as PDF","description":"Generates a PDF from the specified resume and uploads it to storage. Returns a URL to download the generated PDF file. If the request is made by an unauthenticated user (e.g. via a public share link), the resume's download count is incremented. Authentication is optional.","tags":["Resume Export"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The unique identifier of the resume to export."}}],"responses":{"200":{"description":"The PDF was generated successfully. Returns a URL to download the file.","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"The URL to download the generated PDF file."}},"required":["url"]}}}}}}},"/resumes/{id}/screenshot":{"get":{"operationId":"getResumeScreenshot","summary":"Get resume screenshot","description":"Returns a URL to a screenshot image of the first page of the specified resume. Screenshots are cached for up to 6 hours and regenerated automatically when the resume is updated. Returns null if the screenshot cannot be generated. Requires authentication.","tags":["Resume Export"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The unique identifier of the resume."}}],"responses":{"200":{"description":"The screenshot URL, or null if the screenshot could not be generated.","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The URL to the screenshot image, or null."}},"required":["url"]}}}}}}},"/statistics/users":{"get":{"operationId":"getUserCount","summary":"Get total number of users","description":"Returns the total number of registered users on this Reactive Resume instance. The count is cached for up to 6 hours for performance. No authentication required.","tags":["Platform Statistics"],"responses":{"200":{"description":"The total number of registered users.","content":{"application/json":{"schema":{"type":"number","description":"The total number of registered users."}}}}}}},"/statistics/resumes":{"get":{"operationId":"getResumeCount","summary":"Get total number of resumes","description":"Returns the total number of resumes created on this Reactive Resume instance. The count is cached for up to 6 hours for performance. No authentication required.","tags":["Platform Statistics"],"responses":{"200":{"description":"The total number of resumes created.","content":{"application/json":{"schema":{"type":"number","description":"The total number of resumes created."}}}}}}},"/statistics/github/stars":{"get":{"operationId":"getGitHubStarCount","summary":"Get GitHub star count","description":"Returns the number of GitHub stars for the Reactive Resume repository. The count is cached for up to 6 hours and falls back to a last-known value if the GitHub API is unavailable. No authentication required.","tags":["Platform Statistics"],"responses":{"200":{"description":"The number of GitHub stars for the Reactive Resume repository.","content":{"application/json":{"schema":{"type":"number","description":"The number of GitHub stars."}}}}}}}}} \ No newline at end of file diff --git a/knip.json b/knip.json index bbe7b61c6..e09cf288f 100644 --- a/knip.json +++ b/knip.json @@ -4,6 +4,12 @@ "tailwind": { "entry": ["src/styles.css"] }, "project": ["src/**/*.{js,jsx,ts,tsx,mdx,css}"], "ignoreBinaries": ["mint"], - "ignoreDependencies": ["npm-check-updates", "reflect-metadata", "node-addon-api", "node-gyp"], + "ignoreDependencies": [ + "@modelcontextprotocol/sdk", + "npm-check-updates", + "reflect-metadata", + "node-addon-api", + "node-gyp" + ], "ignore": ["src/schema/**/*.ts", "src/components/**/*.{ts,tsx}", "src/routeTree.gen.ts"] } diff --git a/locales/af-ZA.po b/locales/af-ZA.po index a40fe2336..892b06fdd 100644 Binary files a/locales/af-ZA.po and b/locales/af-ZA.po differ diff --git a/locales/am-ET.po b/locales/am-ET.po index aff4da525..da9b20bfa 100644 --- a/locales/am-ET.po +++ b/locales/am-ET.po @@ -207,6 +207,10 @@ msgstr "ከዚህ በኋላ ረድፍ ያክሉ" msgid "Add Row Before" msgstr "ከዚህ በፊት ረድፍ ያክሉ" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "አፍሪካንስ" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "አልባኒኛ" @@ -340,6 +348,10 @@ msgstr "የስልጠና መስክ" msgid "Artificial Intelligence" msgstr "አርቲፊሻል ኢንተለጀንስ" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "የመገናኛ መጠን" @@ -534,6 +546,10 @@ msgstr "ቻይንኛ (ባለባለት)" msgid "Circle" msgstr "ክብ" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "ምርጫን ሰርዝ" @@ -945,6 +961,10 @@ msgstr "የየታሪክዎን ቅጂ በመፍጠር ላይ…" msgid "Dutch" msgstr "ደች" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "ትምህርት" @@ -1896,6 +1916,10 @@ msgstr "የይለፍ ቃልዎ አስታውሰዎ? <0><1>አሁን ይግቡ <2/ msgid "Remove Password" msgstr "የይለፍ ቃል አስወግድ" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "የይለፍ ቃል ጥበቃን በማስወገድ ላይ…" @@ -2357,6 +2381,10 @@ msgstr "ከዚያም መተግበሪያው ሰጥቶት የ 6 አሃዝ ኮድ msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF በማመንጨት ጊዜ ችግኝ ተፈጥሯል፣ እባክዎን ጥቂት ጊዜ በኋላ ደግመው ይሞክሩ።" +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "የየታሪክ ማቅረቢያን አዘምን" msgid "Update your password" msgstr "የይለፍ ቃልዎን አዘምኑ" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "የይለፍ ቃልዎን በመዘመን ላይ…" diff --git a/locales/ar-SA.po b/locales/ar-SA.po index 45c8cf4a1..efc59b6a2 100644 --- a/locales/ar-SA.po +++ b/locales/ar-SA.po @@ -207,6 +207,10 @@ msgstr "إضافة صف بعد" msgid "Add Row Before" msgstr "إضافة صف قبل" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "الأفريقانس" msgid "AI" msgstr "الذكاء الاصطناعي" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "الألبانية" @@ -340,6 +348,10 @@ msgstr "مجال الدراسة" msgid "Artificial Intelligence" msgstr "الذكاء الاصطناعي" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "نسبة الأبعاد" @@ -534,6 +546,10 @@ msgstr "الصينية (التقليدية)" msgid "Circle" msgstr "دائرة" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "مسح التحديد" @@ -945,6 +961,10 @@ msgstr "جاري استنساخ سيرتك الذاتية..." msgid "Dutch" msgstr "الهولندية" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "التعليم" @@ -1896,6 +1916,10 @@ msgstr "هل تذكّرت كلمة المرور؟ <0><1>سجّل الدخول ا msgid "Remove Password" msgstr "إزالة كلمة المرور" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "جاري إزالة حماية كلمة المرور..." @@ -2357,6 +2381,10 @@ msgstr "بعد ذلك، أدخِل الرمز المكوَّن من 6 أرقام msgid "There was a problem while generating the PDF, please try again in some time." msgstr "حدثت مشكلة أثناء إنشاء ملف PDF، يُرجى المحاولة مرة أخرى بعد فترة." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "تحديث السيرة الذاتية" msgid "Update your password" msgstr "حدّث كلمة المرور الخاصة بك" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "جاري تحديث كلمة المرور..." diff --git a/locales/az-AZ.po b/locales/az-AZ.po index 506f3de80..ebb085b44 100644 --- a/locales/az-AZ.po +++ b/locales/az-AZ.po @@ -207,6 +207,10 @@ msgstr "Sonra Sətir əlavə et" msgid "Add Row Before" msgstr "Əvvəl Sətir əlavə et" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "Süni İntellekt" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanca" @@ -340,6 +348,10 @@ msgstr "Təhsil sahəsi" msgid "Artificial Intelligence" msgstr "Süni İntellekt" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Propor­siya" @@ -534,6 +546,10 @@ msgstr "Çin (Ənənəvi)" msgid "Circle" msgstr "Dairə" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Seçimi təmizlə" @@ -945,6 +961,10 @@ msgstr "Özgeçmişiniz dublikat edilir..." msgid "Dutch" msgstr "Niderland" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Təhsil" @@ -1896,6 +1916,10 @@ msgstr "Parolunuzu xatırladınız? <0><1>İndi daxil olun <2/>" msgid "Remove Password" msgstr "Parolu Sil" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Parol qorunması silinir..." @@ -2357,6 +2381,10 @@ msgstr "Sonra, davam etmək üçün tətbiqin təqdim etdiyi 6 rəqəmli kodu da msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF yaradılarkən problem yarandı, zəhmət olmasa, bir müddət sonra yenidən cəhd edin." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Özgeçmişi Yenilə" msgid "Update your password" msgstr "Parolunuzu yeniləyin" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Parolunuz yenilənir..." diff --git a/locales/bg-BG.po b/locales/bg-BG.po index 206ae0e66..1d7c7a1b2 100644 --- a/locales/bg-BG.po +++ b/locales/bg-BG.po @@ -207,6 +207,10 @@ msgstr "Добавяне на ред след" msgid "Add Row Before" msgstr "Добавяне на ред преди" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Африканс" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Албански" @@ -340,6 +348,10 @@ msgstr "Област на обучение" msgid "Artificial Intelligence" msgstr "Изкуствен интелект" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Съотношение на страните" @@ -534,6 +546,10 @@ msgstr "Китайски (традиционен)" msgid "Circle" msgstr "Кръг" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Изчистване на избора" @@ -945,6 +961,10 @@ msgstr "Вашата автобиография се дублира..." msgid "Dutch" msgstr "Нидерландски" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Образование" @@ -1896,6 +1916,10 @@ msgstr "Спомнихте си паролата? <0><1>Влезте сега <2 msgid "Remove Password" msgstr "Премахване на парола" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Премахване на защитата с парола..." @@ -2357,6 +2381,10 @@ msgstr "След това въведете шестцифрения код, ко msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Възникна проблем при генерирането на PDF, моля, опитайте отново след известно време." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Актуализиране на автобиография" msgid "Update your password" msgstr "Актуализирайте паролата си" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Актуализиране на паролата ви..." diff --git a/locales/bn-BD.po b/locales/bn-BD.po index 63e6aaa78..b4bb2cee7 100644 --- a/locales/bn-BD.po +++ b/locales/bn-BD.po @@ -207,6 +207,10 @@ msgstr "পরের দিকে সারি যোগ করুন" msgid "Add Row Before" msgstr "আগের দিকে সারি যোগ করুন" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "আফ্রিকান্স" msgid "AI" msgstr "এআই" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "আলবেনিয়ান" @@ -340,6 +348,10 @@ msgstr "অধ্যয়নের এলাকা" msgid "Artificial Intelligence" msgstr "কৃত্রিম বুদ্ধিমত্তা" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "আকারের অনুপাত" @@ -534,6 +546,10 @@ msgstr "চীনা (প্রচলিত)" msgid "Circle" msgstr "বৃত্ত" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "নির্বাচন মুছে ফেলুন" @@ -945,6 +961,10 @@ msgstr "আপনার জীবনবৃত্তান্ত ডুপ্ল msgid "Dutch" msgstr "ডাচ" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "শিক্ষা" @@ -1896,6 +1916,10 @@ msgstr "পাসওয়ার্ড মনে আছে? <0><1>এখনই msgid "Remove Password" msgstr "পাসওয়ার্ড সরিয়ে ফেলুন" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "পাসওয়ার্ড সুরক্ষা সরানো হচ্ছে..." @@ -2357,6 +2381,10 @@ msgstr "তারপর, অ্যাপটি যে ৬ সংখ্যার msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF তৈরি করার সময় একটি সমস্যা হয়েছে, অনুগ্রহ করে কিছু সময় পরে আবার চেষ্টা করুন।" +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "জীবনবৃত্তান্ত আপডেট করুন" msgid "Update your password" msgstr "আপনার পাসওয়ার্ড আপডেট করুন" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "আপনার পাসওয়ার্ড আপডেট করা হচ্ছে..." diff --git a/locales/ca-ES.po b/locales/ca-ES.po index 88e461916..322547630 100644 --- a/locales/ca-ES.po +++ b/locales/ca-ES.po @@ -207,6 +207,10 @@ msgstr "Afegeix una fila després" msgid "Add Row Before" msgstr "Afegeix una fila abans" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "IA" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanès" @@ -340,6 +348,10 @@ msgstr "Àrea d’estudi" msgid "Artificial Intelligence" msgstr "Intel·ligència artificial" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Relació d’aspecte" @@ -534,6 +546,10 @@ msgstr "Xinès (tradicional)" msgid "Circle" msgstr "Cercle" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Esborra la selecció" @@ -945,6 +961,10 @@ msgstr "S’està duplicant el currículum..." msgid "Dutch" msgstr "Neerlandès" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Educació" @@ -1896,6 +1916,10 @@ msgstr "Recordes la contrasenya? <0><1>Inicia sessió ara <2/>" msgid "Remove Password" msgstr "Elimina la contrasenya" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "S’està desactivant la protecció amb contrasenya..." @@ -2357,6 +2381,10 @@ msgstr "A continuació, introdueix el codi de 6 dígits que proporciona l’apli msgid "There was a problem while generating the PDF, please try again in some time." msgstr "S’ha produït un problema en generar el PDF, torna-ho a provar més tard." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Actualitza el currículum" msgid "Update your password" msgstr "Actualitza la contrasenya" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "S’està actualitzant la contrasenya..." diff --git a/locales/cs-CZ.po b/locales/cs-CZ.po index 7b8f47432..fc087f7dc 100644 --- a/locales/cs-CZ.po +++ b/locales/cs-CZ.po @@ -207,6 +207,10 @@ msgstr "Přidat řádek za" msgid "Add Row Before" msgstr "Přidat řádek před" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikánština" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albánština" @@ -340,6 +348,10 @@ msgstr "Studijní obor" msgid "Artificial Intelligence" msgstr "Umělá inteligence" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Poměr stran" @@ -534,6 +546,10 @@ msgstr "Čínština (tradiční)" msgid "Circle" msgstr "Kruh" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Zrušit výběr" @@ -945,6 +961,10 @@ msgstr "Duplikování životopisu…" msgid "Dutch" msgstr "Nizozemština" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Vzdělání" @@ -1896,6 +1916,10 @@ msgstr "Pamatujete si heslo? <0><1>Přihlaste se nyní <2/>" msgid "Remove Password" msgstr "Odebrat heslo" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Odstraňování ochrany heslem…" @@ -2357,6 +2381,10 @@ msgstr "Poté zadejte šestimístný kód, který aplikace poskytne, abyste mohl msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Při generování PDF došlo k problému, zkuste to prosím znovu za chvíli." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Aktualizovat životopis" msgid "Update your password" msgstr "Aktualizujte své heslo" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Aktualizace hesla…" diff --git a/locales/da-DK.po b/locales/da-DK.po index d9cb0e88f..8e3fcf9b2 100644 --- a/locales/da-DK.po +++ b/locales/da-DK.po @@ -207,6 +207,10 @@ msgstr "Tilføj række efter" msgid "Add Row Before" msgstr "Tilføj række før" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albansk" @@ -340,6 +348,10 @@ msgstr "Studieområde" msgid "Artificial Intelligence" msgstr "Kunstig intelligens" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Billedformat" @@ -534,6 +546,10 @@ msgstr "Kinesisk (traditionelt)" msgid "Circle" msgstr "Cirkel" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Ryd markering" @@ -945,6 +961,10 @@ msgstr "Duplikerer dit CV..." msgid "Dutch" msgstr "Hollandsk" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Uddannelse" @@ -1896,6 +1916,10 @@ msgstr "Kan du huske din adgangskode? <0><1>Log ind nu <2/>" msgid "Remove Password" msgstr "Fjern adgangskode" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Fjerner adgangskodebeskyttelse..." @@ -2357,6 +2381,10 @@ msgstr "Indtast derefter den 6-cifrede kode, som appen giver, for at fortsætte. msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Der opstod et problem under generering af PDF'en, prøv igen om lidt." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Opdater CV" msgid "Update your password" msgstr "Opdater din adgangskode" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Opdaterer din adgangskode..." diff --git a/locales/de-DE.po b/locales/de-DE.po index 5c9cd5a62..dc42f18ef 100644 --- a/locales/de-DE.po +++ b/locales/de-DE.po @@ -207,6 +207,10 @@ msgstr "Zeile danach einfügen" msgid "Add Row Before" msgstr "Zeile davor einfügen" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "KI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanisch" @@ -340,6 +348,10 @@ msgstr "Studienfach" msgid "Artificial Intelligence" msgstr "Künstliche Intelligenz" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Seitenverhältnis" @@ -534,6 +546,10 @@ msgstr "Chinesisch (traditionell)" msgid "Circle" msgstr "Kreis" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Auswahl löschen" @@ -945,6 +961,10 @@ msgstr "Ihr Lebenslauf wird dupliziert..." msgid "Dutch" msgstr "Niederländisch" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Ausbildung" @@ -1896,6 +1916,10 @@ msgstr "Sie erinnern sich wieder an Ihr Passwort? <0><1>Jetzt anmelden <2/>< msgid "Remove Password" msgstr "Passwort entfernen" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Passwortschutz wird entfernt..." @@ -2357,6 +2381,10 @@ msgstr "Geben Sie dann den 6-stelligen Code ein, den die App bereitstellt, um fo msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Beim Erzeugen des PDFs ist ein Problem aufgetreten, bitte versuche es in einiger Zeit erneut." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Lebenslauf aktualisieren" msgid "Update your password" msgstr "Aktualisieren Sie Ihr Passwort" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Ihr Passwort wird aktualisiert..." diff --git a/locales/el-GR.po b/locales/el-GR.po index 39796e983..1df30f429 100644 --- a/locales/el-GR.po +++ b/locales/el-GR.po @@ -207,6 +207,10 @@ msgstr "Προσθήκη γραμμής μετά" msgid "Add Row Before" msgstr "Προσθήκη γραμμής πριν" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Αφρικάανς" msgid "AI" msgstr "ΤΝ" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Αλβανικά" @@ -340,6 +348,10 @@ msgstr "Τομέας σπουδών" msgid "Artificial Intelligence" msgstr "Τεχνητή Νοημοσύνη" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Αναλογία διαστάσεων" @@ -534,6 +546,10 @@ msgstr "Κινέζικα (Παραδοσιακά)" msgid "Circle" msgstr "Κύκλος" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Απαλοιφή επιλογής" @@ -945,6 +961,10 @@ msgstr "Δημιουργία αντιγράφου του βιογραφικού msgid "Dutch" msgstr "Ολλανδικά" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Εκπαίδευση" @@ -1896,6 +1916,10 @@ msgstr "Θυμάστε τον κωδικό πρόσβασής σας; <0><1>Συ msgid "Remove Password" msgstr "Κατάργηση κωδικού πρόσβασης" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Κατάργηση προστασίας με κωδικό πρόσβασης..." @@ -2357,6 +2381,10 @@ msgstr "Στη συνέχεια, εισαγάγετε τον 6ψήφιο κωδ msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Παρουσιάστηκε πρόβλημα κατά τη δημιουργία του PDF, δοκιμάστε ξανά σε λίγο." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Ενημέρωση βιογραφικού σημειώματος" msgid "Update your password" msgstr "Ενημερώστε τον κωδικό πρόσβασής σας" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Ενημέρωση του κωδικού πρόσβασής σας..." diff --git a/locales/en-US.po b/locales/en-US.po index 6d1623c45..41e782184 100644 --- a/locales/en-US.po +++ b/locales/en-US.po @@ -202,6 +202,10 @@ msgstr "Add Row After" msgid "Add Row Before" msgstr "Add Row Before" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "Added" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -220,6 +224,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "AI Chat" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanian" @@ -335,6 +343,10 @@ msgstr "Area of Study" msgid "Artificial Intelligence" msgstr "Artificial Intelligence" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "Ask me to update your resume..." + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Aspect Ratio" @@ -529,6 +541,10 @@ msgstr "Chinese (Traditional)" msgid "Circle" msgstr "Circle" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "Clear chat history" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Clear selection" @@ -940,6 +956,10 @@ msgstr "Duplicating your resume..." msgid "Dutch" msgstr "Dutch" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "e.g. Change my name to..." + #: src/utils/resume/section.tsx msgid "Education" msgstr "Education" @@ -1891,6 +1911,10 @@ msgstr "Remember your password? <0><1>Sign in now <2/>" msgid "Remove Password" msgstr "Remove Password" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "Removed" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Removing password protection..." @@ -2352,6 +2376,10 @@ msgstr "Then, enter the 6 digit code that the app provides to continue." msgid "There was a problem while generating the PDF, please try again in some time." msgstr "There was a problem while generating the PDF, please try again in some time." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "Thinking..." + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2615,6 +2643,10 @@ msgstr "Update Resume" msgid "Update your password" msgstr "Update your password" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "Updated" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Updating your password..." diff --git a/locales/es-ES.po b/locales/es-ES.po index 6f74e0681..af7b5cc9a 100644 --- a/locales/es-ES.po +++ b/locales/es-ES.po @@ -207,6 +207,10 @@ msgstr "Añadir fila después" msgid "Add Row Before" msgstr "Añadir fila antes" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikáans" msgid "AI" msgstr "IA" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanés" @@ -340,6 +348,10 @@ msgstr "Área de estudio" msgid "Artificial Intelligence" msgstr "Inteligencia artificial" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Relación de aspecto" @@ -534,6 +546,10 @@ msgstr "Chino (tradicional)" msgid "Circle" msgstr "Círculo" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Borrar selección" @@ -945,6 +961,10 @@ msgstr "Duplicando tu currículum..." msgid "Dutch" msgstr "Neerlandés" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Formación académica" @@ -1896,6 +1916,10 @@ msgstr "¿Recuerdas tu contraseña? <0><1>Inicia sesión ahora <2/>" msgid "Remove Password" msgstr "Quitar contraseña" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Quitando la protección con contraseña..." @@ -2357,6 +2381,10 @@ msgstr "Luego, introduce el código de 6 dígitos que te proporciona la aplicaci msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Ha habido un problema al generar el PDF, inténtalo de nuevo dentro de un rato." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Actualizar currículum" msgid "Update your password" msgstr "Actualiza tu contraseña" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Actualizando tu contraseña..." diff --git a/locales/fa-IR.po b/locales/fa-IR.po index 79b200d8c..a07aa99d9 100644 --- a/locales/fa-IR.po +++ b/locales/fa-IR.po @@ -207,6 +207,10 @@ msgstr "افزودن ردیف بعد از این" msgid "Add Row Before" msgstr "افزودن ردیف قبل از این" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "آفریکانس" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "آلبانیایی" @@ -340,6 +348,10 @@ msgstr "حوزهٔ تحصیل" msgid "Artificial Intelligence" msgstr "هوش مصنوعی" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "نسبت تصویر" @@ -534,6 +546,10 @@ msgstr "چینی (سنتی)" msgid "Circle" msgstr "دایره" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "پاک کردن انتخاب" @@ -945,6 +961,10 @@ msgstr "در حال تکثیر رزومه شما..." msgid "Dutch" msgstr "هلندی" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "تحصیلات" @@ -1896,6 +1916,10 @@ msgstr "گذرواژه‌تان را به یاد آوردید؟ <0><1>همین msgid "Remove Password" msgstr "حذف گذرواژه" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "در حال حذف حفاظت با گذرواژه..." @@ -2357,6 +2381,10 @@ msgstr "سپس، کد ۶ رقمی که اپ در اختیار شما می‌گذ msgid "There was a problem while generating the PDF, please try again in some time." msgstr "هنگام تولید PDF مشکلی پیش آمد، لطفاً بعداً دوباره تلاش کنید." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "به‌روزرسانی رزومه" msgid "Update your password" msgstr "گذرواژهٔ خود را به‌روزرسانی کنید" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "در حال به‌روزرسانی گذرواژه شما..." diff --git a/locales/fi-FI.po b/locales/fi-FI.po index e17f04731..4e5eee968 100644 --- a/locales/fi-FI.po +++ b/locales/fi-FI.po @@ -207,6 +207,10 @@ msgstr "Lisää rivi jälkeen" msgid "Add Row Before" msgstr "Lisää rivi ennen" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "afrikaans" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "albania" @@ -340,6 +348,10 @@ msgstr "Opintoala" msgid "Artificial Intelligence" msgstr "Tekoäly" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Kuvasuhde" @@ -534,6 +546,10 @@ msgstr "kiina (perinteinen)" msgid "Circle" msgstr "Ympyrä" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Tyhjennä valinta" @@ -945,6 +961,10 @@ msgstr "Monistetaan ansioluetteloasi..." msgid "Dutch" msgstr "hollanti" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Koulutus" @@ -1896,6 +1916,10 @@ msgstr "Muistatko salasanasi? <0><1>Kirjaudu sisään nyt <2/>" msgid "Remove Password" msgstr "Poista salasana" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Poistetaan salasanasuojausta..." @@ -2357,6 +2381,10 @@ msgstr "Syötä sitten sovelluksen antama kuusinumeroinen koodi jatkaaksesi." msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF:n luonnissa ilmeni ongelma, yritä hetken kuluttua uudelleen." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Päivitä ansioluettelo" msgid "Update your password" msgstr "Päivitä salasanasi" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Päivitetään salasanaasi..." diff --git a/locales/fr-FR.po b/locales/fr-FR.po index af4d6e52f..7ae62235d 100644 --- a/locales/fr-FR.po +++ b/locales/fr-FR.po @@ -207,6 +207,10 @@ msgstr "Ajouter une ligne après" msgid "Add Row Before" msgstr "Ajouter une ligne avant" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "IA" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanais" @@ -340,6 +348,10 @@ msgstr "Domaine d'étude" msgid "Artificial Intelligence" msgstr "Intelligence artificielle" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Format d'image" @@ -534,6 +546,10 @@ msgstr "Chinois (traditionnel)" msgid "Circle" msgstr "Cercle" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Effacer la sélection" @@ -945,6 +961,10 @@ msgstr "Duplication de votre CV..." msgid "Dutch" msgstr "Néerlandais" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Formation" @@ -1896,6 +1916,10 @@ msgstr "Vous vous souvenez de votre mot de passe ? <0><1>Connectez-vous maintena msgid "Remove Password" msgstr "Supprimer le mot de passe" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Suppression de la protection par mot de passe..." @@ -2357,6 +2381,10 @@ msgstr "Ensuite, entrez le code à 6 chiffres fourni par l'application pour cont msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Un problème est survenu lors de la génération du PDF, veuillez réessayer dans quelque temps." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Modifier le CV" msgid "Update your password" msgstr "Modifier votre mot de passe" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Mise à jour de votre mot de passe..." diff --git a/locales/he-IL.po b/locales/he-IL.po index e5996d5da..2cc253b25 100644 --- a/locales/he-IL.po +++ b/locales/he-IL.po @@ -207,6 +207,10 @@ msgstr "הוספת שורה אחרי" msgid "Add Row Before" msgstr "הוספת שורה לפני" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "אפריקאנס" msgid "AI" msgstr "בינה מלאכותית" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "אלבנית" @@ -340,6 +348,10 @@ msgstr "תחום לימודים" msgid "Artificial Intelligence" msgstr "בינה מלאכותית" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "יחס גובה־רוחב" @@ -534,6 +546,10 @@ msgstr "סינית (מסורתית)" msgid "Circle" msgstr "עיגול" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "ניקוי הבחירה" @@ -945,6 +961,10 @@ msgstr "משכפל את קורות החיים שלך..." msgid "Dutch" msgstr "הולנדית" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "השכלה" @@ -1896,6 +1916,10 @@ msgstr "נזכרת בסיסמה? <0><1>התחברות עכשיו <2/>" msgid "Remove Password" msgstr "הסרת סיסמה" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "מסיר את ההגנה באמצעות סיסמה..." @@ -2357,6 +2381,10 @@ msgstr "לאחר מכן, הזן את הקוד בן 6 הספרות שהאפליק msgid "There was a problem while generating the PDF, please try again in some time." msgstr "אירעה בעיה בעת יצירת קובץ ה־PDF, נא לנסות שוב מאוחר יותר." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "עדכון קורות חיים" msgid "Update your password" msgstr "עדכון הסיסמה שלך" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "מעדכן את הסיסמה שלך..." diff --git a/locales/hi-IN.po b/locales/hi-IN.po index ec3bbfa92..7f741c80b 100644 --- a/locales/hi-IN.po +++ b/locales/hi-IN.po @@ -207,6 +207,10 @@ msgstr "इसके बाद पंक्ति जोड़ें" msgid "Add Row Before" msgstr "इसके पहले पंक्ति जोड़ें" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "अफ्रीकान्स" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "अल्बानियाई" @@ -340,6 +348,10 @@ msgstr "अध्ययन का क्षेत्र" msgid "Artificial Intelligence" msgstr "कृत्रिम बुद्धिमत्ता" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "आकार अनुपात" @@ -534,6 +546,10 @@ msgstr "चीनी (परंपरागत)" msgid "Circle" msgstr "गोला" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "चयन साफ़ करें" @@ -945,6 +961,10 @@ msgstr "आपका रेज़्यूमे डुप्लिकेट क msgid "Dutch" msgstr "डच" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "शिक्षा" @@ -1896,6 +1916,10 @@ msgstr "पासवर्ड याद है? <0><1>अभी साइन इ msgid "Remove Password" msgstr "पासवर्ड हटाएँ" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "पासवर्ड सुरक्षा हटाई जा रही है..." @@ -2357,6 +2381,10 @@ msgstr "फिर, जारी रखने के लिए ऐप द्व msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF जेनरेट करते समय कोई समस्या आई, कृपया कुछ समय बाद फिर से प्रयास करें।" +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "रेज़्यूमे अपडेट करें" msgid "Update your password" msgstr "अपना पासवर्ड अपडेट करें" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "आपका पासवर्ड अपडेट किया जा रहा है..." diff --git a/locales/hu-HU.po b/locales/hu-HU.po index 3bfd56fce..5d571a5be 100644 --- a/locales/hu-HU.po +++ b/locales/hu-HU.po @@ -207,6 +207,10 @@ msgstr "Sor hozzáadása alá" msgid "Add Row Before" msgstr "Sor hozzáadása fölé" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "afrikaans" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "albán" @@ -340,6 +348,10 @@ msgstr "Tanulmányok területe" msgid "Artificial Intelligence" msgstr "Mesterséges intelligencia" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Méretarány" @@ -534,6 +546,10 @@ msgstr "kínai (hagyományos)" msgid "Circle" msgstr "Kör" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Kijelölés törlése" @@ -945,6 +961,10 @@ msgstr "Önéletrajz duplikálása..." msgid "Dutch" msgstr "holland" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Tanulmányok" @@ -1896,6 +1916,10 @@ msgstr "Eszébe jutott a jelszó? <0><1>Jelentkezz be most <2/>" msgid "Remove Password" msgstr "Jelszó eltávolítása" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Jelszóvédelem eltávolítása..." @@ -2357,6 +2381,10 @@ msgstr "Ezután írd be a folytatáshoz az alkalmazás által megadott 6 számje msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Hiba történt a PDF generálása közben, kérjük, próbáld meg később újra." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Önéletrajz frissítése" msgid "Update your password" msgstr "Jelszó frissítése" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Jelszó frissítése..." diff --git a/locales/id-ID.po b/locales/id-ID.po index 831dac437..3f7225901 100644 --- a/locales/id-ID.po +++ b/locales/id-ID.po @@ -207,6 +207,10 @@ msgstr "Tambah Baris Setelah" msgid "Add Row Before" msgstr "Tambah Baris Sebelum" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "Kecerdasan Buatan" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albania" @@ -340,6 +348,10 @@ msgstr "Bidang Studi" msgid "Artificial Intelligence" msgstr "Kecerdasan Buatan" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Rasio Aspek" @@ -534,6 +546,10 @@ msgstr "Cina (Tradisional)" msgid "Circle" msgstr "Lingkaran" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Hapus pilihan" @@ -945,6 +961,10 @@ msgstr "Menduplikasi resume Anda..." msgid "Dutch" msgstr "Belanda" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Pendidikan" @@ -1896,6 +1916,10 @@ msgstr "Ingat kata sandi Anda? <0><1>Masuk sekarang <2/>" msgid "Remove Password" msgstr "Hapus Kata Sandi" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Menghapus perlindungan kata sandi..." @@ -2357,6 +2381,10 @@ msgstr "Lalu, masukkan kode 6 digit yang diberikan aplikasi untuk melanjutkan." msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Terjadi masalah saat membuat PDF, silakan coba lagi nanti." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Perbarui Resume" msgid "Update your password" msgstr "Perbarui kata sandi Anda" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Memperbarui kata sandi Anda..." diff --git a/locales/it-IT.po b/locales/it-IT.po index 532008686..060cfcd25 100644 --- a/locales/it-IT.po +++ b/locales/it-IT.po @@ -207,6 +207,10 @@ msgstr "Aggiungi riga dopo" msgid "Add Row Before" msgstr "Aggiungi riga prima" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "IA" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanese" @@ -340,6 +348,10 @@ msgstr "Area di studio" msgid "Artificial Intelligence" msgstr "Intelligenza artificiale" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Proporzioni" @@ -534,6 +546,10 @@ msgstr "Cinese (tradizionale)" msgid "Circle" msgstr "Cerchio" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Pulisci selezione" @@ -945,6 +961,10 @@ msgstr "Duplicazione del tuo curriculum in corso..." msgid "Dutch" msgstr "Olandese" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Formazione" @@ -1896,6 +1916,10 @@ msgstr "Ti ricordi la password? <0><1>Accedi ora <2/>" msgid "Remove Password" msgstr "Rimuovi password" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Rimozione della protezione tramite password..." @@ -2357,6 +2381,10 @@ msgstr "Quindi inserisci il codice a 6 cifre fornito dall'app per continuare." msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Si è verificato un problema durante la generazione del PDF, riprova tra qualche istante." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Aggiorna curriculum" msgid "Update your password" msgstr "Aggiorna la tua password" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Aggiornamento della tua password in corso..." diff --git a/locales/ja-JP.po b/locales/ja-JP.po index 94b667cde..1fcaf6124 100644 --- a/locales/ja-JP.po +++ b/locales/ja-JP.po @@ -207,6 +207,10 @@ msgstr "後に行を追加" msgid "Add Row Before" msgstr "前に行を追加" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "アフリカーンス語" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "アルバニア語" @@ -340,6 +348,10 @@ msgstr "研究分野" msgid "Artificial Intelligence" msgstr "人工知能" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "アスペクト比" @@ -534,6 +546,10 @@ msgstr "中国語(繁体字)" msgid "Circle" msgstr "円" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "選択をクリア" @@ -945,6 +961,10 @@ msgstr "履歴書を複製しています..." msgid "Dutch" msgstr "オランダ語" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "学歴" @@ -1896,6 +1916,10 @@ msgstr "パスワードを思い出しましたか?<0><1>今すぐサインイ msgid "Remove Password" msgstr "パスワードを削除" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "パスワード保護を解除しています..." @@ -2357,6 +2381,10 @@ msgstr "次に、続行するためにアプリが表示する 6 桁のコード msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF の生成中に問題が発生しました。しばらくしてからもう一度お試しください。" +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "履歴書を更新" msgid "Update your password" msgstr "パスワードを更新してください。" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "パスワードを更新しています..." diff --git a/locales/km-KH.po b/locales/km-KH.po index 0a2818f85..ac0dffe1f 100644 --- a/locales/km-KH.po +++ b/locales/km-KH.po @@ -207,6 +207,10 @@ msgstr "បន្ថែម​ជួរដេក​នៅ​ក្រោយ" msgid "Add Row Before" msgstr "បន្ថែម​ជួរដេក​នៅ​មុខ" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanian" @@ -340,6 +348,10 @@ msgstr "ជំនាញ​រៀន" msgid "Artificial Intelligence" msgstr "បញ្ញាសិប្បនិម្មិត" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "សមាមាត្រទ្រង់ទ្រាយ" @@ -534,6 +546,10 @@ msgstr "Chinese (Traditional)" msgid "Circle" msgstr "រង្វង់" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "សម្អាត​ការ​ជ្រើសរើស" @@ -945,6 +961,10 @@ msgstr "កំពុង​ស្ទួន​ប្រវត្តិរូប​ msgid "Dutch" msgstr "Dutch" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "ការ​សិក្សា" @@ -1896,6 +1916,10 @@ msgstr "ចង់​ចាំ​ពាក្យសម្ងាត់វិញ​ msgid "Remove Password" msgstr "ដក​ពាក្យសម្ងាត់" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "កំពុង​ដក​ការ​ការពារ​ដោយ​ពាក្យសម្ងាត់..." @@ -2357,6 +2381,10 @@ msgstr "បន្ទាប់មក បញ្ចូល​កូដ ៦ ខ្ទ msgid "There was a problem while generating the PDF, please try again in some time." msgstr "មាន​បញ្ហា​មួយ​កើតឡើង ខណៈពេល​កំពុង​បង្កើត PDF សូម​ព្យាយាម​ម្ដង​ទៀត​ក្រោយ​មក។" +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "បច្ចុប្បន្នភាព​ប្រវត្តិរ msgid "Update your password" msgstr "បច្ចុប្បន្នភាព​ពាក្យសម្ងាត់​របស់​អ្នក" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "កំពុង​បច្ចុប្បន្នភាព​ពាក្យសម្ងាត់​របស់​អ្នក..." diff --git a/locales/kn-IN.po b/locales/kn-IN.po index 1e1475525..878bebc7c 100644 --- a/locales/kn-IN.po +++ b/locales/kn-IN.po @@ -207,6 +207,10 @@ msgstr "ಸಾಲನ್ನು ನಂತರ ಸೇರಿಸಿ" msgid "Add Row Before" msgstr "ಸಾಲನ್ನು ಮೊದಲು ಸೇರಿಸಿ" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "ಆಫ್ರಿಕಾನ್ಸ್" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "ಅಲ್ಬೇನಿಯನ್" @@ -340,6 +348,10 @@ msgstr "ಅಧ್ಯಯನದ ಕ್ಷೇತ್ರ" msgid "Artificial Intelligence" msgstr "ಕೃತಕ ಬುದ್ಧಿವಂತಿಕೆ" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "ಆಕಾರ ಅನುಪಾತ" @@ -534,6 +546,10 @@ msgstr "ಚೈನೀಸ್ (ಸಾಂಪ್ರದಾಯಿಕ)" msgid "Circle" msgstr "ವೃತ್ತ" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "ಆಯ್ಕೆಯನ್ನು ತೆರವುಗೊಳಿಸಿ" @@ -945,6 +961,10 @@ msgstr "ನಿಮ್ಮ ರೆಸ್ಯೂಮ್ ನಕಲಿಸಲಾಗುತ msgid "Dutch" msgstr "ಡಚ್" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "ಶಿಕ್ಷಣ" @@ -1896,6 +1916,10 @@ msgstr "ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ನೆನಪಿದೆಯ msgid "Remove Password" msgstr "ಪಾಸ್‌ವರ್ಡ್ ತೆಗೆದುಹಾಕಿ" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "ಪಾಸ್‌ವರ್ಡ್ ರಕ್ಷಣೆಯನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತಿದೆ..." @@ -2357,6 +2381,10 @@ msgstr "ನಂತರ, ಆ್ಯಪ್ ನೀಡುವ 6 ಅಂಕಿಯ ಕೋ msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF ರಚಿಸುವಾಗ ಒಂದು ಸಮಸ್ಯೆ ಉಂಟಾಯಿತು, ದಯವಿಟ್ಟು ಸ್ವಲ್ಪ ಸಮಯದ ಬಳಿಕ ಮರುಪ್ರಯತ್ನಿಸಿ." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "ರೆಸ್ಯೂಮ್ ನವೀಕರಿಸಿ" msgid "Update your password" msgstr "ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನವೀಕರಿಸಿ" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನವೀಕರಿಸಲಾಗುತ್ತಿದೆ..." diff --git a/locales/ko-KR.po b/locales/ko-KR.po index f11151b20..80f32d8bc 100644 --- a/locales/ko-KR.po +++ b/locales/ko-KR.po @@ -207,6 +207,10 @@ msgstr "뒤에 행 추가" msgid "Add Row Before" msgstr "앞에 행 추가" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "아프리칸스어" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "알바니아어" @@ -340,6 +348,10 @@ msgstr "연구 분야" msgid "Artificial Intelligence" msgstr "인공지능" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "가로세로 비율" @@ -534,6 +546,10 @@ msgstr "중국어(번체)" msgid "Circle" msgstr "원" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "선택 해제" @@ -945,6 +961,10 @@ msgstr "이력서를 복제하는 중입니다..." msgid "Dutch" msgstr "네덜란드어" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "학력" @@ -1896,6 +1916,10 @@ msgstr "비밀번호가 기억나시나요? <0><1>지금 로그인하기 <2/><1>Prisijunkite dabar <2/>" msgid "Remove Password" msgstr "Pašalinti slaptažodį" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Šalinama apsauga slaptažodžiu..." @@ -2357,6 +2381,10 @@ msgstr "Tada įveskite programos sugeneruotą 6 skaitmenų kodą, kad tęstumėt msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Kilo problema generuojant PDF. Bandykite dar kartą po kurio laiko." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Atnaujinti gyvenimo aprašymą" msgid "Update your password" msgstr "Atnaujinkite savo slaptažodį" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Atnaujinamas jūsų slaptažodis..." diff --git a/locales/lv-LV.po b/locales/lv-LV.po index e16c430d0..9a6a69c02 100644 --- a/locales/lv-LV.po +++ b/locales/lv-LV.po @@ -207,6 +207,10 @@ msgstr "Pievienot rindu pēc" msgid "Add Row Before" msgstr "Pievienot rindu pirms" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikandu" msgid "AI" msgstr "MI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albāņu" @@ -340,6 +348,10 @@ msgstr "Studiju joma" msgid "Artificial Intelligence" msgstr "Mākslīgais intelekts" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Proporcijas" @@ -534,6 +546,10 @@ msgstr "Ķīniešu (tradicionālā)" msgid "Circle" msgstr "Aplis" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Notīrīt izvēli" @@ -945,6 +961,10 @@ msgstr "Tiek dublēts jūsu CV..." msgid "Dutch" msgstr "Holandiešu" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Izglītība" @@ -1896,6 +1916,10 @@ msgstr "Atceraties savu paroli? <0><1>Piesakieties tagad <2/>" msgid "Remove Password" msgstr "Noņemt paroli" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Tiek noņemta paroles aizsardzība..." @@ -2357,6 +2381,10 @@ msgstr "Pēc tam ievadiet 6 ciparu kodu, ko nodrošina lietotne, lai turpinātu. msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Radās problēma, ģenerējot PDF, lūdzu, mēģiniet vēlreiz pēc kāda laika." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Atjaunināt CV" msgid "Update your password" msgstr "Atjauniniet savu paroli" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Tiek atjaunināta jūsu parole..." diff --git a/locales/ml-IN.po b/locales/ml-IN.po index 30622c0c9..474b3f218 100644 --- a/locales/ml-IN.po +++ b/locales/ml-IN.po @@ -207,6 +207,10 @@ msgstr "വരി പിന്നീട് ചേർക്കുക" msgid "Add Row Before" msgstr "വരി മുമ്പ് ചേർക്കുക" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "ആഫ്രിക്കാൻസ്" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "അൽബേനിയൻ" @@ -340,6 +348,10 @@ msgstr "പഠന മേഖല" msgid "Artificial Intelligence" msgstr "ആർട്ടിഫിഷ്യൽ ഇന്റലിജൻസ്" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "ആസ്പെക്ട് റേഷ്യോ" @@ -534,6 +546,10 @@ msgstr "ചൈനീസ് (ട്രഡീഷണൽ)" msgid "Circle" msgstr "വൃത്തം" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "തിരഞ്ഞെടുപ്പ് ക്ലിയർ ചെയ്യുക" @@ -945,6 +961,10 @@ msgstr "നിങ്ങളുടെ റിസ്യൂം ഡൂപ്ലിക msgid "Dutch" msgstr "ഡച്ച്" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "വിദ്യാഭ്യാസം" @@ -1896,6 +1916,10 @@ msgstr "നിങ്ങളുടെ പാസ്‌വേഡ് ഓർമ്മ msgid "Remove Password" msgstr "പാസ്‌വേഡ് നീക്കുക" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "പാസ്‌വേഡ് സംരക്ഷണം നീക്കം ചെയ്യുന്നു..." @@ -2357,6 +2381,10 @@ msgstr "ശേഷം, ആപ്പ് നൽകുന്ന 6 അക്ക ക msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF നിർമ്മിക്കുന്നതിനിടെ ഒരു പ്രശ്നം ഉണ്ടായി, ദയവായി കുറച്ചുസമയം കഴിഞ്ഞ് വീണ്ടും ശ്രമിക്കുക." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "റിസ്യൂം അപ്‌ഡേറ്റ് ചെയ്യു msgid "Update your password" msgstr "നിങ്ങളുടെ പാസ്‌വേഡ് അപ്‌ഡേറ്റ് ചെയ്യുക" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "നിങ്ങളുടെ പാസ്‌വേഡ് അപ്‌ഡേറ്റ് ചെയ്യുന്നു..." diff --git a/locales/mr-IN.po b/locales/mr-IN.po index 6a1a1aaf2..93640b655 100644 --- a/locales/mr-IN.po +++ b/locales/mr-IN.po @@ -207,6 +207,10 @@ msgstr "नंतर ओळ जोडा" msgid "Add Row Before" msgstr "आधी ओळ जोडा" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "आफ्रिकान्स" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "अल्बेनियन" @@ -340,6 +348,10 @@ msgstr "अभ्यासाचे क्षेत्र" msgid "Artificial Intelligence" msgstr "कृत्रिम बुद्धिमत्ता" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "प्रसर गुणोत्तर" @@ -534,6 +546,10 @@ msgstr "चीनी (परंपरागत)" msgid "Circle" msgstr "गोलाकार" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "निवड साफ करा" @@ -945,6 +961,10 @@ msgstr "तुमचा रेझ्युमे डुप्लिकेट क msgid "Dutch" msgstr "डच" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "शिक्षण" @@ -1896,6 +1916,10 @@ msgstr "पासवर्ड आठवला? <0><1>आता साइन इ msgid "Remove Password" msgstr "पासवर्ड काढा" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "पासवर्ड संरक्षण काढून टाकले जात आहे..." @@ -2357,6 +2381,10 @@ msgstr "त्यानंतर, पुढे जाण्यासाठी msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF तयार करताना समस्या आली, कृपया थोड्या वेळाने पुन्हा प्रयत्न करा." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "रेझ्युमे अपडेट करा" msgid "Update your password" msgstr "तुमचा पासवर्ड अपडेट करा" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "तुमचा पासवर्ड अपडेट केला जात आहे..." diff --git a/locales/ms-MY.po b/locales/ms-MY.po index 60316834b..1666a719f 100644 --- a/locales/ms-MY.po +++ b/locales/ms-MY.po @@ -207,6 +207,10 @@ msgstr "Tambah Baris Selepas" msgid "Add Row Before" msgstr "Tambah Baris Sebelum" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanian" @@ -340,6 +348,10 @@ msgstr "Bidang Pengajian" msgid "Artificial Intelligence" msgstr "Kecerdasan Buatan" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Nisbah Aspek" @@ -534,6 +546,10 @@ msgstr "Cina (Tradisional)" msgid "Circle" msgstr "Bulatan" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Kosongkan pilihan" @@ -945,6 +961,10 @@ msgstr "Menduplikasi resume anda..." msgid "Dutch" msgstr "Belanda" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Pendidikan" @@ -1896,6 +1916,10 @@ msgstr "Masih ingat kata laluan anda? <0><1>Log masuk sekarang <2/>" msgid "Remove Password" msgstr "Buang Kata Laluan" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Membuang perlindungan kata laluan..." @@ -2357,6 +2381,10 @@ msgstr "Kemudian, masukkan kod 6 digit yang diberikan oleh apl untuk meneruskan. msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Terdapat masalah semasa menjana PDF, sila cuba lagi selepas beberapa ketika." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Kemas Kini Resume" msgid "Update your password" msgstr "Kemas kini kata laluan anda" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Mengemas kini kata laluan anda..." diff --git a/locales/ne-NP.po b/locales/ne-NP.po index de2c61300..204e7043c 100644 --- a/locales/ne-NP.po +++ b/locales/ne-NP.po @@ -207,6 +207,10 @@ msgstr "पछि पङ्क्ति थप्नुहोस्" msgid "Add Row Before" msgstr "अघिल्लो पङ्क्ति थप्नुहोस्" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "अफ्रिकान्स" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "अल्बानियन" @@ -340,6 +348,10 @@ msgstr "अध्ययन क्षेत्र" msgid "Artificial Intelligence" msgstr "कृत्रिम बौद्धिकता" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "आकार अनुपात (Aspect Ratio)" @@ -534,6 +546,10 @@ msgstr "चिनियाँ (परम्परागत)" msgid "Circle" msgstr "वृत्त" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "चयन खाली गर्नुहोस्" @@ -945,6 +961,10 @@ msgstr "तपाईंको बायोडाटा नक्कल हुँ msgid "Dutch" msgstr "डच" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "शिक्षा" @@ -1896,6 +1916,10 @@ msgstr "पासवर्ड सम्झनुभयो? <0><1>अहिले msgid "Remove Password" msgstr "पासवर्ड हटाउनुहोस्" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "पासवर्ड सुरक्षा हटाइँदैछ..." @@ -2357,6 +2381,10 @@ msgstr "त्यसपछि, जारी राख्न एपले दि msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF बनाउने क्रममा समस्या आयो, कृपया केही समयपछि पुनः प्रयास गर्नुहोस्।" +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "बायोडाटा अद्यावधिक गर्नुह msgid "Update your password" msgstr "तपाईंको पासवर्ड अद्यावधिक गर्नुहोस्" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "तपाईंको पासवर्ड अद्यावधिक हुँदैछ..." diff --git a/locales/nl-NL.po b/locales/nl-NL.po index bcdb776ed..043e5a0b6 100644 --- a/locales/nl-NL.po +++ b/locales/nl-NL.po @@ -207,6 +207,10 @@ msgstr "Rij erna toevoegen" msgid "Add Row Before" msgstr "Rij ervoor toevoegen" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanees" @@ -340,6 +348,10 @@ msgstr "Studierichting" msgid "Artificial Intelligence" msgstr "Kunstmatige intelligentie" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Beeldverhouding" @@ -534,6 +546,10 @@ msgstr "Chinees (traditioneel)" msgid "Circle" msgstr "Cirkel" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Selectie wissen" @@ -945,6 +961,10 @@ msgstr "Uw cv wordt gedupliceerd..." msgid "Dutch" msgstr "Nederlands" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Opleiding" @@ -1896,6 +1916,10 @@ msgstr "Herinnert u zich uw wachtwoord? <0><1>Meld u nu aan <2/>" msgid "Remove Password" msgstr "Wachtwoord verwijderen" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Wachtwoordbeveiliging wordt verwijderd..." @@ -2357,6 +2381,10 @@ msgstr "Voer vervolgens de 6-cijferige code in die de app geeft om door te gaan. msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Er is een probleem opgetreden bij het genereren van de PDF, probeer het over enige tijd opnieuw." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Cv bijwerken" msgid "Update your password" msgstr "Werk uw wachtwoord bij" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Uw wachtwoord wordt bijgewerkt..." diff --git a/locales/no-NO.po b/locales/no-NO.po index 53daf3088..345f27230 100644 --- a/locales/no-NO.po +++ b/locales/no-NO.po @@ -207,6 +207,10 @@ msgstr "Legg til rad etter" msgid "Add Row Before" msgstr "Legg til rad før" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "KI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albansk" @@ -340,6 +348,10 @@ msgstr "Studiefelt" msgid "Artificial Intelligence" msgstr "Kunstig intelligens" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Størrelsesforhold" @@ -534,6 +546,10 @@ msgstr "Kinesisk (tradisjonell)" msgid "Circle" msgstr "Sirkel" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Fjern valg" @@ -945,6 +961,10 @@ msgstr "Dupliserer CV-en din..." msgid "Dutch" msgstr "Nederlandsk" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Utdanning" @@ -1896,6 +1916,10 @@ msgstr "Husker du passordet ditt? <0><1>Logg inn nå <2/>" msgid "Remove Password" msgstr "Fjern passord" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Fjerner passordbeskyttelse..." @@ -2357,6 +2381,10 @@ msgstr "Skriv deretter inn den 6-sifrede koden som appen gir deg for å fortsett msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Det oppstod et problem under generering av PDF-en, prøv igjen om en stund." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Oppdater CV" msgid "Update your password" msgstr "Oppdater passordet ditt" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Oppdaterer passordet ditt..." diff --git a/locales/or-IN.po b/locales/or-IN.po index ac24bf1c2..2cb45ee04 100644 --- a/locales/or-IN.po +++ b/locales/or-IN.po @@ -207,6 +207,10 @@ msgstr "ପରେ ପଙ୍କ୍ତି ଯୋଡନ୍ତୁ" msgid "Add Row Before" msgstr "ପୂର୍ବେ ପଙ୍କ୍ତି ଯୋଡନ୍ତୁ" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "ଆଫ୍ରିକାନ୍ସ" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "ଆଲବାନିଆନ୍" @@ -340,6 +348,10 @@ msgstr "ଅଧ୍ୟୟନ କ୍ଷେତ୍ର" msgid "Artificial Intelligence" msgstr "କୃତ୍ରିମ ବୁଦ୍ଧିମତ୍ତା" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "ଆସ୍ପେକ୍ଟ ଅନୁପାତ" @@ -534,6 +546,10 @@ msgstr "ଚାଇନିଜ୍ (ପାରମ୍ପରିକ)" msgid "Circle" msgstr "ବୃତ୍ତ" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "ଚୟନ ସଫା କରନ୍ତୁ" @@ -945,6 +961,10 @@ msgstr "ଆପଣଙ୍କ ରେଜ୍ୟୁମେ ନକଲ ହେଉଛି... msgid "Dutch" msgstr "ଡଚ୍" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "ଶିକ୍ଷା" @@ -1896,6 +1916,10 @@ msgstr "ପାସୱାର୍ଡ ମନେ ପକାଇଲେ କି? <0><1>ଏ msgid "Remove Password" msgstr "ପାସୱାର୍ଡ ଅପସାରଣ କରନ୍ତୁ" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "ପାସୱାର୍ଡ ସୁରକ୍ଷା ଅପସାରଣ ହେଉଛି..." @@ -2357,6 +2381,10 @@ msgstr "ତାପରେ, ଆଗକୁ ବଢ଼ିବା ପାଇଁ ଆପ୍ msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF ସୃଷ୍ଟି କରୁଥିବା ସମୟରେ ସମସ୍ୟା ହୋଇଛି, ଦୟାକରି କିଛି ସମୟ ପରେ ପୁନଃ ଚେଷ୍ଟା କରନ୍ତୁ।" +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "ରେଜ୍ୟୁମେ ଅଦ୍ୟତନ କରନ୍ତୁ" msgid "Update your password" msgstr "ଆପଣଙ୍କ ପାସୱାର୍ଡ ଅଦ୍ୟତନ କରନ୍ତୁ" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "ଆପଣଙ୍କ ପାସୱାର୍ଡ ଅଦ୍ୟତନ ହେଉଛି..." diff --git a/locales/pl-PL.po b/locales/pl-PL.po index 2a7f45285..aa6cd1b7b 100644 --- a/locales/pl-PL.po +++ b/locales/pl-PL.po @@ -207,6 +207,10 @@ msgstr "Dodaj wiersz po" msgid "Add Row Before" msgstr "Dodaj wiersz przed" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albański" @@ -340,6 +348,10 @@ msgstr "Kierunek studiów" msgid "Artificial Intelligence" msgstr "Sztuczna inteligencja" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Proporcje obrazu" @@ -534,6 +546,10 @@ msgstr "Chiński (tradycyjny)" msgid "Circle" msgstr "Koło" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Wyczyść wybór" @@ -945,6 +961,10 @@ msgstr "Duplikowanie CV..." msgid "Dutch" msgstr "Holenderski" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Wykształcenie" @@ -1896,6 +1916,10 @@ msgstr "Pamiętasz hasło? <0><1>Zaloguj się teraz <2/>" msgid "Remove Password" msgstr "Usuń hasło" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Wyłączanie ochrony hasłem..." @@ -2357,6 +2381,10 @@ msgstr "Następnie wpisz 6-cyfrowy kod podany przez aplikację, aby kontynuować msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Wystąpił problem podczas generowania pliku PDF, spróbuj ponownie za chwilę." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Zaktualizuj CV" msgid "Update your password" msgstr "Zaktualizuj swoje hasło" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Aktualizowanie hasła..." diff --git a/locales/pt-BR.po b/locales/pt-BR.po index 0a3867ec5..0bdbcb753 100644 --- a/locales/pt-BR.po +++ b/locales/pt-BR.po @@ -207,6 +207,10 @@ msgstr "Adicionar linha depois" msgid "Add Row Before" msgstr "Adicionar linha antes" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Africâner" msgid "AI" msgstr "IA" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanês" @@ -340,6 +348,10 @@ msgstr "Área de estudo" msgid "Artificial Intelligence" msgstr "Inteligência Artificial" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Proporção da imagem" @@ -534,6 +546,10 @@ msgstr "Chinês (Tradicional)" msgid "Circle" msgstr "Círculo" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Limpar seleção" @@ -945,6 +961,10 @@ msgstr "Duplicando seu currículo..." msgid "Dutch" msgstr "Holandês" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Formação" @@ -1896,6 +1916,10 @@ msgstr "Lembrou da sua senha? <0><1>Entre agora <2/>" msgid "Remove Password" msgstr "Remover senha" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Removendo proteção por senha..." @@ -2357,6 +2381,10 @@ msgstr "Em seguida, insira o código de 6 dígitos fornecido pelo aplicativo par msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Houve um problema ao gerar o PDF, tente novamente em alguns instantes." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Atualizar currículo" msgid "Update your password" msgstr "Atualize sua senha" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Atualizando sua senha..." diff --git a/locales/pt-PT.po b/locales/pt-PT.po index db1bd6d21..d6d71223e 100644 --- a/locales/pt-PT.po +++ b/locales/pt-PT.po @@ -207,6 +207,10 @@ msgstr "Adicionar linha após" msgid "Add Row Before" msgstr "Adicionar linha antes" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Africâner" msgid "AI" msgstr "IA" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanês" @@ -340,6 +348,10 @@ msgstr "Área de estudo" msgid "Artificial Intelligence" msgstr "Inteligência Artificial" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Proporção" @@ -534,6 +546,10 @@ msgstr "Chinês (tradicional)" msgid "Circle" msgstr "Círculo" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Limpar seleção" @@ -945,6 +961,10 @@ msgstr "A duplicar o seu currículo..." msgid "Dutch" msgstr "Neerlandês" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Formação" @@ -1896,6 +1916,10 @@ msgstr "Lembra-se da sua senha? <0><1>Inicie sessão agora <2/>" msgid "Remove Password" msgstr "Remover senha" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "A remover a proteção por senha..." @@ -2357,6 +2381,10 @@ msgstr "Em seguida, introduza o código de 6 dígitos fornecido pela aplicação msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Houve um problema ao gerar o PDF, tente novamente dentro de algum tempo." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Atualizar currículo" msgid "Update your password" msgstr "Atualize a sua senha" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "A atualizar a sua senha..." diff --git a/locales/ro-RO.po b/locales/ro-RO.po index 6905b02b0..16e06f513 100644 --- a/locales/ro-RO.po +++ b/locales/ro-RO.po @@ -207,6 +207,10 @@ msgstr "Adăugați rând după" msgid "Add Row Before" msgstr "Adăugați rând înainte" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albaneză" @@ -340,6 +348,10 @@ msgstr "Domeniu de studiu" msgid "Artificial Intelligence" msgstr "Inteligență artificială" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Raport de aspect" @@ -534,6 +546,10 @@ msgstr "Chineză (tradițională)" msgid "Circle" msgstr "Cerc" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Ștergeți selecția" @@ -945,6 +961,10 @@ msgstr "Se duplică CV-ul..." msgid "Dutch" msgstr "Olandeză" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Educație" @@ -1896,6 +1916,10 @@ msgstr "Vă amintiți parola? <0><1>Autentificați-vă acum <2/>" msgid "Remove Password" msgstr "Elimină parola" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Se elimină protecția prin parolă..." @@ -2357,6 +2381,10 @@ msgstr "Apoi introduceți codul din 6 cifre oferit de aplicație pentru a contin msgid "There was a problem while generating the PDF, please try again in some time." msgstr "A apărut o problemă la generarea PDF-ului, vă rugăm să încercați din nou peste câteva momente." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Actualizați CV-ul" msgid "Update your password" msgstr "Actualizați-vă parola" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Se actualizează parola..." diff --git a/locales/ru-RU.po b/locales/ru-RU.po index bd4810619..d1e28301b 100644 --- a/locales/ru-RU.po +++ b/locales/ru-RU.po @@ -207,6 +207,10 @@ msgstr "Добавить строку после" msgid "Add Row Before" msgstr "Добавить строку до" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Африкаанс" msgid "AI" msgstr "ИИ" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Албанский" @@ -340,6 +348,10 @@ msgstr "Область обучения" msgid "Artificial Intelligence" msgstr "Искусственный интеллект" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Соотношение сторон" @@ -534,6 +546,10 @@ msgstr "Китайский (традиционный)" msgid "Circle" msgstr "Круг" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Очистить выбор" @@ -945,6 +961,10 @@ msgstr "Дублирование вашего резюме..." msgid "Dutch" msgstr "Нидерландский" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Образование" @@ -1896,6 +1916,10 @@ msgstr "Вспомнили пароль? <0><1>Войдите сейчас <2/>< msgid "Remove Password" msgstr "Удалить пароль" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Отключение защиты паролем..." @@ -2357,6 +2381,10 @@ msgstr "Затем введите шестизначный код, предос msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Возникла проблема при генерации PDF, пожалуйста, попробуйте еще раз через некоторое время." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Обновить резюме" msgid "Update your password" msgstr "Обновите пароль" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Обновление пароля..." diff --git a/locales/sk-SK.po b/locales/sk-SK.po index 0ff1e72ef..276aa61ba 100644 --- a/locales/sk-SK.po +++ b/locales/sk-SK.po @@ -207,6 +207,10 @@ msgstr "Pridať riadok za" msgid "Add Row Before" msgstr "Pridať riadok pred" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikánčina" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albánčina" @@ -340,6 +348,10 @@ msgstr "Študijný odbor" msgid "Artificial Intelligence" msgstr "Umelá inteligencia" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Pomer strán" @@ -534,6 +546,10 @@ msgstr "Čínština (tradičná)" msgid "Circle" msgstr "Kruh" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Zrušiť výber" @@ -945,6 +961,10 @@ msgstr "Duplikujem tvoj životopis..." msgid "Dutch" msgstr "Holandčina" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Vzdelanie" @@ -1896,6 +1916,10 @@ msgstr "Spomínaš si na heslo? <0><1>Prihlás sa teraz <2/>" msgid "Remove Password" msgstr "Odstrániť heslo" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Odstraňujem ochranu heslom..." @@ -2357,6 +2381,10 @@ msgstr "Potom zadaj 6‑ciferný kód, ktorý ti aplikácia vygeneruje, aby si p msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Pri generovaní PDF sa vyskytol problém, skús to prosím znova o chvíľu." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Aktualizovať životopis" msgid "Update your password" msgstr "Aktualizuj svoje heslo" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Aktualizujem tvoje heslo..." diff --git a/locales/sq-AL.po b/locales/sq-AL.po index 8777e501e..cb0df7c5c 100644 --- a/locales/sq-AL.po +++ b/locales/sq-AL.po @@ -207,6 +207,10 @@ msgstr "Shto rresht pas" msgid "Add Row Before" msgstr "Shto rresht para" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikanisht" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Shqip" @@ -340,6 +348,10 @@ msgstr "Fusha e studimit" msgid "Artificial Intelligence" msgstr "Inteligjenca Artificiale" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Proporcioni" @@ -534,6 +546,10 @@ msgstr "Kinezçe (Tradicionale)" msgid "Circle" msgstr "Rreth" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Pastro përzgjedhjen" @@ -945,6 +961,10 @@ msgstr "Po dyfishohet CV-ja juaj..." msgid "Dutch" msgstr "Holandisht" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Arsimimi" @@ -1896,6 +1916,10 @@ msgstr "E kujtuat fjalëkalimin? <0><1>Hyni tani <2/>" msgid "Remove Password" msgstr "Hiq fjalëkalimin" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Po hiqet mbrojtja me fjalëkalim..." @@ -2357,6 +2381,10 @@ msgstr "Më pas, futni kodin 6-shifror që jep aplikacioni për të vazhduar." msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Pati një problem gjatë gjenerimit të PDF-së, ju lutemi provoni përsëri pas pak." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Përditëso CV-në" msgid "Update your password" msgstr "Përditësoni fjalëkalimin tuaj" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Po përditësohet fjalëkalimi juaj..." diff --git a/locales/sr-SP.po b/locales/sr-SP.po index f6f8968fc..b1219d039 100644 --- a/locales/sr-SP.po +++ b/locales/sr-SP.po @@ -207,6 +207,10 @@ msgstr "Додај ред после" msgid "Add Row Before" msgstr "Додај ред пре" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Африканс" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Албански" @@ -340,6 +348,10 @@ msgstr "Област студија" msgid "Artificial Intelligence" msgstr "Вештачка интелигенција" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Однос стране" @@ -534,6 +546,10 @@ msgstr "Кинески (традиционални)" msgid "Circle" msgstr "Круг" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Обриши избор" @@ -945,6 +961,10 @@ msgstr "Дуплирање вашег резимеа..." msgid "Dutch" msgstr "Холандски" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Образовање" @@ -1896,6 +1916,10 @@ msgstr "Сећате се лозинке? <0><1>Пријавите се сада msgid "Remove Password" msgstr "Уклони лозинку" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Уклањање заштите лозинком..." @@ -2357,6 +2381,10 @@ msgstr "Затим унесите шестоцифрени кôд који ап msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Дошло је до проблема током генерисања PDF-а, покушајте поново након неког времена." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Ажурирај резиме" msgid "Update your password" msgstr "Ажурирајте своју лозинку" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Ажурирање ваше лозинке..." diff --git a/locales/sv-SE.po b/locales/sv-SE.po index 0f4e04c33..eeb8146f7 100644 --- a/locales/sv-SE.po +++ b/locales/sv-SE.po @@ -207,6 +207,10 @@ msgstr "Lägg till rad efter" msgid "Add Row Before" msgstr "Lägg till rad före" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikanska" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Albanska" @@ -340,6 +348,10 @@ msgstr "Studieområde" msgid "Artificial Intelligence" msgstr "Artificiell intelligens" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Bildförhållande" @@ -534,6 +546,10 @@ msgstr "Kinesiska (traditionell)" msgid "Circle" msgstr "Cirkel" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Rensa markering" @@ -945,6 +961,10 @@ msgstr "Duplicerar ditt CV..." msgid "Dutch" msgstr "Nederländska" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Utbildning" @@ -1896,6 +1916,10 @@ msgstr "Kommer du ihåg ditt lösenord? <0><1>Logga in nu <2/>" msgid "Remove Password" msgstr "Ta bort lösenord" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Tar bort lösenordsskydd..." @@ -2357,6 +2381,10 @@ msgstr "Ange sedan den sexsiffriga kod som appen ger för att fortsätta." msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Det uppstod ett problem när PDF-filen skulle genereras, försök igen om en stund." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Uppdatera CV" msgid "Update your password" msgstr "Uppdatera ditt lösenord" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Uppdaterar ditt lösenord..." diff --git a/locales/ta-IN.po b/locales/ta-IN.po index b284bb35d..9b8147ed9 100644 --- a/locales/ta-IN.po +++ b/locales/ta-IN.po @@ -207,6 +207,10 @@ msgstr "பின் வரியைச் சேர்க்கவும்" msgid "Add Row Before" msgstr "முன் வரியைச் சேர்க்கவும்" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "ஆஃப்ரிகான்ஸ்" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "அல்பேனியன்" @@ -340,6 +348,10 @@ msgstr "கற்றல் துறை" msgid "Artificial Intelligence" msgstr "செயற்கை நுண்ணறிவு" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "ஒப்புத்திணைவு விகிதம்" @@ -534,6 +546,10 @@ msgstr "சீனம் (சம்பிரதாய)" msgid "Circle" msgstr "வட்டம்" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "தேர்வை அழிக்கவும்" @@ -945,6 +961,10 @@ msgstr "உங்கள் ரெஸ்யூமியின் நகலை உ msgid "Dutch" msgstr "டச்சு" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "கல்வி" @@ -1896,6 +1916,10 @@ msgstr "உங்கள் கடவுச்சொல் நினைவில msgid "Remove Password" msgstr "கடவுச்சொல்லை நீக்கு" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "கடவுச்சொல் பாதுகாப்பை நீக்கிக் கொண்டிருக்கிறது..." @@ -2357,6 +2381,10 @@ msgstr "பின்னர், செயலி வழங்கும் 6 இல msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF உருவாக்கும் போது ஒரு பிரச்சனை ஏற்பட்டது, தயவுசெய்து சில நேரம் கழித்து மீண்டும் முயற்சிக்கவும்." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "ரெஸ்யூமியை புதுப்பிக்கவு msgid "Update your password" msgstr "உங்கள் கடவுச்சொல்லை புதுப்பிக்கவும்" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "உங்கள் கடவுச்சொல்லை புதுப்பித்து கொண்டிருக்கிறது..." diff --git a/locales/te-IN.po b/locales/te-IN.po index 40d23b368..a76a7f882 100644 --- a/locales/te-IN.po +++ b/locales/te-IN.po @@ -207,6 +207,10 @@ msgstr "తరువాత వరుస చేర్చండి" msgid "Add Row Before" msgstr "ముందు వరుస చేర్చండి" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "ఆఫ్రికాన్స్" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "అల్బేనియన్" @@ -340,6 +348,10 @@ msgstr "అధ్యయన విభాగం" msgid "Artificial Intelligence" msgstr "ఆర్టిఫిషియల్ ఇంటెలిజెన్స్" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "కారక నిష్పత్తి" @@ -534,6 +546,10 @@ msgstr "చైనీస్ (సాంప్రదాయ)" msgid "Circle" msgstr "వృత్తం" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "ఎంపికను క్లియర్ చేయండి" @@ -945,6 +961,10 @@ msgstr "మీ రిజ్యూమ్‌ను నకిలీ చేస్త msgid "Dutch" msgstr "డచ్" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "విద్య" @@ -1896,6 +1916,10 @@ msgstr "మీకు పాస్‌వర్డ్ గుర్తుంది? msgid "Remove Password" msgstr "పాస్‌వర్డ్‌ను తీసివేయండి" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "పాస్‌వర్డ్ రక్షణను తీసివేస్తున్నాము..." @@ -2357,6 +2381,10 @@ msgstr "తర్వాత, యాప్ ఇచ్చిన 6 అంకెల msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF రూపొందించడంలో సమస్య ఏర్పడింది, దయచేసి కొద్దిసేపటి తరువాత మళ్లీ ప్రయత్నించండి." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "రిజ్యూమ్‌ను నవీకరించండి" msgid "Update your password" msgstr "మీ పాస్‌వర్డ్‌ను నవీకరించండి" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "మీ పాస్‌వర్డ్‌ను నవీకరిస్తోంది..." diff --git a/locales/th-TH.po b/locales/th-TH.po index 9631fa470..9cfe9203b 100644 --- a/locales/th-TH.po +++ b/locales/th-TH.po @@ -207,6 +207,10 @@ msgstr "เพิ่มแถวหลัง" msgid "Add Row Before" msgstr "เพิ่มแวก่อน" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "อาฟรีกานส์" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "แอลเบเนีย" @@ -340,6 +348,10 @@ msgstr "สาขาวิชา" msgid "Artificial Intelligence" msgstr "ปัญญาประดิษฐ์" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "อัตราส่วนภาพ" @@ -534,6 +546,10 @@ msgstr "จีน (ตัวเต็ม)" msgid "Circle" msgstr "วงกลม" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "ล้างการเลือก" @@ -945,6 +961,10 @@ msgstr "กำลังคัดลอกเรซูเม่ของคุณ msgid "Dutch" msgstr "ดัตช์" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "การศึกษา" @@ -1896,6 +1916,10 @@ msgstr "จำรหัสผ่านของคุณได้หรือไ msgid "Remove Password" msgstr "ลบรหัสผ่าน" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "กำลังลบการป้องกันด้วยรหัสผ่าน..." @@ -2357,6 +2381,10 @@ msgstr "จากนั้น กรอกรหัส 6 หลักที่ msgid "There was a problem while generating the PDF, please try again in some time." msgstr "เกิดปัญหาในการสร้าง PDF โปรดลองใหม่อีกครั้งในภายหลัง" +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "อัปเดตประวัติย่อ" msgid "Update your password" msgstr "อัปเดตรหัสผ่านของคุณ" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "กำลังอัปเดตรหัสผ่านของคุณ..." diff --git a/locales/tr-TR.po b/locales/tr-TR.po index c4a676920..d765340ef 100644 --- a/locales/tr-TR.po +++ b/locales/tr-TR.po @@ -207,6 +207,10 @@ msgstr "Sonra Satır Ekle" msgid "Add Row Before" msgstr "Önce Satır Ekle" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "Yapay Zeka" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Arnavutça" @@ -340,6 +348,10 @@ msgstr "Çalışma alanı" msgid "Artificial Intelligence" msgstr "Yapay Zekâ" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "En/Boy Oranı" @@ -534,6 +546,10 @@ msgstr "Çince (Geleneksel)" msgid "Circle" msgstr "Daire" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Seçimi temizle" @@ -945,6 +961,10 @@ msgstr "Özgeçmişiniz çoğaltılıyor..." msgid "Dutch" msgstr "Felemenkçe" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Eğitim" @@ -1896,6 +1916,10 @@ msgstr "Şifrenizi hatırlıyor musunuz? <0><1>Şimdi giriş yapın <2/> msgid "Remove Password" msgstr "Şifreyi Kaldır" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Şifre koruması kaldırılıyor..." @@ -2357,6 +2381,10 @@ msgstr "Daha sonra, devam etmek için uygulamanın verdiği 6 haneli kodu girin. msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF oluşturulurken bir sorun oluştu, lütfen daha sonra tekrar deneyin." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Özgeçmişi Güncelle" msgid "Update your password" msgstr "Şifrenizi güncelleyin" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Şifreniz güncelleniyor..." diff --git a/locales/uk-UA.po b/locales/uk-UA.po index 7efda387c..6ae368a14 100644 --- a/locales/uk-UA.po +++ b/locales/uk-UA.po @@ -207,6 +207,10 @@ msgstr "Додати Рядок Знизу" msgid "Add Row Before" msgstr "Додати Рядок Згори" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Африканська" msgid "AI" msgstr "ШІ" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Албанська" @@ -340,6 +348,10 @@ msgstr "Освітня програма" msgid "Artificial Intelligence" msgstr "Штучний інтелект" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Пропорції" @@ -534,6 +546,10 @@ msgstr "Китайська (традиційна)" msgid "Circle" msgstr "Кругле" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Очистити вибір" @@ -945,6 +961,10 @@ msgstr "Дублювання резюме..." msgid "Dutch" msgstr "Голландська" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Освіта" @@ -1896,6 +1916,10 @@ msgstr "Пам’ятаєте свій пароль? <0><1>Увійдіть за msgid "Remove Password" msgstr "Видалити пароль" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Видалення захисту паролем..." @@ -2357,6 +2381,10 @@ msgstr "Далі введіть шестизначний код, який над msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Сталася проблема під час створення PDF, будь ласка, спробуйте ще раз пізніше." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Оновити резюме" msgid "Update your password" msgstr "Оновіть свій пароль" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Оновлення пароля..." diff --git a/locales/uz-UZ.po b/locales/uz-UZ.po index e13d1cc43..82378ba1f 100644 --- a/locales/uz-UZ.po +++ b/locales/uz-UZ.po @@ -207,6 +207,10 @@ msgstr "Qatordan keyin qator qo‘shish" msgid "Add Row Before" msgstr "Qatordan oldin qator qo‘shish" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Afrikaans" msgid "AI" msgstr "SO" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Alban tili" @@ -340,6 +348,10 @@ msgstr "Ta'lim sohasi" msgid "Artificial Intelligence" msgstr "Sun'iy intellekt" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Tomonlar nisbati" @@ -534,6 +546,10 @@ msgstr "Xitoy (An’anaviy)" msgid "Circle" msgstr "Doira" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Tanlovni tozalash" @@ -945,6 +961,10 @@ msgstr "Rezyume nusxalanmoqda..." msgid "Dutch" msgstr "Golland tili" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Ta'lim" @@ -1896,6 +1916,10 @@ msgstr "Parolingiz esingizdami? <0><1>Hozir kiring <2/>" msgid "Remove Password" msgstr "Parolni olib tashlash" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Parol himoyasi olib tashlanmoqda..." @@ -2357,6 +2381,10 @@ msgstr "Keyin, davom etish uchun ilova taqdim etgan 6 xonali kodni kiriting." msgid "There was a problem while generating the PDF, please try again in some time." msgstr "PDF yaratishda muammo yuzaga keldi, iltimos, birozdan so'ng qaytadan urinib ko'ring." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Rezyumeni yangilash" msgid "Update your password" msgstr "Parolingizni yangilash" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Parolingiz yangilanmoqda..." diff --git a/locales/vi-VN.po b/locales/vi-VN.po index f51b10bbb..9ee3c1510 100644 --- a/locales/vi-VN.po +++ b/locales/vi-VN.po @@ -207,6 +207,10 @@ msgstr "Thêm dòng sau" msgid "Add Row Before" msgstr "Thêm dòng trước" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "Tiếng Afrikaans" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "Tiếng Albania" @@ -340,6 +348,10 @@ msgstr "Lĩnh vực học tập" msgid "Artificial Intelligence" msgstr "Trí tuệ nhân tạo" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "Tỷ lệ khung hình" @@ -534,6 +546,10 @@ msgstr "Tiếng Trung (Phồn thể)" msgid "Circle" msgstr "Vòng tròn" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "Xóa lựa chọn" @@ -945,6 +961,10 @@ msgstr "Đang tạo bản sao bản lý lịch của bạn..." msgid "Dutch" msgstr "Tiếng Hà Lan" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "Giáo dục" @@ -1896,6 +1916,10 @@ msgstr "Bạn nhớ mật khẩu? <0><1>Đăng nhập ngay <2/>" msgid "Remove Password" msgstr "Xóa mật khẩu" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "Đang xóa bảo vệ mật khẩu..." @@ -2357,6 +2381,10 @@ msgstr "Sau đó, nhập mã 6 chữ số mà ứng dụng cung cấp để ti msgid "There was a problem while generating the PDF, please try again in some time." msgstr "Đã xảy ra sự cố khi tạo PDF, hãy thử lại sau." +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "Cập nhật resume" msgid "Update your password" msgstr "Cập nhật mật khẩu của bạn" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "Đang cập nhật mật khẩu của bạn..." diff --git a/locales/zh-CN.po b/locales/zh-CN.po index 3c973c8b6..316658113 100644 --- a/locales/zh-CN.po +++ b/locales/zh-CN.po @@ -207,6 +207,10 @@ msgstr "在后面添加行" msgid "Add Row Before" msgstr "在前面添加行" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "南非语" msgid "AI" msgstr "AI(人工智能)" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "阿尔巴尼亚语" @@ -340,6 +348,10 @@ msgstr "学习领域" msgid "Artificial Intelligence" msgstr "人工智能" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "宽高比" @@ -534,6 +546,10 @@ msgstr "中文(繁体)" msgid "Circle" msgstr "圆形" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "清除选择" @@ -945,6 +961,10 @@ msgstr "正在复制你的简历…" msgid "Dutch" msgstr "荷兰语" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "教育经历" @@ -1896,6 +1916,10 @@ msgstr "想起你的密码了?<0><1>立即登录 <2/>" msgid "Remove Password" msgstr "移除密码" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "正在移除密码保护…" @@ -2357,6 +2381,10 @@ msgstr "然后,输入应用提供的 6 位验证码以继续。" msgid "There was a problem while generating the PDF, please try again in some time." msgstr "生成 PDF 时出现问题,请稍后重试。" +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "更新简历" msgid "Update your password" msgstr "更新你的密码" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "正在更新你的密码…" diff --git a/locales/zh-TW.po b/locales/zh-TW.po index 71925614b..ba83654a3 100644 --- a/locales/zh-TW.po +++ b/locales/zh-TW.po @@ -207,6 +207,10 @@ msgstr "在後方新增列" msgid "Add Row Before" msgstr "在前方新增列" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -225,6 +229,10 @@ msgstr "南非荷蘭語" msgid "AI" msgstr "AI" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "阿爾巴尼亞語" @@ -340,6 +348,10 @@ msgstr "學習領域" msgid "Artificial Intelligence" msgstr "人工智慧" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "顯示比例" @@ -534,6 +546,10 @@ msgstr "中文(繁體)" msgid "Circle" msgstr "圓形" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "清除選取" @@ -945,6 +961,10 @@ msgstr "正在複製您的履歷…" msgid "Dutch" msgstr "荷蘭語" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "學歷" @@ -1896,6 +1916,10 @@ msgstr "想起密碼了嗎?<0><1>立即登入 <2/>" msgid "Remove Password" msgstr "移除密碼" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "正在移除密碼保護…" @@ -2357,6 +2381,10 @@ msgstr "接著,請輸入應用程式提供的 6 位數驗證碼以繼續。" msgid "There was a problem while generating the PDF, please try again in some time." msgstr "產生 PDF 時發生問題,請稍後再試一次。" +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2620,6 +2648,10 @@ msgstr "更新履歷" msgid "Update your password" msgstr "更新您的密碼" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "正在更新您的密碼…" diff --git a/locales/zu-ZA.po b/locales/zu-ZA.po index 411f6f8e7..3297cdd58 100644 --- a/locales/zu-ZA.po +++ b/locales/zu-ZA.po @@ -202,6 +202,10 @@ msgstr "" msgid "Add Row Before" msgstr "" +#: src/components/ai/chat.tsx +msgid "Added" +msgstr "" + #. placeholder {0}: passkey.createdAt.toLocaleDateString() #: src/routes/dashboard/settings/authentication/-components/passkeys.tsx msgid "Added on {0}" @@ -220,6 +224,10 @@ msgstr "" msgid "AI" msgstr "" +#: src/components/ai/chat.tsx +msgid "AI Chat" +msgstr "" + #: src/utils/locale.ts msgid "Albanian" msgstr "" @@ -335,6 +343,10 @@ msgstr "" msgid "Artificial Intelligence" msgstr "" +#: src/components/ai/chat.tsx +msgid "Ask me to update your resume..." +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/left/sections/picture.tsx msgid "Aspect Ratio" msgstr "" @@ -529,6 +541,10 @@ msgstr "" msgid "Circle" msgstr "" +#: src/components/ai/chat.tsx +msgid "Clear chat history" +msgstr "" + #: src/components/ui/multiple-combobox.tsx msgid "Clear selection" msgstr "" @@ -940,6 +956,10 @@ msgstr "" msgid "Dutch" msgstr "" +#: src/components/ai/chat.tsx +msgid "e.g. Change my name to..." +msgstr "" + #: src/utils/resume/section.tsx msgid "Education" msgstr "" @@ -1891,6 +1911,10 @@ msgstr "" msgid "Remove Password" msgstr "" +#: src/components/ai/chat.tsx +msgid "Removed" +msgstr "" + #: src/routes/builder/$resumeId/-sidebar/right/sections/sharing.tsx msgid "Removing password protection..." msgstr "" @@ -2352,6 +2376,10 @@ msgstr "" msgid "There was a problem while generating the PDF, please try again in some time." msgstr "" +#: src/components/ai/chat.tsx +msgid "Thinking..." +msgstr "" + #: src/routes/builder/$resumeId/-components/header.tsx #: src/routes/dashboard/resumes/-components/menus/context-menu.tsx #: src/routes/dashboard/resumes/-components/menus/dropdown-menu.tsx @@ -2615,6 +2643,10 @@ msgstr "" msgid "Update your password" msgstr "" +#: src/components/ai/chat.tsx +msgid "Updated" +msgstr "" + #: src/dialogs/auth/change-password.tsx msgid "Updating your password..." msgstr "" diff --git a/mcp/index.ts b/mcp/index.ts new file mode 100644 index 000000000..5907fa5e6 --- /dev/null +++ b/mcp/index.ts @@ -0,0 +1,434 @@ +#!/usr/bin/env node + +/** + * Reactive Resume MCP server — single entry point. Run with: + * npx tsx /path/to/reactive-resume/mcp + * + * Env: REACTIVE_RESUME_API_KEY (required), REACTIVE_RESUME_URL (default https://rxresu.me), + * TRANSPORT (stdio | http), PORT (default 3100). + */ + +import * as http from "node:http"; +import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import type { Operation } from "fast-json-patch"; +import { z } from "zod"; +import type { RouterInput, RouterOutput } from "@/integrations/orpc/client"; +import { jsonPatchOperationSchema } from "@/utils/resume/patch"; +import schemaJSON from "../src/schema/schema.json"; + +// --- Env --- +const API_KEY = process.env.REACTIVE_RESUME_API_KEY; +const BASE_URL = (process.env.REACTIVE_RESUME_URL ?? "https://rxresu.me").replace(/\/$/, ""); +const TRANSPORT = process.env.TRANSPORT ?? "stdio"; +const PORT = Number.parseInt(process.env.PORT ?? "3100", 10); + +if (!API_KEY) { + console.error("ERROR: REACTIVE_RESUME_API_KEY is required. Create one in Settings > API Keys."); + process.exit(1); +} + +const apiKey = API_KEY; + +// --- API client --- +async function apiRequest(method: string, path: string, body?: unknown): Promise { + const url = `${BASE_URL}${path}`; + + const res = await fetch(url, { + method, + headers: { + "x-api-key": apiKey, + Accept: "application/json", + "Content-Type": "application/json", + }, + body: body ? JSON.stringify(body) : undefined, + }); + + if (!res.ok) { + const text = await res.text().catch(() => "Unknown error"); + throw new Error(`Reactive Resume API error (${res.status}): ${text}`); + } + + return res.json() as Promise; +} + +async function listResumes(): Promise { + return apiRequest("GET", "/api/openapi/resumes"); +} + +async function getResume(id: string): Promise { + return apiRequest("GET", `/api/openapi/resumes/${encodeURIComponent(id)}`); +} + +async function patchResume(id: string, operations: Operation[]): Promise { + return apiRequest("PATCH", `/api/openapi/resumes/${encodeURIComponent(id)}`, { operations }); +} + +async function createResume(input: RouterInput["resume"]["create"]): Promise { + return apiRequest("POST", "/api/openapi/resumes", input); +} + +async function deleteResume(id: string): Promise { + return apiRequest("DELETE", `/api/openapi/resumes/${encodeURIComponent(id)}`); +} + +async function setResumeLocked(id: string, isLocked: boolean): Promise { + return apiRequest("POST", `/api/openapi/resumes/${encodeURIComponent(id)}/lock`, { isLocked }); +} + +// --- MCP server --- +const server = new McpServer({ name: "reactive-resume-mcp-server", version: "1.0.0" }); + +// Tool: list_resumes +server.registerTool( + "list_resumes", + { + title: "List Resumes", + description: + "List all resumes for the authenticated user. Returns id, name, slug, tags, visibility, lock status, timestamps.", + inputSchema: z.object({}).strict(), + }, + async () => { + try { + const resumes = await listResumes(); + if (resumes.length === 0) + return { + content: [{ type: "text", text: "No resumes found. Use create_resume to create one." }], + }; + const lines = [`# Your Resumes (${resumes.length})`, ""]; + for (const r of resumes) { + const tags = r.tags.length > 0 ? ` [${r.tags.join(", ")}]` : ""; + const flags = [r.isPublic ? "public" : "private", r.isLocked ? "locked" : ""].filter(Boolean).join(", "); + lines.push(`- **${r.name}** (${r.id})${tags}`); + lines.push(` Status: ${flags} | Updated: ${r.updatedAt}`); + } + return { content: [{ type: "text", text: lines.join("\n") }] }; + } catch (error) { + return { + isError: true, + content: [ + { type: "text", text: `Error listing resumes: ${error instanceof Error ? error.message : String(error)}` }, + ], + }; + } + }, +); + +// Tool: get_resume +server.registerTool( + "get_resume", + { + title: "Get Resume", + description: "Get the full data of a specific resume by ID. Use list_resumes to find IDs.", + inputSchema: z.object({ id: z.string().min(1).describe("Resume ID") }).strict(), + }, + async ({ id }: { id: string }) => { + try { + const resume = await getResume(id); + return { content: [{ type: "text", text: JSON.stringify(resume.data, null, 2) }] }; + } catch (error) { + return { + isError: true, + content: [ + { + type: "text", + text: `Error getting resume: ${error instanceof Error ? error.message : String(error)}. Use list_resumes to find valid IDs.`, + }, + ], + }; + } + }, +); + +// Tool: patch_resume +server.registerTool( + "patch_resume", + { + title: "Patch Resume", + description: + "Apply JSON Patch (RFC 6902) operations. Use get_resume first to inspect structure. Paths like /basics/name, /sections/skills/items/-.", + inputSchema: z + .object({ + id: z.string().min(1).describe("Resume ID"), + operations: z.array(jsonPatchOperationSchema).min(1).describe("JSON Patch operations"), + }) + .strict(), + }, + async ({ id, operations }: { id: string; operations: Operation[] }) => { + try { + const resume = await patchResume(id, operations); + const summary = operations.map((op) => `${op.op} ${op.path}`).join(", "); + + return { + content: [{ type: "text", text: `Applied ${operations.length} operation(s) to "${resume.name}": ${summary}` }], + }; + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + let hint = ""; + if (msg.includes("400")) hint = " Use get_resume to check structure and paths."; + if (msg.includes("403")) hint = " Resume is locked. Use unlock_resume first."; + if (msg.includes("404")) hint = " Use list_resumes to find valid IDs."; + return { isError: true, content: [{ type: "text", text: `Error patching resume: ${msg}${hint}` }] }; + } + }, +); + +// Tool: create_resume +server.registerTool( + "create_resume", + { + title: "Create Resume", + description: + "Create a new resume with a name, slug, and optional tags. Set withSampleData to true to pre-fill with example content.", + inputSchema: z + .object({ + name: z.string().min(1).max(64).describe("Name for the new resume"), + slug: z.string().min(1).max(64).describe("URL-friendly slug (must be unique across your resumes)"), + tags: z.array(z.string()).optional().default([]).describe("Optional tags to categorize the resume"), + withSampleData: z.boolean().optional().default(false).describe("If true, pre-fill the resume with sample data"), + }) + .strict(), + }, + async ({ + name, + slug, + tags, + withSampleData, + }: { + name: string; + slug: string; + tags: string[]; + withSampleData: boolean; + }) => { + try { + const id = await createResume({ name, slug, tags, withSampleData }); + + return { + content: [ + { + type: "text", + text: `Created resume "${name}" (${id}) with slug "${slug}".${withSampleData ? " Pre-filled with sample data." : ""} Use get_resume to view or patch_resume to edit it.`, + }, + ], + }; + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + let hint = ""; + if (msg.includes("400")) hint = " The slug may already be in use — try a different one."; + return { isError: true, content: [{ type: "text", text: `Error creating resume: ${msg}${hint}` }] }; + } + }, +); + +// Tool: delete_resume +server.registerTool( + "delete_resume", + { + title: "Delete Resume", + description: + "Permanently delete a resume and its associated files (screenshots, PDFs). Locked resumes cannot be deleted — unlock first. This action is irreversible.", + inputSchema: z + .object({ + id: z.string().min(1).describe("Resume ID to delete. Use list_resumes to find IDs."), + }) + .strict(), + }, + async ({ id }: { id: string }) => { + try { + await deleteResume(id); + + return { content: [{ type: "text", text: `Successfully deleted resume (${id}) and its associated files.` }] }; + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + let hint = ""; + if (msg.includes("403")) hint = " The resume may be locked. Use unlock_resume first."; + if (msg.includes("404")) hint = " Use list_resumes to find valid IDs."; + return { isError: true, content: [{ type: "text", text: `Error deleting resume: ${msg}${hint}` }] }; + } + }, +); + +// Tool: lock_resume +server.registerTool( + "lock_resume", + { + title: "Lock Resume", + description: + "Lock a resume to prevent edits, patches, or deletion. Useful for protecting finalized resumes from accidental changes.", + inputSchema: z + .object({ + id: z.string().min(1).describe("Resume ID to lock. Use list_resumes to find IDs."), + }) + .strict(), + }, + async ({ id }: { id: string }) => { + try { + await setResumeLocked(id, true); + + return { + content: [ + { + type: "text", + text: `Resume (${id}) is now locked. It cannot be edited, patched, or deleted until unlocked.`, + }, + ], + }; + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + let hint = ""; + if (msg.includes("404")) hint = " Use list_resumes to find valid IDs."; + return { isError: true, content: [{ type: "text", text: `Error locking resume: ${msg}${hint}` }] }; + } + }, +); + +// Tool: unlock_resume +server.registerTool( + "unlock_resume", + { + title: "Unlock Resume", + description: "Unlock a previously locked resume, allowing edits, patches, and deletion again.", + inputSchema: z + .object({ + id: z.string().min(1).describe("Resume ID to unlock. Use list_resumes to find IDs."), + }) + .strict(), + }, + async ({ id }: { id: string }) => { + try { + await setResumeLocked(id, false); + + return { + content: [{ type: "text", text: `Resume (${id}) is now unlocked. It can be edited, patched, and deleted.` }], + }; + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + let hint = ""; + if (msg.includes("404")) hint = " Use list_resumes to find valid IDs."; + return { isError: true, content: [{ type: "text", text: `Error unlocking resume: ${msg}${hint}` }] }; + } + }, +); + +// Resource: resume://{id} +const resumeTemplate = new ResourceTemplate("resume://{id}", { + list: async () => { + const resumes = await listResumes(); + + return { + resources: resumes.map((r) => ({ + uri: `resume://${r.id}`, + name: r.name, + mimeType: "application/json" as const, + description: `Resume: ${r.name}`, + })), + }; + }, +}); + +server.registerResource( + "resume", + resumeTemplate, + { + description: "Full resume data as JSON. Use resume://{id} with ID from list_resumes.", + mimeType: "application/json", + }, + async (uri: URL) => { + const id = uri.href.replace(/^resume:\/\//, ""); + if (!id) throw new Error("Invalid resume URI: resume://{id}"); + const resume = await getResume(id); + return { + contents: [{ uri: uri.href, mimeType: "application/json" as const, text: JSON.stringify(resume.data, null, 2) }], + }; + }, +); + +// Resource: resume://schema +server.registerResource( + "resume-schema", + "resume://schema", + { + description: "Resume Data JSON Schema for generating correct JSON Patch operations.", + mimeType: "application/json", + }, + async (uri: URL) => ({ + contents: [{ uri: uri.href, mimeType: "application/json" as const, text: JSON.stringify(schemaJSON, null, 2) }], + }), +); + +// --- Transport: stdio (default) --- +async function runStdio(): Promise { + const transport = new StdioServerTransport(); + await server.connect(transport); + console.error("Reactive Resume MCP server running via stdio"); +} + +// --- Transport: HTTP (Node http server) --- +function readBody(req: http.IncomingMessage): Promise { + return new Promise((resolve, reject) => { + const chunks: Buffer[] = []; + + req.on("data", (chunk) => chunks.push(chunk)); + + req.on("end", () => { + const raw = Buffer.concat(chunks).toString("utf8"); + if (!raw.trim()) return resolve(undefined); + + try { + resolve(JSON.parse(raw)); + } catch { + reject(new Error("Invalid JSON body")); + } + }); + + req.on("error", reject); + }); +} + +async function runHttp(): Promise { + const { StreamableHTTPServerTransport } = await import("@modelcontextprotocol/sdk/server/streamableHttp.js"); + + const httpServer = http.createServer(async (req, res) => { + if (req.method !== "POST" || req.url !== "/mcp") { + res.writeHead(404, { "Content-Type": "text/plain" }); + res.end("Not Found"); + return; + } + + let body: unknown; + + try { + body = await readBody(req); + } catch { + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32700, message: "Parse error" }, id: null })); + return; + } + + const transport = new StreamableHTTPServerTransport({ + sessionIdGenerator: undefined, + enableJsonResponse: true, + }); + + res.on("close", () => transport.close()); + + await server.connect(transport); + await transport.handleRequest(req as never, res as never, body); + }); + + httpServer.listen(PORT, "127.0.0.1", () => { + console.error(`Reactive Resume MCP server running on http://127.0.0.1:${PORT}/mcp`); + }); +} + +if (TRANSPORT === "http") { + runHttp().catch((err) => { + console.error("Server error:", err); + process.exit(1); + }); +} else { + runStdio().catch((err) => { + console.error("Server error:", err); + process.exit(1); + }); +} diff --git a/package.json b/package.json index 4dc99c433..d7ca24cff 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.0.6", + "version": "5.0.7", "license": "MIT", "type": "module", "packageManager": "pnpm@10.29.1+sha512.48dae233635a645768a3028d19545cacc1688639eeb1f3734e42d6d6b971afbf22aa1ac9af52a173d9c3a20c15857cfa400f19994d79a2f626fcc73fccda9bbc", @@ -26,14 +26,15 @@ "docs:dev": "cd docs && npx mint dev", "knip": "knip", "lingui:extract": "lingui extract --clean --overwrite", - "lint": "biome check --write .", + "lint": "biome check --write", "start": "node .output/server/index.mjs", - "typecheck": "tsc --noEmit" + "typecheck": "tsgo --noEmit" }, "dependencies": { - "@ai-sdk/anthropic": "^3.0.38", + "@ai-sdk/anthropic": "^3.0.39", "@ai-sdk/google": "^3.0.22", "@ai-sdk/openai": "^3.0.26", + "@ai-sdk/react": "^3.0.79", "@aws-sdk/client-s3": "^3.985.0", "@better-auth/core": "1.5.0-beta.13", "@better-auth/passkey": "1.5.0-beta.13", @@ -56,10 +57,10 @@ "@sindresorhus/slugify": "^3.0.0", "@t3-oss/env-core": "^0.13.10", "@tanstack/react-query": "5.90.20", - "@tanstack/react-router": "^1.158.4", - "@tanstack/react-router-ssr-query": "^1.158.4", - "@tanstack/react-start": "^1.159.2", - "@tanstack/zod-adapter": "^1.158.4", + "@tanstack/react-router": "^1.159.3", + "@tanstack/react-router-ssr-query": "^1.159.3", + "@tanstack/react-start": "^1.159.3", + "@tanstack/zod-adapter": "^1.159.3", "@tiptap/extension-highlight": "^3.19.0", "@tiptap/extension-table": "^3.19.0", "@tiptap/extension-text-align": "^3.19.0", @@ -76,6 +77,7 @@ "dompurify": "^3.3.1", "drizzle-orm": "^1.0.0-beta.15-859cf75", "drizzle-zod": "^0.8.3", + "@modelcontextprotocol/sdk": "^1.26.0", "es-toolkit": "^1.44.0", "fast-deep-equal": "^3.1.3", "fast-json-patch": "^3.1.1", @@ -127,6 +129,7 @@ "@types/pg": "^8.16.0", "@types/react": "^19.2.13", "@types/react-dom": "^19.2.3", + "@typescript/native-preview": "7.0.0-dev.20260208.1", "@vitejs/plugin-react": "^5.1.3", "babel-plugin-macros": "^3.1.0", "drizzle-kit": "^1.0.0-beta.15-859cf75", @@ -136,13 +139,12 @@ "node-gyp": "^12.2.0", "npm-check-updates": "^19.3.2", "tsx": "^4.21.0", - "typescript": "^5.9.3", - "vite": "npm:rolldown-vite@latest", + "vite": "^8.0.0-beta.13", "vite-plugin-pwa": "^1.2.0" }, "pnpm": { "overrides": { - "vite": "npm:rolldown-vite@latest" + "vite": "^8.0.0-beta.13" }, "onlyBuiltDependencies": [ "@prisma/engines", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d64c0a654..49d91b36b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,21 +5,24 @@ settings: excludeLinksFromLockfile: false overrides: - vite: npm:rolldown-vite@latest + vite: ^8.0.0-beta.13 importers: .: dependencies: '@ai-sdk/anthropic': - specifier: ^3.0.38 - version: 3.0.38(zod@4.3.6) + specifier: ^3.0.39 + version: 3.0.39(zod@4.3.6) '@ai-sdk/google': specifier: ^3.0.22 version: 3.0.22(zod@4.3.6) '@ai-sdk/openai': specifier: ^3.0.26 version: 3.0.26(zod@4.3.6) + '@ai-sdk/react': + specifier: ^3.0.79 + version: 3.0.79(react@19.2.4)(zod@4.3.6) '@aws-sdk/client-s3': specifier: ^3.985.0 version: 3.985.0 @@ -28,7 +31,7 @@ importers: version: 1.5.0-beta.13(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.2.1(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0) '@better-auth/passkey': specifier: 1.5.0-beta.13 - version: 1.5.0-beta.13(c9c4d2458e1510ceec4f373476625b2a) + version: 1.5.0-beta.13(eba5bf2b9716b4fc672d4feef57d2195) '@dnd-kit/core': specifier: ^6.3.1 version: 6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -50,6 +53,9 @@ importers: '@lingui/react': specifier: ^5.9.0 version: 5.9.0(@lingui/babel-plugin-lingui-macro@5.9.0(babel-plugin-macros@3.1.0)(typescript@5.9.3))(babel-plugin-macros@3.1.0)(react@19.2.4) + '@modelcontextprotocol/sdk': + specifier: ^1.26.0 + version: 1.26.0(zod@4.3.6) '@monaco-editor/react': specifier: 4.8.0-rc.3 version: 4.8.0-rc.3(monaco-editor@0.55.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -87,17 +93,17 @@ importers: specifier: 5.90.20 version: 5.90.20(react@19.2.4) '@tanstack/react-router': - specifier: ^1.158.4 - version: 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^1.159.3 + version: 1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-router-ssr-query': - specifier: ^1.158.4 - version: 1.158.4(@tanstack/query-core@5.90.20)(@tanstack/react-query@5.90.20(react@19.2.4))(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^1.159.3 + version: 1.159.3(@tanstack/query-core@5.90.20)(@tanstack/react-query@5.90.20(react@19.2.4))(@tanstack/react-router@1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-start': - specifier: ^1.159.2 - version: 1.159.2(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) + specifier: ^1.159.3 + version: 1.159.3(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) '@tanstack/zod-adapter': - specifier: ^1.158.4 - version: 1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(zod@4.3.6) + specifier: ^1.159.3 + version: 1.159.3(@tanstack/react-router@1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(zod@4.3.6) '@tiptap/extension-highlight': specifier: ^3.19.0 version: 3.19.0(@tiptap/core@3.19.0(@tiptap/pm@3.19.0)) @@ -127,7 +133,7 @@ importers: version: 6.0.0 better-auth: specifier: 1.5.0-beta.13 - version: 1.5.0-beta.13(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@tanstack/react-start@1.159.2(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)))(drizzle-kit@1.0.0-beta.9-e89174b)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.0.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.18.0)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.5.0-beta.13(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@tanstack/react-start@1.159.3(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)))(drizzle-kit@1.0.0-beta.9-e89174b)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.0.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.18.0)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -269,10 +275,10 @@ importers: version: 5.9.0(babel-plugin-macros@3.1.0)(typescript@5.9.3) '@lingui/vite-plugin': specifier: ^5.9.0 - version: 5.9.0(babel-plugin-macros@3.1.0)(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))(typescript@5.9.3) + version: 5.9.0(babel-plugin-macros@3.1.0)(typescript@5.9.3)(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) '@tailwindcss/vite': specifier: ^4.1.18 - version: 4.1.18(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) + version: 4.1.18(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) '@types/bcrypt': specifier: ^6.0.0 version: 6.0.0 @@ -294,9 +300,12 @@ importers: '@types/react-dom': specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.13) + '@typescript/native-preview': + specifier: 7.0.0-dev.20260208.1 + version: 7.0.0-dev.20260208.1 '@vitejs/plugin-react': specifier: ^5.1.3 - version: 5.1.3(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) + version: 5.1.3(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) babel-plugin-macros: specifier: ^3.1.0 version: 3.1.0 @@ -308,7 +317,7 @@ importers: version: 5.83.1(@types/node@25.2.2)(typescript@5.9.3) nitro: specifier: npm:nitro-nightly@latest - version: nitro-nightly@3.0.1-20260120-140218-d2383f00(@azure/identity@4.13.0)(@electric-sql/pglite@0.3.2)(chokidar@4.0.3)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(lru-cache@11.2.4)(mongodb@7.0.0(socks@2.8.7))(mysql2@3.15.3)(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))(rolldown@1.0.0-beta.53)(rollup@2.79.2) + version: nitro-nightly@3.0.1-20260120-140218-d2383f00(@azure/identity@4.13.0)(@electric-sql/pglite@0.3.2)(chokidar@4.0.3)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(lru-cache@11.2.4)(mongodb@7.0.0(socks@2.8.7))(mysql2@3.15.3)(rolldown@1.0.0-rc.3)(rollup@2.79.2)(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) node-addon-api: specifier: ^8.5.0 version: 8.5.0 @@ -321,20 +330,17 @@ importers: tsx: specifier: ^4.21.0 version: 4.21.0 - typescript: - specifier: ^5.9.3 - version: 5.9.3 vite: - specifier: npm:rolldown-vite@latest - version: rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) + specifier: ^8.0.0-beta.13 + version: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) vite-plugin-pwa: specifier: ^1.2.0 - version: 1.2.0(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0) + version: 1.2.0(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0) packages: - '@ai-sdk/anthropic@3.0.38': - resolution: {integrity: sha512-9MchyPRPni0WzrFeIGNevZpQVfWxaS+MQFupIXYQo9VgHnuO1Vyrp9SBmjkkuoAdBs7GomsWqLZCcNMJAVbdFA==} + '@ai-sdk/anthropic@3.0.39': + resolution: {integrity: sha512-OZXS78H3hgJ31YVlNCLQcM67D7hP5vQyDBGVwBuE20FopQqTRSAQY1nMBPe6aUzuoNthTfROIXtIqqX9Fv65Ww==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -367,6 +373,12 @@ packages: resolution: {integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==} engines: {node: '>=18'} + '@ai-sdk/react@3.0.79': + resolution: {integrity: sha512-s/Y+/sISlsEX5Zo/by0jwOyA6vnQ7+CldpRYGv5hMmgnarZ1m5B6myw3Y1Bc2xnozUy+wrmwA6HttlmR4xOOEg==} + engines: {node: '>=18'} + peerDependencies: + react: ^18 || ~19.0.1 || ~19.1.2 || ^19.2.1 + '@antfu/ni@25.0.0': resolution: {integrity: sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA==} hasBin: true @@ -2011,7 +2023,7 @@ packages: resolution: {integrity: sha512-qNr4UE/QZ36mo5+XVQ0hTWoQSIULoVQ2b1G+aNbGk6Z7olc8yYAtdytJyOCTEk9gCBeyMBTK7zonlxVngNsCfA==} engines: {node: '>=20.0.0'} peerDependencies: - vite: ^3 || ^4 || ^5.0.9 || ^6 || ^7 + vite: ^8.0.0-beta.13 '@messageformat/parser@5.1.1': resolution: {integrity: sha512-3p0YRGCcTUCYvBKLIxtDDyrJ0YijGIwrTRu1DT8gIviIDZru8H23+FkY6MJBzM1n9n20CiM4VeDYuBsrrwnLjg==} @@ -2319,12 +2331,12 @@ packages: cpu: [x64] os: [win32] - '@oxc-project/runtime@0.101.0': - resolution: {integrity: sha512-t3qpfVZIqSiLQ5Kqt/MC4Ge/WCOGrrcagAdzTcDaggupjiGxUx4nJF2v6wUCXWSzWHn5Ns7XLv13fCJEwCOERQ==} + '@oxc-project/runtime@0.112.0': + resolution: {integrity: sha512-4vYtWXMnXM6EaweCxbJ6bISAhkNHeN33SihvuX3wrpqaSJA4ZEoW35i9mSvE74+GDf1yTeVE+aEHA+WBpjDk/g==} engines: {node: ^20.19.0 || >=22.12.0} - '@oxc-project/types@0.101.0': - resolution: {integrity: sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==} + '@oxc-project/types@0.112.0': + resolution: {integrity: sha512-m6RebKHIRsax2iCwVpYW2ErQwa4ywHJrE4sCK3/8JK8ZZAWOKXaRJFl/uP51gaVyyXlaS4+chU1nSCdzYf6QqQ==} '@oxc-resolver/binding-android-arm-eabi@11.16.3': resolution: {integrity: sha512-CVyWHu6ACDqDcJxR4nmGiG8vDF4TISJHqRNzac5z/gPQycs/QrP/1pDsJBy0MD7jSw8nVq2E5WqeHQKabBG/Jg==} @@ -3380,83 +3392,83 @@ packages: '@remirror/core-constants@3.0.0': resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} - '@rolldown/binding-android-arm64@1.0.0-beta.53': - resolution: {integrity: sha512-Ok9V8o7o6YfSdTTYA/uHH30r3YtOxLD6G3wih/U9DO0ucBBFq8WPt/DslU53OgfteLRHITZny9N/qCUxMf9kjQ==} + '@rolldown/binding-android-arm64@1.0.0-rc.3': + resolution: {integrity: sha512-0T1k9FinuBZ/t7rZ8jN6OpUKPnUjNdYHoj/cESWrQ3ZraAJ4OMm6z7QjSfCxqj8mOp9kTKc1zHK3kGz5vMu+nQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-beta.53': - resolution: {integrity: sha512-yIsKqMz0CtRnVa6x3Pa+mzTihr4Ty+Z6HfPbZ7RVbk1Uxnco4+CUn7Qbm/5SBol1JD/7nvY8rphAgyAi7Lj6Vg==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.3': + resolution: {integrity: sha512-JWWLzvcmc/3pe7qdJqPpuPk91SoE/N+f3PcWx/6ZwuyDVyungAEJPvKm/eEldiDdwTmaEzWfIR+HORxYWrCi1A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-beta.53': - resolution: {integrity: sha512-GTXe+mxsCGUnJOFMhfGWmefP7Q9TpYUseHvhAhr21nCTgdS8jPsvirb0tJwM3lN0/u/cg7bpFNa16fQrjKrCjQ==} + '@rolldown/binding-darwin-x64@1.0.0-rc.3': + resolution: {integrity: sha512-MTakBxfx3tde5WSmbHxuqlDsIW0EzQym+PJYGF4P6lG2NmKzi128OGynoFUqoD5ryCySEY85dug4v+LWGBElIw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-beta.53': - resolution: {integrity: sha512-9Tmp7bBvKqyDkMcL4e089pH3RsjD3SUungjmqWtyhNOxoQMh0fSmINTyYV8KXtE+JkxYMPWvnEt+/mfpVCkk8w==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.3': + resolution: {integrity: sha512-jje3oopyOLs7IwfvXoS6Lxnmie5JJO7vW29fdGFu5YGY1EDbVDhD+P9vDihqS5X6fFiqL3ZQZCMBg6jyHkSVww==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': - resolution: {integrity: sha512-a1y5fiB0iovuzdbjUxa7+Zcvgv+mTmlGGC4XydVIsyl48eoxgaYkA3l9079hyTyhECsPq+mbr0gVQsFU11OJAQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.3': + resolution: {integrity: sha512-A0n8P3hdLAaqzSFrQoA42p23ZKBYQOw+8EH5r15Sa9X1kD9/JXe0YT2gph2QTWvdr0CVK2BOXiK6ENfy6DXOag==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': - resolution: {integrity: sha512-bpIGX+ov9PhJYV+wHNXl9rzq4F0QvILiURn0y0oepbQx+7stmQsKA0DhPGwmhfvF856wq+gbM8L92SAa/CBcLg==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.3': + resolution: {integrity: sha512-kWXkoxxarYISBJ4bLNf5vFkEbb4JvccOwxWDxuK9yee8lg5XA7OpvlTptfRuwEvYcOZf+7VS69Uenpmpyo5Bjw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': - resolution: {integrity: sha512-bGe5EBB8FVjHBR1mOLOPEFg1Lp3//7geqWkU5NIhxe+yH0W8FVrQ6WRYOap4SUTKdklD/dC4qPLREkMMQ855FA==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.3': + resolution: {integrity: sha512-Z03/wrqau9Bicfgb3Dbs6SYTHliELk2PM2LpG2nFd+cGupTMF5kanLEcj2vuuJLLhptNyS61rtk7SOZ+lPsTUA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': - resolution: {integrity: sha512-qL+63WKVQs1CMvFedlPt0U9PiEKJOAL/bsHMKUDS6Vp2Q+YAv/QLPu8rcvkfIMvQ0FPU2WL0aX4eWwF6e/GAnA==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.3': + resolution: {integrity: sha512-iSXXZsQp08CSilff/DCTFZHSVEpEwdicV3W8idHyrByrcsRDVh9sGC3sev6d8BygSGj3vt8GvUKBPCoyMA4tgQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': - resolution: {integrity: sha512-VGl9JIGjoJh3H8Mb+7xnVqODajBmrdOOb9lxWXdcmxyI+zjB2sux69br0hZJDTyLJfvBoYm439zPACYbCjGRmw==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.3': + resolution: {integrity: sha512-qaj+MFudtdCv9xZo9znFvkgoajLdc+vwf0Kz5N44g+LU5XMe+IsACgn3UG7uTRlCCvhMAGXm1XlpEA5bZBrOcw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': - resolution: {integrity: sha512-B4iIserJXuSnNzA5xBLFUIjTfhNy7d9sq4FUMQY3GhQWGVhS2RWWzzDnkSU6MUt7/aHUrep0CdQfXUJI9D3W7A==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.3': + resolution: {integrity: sha512-U662UnMETyjT65gFmG9ma+XziENrs7BBnENi/27swZPYagubfHRirXHG2oMl+pEax2WvO7Kb9gHZmMakpYqBHQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-beta.53': - resolution: {integrity: sha512-BUjAEgpABEJXilGq/BPh7jeU3WAJ5o15c1ZEgHaDWSz3LB881LQZnbNJHmUiM4d1JQWMYYyR1Y490IBHi2FPJg==} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.3': + resolution: {integrity: sha512-gekrQ3Q2HiC1T5njGyuUJoGpK/l6B/TNXKed3fZXNf9YRTJn3L5MOZsFBn4bN2+UX+8+7hgdlTcEsexX988G4g==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': - resolution: {integrity: sha512-s27uU7tpCWSjHBnxyVXHt3rMrQdJq5MHNv3BzsewCIroIw3DJFjMH1dzCPPMUFxnh1r52Nf9IJ/eWp6LDoyGcw==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.3': + resolution: {integrity: sha512-85y5JifyMgs8m5K2XzR/VDsapKbiFiohl7s5lEj7nmNGO0pkTXE7q6TQScei96BNAsoK7JC3pA7ukA8WRHVJpg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': - resolution: {integrity: sha512-cjWL/USPJ1g0en2htb4ssMjIycc36RvdQAx1WlXnS6DpULswiUTVXPDesTifSKYSyvx24E0YqQkEm0K/M2Z/AA==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.3': + resolution: {integrity: sha512-a4VUQZH7LxGbUJ3qJ/TzQG8HxdHvf+jOnqf7B7oFx1TEBm+j2KNL2zr5SQ7wHkNAcaPevF6gf9tQnVBnC4mD+A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -3464,12 +3476,12 @@ packages: '@rolldown/pluginutils@1.0.0-beta.40': resolution: {integrity: sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w==} - '@rolldown/pluginutils@1.0.0-beta.53': - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} - '@rolldown/pluginutils@1.0.0-rc.2': resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + '@rollup/plugin-babel@5.3.1': resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} engines: {node: '>= 10.0.0'} @@ -3878,7 +3890,7 @@ packages: '@tailwindcss/vite@4.1.18': resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} peerDependencies: - vite: ^5.2.0 || ^6 || ^7 + vite: ^8.0.0-beta.13 '@tanstack/history@1.154.14': resolution: {integrity: sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA==} @@ -3892,8 +3904,8 @@ packages: peerDependencies: react: ^18 || ^19 - '@tanstack/react-router-ssr-query@1.158.4': - resolution: {integrity: sha512-f+XzxO06ILM2i5CGtWqcb3+yaAvp8XgT5hMykKmwwaBnf3Ctc6O8tN/05Ovj0ajXWuROk3HTjg67OcWD7JxI6Q==} + '@tanstack/react-router-ssr-query@1.159.3': + resolution: {integrity: sha512-dNRNvGcyBk++JLF32cXO4KnLECvybVNx7MC+kJFs0/2c2o5I78zrBnol50xT0FaEfdfvwCZB0pjx0qcMpYjIsg==} engines: {node: '>=12'} peerDependencies: '@tanstack/query-core': '>=5.90.0' @@ -3902,34 +3914,34 @@ packages: react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-router@1.158.4': - resolution: {integrity: sha512-i15xXumgvpuM+4NSuIwgouGezuj9eHjZsgpTZSQ7E9pa8rYmhZbWnf8xU68qaLmaKIol/e75o/YzVH2QWHs3iQ==} + '@tanstack/react-router@1.159.3': + resolution: {integrity: sha512-VoQFmn1jR7lO2TIT+UlBNN6AWm+sBf0S7aAsCRDVI7IFuup3V/qBxKMKXDniUt3qMI1xF4gl7r7cQ2Sz8FogAw==} engines: {node: '>=12'} peerDependencies: react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-start-client@1.158.4': - resolution: {integrity: sha512-ctEBgpYAPZ3i4EPZlJ45XS/lXPO73MkELec+hXf8NfK0lDQDaUy7LfWu41NPaftdZFJPOncDCfutwpUXD98YlA==} + '@tanstack/react-start-client@1.159.3': + resolution: {integrity: sha512-85AXk6hm2t2PY1633PucmtKhvuHJRMQF+XUFHaDWyqmL33tj8lpuzpez2Ko0khnJ3R5BHfUEBBD1BAkCPXuHbQ==} engines: {node: '>=22.12.0'} peerDependencies: react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-start-server@1.159.2': - resolution: {integrity: sha512-Bi7wYAlh84DnITgNotzSN78sjlEX3FFd9KsEM050CbNERSYtMyBd+MEMv89BljTuBxjVYOMLHurxOTXo22LH8Q==} + '@tanstack/react-start-server@1.159.3': + resolution: {integrity: sha512-RSSLltVPOe+cEMl0VnIfOMEA/yjSZR/w53YjqypvGljYpgbTaU+feIDdxLOd5rYxNkS3ewENuWPdPkE8jR7+iQ==} engines: {node: '>=22.12.0'} peerDependencies: react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-start@1.159.2': - resolution: {integrity: sha512-7JHkxIGPvDioAeEVlnjqwj3iw9Ket7meUilQ4YWQuIlEnCYgS+KkZ8iefzdfiBhQi0kRrTt6e226JtbM9waTVg==} + '@tanstack/react-start@1.159.3': + resolution: {integrity: sha512-sqZh4cZozeB72Qtt9r8CpclRLQPyw8aAsw+dalXYZxwY2Io+yayTRHJHwqAgVaiWfV18EiT+qyn0akqS1+QXkw==} engines: {node: '>=22.12.0'} peerDependencies: react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - vite: '>=7.0.0' + vite: ^8.0.0-beta.13 '@tanstack/react-store@0.8.0': resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} @@ -3945,13 +3957,13 @@ packages: resolution: {integrity: sha512-RQmqMTT0oV8dS/3Glcq9SPzDZqOPyKb/LVFUkNoTfMwW88WyGnQcYqZAkmVk/CGBWWDfwObOUZoGq5jTF7bG8w==} engines: {node: '>=12'} - '@tanstack/router-plugin@1.158.4': - resolution: {integrity: sha512-g2sytAhljw6Jd6Klu37OZ75+o+vhiGdbWtnBy/4rYLC4NN6hSnjgJQRI3+h1CI1KQ4EUgsZYZr/hgE1KHoiWYQ==} + '@tanstack/router-plugin@1.159.3': + resolution: {integrity: sha512-gWBkJ3DCr77O4qkE5bppMO8EkKvlIX4vLM7hOrBjKUbMlC3aqplk8XaIyf9rZy/VpsIyVJAIOBWqvHHLv80Reg==} engines: {node: '>=12'} peerDependencies: '@rsbuild/core': '>=1.0.2' - '@tanstack/react-router': ^1.158.4 - vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' + '@tanstack/react-router': ^1.159.3 + vite: ^8.0.0-beta.13 vite-plugin-solid: ^2.11.10 webpack: '>=5.92.0' peerDependenciesMeta: @@ -3985,11 +3997,11 @@ packages: resolution: {integrity: sha512-D69B78L6pcFN5X5PHaydv7CScQcKLzJeEYqs7jpuyyqGQHSUIZUjS955j+Sir8cHhuDIovCe2LmsYHeZfWf3dQ==} engines: {node: '>=22.12.0'} - '@tanstack/start-plugin-core@1.159.2': - resolution: {integrity: sha512-eHtszoiF4XghxSKztWklqaqC/eQPdTP/0G/IvqBvwdc8QsLIXoKn1EEAwnMHXzDWRS9wcR0SDCcJcHF4lIkJQg==} + '@tanstack/start-plugin-core@1.159.3': + resolution: {integrity: sha512-TrcxOf8buf+x7jMI3gBf0ugOcIGCvWEIHf0FSCsuWLNEv/gt2aCOa5AnttdEHcDOW7s1xM2BM5RAjC0MD7qPuQ==} engines: {node: '>=22.12.0'} peerDependencies: - vite: '>=7.0.0' + vite: ^8.0.0-beta.13 '@tanstack/start-server-core@1.159.2': resolution: {integrity: sha512-vglvDC+SAPyZShoJgjYO9fJASqLQpzQ5ZYAhsV3Y15NiFk0AnKltfBGd9oV1BuhKJrFSE6e/Ik2zKPKADE/iYw==} @@ -4006,8 +4018,8 @@ packages: resolution: {integrity: sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg==} engines: {node: '>=12'} - '@tanstack/zod-adapter@1.158.4': - resolution: {integrity: sha512-tjCwJIbWiAae7JOWwgQ5Exc7YZgWLy3pjnXQ8/ON64p0+tHGDI8usrL5dJMEhRNOt7T3+3ytmRNRaVj8vVDvRw==} + '@tanstack/zod-adapter@1.159.3': + resolution: {integrity: sha512-uyi/rCblwuSg2Rz0ufgjyRla4N6ouBUmF+DTDkIvpWcM/uE08xoCl4wDwwmrryZTuB8xMfmfw3ukmGJBii2mSA==} engines: {node: '>=12'} peerDependencies: '@tanstack/react-router': '>=1.43.2' @@ -4288,6 +4300,45 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260208.1': + resolution: {integrity: sha512-ixnfsxZVziOh/tsuqrjJvXvfBqcilASOnWCsGLaBL9LwpY/0kZxfwvqR8c9DAyB9ilYsmrbu6mi8VtE39eNL9g==} + cpu: [arm64] + os: [darwin] + + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260208.1': + resolution: {integrity: sha512-LH5gacYZOG/mwCBSCYOVMZSQLWNuvBLjJcvm5W7UrTvnMvij9n/spfjHeRicJ1FdHeskCYvOVttshOUxZTQnOA==} + cpu: [x64] + os: [darwin] + + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260208.1': + resolution: {integrity: sha512-adQ3+tzalW6TbLFoL3PqKpL2MyaAaUW8EfmmKmUSpSM2w1ynKChIYmk0KKOFMQXoK3o3hxkvg8PoQbzk8nSEtQ==} + cpu: [arm64] + os: [linux] + + '@typescript/native-preview-linux-arm@7.0.0-dev.20260208.1': + resolution: {integrity: sha512-Ep5dHLBW+q3uJBI3WDIWuqBoazjZAo+EIyY/kkv/eoy8vUPsvMElv4vyvLJEYbhlpSrOFYVk8J2KiV+UqvpoVw==} + cpu: [arm] + os: [linux] + + '@typescript/native-preview-linux-x64@7.0.0-dev.20260208.1': + resolution: {integrity: sha512-lCJU9WYwrMWTLkQdvLs6KmFvz/0yZ951D756vsRdC43rLSmzb1GS4T8u9TJ9m5vuM1UST9Mj0+ID5lq5RfHnVA==} + cpu: [x64] + os: [linux] + + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260208.1': + resolution: {integrity: sha512-ZEjw0C5dtr9felIUTcpQ65zlTZANmdKcU+qakczrVOyUnF31+FyQtP/Fp2YPOteOAmwrxfCtCsw1Es4zSgtSeA==} + cpu: [arm64] + os: [win32] + + '@typescript/native-preview-win32-x64@7.0.0-dev.20260208.1': + resolution: {integrity: sha512-2ARKZBZwSyxLvQqIl2uqzHESKOYwmEYLJL02B9gPOYUyJOBG+mA75TyeOVTRuafDQv+Fp4xBDDyPOon5ARh+KQ==} + cpu: [x64] + os: [win32] + + '@typescript/native-preview@7.0.0-dev.20260208.1': + resolution: {integrity: sha512-Uvrv3FciZTvvdSpmaaJscQ3Nut9/IPFkHh5CIy0IuDHIqwCoHvkkTOdIFE/rgMfHkIlQHhnj9oF94kzRu8YnXg==} + hasBin: true + '@typespec/ts-http-runtime@0.3.2': resolution: {integrity: sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg==} engines: {node: '>=20.0.0'} @@ -4300,7 +4351,7 @@ packages: resolution: {integrity: sha512-NVUnA6gQCl8jfoYqKqQU5Clv0aPw14KkZYCsX6T9Lfu9slI0LOU10OTwFHS/WmptsMMpshNd/1tuWsHQ2Uk+cg==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + vite: ^8.0.0-beta.13 abbrev@4.0.0: resolution: {integrity: sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==} @@ -4994,6 +5045,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} @@ -6503,7 +6558,7 @@ packages: peerDependencies: rolldown: '>=1.0.0-beta.0' rollup: ^4 - vite: ^7 || ^8 || >=8.0.0-0 + vite: ^8.0.0-beta.13 xml2js: ^0.6.2 peerDependenciesMeta: rolldown: @@ -7212,48 +7267,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rolldown-vite@7.3.1: - resolution: {integrity: sha512-LYzdNAjRHhF2yA4JUQm/QyARyi216N2rpJ0lJZb8E9FU2y5v6Vk+xq/U4XBOxMefpWixT5H3TslmAHm1rqIq2w==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - esbuild: ^0.27.0 - jiti: '>=1.21.0' - less: ^4.0.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - esbuild: - optional: true - jiti: - optional: true - less: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - rolldown@1.0.0-beta.53: - resolution: {integrity: sha512-Qd9c2p0XKZdgT5AYd+KgAMggJ8ZmCs3JnS9PTMWkyUfteKlfmKtxJbWTHkVakxwXs1Ub7jrRYVeFeF7N0sQxyw==} + rolldown@1.0.0-rc.3: + resolution: {integrity: sha512-Po/YZECDOqVXjIXrtC5h++a5NLvKAQNrd9ggrIG3sbDfGO5BqTUsrI6l8zdniKRp3r5Tp/2JTrXqx4GIguFCMw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -7572,6 +7587,11 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + swr@2.4.0: + resolution: {integrity: sha512-sUlC20T8EOt1pHmDiqueUWMmRRX03W7w5YxovWX7VR2KHEPCTMly85x05vpkP5i6Bu4h44ePSMD9Tc+G2MItFw==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + tagged-tag@1.0.0: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} @@ -7628,6 +7648,10 @@ packages: threads@1.7.0: resolution: {integrity: sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ==} + throttleit@2.1.0: + resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} + engines: {node: '>=18'} + tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -7957,17 +7981,60 @@ packages: engines: {node: '>=16.0.0'} peerDependencies: '@vite-pwa/assets-generator': ^1.0.0 - vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + vite: ^8.0.0-beta.13 workbox-build: ^7.4.0 workbox-window: ^7.4.0 peerDependenciesMeta: '@vite-pwa/assets-generator': optional: true + vite@8.0.0-beta.13: + resolution: {integrity: sha512-7s/rfpYOAo7WUHh9irzaGjhhKb12hGv0BpDegAMV5A391wdyvM45WtX6VMV7hvEtZF2j/QtpDpR6ldXI3GgARQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.0.0-alpha.24 + esbuild: ^0.27.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vitefu@1.1.1: resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + vite: ^8.0.0-beta.13 peerDependenciesMeta: vite: optional: true @@ -8220,7 +8287,7 @@ packages: snapshots: - '@ai-sdk/anthropic@3.0.38(zod@4.3.6)': + '@ai-sdk/anthropic@3.0.39(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 '@ai-sdk/provider-utils': 4.0.14(zod@4.3.6) @@ -8256,6 +8323,16 @@ snapshots: dependencies: json-schema: 0.4.0 + '@ai-sdk/react@3.0.79(react@19.2.4)(zod@4.3.6)': + dependencies: + '@ai-sdk/provider-utils': 4.0.14(zod@4.3.6) + ai: 6.0.77(zod@4.3.6) + react: 19.2.4 + swr: 2.4.0(react@19.2.4) + throttleit: 2.1.0 + transitivePeerDependencies: + - zod + '@antfu/ni@25.0.0': dependencies: ansis: 4.2.0 @@ -9700,14 +9777,14 @@ snapshots: '@better-auth/utils': 0.3.1 mongodb: 7.0.0(socks@2.8.7) - '@better-auth/passkey@1.5.0-beta.13(c9c4d2458e1510ceec4f373476625b2a)': + '@better-auth/passkey@1.5.0-beta.13(eba5bf2b9716b4fc672d4feef57d2195)': dependencies: '@better-auth/core': 1.5.0-beta.13(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.2.1(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0) '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 '@simplewebauthn/browser': 13.2.2 '@simplewebauthn/server': 13.2.2 - better-auth: 1.5.0-beta.13(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@tanstack/react-start@1.159.2(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)))(drizzle-kit@1.0.0-beta.9-e89174b)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.0.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.18.0)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + better-auth: 1.5.0-beta.13(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@tanstack/react-start@1.159.3(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)))(drizzle-kit@1.0.0-beta.9-e89174b)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.0.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.18.0)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) better-call: 1.2.1(zod@4.3.6) nanostores: 1.1.0 zod: 4.3.6 @@ -10317,11 +10394,11 @@ snapshots: '@lingui/babel-plugin-lingui-macro': 5.9.0(babel-plugin-macros@3.1.0)(typescript@5.9.3) babel-plugin-macros: 3.1.0 - '@lingui/vite-plugin@5.9.0(babel-plugin-macros@3.1.0)(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))(typescript@5.9.3)': + '@lingui/vite-plugin@5.9.0(babel-plugin-macros@3.1.0)(typescript@5.9.3)(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))': dependencies: '@lingui/cli': 5.9.0(babel-plugin-macros@3.1.0)(typescript@5.9.3) '@lingui/conf': 5.9.0(typescript@5.9.3) - vite: rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) + vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -10353,6 +10430,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@modelcontextprotocol/sdk@1.26.0(zod@4.3.6)': + dependencies: + '@hono/node-server': 1.19.9(hono@4.11.4) + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + content-type: 1.0.5 + cors: 2.8.5 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.2.1(express@5.2.1) + hono: 4.11.4 + jose: 6.1.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.3.6 + zod-to-json-schema: 3.25.1(zod@4.3.6) + transitivePeerDependencies: + - supports-color + '@monaco-editor/loader@1.7.0': dependencies: state-local: 1.0.7 @@ -10673,9 +10772,9 @@ snapshots: '@oxc-minify/binding-win32-x64-msvc@0.110.0': optional: true - '@oxc-project/runtime@0.101.0': {} + '@oxc-project/runtime@0.112.0': {} - '@oxc-project/types@0.101.0': {} + '@oxc-project/types@0.112.0': {} '@oxc-resolver/binding-android-arm-eabi@11.16.3': optional: true @@ -11759,53 +11858,53 @@ snapshots: '@remirror/core-constants@3.0.0': {} - '@rolldown/binding-android-arm64@1.0.0-beta.53': + '@rolldown/binding-android-arm64@1.0.0-rc.3': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-beta.53': + '@rolldown/binding-darwin-arm64@1.0.0-rc.3': optional: true - '@rolldown/binding-darwin-x64@1.0.0-beta.53': + '@rolldown/binding-darwin-x64@1.0.0-rc.3': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-beta.53': + '@rolldown/binding-freebsd-x64@1.0.0-rc.3': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.3': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.3': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.3': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.3': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': + '@rolldown/binding-linux-x64-musl@1.0.0-rc.3': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': + '@rolldown/binding-openharmony-arm64@1.0.0-rc.3': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.53': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.3': dependencies: '@napi-rs/wasm-runtime': 1.1.1 optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.3': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.3': optional: true '@rolldown/pluginutils@1.0.0-beta.40': {} - '@rolldown/pluginutils@1.0.0-beta.53': {} - '@rolldown/pluginutils@1.0.0-rc.2': {} + '@rolldown/pluginutils@1.0.0-rc.3': {} + '@rollup/plugin-babel@5.3.1(@babel/core@7.29.0)(@types/babel__core@7.20.5)(rollup@2.79.2)': dependencies: '@babel/core': 7.29.0 @@ -12298,12 +12397,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 - '@tailwindcss/vite@4.1.18(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))': + '@tailwindcss/vite@4.1.18(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))': dependencies: '@tailwindcss/node': 4.1.18 '@tailwindcss/oxide': 4.1.18 tailwindcss: 4.1.18 - vite: rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) + vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) '@tanstack/history@1.154.14': {} @@ -12314,18 +12413,18 @@ snapshots: '@tanstack/query-core': 5.90.20 react: 19.2.4 - '@tanstack/react-router-ssr-query@1.158.4(@tanstack/query-core@5.90.20)(@tanstack/react-query@5.90.20(react@19.2.4))(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-router-ssr-query@1.159.3(@tanstack/query-core@5.90.20)(@tanstack/react-query@5.90.20(react@19.2.4))(@tanstack/react-router@1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/query-core': 5.90.20 '@tanstack/react-query': 5.90.20(react@19.2.4) - '@tanstack/react-router': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router': 1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/router-ssr-query-core': 1.158.4(@tanstack/query-core@5.90.20)(@tanstack/router-core@1.158.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - '@tanstack/router-core' - '@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-router@1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/history': 1.154.14 '@tanstack/react-store': 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -12333,12 +12432,13 @@ snapshots: isbot: 5.1.33 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + srvx: 0.11.2 tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/react-start-client@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-start-client@1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/react-router': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router': 1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/router-core': 1.158.4 '@tanstack/start-client-core': 1.158.4 react: 19.2.4 @@ -12346,10 +12446,10 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/react-start-server@1.159.2(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-start-server@1.159.3(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/history': 1.154.14 - '@tanstack/react-router': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router': 1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/router-core': 1.158.4 '@tanstack/start-client-core': 1.158.4 '@tanstack/start-server-core': 1.159.2(crossws@0.4.3(srvx@0.10.1)) @@ -12358,19 +12458,19 @@ snapshots: transitivePeerDependencies: - crossws - '@tanstack/react-start@1.159.2(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))': + '@tanstack/react-start@1.159.3(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))': dependencies: - '@tanstack/react-router': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-start-client': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-start-server': 1.159.2(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router': 1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-client': 1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-server': 1.159.3(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/router-utils': 1.158.0 '@tanstack/start-client-core': 1.158.4 - '@tanstack/start-plugin-core': 1.159.2(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.3(srvx@0.10.1))(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) + '@tanstack/start-plugin-core': 1.159.3(@tanstack/react-router@1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.3(srvx@0.10.1))(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) '@tanstack/start-server-core': 1.159.2(crossws@0.4.3(srvx@0.10.1)) pathe: 2.0.3 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - vite: rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) + vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) transitivePeerDependencies: - '@rsbuild/core' - crossws @@ -12408,7 +12508,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))': + '@tanstack/router-plugin@1.159.3(@tanstack/react-router@1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) @@ -12424,8 +12524,8 @@ snapshots: unplugin: 2.3.11 zod: 3.25.76 optionalDependencies: - '@tanstack/react-router': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - vite: rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) + '@tanstack/react-router': 1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) transitivePeerDependencies: - supports-color @@ -12459,7 +12559,7 @@ snapshots: '@tanstack/start-fn-stubs@1.154.7': {} - '@tanstack/start-plugin-core@1.159.2(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.3(srvx@0.10.1))(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))': + '@tanstack/start-plugin-core@1.159.3(@tanstack/react-router@1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.3(srvx@0.10.1))(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))': dependencies: '@babel/code-frame': 7.27.1 '@babel/core': 7.29.0 @@ -12467,7 +12567,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.40 '@tanstack/router-core': 1.158.4 '@tanstack/router-generator': 1.158.4 - '@tanstack/router-plugin': 1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) + '@tanstack/router-plugin': 1.159.3(@tanstack/react-router@1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) '@tanstack/router-utils': 1.158.0 '@tanstack/start-client-core': 1.158.4 '@tanstack/start-server-core': 1.159.2(crossws@0.4.3(srvx@0.10.1)) @@ -12477,8 +12577,8 @@ snapshots: srvx: 0.11.2 tinyglobby: 0.2.15 ufo: 1.6.3 - vite: rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) - vitefu: 1.1.1(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) + vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) + vitefu: 1.1.1(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) xmlbuilder2: 4.0.3 zod: 3.25.76 transitivePeerDependencies: @@ -12509,9 +12609,9 @@ snapshots: '@tanstack/virtual-file-routes@1.154.7': {} - '@tanstack/zod-adapter@1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(zod@4.3.6)': + '@tanstack/zod-adapter@1.159.3(@tanstack/react-router@1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(zod@4.3.6)': dependencies: - '@tanstack/react-router': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router': 1.159.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) zod: 4.3.6 '@tediousjs/connection-string@0.5.0': {} @@ -12832,6 +12932,37 @@ snapshots: '@types/node': 25.2.2 optional: true + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260208.1': + optional: true + + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260208.1': + optional: true + + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260208.1': + optional: true + + '@typescript/native-preview-linux-arm@7.0.0-dev.20260208.1': + optional: true + + '@typescript/native-preview-linux-x64@7.0.0-dev.20260208.1': + optional: true + + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260208.1': + optional: true + + '@typescript/native-preview-win32-x64@7.0.0-dev.20260208.1': + optional: true + + '@typescript/native-preview@7.0.0-dev.20260208.1': + optionalDependencies: + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260208.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260208.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260208.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260208.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260208.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260208.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260208.1 + '@typespec/ts-http-runtime@0.3.2': dependencies: http-proxy-agent: 7.0.2 @@ -12842,7 +12973,7 @@ snapshots: '@vercel/oidc@3.1.0': {} - '@vitejs/plugin-react@5.1.3(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))': + '@vitejs/plugin-react@5.1.3(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -12850,7 +12981,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.2 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) + vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) transitivePeerDependencies: - supports-color @@ -13054,7 +13185,7 @@ snapshots: node-addon-api: 8.5.0 node-gyp-build: 4.8.4 - better-auth@1.5.0-beta.13(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@tanstack/react-start@1.159.2(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)))(drizzle-kit@1.0.0-beta.9-e89174b)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.0.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.18.0)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + better-auth@1.5.0-beta.13(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@tanstack/react-start@1.159.3(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)))(drizzle-kit@1.0.0-beta.9-e89174b)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.0.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.18.0)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@better-auth/core': 1.5.0-beta.13(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.2.1(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0) '@better-auth/drizzle-adapter': 1.5.0-beta.13(@better-auth/core@1.5.0-beta.13(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.2.1(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0))(@better-auth/utils@0.3.1)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))) @@ -13075,7 +13206,7 @@ snapshots: zod: 4.3.6 optionalDependencies: '@prisma/client': 7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3) - '@tanstack/react-start': 1.159.2(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) + '@tanstack/react-start': 1.159.3(crossws@0.4.3(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)) drizzle-kit: 1.0.0-beta.9-e89174b drizzle-orm: 1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) mongodb: 7.0.0(socks@2.8.7) @@ -13522,6 +13653,8 @@ snapshots: depd@2.0.0: {} + dequal@2.0.3: {} + destr@2.0.5: {} detect-libc@2.1.2: {} @@ -14935,7 +15068,7 @@ snapshots: nf3@0.3.5: {} - nitro-nightly@3.0.1-20260120-140218-d2383f00(@azure/identity@4.13.0)(@electric-sql/pglite@0.3.2)(chokidar@4.0.3)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(lru-cache@11.2.4)(mongodb@7.0.0(socks@2.8.7))(mysql2@3.15.3)(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))(rolldown@1.0.0-beta.53)(rollup@2.79.2): + nitro-nightly@3.0.1-20260120-140218-d2383f00(@azure/identity@4.13.0)(@electric-sql/pglite@0.3.2)(chokidar@4.0.3)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(lru-cache@11.2.4)(mongodb@7.0.0(socks@2.8.7))(mysql2@3.15.3)(rolldown@1.0.0-rc.3)(rollup@2.79.2)(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)): dependencies: consola: 3.4.2 crossws: 0.4.3(srvx@0.10.1) @@ -14952,9 +15085,9 @@ snapshots: unenv: 2.0.0-rc.24 unstorage: 2.0.0-alpha.5(@azure/identity@4.13.0)(chokidar@4.0.3)(db0@0.3.4(@electric-sql/pglite@0.3.2)(drizzle-orm@1.0.0-beta.9-e89174b(@electric-sql/pglite@0.3.2)(@opentelemetry/api@1.9.0)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/mssql@9.1.9)(@types/pg@8.16.0)(mssql@11.0.1)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mysql2@3.15.3))(lru-cache@11.2.4)(mongodb@7.0.0(socks@2.8.7))(ofetch@2.0.0-alpha.3) optionalDependencies: - rolldown: 1.0.0-beta.53 + rolldown: 1.0.0-rc.3 rollup: 2.79.2 - vite: rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) + vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -15846,41 +15979,24 @@ snapshots: rfdc@1.4.1: {} - rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0): + rolldown@1.0.0-rc.3: dependencies: - '@oxc-project/runtime': 0.101.0 - fdir: 6.5.0(picomatch@4.0.3) - lightningcss: 1.31.1 - picomatch: 4.0.3 - postcss: 8.5.6 - rolldown: 1.0.0-beta.53 - tinyglobby: 0.2.15 + '@oxc-project/types': 0.112.0 + '@rolldown/pluginutils': 1.0.0-rc.3 optionalDependencies: - '@types/node': 25.2.2 - esbuild: 0.27.2 - fsevents: 2.3.3 - jiti: 2.6.1 - terser: 5.46.0 - tsx: 4.21.0 - - rolldown@1.0.0-beta.53: - dependencies: - '@oxc-project/types': 0.101.0 - '@rolldown/pluginutils': 1.0.0-beta.53 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.53 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.53 - '@rolldown/binding-darwin-x64': 1.0.0-beta.53 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.53 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.53 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.53 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.53 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.53 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.53 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.53 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.53 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.53 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.53 + '@rolldown/binding-android-arm64': 1.0.0-rc.3 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.3 + '@rolldown/binding-darwin-x64': 1.0.0-rc.3 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.3 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.3 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.3 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.3 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.3 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.3 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.3 rollup@2.79.2: optionalDependencies: @@ -16295,6 +16411,12 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + swr@2.4.0(react@19.2.4): + dependencies: + dequal: 2.0.3 + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) + tagged-tag@1.0.0: {} tailwind-merge@3.4.0: {} @@ -16397,6 +16519,8 @@ snapshots: transitivePeerDependencies: - supports-color + throttleit@2.1.0: {} + tiny-invariant@1.3.3: {} tiny-warning@1.0.3: {} @@ -16632,20 +16756,37 @@ snapshots: vary@1.1.2: {} - vite-plugin-pwa@1.2.0(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0): + vite-plugin-pwa@1.2.0(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0): dependencies: debug: 4.4.3 pretty-bytes: 6.1.1 tinyglobby: 0.2.15 - vite: rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) + vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) workbox-build: 7.4.0(@types/babel__core@7.20.5) workbox-window: 7.4.0 transitivePeerDependencies: - supports-color - vitefu@1.1.1(rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)): + vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0): + dependencies: + '@oxc-project/runtime': 0.112.0 + fdir: 6.5.0(picomatch@4.0.3) + lightningcss: 1.31.1 + picomatch: 4.0.3 + postcss: 8.5.6 + rolldown: 1.0.0-rc.3 + tinyglobby: 0.2.15 optionalDependencies: - vite: rolldown-vite@7.3.1(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) + '@types/node': 25.2.2 + esbuild: 0.27.2 + fsevents: 2.3.3 + jiti: 2.6.1 + terser: 5.46.0 + tsx: 4.21.0 + + vitefu@1.1.1(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)): + optionalDependencies: + vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0) w3c-keyname@2.2.8: {} @@ -16931,6 +17072,10 @@ snapshots: dependencies: zod: 3.25.76 + zod-to-json-schema@3.25.1(zod@4.3.6): + dependencies: + zod: 4.3.6 + zod@3.25.76: {} zod@4.3.6: {} diff --git a/src/components/ai/chat.tsx b/src/components/ai/chat.tsx new file mode 100644 index 000000000..9d05ea530 --- /dev/null +++ b/src/components/ai/chat.tsx @@ -0,0 +1,408 @@ +import { useChat } from "@ai-sdk/react"; +import { t } from "@lingui/core/macro"; +import { Trans } from "@lingui/react/macro"; +import { eventIteratorToUnproxiedDataStream } from "@orpc/client"; +import { + CheckCircleIcon, + CircleNotchIcon, + PaperPlaneRightIcon, + SparkleIcon, + StopIcon, + TrashSimpleIcon, +} from "@phosphor-icons/react"; +import type { UIMessage } from "ai"; +import type { Operation } from "fast-json-patch"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { toast } from "sonner"; +import { Button } from "@/components/ui/button"; +import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { useAIStore } from "@/integrations/ai/store"; +import { client } from "@/integrations/orpc/client"; +import { applyResumePatches } from "@/utils/resume/patch"; +import { cn } from "@/utils/style"; +import { useResumeStore } from "../resume/store/resume"; + +/** + * Extract patch operations from the latest assistant messages' tool call parts. + * Returns operations that haven't been applied yet (tracked by processedToolCallIds). + */ +function extractNewPatchOperations( + messages: UIMessage[], + processedIds: Set, +): { operations: Operation[]; newIds: string[] } { + const operations: Operation[] = []; + const newIds: string[] = []; + + for (const message of messages) { + if (message.role !== "assistant") continue; + for (const part of message.parts) { + if (part.type !== "tool-patch_resume") continue; + + // biome-ignore lint/suspicious/noExplicitAny: AI SDK tool parts have dynamic shapes + const toolPart = part as any; + if (toolPart.state !== "output-available") continue; + + const callId = toolPart.toolCallId as string; + if (processedIds.has(callId)) continue; + + const result = toolPart.output as { success: boolean; appliedOperations?: Operation[] } | undefined; + if (result?.success && result.appliedOperations) { + operations.push(...result.appliedOperations); + newIds.push(callId); + } + } + } + + return { operations, newIds }; +} + +/** + * LocalStorage helpers for persisting chat messages per resume. + */ +const STORAGE_KEY_PREFIX = "ai-chat-messages"; + +function getStorageKey(resumeId: string): string { + return `${STORAGE_KEY_PREFIX}:${resumeId}`; +} + +function loadStoredMessages(resumeId: string): UIMessage[] { + try { + const stored = localStorage.getItem(getStorageKey(resumeId)); + if (!stored) return []; + return JSON.parse(stored) as UIMessage[]; + } catch { + return []; + } +} + +function saveStoredMessages(resumeId: string, messages: UIMessage[]): void { + try { + localStorage.setItem(getStorageKey(resumeId), JSON.stringify(messages)); + } catch { + // Silently fail if localStorage is full or unavailable + } +} + +function clearStoredMessages(resumeId: string): void { + localStorage.removeItem(getStorageKey(resumeId)); +} + +function formatPath(path: string): string { + return path.replace(/^\//, "").replace(/\//g, " › "); +} + +function formatOperationLabel(op: string): string { + switch (op) { + case "replace": + return t`Updated`; + case "add": + return t`Added`; + case "remove": + return t`Removed`; + default: + return op; + } +} + +function ToolBadge({ state, operations }: { state: string; operations?: { op: string; path: string }[] }) { + const isDone = state === "output-available"; + + return ( +
+ + {isDone ? ( + + ) : ( + + )} + {isDone ? "Changes applied" : "Applying changes..."} + + + {isDone && operations && operations.length > 0 && ( +
+ {operations.map((op, i) => ( + + + {formatOperationLabel(op.op)} {formatPath(op.path)} + + ))} +
+ )} +
+ ); +} + +function MessageParts({ message }: { message: UIMessage }) { + const parts = message.parts; + + if (parts.length === 0) return null; + + return ( +
+ {parts.map((part, i) => { + if (part.type === "step-start") { + if (i === 0) return null; + return
; + } + + if (part.type === "text" && part.text.trim()) { + return ( +

+ {part.text} +

+ ); + } + + if (part.type === "reasoning" && part.text.trim()) { + return ( +

+ {part.text} +

+ ); + } + + if (part.type === "tool-patch_resume") { + // biome-ignore lint/suspicious/noExplicitAny: AI SDK tool parts have dynamic shapes + const toolPart = part as any; + const state = toolPart.state as string; + const operations = toolPart.input?.operations as { op: string; path: string }[] | undefined; + return ; + } + + return null; + })} +
+ ); +} + +export function AIChat() { + const enabled = useAIStore((s) => s.enabled); + const provider = useAIStore((s) => s.provider); + const model = useAIStore((s) => s.model); + const apiKey = useAIStore((s) => s.apiKey); + const baseURL = useAIStore((s) => s.baseURL); + + const resumeId = useResumeStore((s) => s.resume.id); + const resumeData = useResumeStore((s) => s.resume.data); + const updateResumeData = useResumeStore((s) => s.updateResumeData); + + const [input, setInput] = useState(""); + const [open, setOpen] = useState(false); + const bottomRef = useRef(null); + const inputRef = useRef(null); + const processedToolCallIds = useRef(new Set()); + + // Load stored messages once on mount and pre-populate processedToolCallIds + // so that already-applied patches are not re-applied. + const [initialMessages] = useState(() => { + const stored = loadStoredMessages(resumeId); + + for (const msg of stored) { + if (msg.role !== "assistant") continue; + for (const part of msg.parts) { + if (part.type !== "tool-patch_resume") continue; + // biome-ignore lint/suspicious/noExplicitAny: AI SDK tool parts have dynamic shapes + const toolPart = part as any; + if (toolPart.state === "output-available") { + processedToolCallIds.current.add(toolPart.toolCallId as string); + } + } + } + + return stored; + }); + + const { messages, sendMessage, status, stop, setMessages } = useChat({ + messages: initialMessages, + transport: { + async sendMessages(options) { + return eventIteratorToUnproxiedDataStream( + await client.ai.chat( + { + provider, + model, + apiKey, + baseURL, + messages: options.messages, + resumeData, + }, + { signal: options.abortSignal }, + ), + ); + }, + reconnectToStream() { + throw new Error("Unsupported"); + }, + }, + onError(error) { + toast.error("AI chat error", { description: error.message }); + }, + }); + + // Apply patches when new tool results arrive + useEffect(() => { + const { operations, newIds } = extractNewPatchOperations(messages, processedToolCallIds.current); + if (operations.length === 0) return; + + try { + const patched = applyResumePatches(resumeData, operations); + updateResumeData((draft) => { + Object.assign(draft, patched); + }); + for (const id of newIds) processedToolCallIds.current.add(id); + } catch (error) { + toast.error("Failed to apply resume changes", { + description: error instanceof Error ? error.message : "Unknown error", + }); + } + }, [messages, resumeData, updateResumeData]); + + // Persist messages to localStorage whenever they change + useEffect(() => { + saveStoredMessages(resumeId, messages); + }, [resumeId, messages]); + + // Auto-scroll to bottom (sentinel so it works with ScrollArea viewport) + useEffect(() => { + bottomRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [messages]); + + // Refocus the input when the AI finishes responding + useEffect(() => { + if (status === "ready") inputRef.current?.focus(); + }, [status]); + + const handleOpenChange = useCallback((nextOpen: boolean) => { + setOpen(nextOpen); + }, []); + + const handleClearMessages = useCallback(() => { + setMessages([]); + clearStoredMessages(resumeId); + processedToolCallIds.current.clear(); + }, [resumeId, setMessages]); + + const handleSubmit = useCallback( + (e: React.SubmitEvent) => { + e.preventDefault(); + if (!input.trim() || status !== "ready") return; + sendMessage({ text: input }); + setInput(""); + }, + [input, status, sendMessage], + ); + + if (!enabled) return null; + + const isLoading = status === "submitted" || status === "streaming"; + + return ( + + + + + + + {/* Header with clear button */} +
+

+ AI Chat +

+ +
+ + {/* Message list — min-h-0 so flex constrains height and viewport scrolls */} + +
+ {messages.length === 0 && ( +
+

+ Ask me to update your resume... +

+
+ )} + +
+ {messages.map((message) => ( +
+
+ {message.role === "user" ? ( +

+ {message.parts.map((part, i) => + part.type === "text" ? {part.text} : null, + )} +

+ ) : ( + + )} +
+
+ ))} + + {status === "submitted" && ( +
+
+
+ + + Thinking... + +
+
+
+ )} + +
+
+
+ + + {/* Input form — shrink-0 so it stays visible when content scrolls */} +
+ setInput(e.target.value)} + placeholder={t`e.g. Change my name to...`} + className="flex-1 bg-transparent text-[13px] outline-none placeholder:text-muted-foreground" + /> + {isLoading ? ( + + ) : ( + + )} +
+ + + ); +} diff --git a/src/components/resume/shared/items/cover-letter-item.tsx b/src/components/resume/shared/items/cover-letter-item.tsx index ea8dc6d8b..b8de61d09 100644 --- a/src/components/resume/shared/items/cover-letter-item.tsx +++ b/src/components/resume/shared/items/cover-letter-item.tsx @@ -12,17 +12,13 @@ export function CoverLetterItem({ className, ...item }: CoverLetterItemProps) { return (
- {stripHtml(item.recipient) && ( -
- -
- )} +
+ +
- {stripHtml(item.content) && ( -
- -
- )} +
+ +
); } diff --git a/src/components/resume/shared/items/skills-item.tsx b/src/components/resume/shared/items/skills-item.tsx index 49ac23f9b..e12c3c3b1 100644 --- a/src/components/resume/shared/items/skills-item.tsx +++ b/src/components/resume/shared/items/skills-item.tsx @@ -17,15 +17,11 @@ export function SkillsItem({ className, ...item }: SkillsItemProps) {
{/* Proficiency */} - {item.proficiency && ( - {item.proficiency} - )} + {item.proficiency &&
{item.proficiency}
} {/* Keywords */} {item.keywords.length > 0 && ( - - {item.keywords.join(", ")} - +
{item.keywords.join(", ")}
)} {/* Level */} diff --git a/src/components/resume/templates/lapras.tsx b/src/components/resume/templates/lapras.tsx index 9ce5c8956..2340cff5e 100644 --- a/src/components/resume/templates/lapras.tsx +++ b/src/components/resume/templates/lapras.tsx @@ -65,7 +65,7 @@ function Header() { return (
diff --git a/src/components/resume/templates/onyx.tsx b/src/components/resume/templates/onyx.tsx index d8c033379..a74db545b 100644 --- a/src/components/resume/templates/onyx.tsx +++ b/src/components/resume/templates/onyx.tsx @@ -43,7 +43,7 @@ function Header() { const basics = useResumeStore((state) => state.resume.data.basics); return ( -
+
diff --git a/src/components/ui/combobox.tsx b/src/components/ui/combobox.tsx index 6f30e7f4d..9fa396b3e 100644 --- a/src/components/ui/combobox.tsx +++ b/src/components/ui/combobox.tsx @@ -129,7 +129,7 @@ function Combobox({ {options.map((option) => { const isSelected = selectedValue === option.value; - const isDisabled = option.disabled ?? (false || disabled); + const isDisabled = option.disabled ?? disabled; return ( {children} diff --git a/src/integrations/ai/prompts/chat-system.md b/src/integrations/ai/prompts/chat-system.md new file mode 100644 index 000000000..38146a6fe --- /dev/null +++ b/src/integrations/ai/prompts/chat-system.md @@ -0,0 +1,65 @@ +You are an expert resume writer and a specialist in JSON Patch (RFC 6902) operations. Your role is to help the user improve and modify their resume through natural conversation. + +## Your Capabilities + +- You can read and understand the user's current resume data (provided below). +- You can modify the resume by calling the `patch_resume` tool with JSON Patch operations. +- You can advise on resume best practices, wording, and structure. + +## Rules + +1. **Always use the `patch_resume` tool** to make changes. Never output raw JSON or patch operations in your text response. +2. **Generate the minimal set of operations** needed for each change. Do not replace entire objects when only a single field needs updating. +3. **Preserve existing data** unless the user explicitly asks to remove or replace it. +4. **Confirm before destructive actions** like removing sections or clearing large amounts of content. +5. **Stay on topic.** Only discuss resume-related content. Politely decline off-topic requests. +6. **Do not fabricate content.** Only add information the user provides or explicitly asks you to generate. If generating content (e.g. a summary), make it clear you are drafting and ask for approval. +7. **HTML content fields** (description, summary content, cover letter content) must use valid HTML. Use `

` for paragraphs, `

    `/`
  • ` for lists, `` for bold, `` for italic. +8. **IDs for new items** must be valid UUIDs (use the format `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`). + +## Resume Data Structure + +The resume data is a JSON object with these top-level keys: + +- `basics` — name, headline, email, phone, location, website, customFields +- `summary` — title, content (HTML), columns, hidden +- `picture` — url, size, rotation, aspectRatio, border/shadow settings +- `sections` — built-in sections, each with title, columns, hidden, items[] + - `profiles` — items: { network, username, icon, website } + - `experience` — items: { company, position, location, period, website, description } + - `education` — items: { school, degree, area, grade, location, period, website, description } + - `projects` — items: { name, period, website, description } + - `skills` — items: { name, proficiency, level, keywords[], icon } + - `languages` — items: { language, fluency, level } + - `interests` — items: { name, keywords[], icon } + - `awards` — items: { title, awarder, date, website, description } + - `certifications` — items: { title, issuer, date, website, description } + - `publications` — items: { title, publisher, date, website, description } + - `volunteer` — items: { organization, location, period, website, description } + - `references` — items: { name, position, website, phone, description } +- `customSections` — array of user-created sections with id, type, title, items[] +- `metadata` — template, layout, css, page, design, typography, notes + +Every item in a section has: `id` (UUID), `hidden` (boolean), and optionally `options`. +Every `website` field is an object: `{ url: string, label: string }`. + +## JSON Patch Path Examples + +| Action | Operation | +|--------|-----------| +| Change name | `{ "op": "replace", "path": "/basics/name", "value": "Jane Doe" }` | +| Update headline | `{ "op": "replace", "path": "/basics/headline", "value": "Senior Engineer" }` | +| Replace summary content | `{ "op": "replace", "path": "/summary/content", "value": "

    Experienced engineer...

    " }` | +| Add experience item | `{ "op": "add", "path": "/sections/experience/items/-", "value": { ...full item object } }` | +| Remove skill at index 2 | `{ "op": "remove", "path": "/sections/skills/items/2" }` | +| Update a specific item field | `{ "op": "replace", "path": "/sections/experience/items/0/company", "value": "New Corp" }` | +| Change template | `{ "op": "replace", "path": "/metadata/template", "value": "bronzor" }` | +| Change primary color | `{ "op": "replace", "path": "/metadata/design/colors/primary", "value": "rgba(37, 99, 235, 1)" }` | +| Hide a section | `{ "op": "replace", "path": "/sections/interests/hidden", "value": true }` | +| Rename a section title | `{ "op": "replace", "path": "/sections/experience/title", "value": "Work History" }` | + +## Current Resume Data + +```json +{{RESUME_DATA}} +``` diff --git a/src/integrations/ai/tools/patch-resume.ts b/src/integrations/ai/tools/patch-resume.ts new file mode 100644 index 000000000..a5ba70aa6 --- /dev/null +++ b/src/integrations/ai/tools/patch-resume.ts @@ -0,0 +1,22 @@ +import type { Operation } from "fast-json-patch"; +import z from "zod"; +import type { ResumeData } from "@/schema/resume/data"; +import { applyResumePatches, jsonPatchOperationSchema } from "@/utils/resume/patch"; + +export const patchResumeInputSchema = z.object({ + operations: z + .array(jsonPatchOperationSchema) + .min(1) + .describe("Array of JSON Patch (RFC 6902) operations to apply to the resume"), +}); + +export const patchResumeDescription = `Apply JSON Patch (RFC 6902) operations to modify the user's resume data. +Use this tool whenever the user asks to change, add, or remove content from their resume. +Always generate the minimal set of operations needed. Prefer "replace" for updates, "add" for new content, "remove" for deletions. +Use the special "-" index to append to arrays (e.g. "/sections/experience/items/-").`; + +export function executePatchResume(resumeData: ResumeData, operations: Operation[]) { + // Validates operations structurally and against the schema; throws on invalid + applyResumePatches(resumeData, operations); + return { success: true as const, appliedOperations: operations }; +} diff --git a/src/integrations/auth/config.ts b/src/integrations/auth/config.ts index 7fb2f3b69..14e78f4bc 100644 --- a/src/integrations/auth/config.ts +++ b/src/integrations/auth/config.ts @@ -2,7 +2,7 @@ import { BetterAuthError } from "@better-auth/core/error"; import { passkey } from "@better-auth/passkey"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { betterAuth } from "better-auth/minimal"; -import { apiKey, type GenericOAuthConfig, genericOAuth, twoFactor } from "better-auth/plugins"; +import { apiKey, type GenericOAuthConfig, genericOAuth, openAPI, twoFactor } from "better-auth/plugins"; import { username } from "better-auth/plugins/username"; import { tanstackStartCookies } from "better-auth/tanstack-start"; import { and, eq, or } from "drizzle-orm"; @@ -211,6 +211,7 @@ const getAuthConfig = () => { }, plugins: [ + openAPI(), apiKey({ enableSessionForAPIKeys: true, rateLimit: { diff --git a/src/integrations/orpc/client.ts b/src/integrations/orpc/client.ts index 26f9c7ded..dc9b1831d 100644 --- a/src/integrations/orpc/client.ts +++ b/src/integrations/orpc/client.ts @@ -1,6 +1,6 @@ -import { createORPCClient } from "@orpc/client"; +import { createORPCClient, onError } from "@orpc/client"; import { RPCLink } from "@orpc/client/fetch"; -import { BatchLinkPlugin } from "@orpc/client/plugins"; +import { BatchLinkPlugin, SimpleCsrfProtectionLinkPlugin } from "@orpc/client/plugins"; import { createRouterClient, type InferRouterInputs, type InferRouterOutputs, type RouterClient } from "@orpc/server"; import { createTanstackQueryUtils } from "@orpc/tanstack-query"; import { createIsomorphicFn } from "@tanstack/react-start"; @@ -11,6 +11,11 @@ import { getLocale } from "@/utils/locale"; export const getORPCClient = createIsomorphicFn() .server((): RouterClient => { return createRouterClient(router, { + interceptors: [ + onError((error) => { + console.error(`ERROR [oRPC]: ${error}`); + }), + ], context: async () => { const locale = await getLocale(); const reqHeaders = getRequestHeaders(); @@ -25,10 +30,20 @@ export const getORPCClient = createIsomorphicFn() .client((): RouterClient => { const link = new RPCLink({ url: `${window.location.origin}/api/rpc`, - plugins: [new BatchLinkPlugin({ groups: [{ condition: () => true, context: {} }] })], - fetch: (request, init) => { - return fetch(request, { ...init, credentials: "include" }); - }, + fetch: (request, init) => fetch(request, { ...init, credentials: "include" }), + plugins: [ + new SimpleCsrfProtectionLinkPlugin(), + new BatchLinkPlugin({ + mode: typeof window === "undefined" ? "buffered" : "streaming", + groups: [{ condition: () => true, context: {} }], + }), + ], + interceptors: [ + onError((error) => { + if (error instanceof DOMException && error.name === "AbortError") return; + console.error(`ERROR [oRPC]: ${error}`); + }), + ], }); return createORPCClient(link); diff --git a/src/integrations/orpc/router/ai.ts b/src/integrations/orpc/router/ai.ts index 4d6c07183..ad055c7e3 100644 --- a/src/integrations/orpc/router/ai.ts +++ b/src/integrations/orpc/router/ai.ts @@ -1,11 +1,26 @@ import { ORPCError } from "@orpc/client"; -import { AISDKError } from "ai"; +import { type } from "@orpc/server"; +import { AISDKError, type UIMessage } from "ai"; +import { OllamaError } from "ai-sdk-ollama"; import z, { ZodError } from "zod"; +import type { ResumeData } from "@/schema/resume/data"; import { protectedProcedure } from "../context"; import { aiCredentialsSchema, aiProviderSchema, aiService, fileInputSchema, formatZodError } from "../services/ai"; +type AIProvider = z.infer; + export const aiRouter = { testConnection: protectedProcedure + .route({ + method: "POST", + path: "/ai/test-connection", + tags: ["AI"], + operationId: "testAiConnection", + summary: "Test AI provider connection", + description: + "Validates the connection to an AI provider by sending a simple test prompt. Requires the provider type, model name, API key, and an optional base URL. Supported providers: OpenAI, Anthropic, Google Gemini, Ollama, and Vercel AI Gateway. Requires authentication.", + successDescription: "The AI provider connection was successful.", + }) .input( z.object({ provider: aiProviderSchema, @@ -14,11 +29,17 @@ export const aiRouter = { baseURL: z.string(), }), ) + .errors({ + BAD_GATEWAY: { + message: "The AI provider returned an error or is unreachable.", + status: 502, + }, + }) .handler(async ({ input }) => { try { return await aiService.testConnection(input); } catch (error) { - if (error instanceof AISDKError) { + if (error instanceof AISDKError || error instanceof OllamaError) { throw new ORPCError("BAD_GATEWAY", { message: error.message }); } @@ -27,13 +48,29 @@ export const aiRouter = { }), parsePdf: protectedProcedure + .route({ + method: "POST", + path: "/ai/parse-pdf", + tags: ["AI"], + operationId: "parseResumePdf", + summary: "Parse a PDF file into resume data", + description: + "Extracts structured resume data from a PDF file using the specified AI provider. The file should be sent as a base64-encoded string along with AI provider credentials. Returns a complete ResumeData object. Requires authentication.", + successDescription: "The PDF was successfully parsed into structured resume data.", + }) .input( z.object({ ...aiCredentialsSchema.shape, file: fileInputSchema, }), ) - .handler(async ({ input }) => { + .errors({ + BAD_GATEWAY: { + message: "The AI provider returned an error or is unreachable.", + status: 502, + }, + }) + .handler(async ({ input }): Promise => { try { return await aiService.parsePdf(input); } catch (error) { @@ -49,6 +86,16 @@ export const aiRouter = { }), parseDocx: protectedProcedure + .route({ + method: "POST", + path: "/ai/parse-docx", + tags: ["AI"], + operationId: "parseResumeDocx", + summary: "Parse a DOCX file into resume data", + description: + "Extracts structured resume data from a DOCX or DOC file using the specified AI provider. The file should be sent as a base64-encoded string along with AI provider credentials and the document's media type. Returns a complete ResumeData object. Requires authentication.", + successDescription: "The DOCX was successfully parsed into structured resume data.", + }) .input( z.object({ ...aiCredentialsSchema.shape, @@ -59,6 +106,12 @@ export const aiRouter = { ]), }), ) + .errors({ + BAD_GATEWAY: { + message: "The AI provider returned an error or is unreachable.", + status: 502, + }, + }) .handler(async ({ input }) => { try { return await aiService.parseDocx(input); @@ -71,6 +124,38 @@ export const aiRouter = { throw new Error(formatZodError(error)); } + throw error; + } + }), + + chat: protectedProcedure + .route({ + method: "POST", + path: "/ai/chat", + tags: ["AI"], + operationId: "aiChat", + summary: "Chat with AI to modify resume", + description: + "Streams a chat response from the configured AI provider. The LLM can call the patch_resume tool to generate JSON Patch operations that modify the resume. Requires authentication and AI provider credentials.", + }) + .input( + type<{ + provider: AIProvider; + model: string; + apiKey: string; + baseURL: string; + messages: UIMessage[]; + resumeData: ResumeData; + }>(), + ) + .handler(async ({ input }) => { + try { + return await aiService.chat(input); + } catch (error) { + if (error instanceof AISDKError || error instanceof OllamaError) { + throw new ORPCError("BAD_GATEWAY", { message: error.message }); + } + throw error; } }), diff --git a/src/integrations/orpc/router/auth.ts b/src/integrations/orpc/router/auth.ts index 8764f3ce5..be00b037c 100644 --- a/src/integrations/orpc/router/auth.ts +++ b/src/integrations/orpc/router/auth.ts @@ -1,4 +1,3 @@ -import z from "zod"; import { protectedProcedure, publicProcedure } from "../context"; import { authService, type ProviderList } from "../services/auth"; @@ -7,48 +6,29 @@ export const authRouter = { list: publicProcedure .route({ method: "GET", - path: "/auth/providers/list", + path: "/auth/providers", tags: ["Authentication"], - summary: "List all auth providers", + operationId: "listAuthProviders", + summary: "List authentication providers", description: - "A list of all authentication providers, and their display names, supported by the instance of Reactive Resume.", + "Returns a list of all authentication providers enabled on this Reactive Resume instance, along with their display names. Possible providers include password-based credentials, Google, GitHub, and custom OAuth. No authentication required.", + successDescription: "A map of enabled authentication provider identifiers to their display names.", }) .handler((): ProviderList => { return authService.providers.list(); }), }, - verifyResumePassword: publicProcedure - .route({ - method: "POST", - path: "/auth/verify-resume-password", - tags: ["Authentication", "Resume"], - summary: "Verify resume password", - description: "Verify a resume password, to grant access to the locked resume.", - }) - .input( - z.object({ - slug: z.string().min(1), - username: z.string().min(1), - password: z.string().min(1), - }), - ) - .output(z.boolean()) - .handler(async ({ input }): Promise => { - return await authService.verifyResumePassword({ - slug: input.slug, - username: input.username, - password: input.password, - }); - }), - deleteAccount: protectedProcedure .route({ method: "DELETE", - path: "/auth/delete-account", + path: "/auth/account", tags: ["Authentication"], + operationId: "deleteAccount", summary: "Delete user account", - description: "Delete the authenticated user's account and all associated data.", + description: + "Permanently deletes the authenticated user's account, including all resumes, uploaded files (profile pictures, screenshots, PDFs), and associated data. This action is irreversible. Requires authentication.", + successDescription: "The user account and all associated data have been successfully deleted.", }) .handler(async ({ context }): Promise => { return await authService.deleteAccount({ userId: context.user.id }); diff --git a/src/integrations/orpc/router/flags.ts b/src/integrations/orpc/router/flags.ts index c57329c3b..71cde5d0a 100644 --- a/src/integrations/orpc/router/flags.ts +++ b/src/integrations/orpc/router/flags.ts @@ -1,3 +1,4 @@ +import z from "zod"; import { publicProcedure } from "../context"; import { type FeatureFlags, flagsService } from "../services/flags"; @@ -7,8 +8,17 @@ export const flagsRouter = { method: "GET", path: "/flags", tags: ["Feature Flags"], + operationId: "getFeatureFlags", summary: "Get feature flags", - description: "Returns the current feature flags for this instance.", + description: + "Returns the current feature flags for this Reactive Resume instance. Feature flags control instance-wide settings such as whether new user signups or email-based authentication are disabled. No authentication required.", + successDescription: "The current feature flags for this instance.", }) + .output( + z.object({ + disableSignups: z.boolean().describe("Whether new user signups are disabled on this instance."), + disableEmailAuth: z.boolean().describe("Whether email-based authentication is disabled on this instance."), + }), + ) .handler((): FeatureFlags => flagsService.getFlags()), }; diff --git a/src/integrations/orpc/router/printer.ts b/src/integrations/orpc/router/printer.ts index 7b8adedaa..3449e1329 100644 --- a/src/integrations/orpc/router/printer.ts +++ b/src/integrations/orpc/router/printer.ts @@ -7,13 +7,16 @@ export const printerRouter = { printResumeAsPDF: publicProcedure .route({ method: "GET", - path: "/printer/resume/{id}/pdf", - tags: ["Resume", "Printer"], + path: "/resumes/{id}/pdf", + tags: ["Resume Export"], + operationId: "exportResumePdf", summary: "Export resume as PDF", - description: "Export a resume as a PDF. Returns a URL to download the PDF.", + description: + "Generates a PDF from the specified resume and uploads it to storage. Returns a URL to download the generated PDF file. If the request is made by an unauthenticated user (e.g. via a public share link), the resume's download count is incremented. Authentication is optional.", + successDescription: "The PDF was generated successfully. Returns a URL to download the file.", }) - .input(z.object({ id: z.string() })) - .output(z.object({ url: z.string() })) + .input(z.object({ id: z.string().describe("The unique identifier of the resume to export.") })) + .output(z.object({ url: z.string().describe("The URL to download the generated PDF file.") })) .handler(async ({ input, context }) => { const { id, data, userId } = await resumeService.getByIdForPrinter({ id: input.id }); const url = await printerService.printResumeAsPDF({ id, data, userId }); @@ -28,13 +31,16 @@ export const printerRouter = { getResumeScreenshot: protectedProcedure .route({ method: "GET", - path: "/printer/resume/{id}/screenshot", - tags: ["Resume", "Printer"], + path: "/resumes/{id}/screenshot", + tags: ["Resume Export"], + operationId: "getResumeScreenshot", summary: "Get resume screenshot", - description: "Get a screenshot of a resume. Returns a URL to the screenshot image.", + description: + "Returns a URL to a screenshot image of the first page of the specified resume. Screenshots are cached for up to 6 hours and regenerated automatically when the resume is updated. Returns null if the screenshot cannot be generated. Requires authentication.", + successDescription: "The screenshot URL, or null if the screenshot could not be generated.", }) - .input(z.object({ id: z.string() })) - .output(z.object({ url: z.string().nullable() })) + .input(z.object({ id: z.string().describe("The unique identifier of the resume.") })) + .output(z.object({ url: z.string().nullable().describe("The URL to the screenshot image, or null.") })) .handler(async ({ input }) => { try { const { id, data, userId, updatedAt } = await resumeService.getByIdForPrinter({ id: input.id }); diff --git a/src/integrations/orpc/router/resume.ts b/src/integrations/orpc/router/resume.ts index fe7488d52..3d04e6249 100644 --- a/src/integrations/orpc/router/resume.ts +++ b/src/integrations/orpc/router/resume.ts @@ -9,10 +9,13 @@ const tagsRouter = { list: protectedProcedure .route({ method: "GET", - path: "/resume/tags/list", - tags: ["Resume"], + path: "/resumes/tags", + tags: ["Resumes"], + operationId: "listResumeTags", summary: "List all resume tags", - description: "List all tags for the authenticated user's resumes. Used to populate the filter in the dashboard.", + description: + "Returns a sorted list of all unique tags across the authenticated user's resumes. Useful for populating tag filters in the dashboard. Requires authentication.", + successDescription: "A sorted array of unique tag strings.", }) .output(z.array(z.string())) .handler(async ({ context }) => { @@ -24,19 +27,22 @@ const statisticsRouter = { getById: protectedProcedure .route({ method: "GET", - path: "/resume/statistics/{id}", - tags: ["Resume"], + path: "/resumes/{id}/statistics", + tags: ["Resume Statistics"], + operationId: "getResumeStatistics", summary: "Get resume statistics", - description: "Get the statistics for a resume, such as number of views and downloads.", + description: + "Returns view and download statistics for the specified resume, including total counts and the timestamps of the last view and download. Requires authentication.", + successDescription: "The resume's view and download statistics.", }) - .input(z.object({ id: z.string() })) + .input(z.object({ id: z.string().describe("The unique identifier of the resume.") })) .output( z.object({ - isPublic: z.boolean(), - views: z.number(), - downloads: z.number(), - lastViewedAt: z.date().nullable(), - lastDownloadedAt: z.date().nullable(), + isPublic: z.boolean().describe("Whether the resume is currently public."), + views: z.number().describe("Total number of times the resume has been viewed."), + downloads: z.number().describe("Total number of times the resume has been downloaded."), + lastViewedAt: z.date().nullable().describe("Timestamp of the last view, or null if never viewed."), + lastDownloadedAt: z.date().nullable().describe("Timestamp of the last download, or null if never downloaded."), }), ) .handler(async ({ context, input }) => { @@ -44,7 +50,7 @@ const statisticsRouter = { }), increment: publicProcedure - .route({ tags: ["Internal"], summary: "Increment resume statistics" }) + .route({ tags: ["Internal"], operationId: "incrementResumeStatistics", summary: "Increment resume statistics" }) .input(z.object({ id: z.string(), views: z.boolean().default(false), downloads: z.boolean().default(false) })) .handler(async ({ input }) => { return await resumeService.statistics.increment(input); @@ -58,10 +64,13 @@ export const resumeRouter = { list: protectedProcedure .route({ method: "GET", - path: "/resume/list", - tags: ["Resume"], + path: "/resumes", + tags: ["Resumes"], + operationId: "listResumes", summary: "List all resumes", - description: "List of all the resumes for the authenticated user.", + description: + "Returns a list of all resumes belonging to the authenticated user. Results can be filtered by tags and sorted by last updated date, creation date, or name. Resume data is not included in the response for performance; use the get endpoint to fetch full resume data. Requires authentication.", + successDescription: "A list of resumes with their metadata (without full resume data).", }) .input(resumeDto.list.input.optional().default({ tags: [], sort: "lastUpdatedAt" })) .output(resumeDto.list.output) @@ -76,10 +85,13 @@ export const resumeRouter = { getById: protectedProcedure .route({ method: "GET", - path: "/resume/{id}", - tags: ["Resume"], + path: "/resumes/{id}", + tags: ["Resumes"], + operationId: "getResume", summary: "Get resume by ID", - description: "Get a resume, along with its data, by its ID.", + description: + "Returns a single resume with its full data, identified by its unique ID. Only resumes belonging to the authenticated user can be retrieved. Requires authentication.", + successDescription: "The resume with its full data.", }) .input(resumeDto.getById.input) .output(resumeDto.getById.output) @@ -88,7 +100,7 @@ export const resumeRouter = { }), getByIdForPrinter: serverOnlyProcedure - .route({ tags: ["Internal"], summary: "Get resume by ID for printer" }) + .route({ tags: ["Internal"], operationId: "getResumeForPrinter", summary: "Get resume by ID for printer" }) .input(resumeDto.getById.input) .handler(async ({ input }) => { return await resumeService.getByIdForPrinter({ id: input.id }); @@ -97,10 +109,13 @@ export const resumeRouter = { getBySlug: publicProcedure .route({ method: "GET", - path: "/resume/{username}/{slug}", - tags: ["Resume"], - summary: "Get resume by username and slug", - description: "Get a resume, along with its data, by its username and slug.", + path: "/resumes/{username}/{slug}", + tags: ["Resume Sharing"], + operationId: "getResumeBySlug", + summary: "Get public resume by username and slug", + description: + "Returns a publicly shared resume identified by the owner's username and the resume's slug. If the resume is password-protected and the viewer has not yet verified the password, a 401 error with code NEED_PASSWORD is returned. No authentication required for public resumes; if authenticated as the owner, private resumes are also accessible.", + successDescription: "The public resume with its full data.", }) .input(resumeDto.getBySlug.input) .output(resumeDto.getBySlug.output) @@ -111,10 +126,13 @@ export const resumeRouter = { create: protectedProcedure .route({ method: "POST", - path: "/resume/create", - tags: ["Resume"], + path: "/resumes", + tags: ["Resumes"], + operationId: "createResume", summary: "Create a new resume", - description: "Create a new resume, with the ability to initialize it with sample data.", + description: + "Creates a new resume with the given name, slug, and tags. Optionally initializes the resume with sample data by setting withSampleData to true. The slug must be unique across the user's resumes. Returns the ID of the newly created resume. Requires authentication.", + successDescription: "The ID of the newly created resume.", }) .input(resumeDto.create.input) .output(resumeDto.create.output) @@ -138,10 +156,13 @@ export const resumeRouter = { import: protectedProcedure .route({ method: "POST", - path: "/resume/import", - tags: ["Resume"], + path: "/resumes/import", + tags: ["Resumes"], + operationId: "importResume", summary: "Import a resume", - description: "Import a resume from a file.", + description: + "Creates a new resume from an existing ResumeData object (e.g. from a previously exported JSON file). A random name and slug are generated automatically. Returns the ID of the imported resume. Requires authentication.", + successDescription: "The ID of the imported resume.", }) .input(resumeDto.import.input) .output(resumeDto.import.output) @@ -168,10 +189,13 @@ export const resumeRouter = { update: protectedProcedure .route({ method: "PUT", - path: "/resume/{id}", - tags: ["Resume"], + path: "/resumes/{id}", + tags: ["Resumes"], + operationId: "updateResume", summary: "Update a resume", - description: "Update a resume, along with its data, by its ID.", + description: + "Updates one or more fields of a resume identified by its ID. All fields are optional; only provided fields will be updated. Locked resumes cannot be updated. Requires authentication.", + successDescription: "The updated resume with its full data.", }) .input(resumeDto.update.input) .output(resumeDto.update.output) @@ -196,11 +220,13 @@ export const resumeRouter = { patch: protectedProcedure .route({ method: "PATCH", - path: "/resume/{id}", - tags: ["Resume"], - summary: "Patch a resume", + path: "/resumes/{id}", + tags: ["Resumes"], + operationId: "patchResume", + summary: "Patch resume data", description: - "Apply JSON Patch (RFC 6902) operations to partially update a resume's data. This allows you to make small, targeted changes without sending the entire resume object.", + "Applies JSON Patch (RFC 6902) operations to partially update a resume's data. This allows small, targeted changes (e.g. updating a single field) without sending the entire resume object. Locked resumes cannot be patched. Requires authentication.", + successDescription: "The patched resume with its full data.", }) .input(resumeDto.patch.input) .output(resumeDto.patch.output) @@ -221,10 +247,13 @@ export const resumeRouter = { setLocked: protectedProcedure .route({ method: "POST", - path: "/resume/{id}/set-locked", - tags: ["Resume"], - summary: "Set resume locked status", - description: "Toggle the locked status of a resume, by its ID.", + path: "/resumes/{id}/lock", + tags: ["Resumes"], + operationId: "setResumeLocked", + summary: "Set resume lock status", + description: + "Toggles the locked status of a resume. When locked, a resume cannot be updated, patched, or deleted. Useful for protecting finalized resumes from accidental edits. Requires authentication.", + successDescription: "The resume lock status was updated successfully.", }) .input(resumeDto.setLocked.input) .output(resumeDto.setLocked.output) @@ -238,11 +267,14 @@ export const resumeRouter = { setPassword: protectedProcedure .route({ - method: "POST", - path: "/resume/{id}/set-password", - tags: ["Resume"], - summary: "Set password on a resume", - description: "Set a password on a resume to protect it from unauthorized access when shared publicly.", + method: "PUT", + path: "/resumes/{id}/password", + tags: ["Resume Sharing"], + operationId: "setResumePassword", + summary: "Set resume password", + description: + "Sets or updates a password on a resume. When a password is set, viewers of the public resume must enter the password before the resume data is revealed. The password must be between 6 and 64 characters. Requires authentication.", + successDescription: "The resume password was set successfully.", }) .input(resumeDto.setPassword.input) .output(resumeDto.setPassword.output) @@ -254,13 +286,43 @@ export const resumeRouter = { }); }), - removePassword: protectedProcedure + verifyPassword: publicProcedure .route({ method: "POST", - path: "/resume/{id}/remove-password", - tags: ["Resume"], - summary: "Remove password from a resume", - description: "Remove password protection from a resume.", + path: "/resumes/{username}/{slug}/password/verify", + tags: ["Resume Sharing"], + operationId: "verifyResumePassword", + summary: "Verify resume password", + description: + "Verifies a password for a password-protected public resume. On success, the viewer is granted access to view the resume data for the duration of their session. No authentication required.", + successDescription: "The password was verified successfully and access has been granted.", + }) + .input( + z.object({ + username: z.string().min(1).describe("The username of the resume owner."), + slug: z.string().min(1).describe("The slug of the resume."), + password: z.string().min(1).describe("The password to verify."), + }), + ) + .output(z.boolean()) + .handler(async ({ input }): Promise => { + return await resumeService.verifyPassword({ + username: input.username, + slug: input.slug, + password: input.password, + }); + }), + + removePassword: protectedProcedure + .route({ + method: "DELETE", + path: "/resumes/{id}/password", + tags: ["Resume Sharing"], + operationId: "removeResumePassword", + summary: "Remove resume password", + description: + "Removes password protection from a resume. After removal, the resume (if public) can be viewed without entering a password. Requires authentication.", + successDescription: "The resume password was removed successfully.", }) .input(resumeDto.removePassword.input) .output(resumeDto.removePassword.output) @@ -274,10 +336,13 @@ export const resumeRouter = { duplicate: protectedProcedure .route({ method: "POST", - path: "/resume/{id}/duplicate", - tags: ["Resume"], + path: "/resumes/{id}/duplicate", + tags: ["Resumes"], + operationId: "duplicateResume", summary: "Duplicate a resume", - description: "Duplicate a resume, by its ID.", + description: + "Creates a copy of an existing resume with the same data. Optionally override the name, slug, and tags for the duplicate. If not provided, the original resume's name, slug, and tags are used. Returns the ID of the duplicated resume. Requires authentication.", + successDescription: "The ID of the duplicated resume.", }) .input(resumeDto.duplicate.input) .output(resumeDto.duplicate.output) @@ -297,10 +362,13 @@ export const resumeRouter = { delete: protectedProcedure .route({ method: "DELETE", - path: "/resume/{id}", - tags: ["Resume"], + path: "/resumes/{id}", + tags: ["Resumes"], + operationId: "deleteResume", summary: "Delete a resume", - description: "Delete a resume, by its ID.", + description: + "Permanently deletes a resume and its associated files (screenshots, PDFs) from storage. Locked resumes cannot be deleted; unlock the resume first. Requires authentication.", + successDescription: "The resume and its associated files were deleted successfully.", }) .input(resumeDto.delete.input) .output(resumeDto.delete.output) diff --git a/src/integrations/orpc/router/statistics.ts b/src/integrations/orpc/router/statistics.ts index 791b8c8f4..572f91eb3 100644 --- a/src/integrations/orpc/router/statistics.ts +++ b/src/integrations/orpc/router/statistics.ts @@ -6,12 +6,15 @@ const userRouter = { getCount: publicProcedure .route({ method: "GET", - path: "/statistics/user/count", - tags: ["Statistics"], + path: "/statistics/users", + tags: ["Platform Statistics"], + operationId: "getUserCount", summary: "Get total number of users", - description: "Get the total number of users for the Reactive Resume.", + description: + "Returns the total number of registered users on this Reactive Resume instance. The count is cached for up to 6 hours for performance. No authentication required.", + successDescription: "The total number of registered users.", }) - .output(z.number()) + .output(z.number().describe("The total number of registered users.")) .handler(async (): Promise => { return await statisticsService.user.getCount(); }), @@ -21,12 +24,15 @@ const resumeRouter = { getCount: publicProcedure .route({ method: "GET", - path: "/statistics/resume/count", - tags: ["Statistics"], + path: "/statistics/resumes", + tags: ["Platform Statistics"], + operationId: "getResumeCount", summary: "Get total number of resumes", - description: "Get the total number of resumes for the Reactive Resume.", + description: + "Returns the total number of resumes created on this Reactive Resume instance. The count is cached for up to 6 hours for performance. No authentication required.", + successDescription: "The total number of resumes created.", }) - .output(z.number()) + .output(z.number().describe("The total number of resumes created.")) .handler(async (): Promise => { return await statisticsService.resume.getCount(); }), @@ -37,11 +43,14 @@ const githubRouter = { .route({ method: "GET", path: "/statistics/github/stars", - tags: ["Statistics"], - summary: "Get GitHub Repository stargazers count", - description: "Get the stargazers count for the Reactive Resume GitHub repository, at the time of writing.", + tags: ["Platform Statistics"], + operationId: "getGitHubStarCount", + summary: "Get GitHub star count", + description: + "Returns the number of GitHub stars for the Reactive Resume repository. The count is cached for up to 6 hours and falls back to a last-known value if the GitHub API is unavailable. No authentication required.", + successDescription: "The number of GitHub stars for the Reactive Resume repository.", }) - .output(z.number()) + .output(z.number().describe("The number of GitHub stars.")) .handler(async (): Promise => { return await statisticsService.github.getStarCount(); }), diff --git a/src/integrations/orpc/router/storage.ts b/src/integrations/orpc/router/storage.ts index 1cb15a24c..532cd50ab 100644 --- a/src/integrations/orpc/router/storage.ts +++ b/src/integrations/orpc/router/storage.ts @@ -7,17 +7,26 @@ const storageService = getStorageService(); const fileSchema = z.file().max(10 * 1024 * 1024, "File size must be less than 10MB"); -const filenameSchema = z.object({ filename: z.string().min(1) }); +const filenameSchema = z.object({ + filename: z.string().min(1).describe("The path or filename of the file to delete."), +}); export const storageRouter = { uploadFile: protectedProcedure - .route({ tags: ["Internal"], summary: "Upload a file" }) + .route({ + tags: ["Internal"], + operationId: "uploadFile", + summary: "Upload a file", + description: + "Uploads a file to storage. Images are automatically resized and converted to WebP format. Maximum file size is 10MB. Requires authentication.", + successDescription: "The file was uploaded successfully.", + }) .input(fileSchema) .output( z.object({ - url: z.string(), - path: z.string(), - contentType: z.string(), + url: z.string().describe("The public URL to access the uploaded file."), + path: z.string().describe("The storage path of the uploaded file."), + contentType: z.string().describe("The MIME type of the uploaded file."), }), ) .handler(async ({ context, input: file }) => { @@ -52,9 +61,22 @@ export const storageRouter = { }), deleteFile: protectedProcedure - .route({ tags: ["Internal"], summary: "Delete a file" }) + .route({ + tags: ["Internal"], + operationId: "deleteFile", + summary: "Delete a file", + description: + "Deletes a file from storage by its filename or path. If the filename does not start with 'uploads/', the user's picture directory is assumed. Requires authentication.", + successDescription: "The file was deleted successfully.", + }) .input(filenameSchema) .output(z.void()) + .errors({ + NOT_FOUND: { + message: "The specified file was not found in storage.", + status: 404, + }, + }) .handler(async ({ context, input }): Promise => { // The filename is now the full path from the URL (e.g., "uploads/userId/pictures/timestamp.webp") // We need to extract just the path portion that matches the storage key diff --git a/src/integrations/orpc/services/ai.ts b/src/integrations/orpc/services/ai.ts index 732bcfbc8..3592e44dc 100644 --- a/src/integrations/orpc/services/ai.ts +++ b/src/integrations/orpc/services/ai.ts @@ -1,15 +1,31 @@ import { createAnthropic } from "@ai-sdk/anthropic"; import { createGoogleGenerativeAI } from "@ai-sdk/google"; import { createOpenAI } from "@ai-sdk/openai"; -import { createGateway, generateText, Output } from "ai"; +import { streamToEventIterator } from "@orpc/server"; +import { + convertToModelMessages, + createGateway, + generateText, + Output, + stepCountIs, + streamText, + tool, + type UIMessage, +} from "ai"; import { createOllama } from "ai-sdk-ollama"; import { match } from "ts-pattern"; import type { ZodError } from "zod"; import z, { flattenError } from "zod"; +import chatSystemPromptTemplate from "@/integrations/ai/prompts/chat-system.md?raw"; import docxParserSystemPrompt from "@/integrations/ai/prompts/docx-parser-system.md?raw"; import docxParserUserPrompt from "@/integrations/ai/prompts/docx-parser-user.md?raw"; import pdfParserSystemPrompt from "@/integrations/ai/prompts/pdf-parser-system.md?raw"; import pdfParserUserPrompt from "@/integrations/ai/prompts/pdf-parser-user.md?raw"; +import { + executePatchResume, + patchResumeDescription, + patchResumeInputSchema, +} from "@/integrations/ai/tools/patch-resume"; import type { ResumeData } from "@/schema/resume/data"; import { defaultResumeData, resumeDataSchema } from "@/schema/resume/data"; @@ -141,8 +157,39 @@ export function formatZodError(error: ZodError): string { return JSON.stringify(flattenError(error)); } +function buildChatSystemPrompt(resumeData: ResumeData): string { + return chatSystemPromptTemplate.replace("{{RESUME_DATA}}", JSON.stringify(resumeData, null, 2)); +} + +type ChatInput = z.infer & { + messages: UIMessage[]; + resumeData: ResumeData; +}; + +async function chat(input: ChatInput) { + const model = getModel(input); + const systemPrompt = buildChatSystemPrompt(input.resumeData); + + const result = streamText({ + model, + system: systemPrompt, + messages: await convertToModelMessages(input.messages), + tools: { + patch_resume: tool({ + description: patchResumeDescription, + inputSchema: patchResumeInputSchema, + execute: async ({ operations }) => executePatchResume(input.resumeData, operations), + }), + }, + stopWhen: stepCountIs(3), + }); + + return streamToEventIterator(result.toUIMessageStream()); +} + export const aiService = { testConnection, parsePdf, parseDocx, + chat, }; diff --git a/src/integrations/orpc/services/auth.ts b/src/integrations/orpc/services/auth.ts index 8b1a0f26d..3db775ec2 100644 --- a/src/integrations/orpc/services/auth.ts +++ b/src/integrations/orpc/services/auth.ts @@ -1,11 +1,9 @@ import { ORPCError } from "@orpc/client"; -import { and, eq, isNotNull } from "drizzle-orm"; +import { eq } from "drizzle-orm"; import type { AuthProvider } from "@/integrations/auth/types"; import { schema } from "@/integrations/drizzle"; import { db } from "@/integrations/drizzle/client"; import { env } from "@/utils/env"; -import { verifyPassword } from "@/utils/password"; -import { grantResumeAccess } from "../helpers/resume-access"; import { getStorageService } from "./storage"; export type ProviderList = Partial>; @@ -25,31 +23,6 @@ const providers = { export const authService = { providers, - verifyResumePassword: async (input: { slug: string; username: string; password: string }): Promise => { - const [resume] = await db - .select({ id: schema.resume.id, password: schema.resume.password }) - .from(schema.resume) - .innerJoin(schema.user, eq(schema.resume.userId, schema.user.id)) - .where( - and( - isNotNull(schema.resume.password), - eq(schema.resume.slug, input.slug), - eq(schema.user.username, input.username), - ), - ); - - if (!resume) throw new ORPCError("NOT_FOUND"); - - const passwordHash = resume.password as string; - const isValid = await verifyPassword(input.password, passwordHash); - - if (!isValid) throw new ORPCError("INVALID_PASSWORD"); - - grantResumeAccess(resume.id, passwordHash); - - return true; - }, - deleteAccount: async (input: { userId: string }): Promise => { if (!input.userId || input.userId.length === 0) return; diff --git a/src/integrations/orpc/services/resume.ts b/src/integrations/orpc/services/resume.ts index 0c75cd08a..4c332dea7 100644 --- a/src/integrations/orpc/services/resume.ts +++ b/src/integrations/orpc/services/resume.ts @@ -1,5 +1,5 @@ import { ORPCError } from "@orpc/client"; -import { and, arrayContains, asc, desc, eq, sql } from "drizzle-orm"; +import { and, arrayContains, asc, desc, eq, isNotNull, sql } from "drizzle-orm"; import { get } from "es-toolkit/compat"; import type { Operation } from "fast-json-patch"; import { match } from "ts-pattern"; @@ -9,10 +9,10 @@ import type { ResumeData } from "@/schema/resume/data"; import { defaultResumeData } from "@/schema/resume/data"; import { env } from "@/utils/env"; import type { Locale } from "@/utils/locale"; -import { hashPassword } from "@/utils/password"; +import { hashPassword, verifyPassword } from "@/utils/password"; import { applyResumePatches, ResumePatchError } from "@/utils/resume/patch"; import { generateId } from "@/utils/string"; -import { hasResumeAccess } from "../helpers/resume-access"; +import { grantResumeAccess, hasResumeAccess } from "../helpers/resume-access"; import { getStorageService } from "./storage"; const tags = { @@ -383,6 +383,31 @@ export const resumeService = { .where(and(eq(schema.resume.id, input.id), eq(schema.resume.userId, input.userId))); }, + verifyPassword: async (input: { slug: string; username: string; password: string }) => { + const [resume] = await db + .select({ id: schema.resume.id, password: schema.resume.password }) + .from(schema.resume) + .innerJoin(schema.user, eq(schema.resume.userId, schema.user.id)) + .where( + and( + isNotNull(schema.resume.password), + eq(schema.resume.slug, input.slug), + eq(schema.user.username, input.username), + ), + ); + + if (!resume) throw new ORPCError("NOT_FOUND"); + + const passwordHash = resume.password as string; + const isValid = await verifyPassword(input.password, passwordHash); + + if (!isValid) throw new ORPCError("INVALID_PASSWORD"); + + grantResumeAccess(resume.id, passwordHash); + + return true; + }, + removePassword: async (input: { id: string; userId: string }) => { await db .update(schema.resume) diff --git a/src/routes/api/auth.$.ts b/src/routes/api/auth.$.ts index 4ddbb99d7..5123e2680 100644 --- a/src/routes/api/auth.$.ts +++ b/src/routes/api/auth.$.ts @@ -1,7 +1,13 @@ import { createFileRoute } from "@tanstack/react-router"; import { auth } from "@/integrations/auth/config"; -function handler({ request }: { request: Request }) { +async function handler({ request }: { request: Request }) { + if (request.method === "GET" && request.url.endsWith("/spec.json")) { + const spec = await auth.api.generateOpenAPISchema(); + + return Response.json(spec); + } + return auth.handler(request); } diff --git a/src/routes/api/openapi.$.ts b/src/routes/api/openapi.$.ts index d28833a24..c9ec52ff4 100644 --- a/src/routes/api/openapi.$.ts +++ b/src/routes/api/openapi.$.ts @@ -2,25 +2,28 @@ import { SmartCoercionPlugin } from "@orpc/json-schema"; import { OpenAPIGenerator } from "@orpc/openapi"; import { OpenAPIHandler } from "@orpc/openapi/fetch"; import { onError } from "@orpc/server"; -import { RequestHeadersPlugin } from "@orpc/server/plugins"; +import { BatchHandlerPlugin, RequestHeadersPlugin, StrictGetMethodPlugin } from "@orpc/server/plugins"; import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4"; import { createFileRoute } from "@tanstack/react-router"; import router from "@/integrations/orpc/router"; +import { resumeDataSchema } from "@/schema/resume/data"; import { env } from "@/utils/env"; import { getLocale } from "@/utils/locale"; const openAPIHandler = new OpenAPIHandler(router, { + plugins: [ + new BatchHandlerPlugin(), + new RequestHeadersPlugin(), + new StrictGetMethodPlugin(), + new SmartCoercionPlugin({ + schemaConverters: [new ZodToJsonSchemaConverter()], + }), + ], interceptors: [ onError((error) => { console.error(`ERROR [OpenAPI]: ${error}`); }), ], - plugins: [ - new RequestHeadersPlugin(), - new SmartCoercionPlugin({ - schemaConverters: [new ZodToJsonSchemaConverter()], - }), - ], }); const openAPIGenerator = new OpenAPIGenerator({ @@ -34,13 +37,16 @@ async function handler({ request }: { request: Request }) { const spec = await openAPIGenerator.generate(router, { info: { title: "Reactive Resume", - version: "5.0.0", + version: __APP_VERSION__, description: "Reactive Resume API", license: { name: "MIT", url: "https://github.com/amruthpillai/reactive-resume/blob/main/LICENSE" }, contact: { name: "Amruth Pillai", email: "hello@amruthpillai.com", url: "https://amruthpillai.com" }, }, servers: [{ url: `${env.APP_URL}/api/openapi` }], externalDocs: { url: "https://docs.rxresu.me", description: "Reactive Resume Documentation" }, + commonSchemas: { + ResumeData: { schema: resumeDataSchema }, + }, components: { securitySchemes: { apiKey: { diff --git a/src/routes/api/rpc.$.ts b/src/routes/api/rpc.$.ts index 5e22af1d4..fe4594155 100644 --- a/src/routes/api/rpc.$.ts +++ b/src/routes/api/rpc.$.ts @@ -1,17 +1,27 @@ import { onError } from "@orpc/server"; import { RPCHandler } from "@orpc/server/fetch"; -import { BatchHandlerPlugin, RequestHeadersPlugin } from "@orpc/server/plugins"; +import { + BatchHandlerPlugin, + RequestHeadersPlugin, + SimpleCsrfProtectionHandlerPlugin, + StrictGetMethodPlugin, +} from "@orpc/server/plugins"; import { createFileRoute } from "@tanstack/react-router"; import router from "@/integrations/orpc/router"; import { getLocale } from "@/utils/locale"; const rpcHandler = new RPCHandler(router, { + plugins: [ + new BatchHandlerPlugin(), + new RequestHeadersPlugin(), + new StrictGetMethodPlugin(), + new SimpleCsrfProtectionHandlerPlugin(), + ], interceptors: [ onError((error) => { console.error(`ERROR [oRPC]: ${error}`); }), ], - plugins: [new BatchHandlerPlugin(), new RequestHeadersPlugin()], }); async function handler({ request }: { request: Request }) { diff --git a/src/routes/auth/resume-password.tsx b/src/routes/auth/resume-password.tsx index 26c47dcc1..a40a19631 100644 --- a/src/routes/auth/resume-password.tsx +++ b/src/routes/auth/resume-password.tsx @@ -44,7 +44,7 @@ function RouteComponent() { const { redirect } = Route.useSearch(); const [showPassword, toggleShowPassword] = useToggle(false); - const { mutate: verifyPassword } = useMutation(orpc.auth.verifyResumePassword.mutationOptions()); + const { mutate: verifyPassword } = useMutation(orpc.resume.verifyPassword.mutationOptions()); const [username, slug] = useMemo(() => { const [username, slug] = redirect.split("/").slice(1) as [string, string]; diff --git a/src/routes/builder/$resumeId/-components/dock.tsx b/src/routes/builder/$resumeId/-components/dock.tsx index 893c20bd0..ea906260f 100644 --- a/src/routes/builder/$resumeId/-components/dock.tsx +++ b/src/routes/builder/$resumeId/-components/dock.tsx @@ -19,6 +19,7 @@ import { useHotkeys } from "react-hotkeys-hook"; import { useControls } from "react-zoom-pan-pinch"; import { toast } from "sonner"; import { useCopyToClipboard } from "usehooks-ts"; +import { AIChat } from "@/components/ai/chat"; import { useTemporalStore } from "@/components/resume/store/resume"; import { Button } from "@/components/ui/button"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; @@ -121,6 +122,7 @@ export function BuilderDock() { zoomOut(0.1)} /> centerView()} />
    + onCopyUrl()} /> onDownloadJSON()} /> - + - + div { - box-sizing: border-box !important; - display: block !important; - width: 100% !important; - min-width: 0 !important; - max-width: 100% !important; -} - -[data-slot="scroll-area-viewport"] { - box-sizing: border-box !important; - width: 100% !important; - max-width: 100% !important; -} diff --git a/src/utils/string.ts b/src/utils/string.ts index ba03ff611..11af0fd29 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -64,7 +64,7 @@ export function generateRandomName() { * @param html - The HTML string to strip. * @returns The text content without HTML tags. */ -export function stripHtml(html: string | undefined) { +export function stripHtml(html: string | undefined): string { if (!html) return ""; return html.replace(/<[^>]*>/g, "").trim(); } diff --git a/tsconfig.json b/tsconfig.json index e35230990..eb704e2ff 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,7 +25,6 @@ "noUncheckedSideEffectImports": false, /* Paths */ - "baseUrl": ".", "paths": { "@/*": ["./src/*"] }