Compare commits

...
13 Commits
Author SHA1 Message Date
Amruth Pillai 712298843b chore(release): v5.3.2 (#3542) 2026-09-26 02:55:57 +02:00
Amruth Pillai 8c40313980 feat(deploy): support Vercel Hobby alongside Docker (#3541)
* feat(deploy): support Vercel Hobby alongside Docker

* fix(deploy): include PDFKit runtime font assets

* docs(deploy): document Vercel and Docker setup

* docs(deploy): record storage persistence checks

* refactor(deploy): drop scheduled staging cleanup

Staging uploads are deleted after finalization and expired ones are swept
on each new upload, so the Vercel cron job, its route, and CRON_SECRET are
no longer needed. The Deploy with Vercel wizard now asks for two secrets.

* docs(deploy): restructure Vercel guides

Split the Vercel page into a how-to with its environment reference, move the
large RPC staging protocol to an API reference page, and move CI deployment
checks to the contributing section. Point Deploy with Vercel buttons at main.

* chore: remove agent planning records and fix web app description

Delete superpowers plans/specs, ADRs, issue plans, execution briefs, domain
context maps, and Europass research. Describe apps/web as a TanStack Router
SPA served by apps/server.

* refactor(deploy): simplify Vercel support code

- Share one Redis client and key namespace through @reactive-resume/db/redis
  for API and auth instead of a second auth-only client.
- Drop the auth seeding retry; the provider already treats concurrent inserts
  as no-ops and deployment preparation seeds before runtime.
- Detect staging support from POST /api/storage/stage (404 on Docker) instead
  of a separate GET probe.
- Read staged bodies directly; the signed upload already caps their size.
- Close per-subscription Redis connections with disconnect() alone.
- Check Blob health with one list call instead of write/read/delete.
- Remove redundant tsdown onlyBundle list, dead namespace fallbacks, and the
  conditional spread in the health status.

* fix(deploy): heal stopped runs with dead owners and keep auth up without Redis

- Run owners refresh a Redis heartbeat until they release their claim. Stop
  requests reap the run immediately when the owner has stopped heartbeating,
  instead of leaving the thread blocked until the 15-minute TTL reaper.
- Auth and oRPC rate limiters fall back to per-instance memory limits when
  Redis errors, instead of rejecting every login or failing requests.

* ci: allow esbuild build for Vercel CLI and register deployment deps with knip

pnpm 12 fails dlx installs with ignored build scripts, so allow esbuild
explicitly. The server bundle keeps @vercel/blob, ioredis, and jose external,
and api/index.mjs is the Vercel Function entry.

* fix(web): send buffered RPC bodies instead of teed streams

Reading a request clone turned the original body into a stream, which
browsers send without inspectable request data and which needs duplex
mode. Send the already buffered Blob for direct requests.

* fix(web): send direct RPC bodies as bytes

Blob request bodies are sent as data pipes, so browser tooling cannot
inspect them. Buffer the original request as an ArrayBuffer and send those
bytes; this restores the e2e save assertions that match on request data.
2026-09-26 02:37:22 +02:00
Amruth Pillai 73ed3f9b03 chore(server): update version from 5.2.2 to 5.3.1 2026-09-23 00:12:42 +02:00
Lihan YANGandAmruth Pillai f0bc26cb3d fix(ci): restore Docker publishing with portable runner fallbacks (#3533)
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-09-22 17:07:28 +02:00
s3kfm 0ac320b0e9 fix(web): enabled drag and drop by moving file input on top of the button (#3529) 2026-09-22 14:32:34 +02:00
PerryLinkandAmruth Pillai d3131e0977 fix(import): reject out-of-range months that render as "undefined" (#3527)
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-09-21 19:47:02 +02:00
Santhi PrakashandAmruth Pillai 28d0170b05 fix(resume): detect section headings set in a side column (#3521)
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-09-21 19:46:46 +02:00
Santhi PrakashandAmruth Pillai ac69dd3f1a fix(server): verify migrated schema at startup (#3513)
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-09-21 19:46:36 +02:00
Amruth Pillai 3d4ae8679a Update Star History chart sources in README 2026-09-21 16:30:51 +02:00
Amruth Pillai 4fde62df6d chore: update dependencies 2026-09-19 22:05:55 +02:00
Amruth Pillai b5ff720f9d chore: update translations 2026-09-17 22:27:22 +02:00
Amruth Pillai b953435f2c fix: audit code for reduction 2026-09-17 22:16:44 +02:00
Amruth Pillai a30bf371ff docs: add IDEA.md as a symlink to AGENTS.md 2026-09-17 21:16:00 +02:00
369 changed files with 5487 additions and 23151 deletions
+23 -2
View File
@@ -13,11 +13,22 @@ APP_URL="http://localhost:3000"
# Unset or blank keeps the marketing home. Restart after changes.
# ROOT_RESUME_ID=
# Vercel: APP_URL can be omitted; production uses VERCEL_PROJECT_PRODUCTION_URL.
# --- Database (PostgreSQL) ---
# PostgreSQL connection URL. In Docker Compose, the hostname is usually `postgres`;
# when running directly on your machine, `localhost` is typical.
DATABASE_URL="postgresql://postgres:postgres@postgres:5432/postgres"
# Optional direct connection for migrations (Neon: DATABASE_URL_UNPOOLED alias).
# DATABASE_MIGRATION_URL=""
# DATABASE_POOL_MAX="10"
# When "true", the server refuses to boot if the live database schema has drifted from
# the migration ledger (e.g. a table dropped outside migrations). Default "false" logs
# the drift loudly at startup and continues.
STRICT_SCHEMA_CHECK="false"
# --- Authentication ---
# Generated using `openssl rand -hex 32`
AUTH_SECRET="change-me-to-a-secure-secret-key-in-production"
@@ -66,7 +77,15 @@ SMTP_FROM="Reactive Resume <noreply@rxresu.me>"
SMTP_SECURE="false"
# --- Storage (optional) ---
# If all S3 keys are disabled, the app uses local filesystem storage instead.
# Backend defaults to S3 when all credentials are present, otherwise local.
# Vercel defaults to private Blob. Explicit selection: local, s3, blob.
# STORAGE_BACKEND="local"
# BLOB_READ_WRITE_TOKEN=""
# BLOB_STORE_ID=""
# DEPLOYMENT_NAMESPACE="default"
# Vercel previews need isolated resources before setting ALLOW_PREVIEW_MIGRATIONS=true.
# If all S3 keys are disabled, Docker uses local filesystem storage instead.
# Make sure to mount this directory to a volume or the host filesystem to ensure data integrity.
# LOCAL_STORAGE_PATH overrides where local uploads/cache are written.
# Defaults to /app/data in the official Docker image; in dev, defaults to <workspace>/data.
@@ -81,7 +100,9 @@ S3_BUCKET="reactive-resume"
S3_FORCE_PATH_STYLE="true"
# --- AI Agent Workspace (optional) ---
# Required only for the authenticated /agent workspace and saved AI providers.
# Required for the authenticated /agent workspace and saved AI providers.
# Redis also shares rate limits, resume events, cancellation and view deduplication.
# Vercel Upstash KV_URL is accepted as an alias for REDIS_URL.
REDIS_URL="redis://redis:6379"
ENCRYPTION_SECRET="change-me-to-a-secure-agent-secret-in-production"
+1 -1
View File
@@ -13,7 +13,7 @@ env:
jobs:
autofix:
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ vars.CI_RUNNER_X64 || 'ubuntu-latest' }}
steps:
- name: Checkout Repository
+1 -1
View File
@@ -10,7 +10,7 @@ concurrency:
jobs:
crowdin-sync:
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ vars.CI_RUNNER_X64 || 'ubuntu-latest' }}
permissions:
contents: write
+68 -28
View File
@@ -24,7 +24,7 @@ env:
jobs:
mode:
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ vars.CI_RUNNER_X64 || 'ubuntu-latest' }}
outputs:
nightly: ${{ steps.mode.outputs.nightly }}
@@ -61,10 +61,10 @@ jobs:
matrix:
include:
- platform: linux/amd64
runner: blacksmith-32vcpu-ubuntu-2404
runner: ${{ vars.CI_RUNNER_X64 || 'ubuntu-latest' }}
arch: amd64
- platform: linux/arm64
runner: blacksmith-32vcpu-ubuntu-2404-arm
runner: ${{ vars.CI_RUNNER_ARM64 || 'ubuntu-24.04-arm' }}
arch: arm64
runs-on: ${{ matrix.runner }}
@@ -80,12 +80,38 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Setup Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@v2
with:
cache-key: Dockerfile-${{ matrix.arch }}
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v4
- &registries
name: Determine registries
id: registries
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: |
set -euo pipefail
dockerhub=false
ghcr_image="${GHCR_IMAGE,,}"
docker_image="${DOCKER_IMAGE,,}"
images="$ghcr_image"
if [[ -n "$DOCKER_USERNAME" && -n "$DOCKER_PASSWORD" ]]; then
dockerhub=true
images="${images}"$'\n'"$docker_image"
fi
{
echo "ghcr_image=$ghcr_image"
echo "docker_image=$docker_image"
echo "images<<EOF"
echo "$images"
echo "EOF"
echo "dockerhub=$dockerhub"
} >> "$GITHUB_OUTPUT"
- name: Login to Docker Hub
if: ${{ steps.registries.outputs.dockerhub == 'true' }}
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
@@ -102,15 +128,13 @@ jobs:
id: meta
uses: docker/metadata-action@v6
with:
images: |
${{ env.GHCR_IMAGE }}
${{ env.DOCKER_IMAGE }}
images: ${{ steps.registries.outputs.images }}
tags: |
type=sha,prefix=sha-,suffix=-${{ matrix.arch }}
- name: Cache-only smoke build
if: ${{ needs.mode.outputs.canary == 'true' }}
uses: useblacksmith/build-push-action@v2
uses: docker/build-push-action@v7
with:
context: .
platforms: ${{ matrix.platform }}
@@ -118,7 +142,7 @@ jobs:
- name: Build and Push by Digest
id: build
uses: useblacksmith/build-push-action@v2
uses: docker/build-push-action@v7
with:
context: .
sbom: true
@@ -148,7 +172,11 @@ jobs:
- mode
- build
timeout-minutes: 30
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ vars.CI_RUNNER_X64 || 'ubuntu-latest' }}
env:
DEPLOY: ${{ secrets.SSH_KEY != '' && secrets.SSH_HOST != '' && secrets.SSH_USER != '' }}
PURGE_CLOUDFLARE: ${{ secrets.CLOUDFLARE_ZONE_ID != '' && secrets.CLOUDFLARE_API_TOKEN != '' }}
permissions:
contents: read
@@ -177,7 +205,10 @@ jobs:
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v4
- *registries
- name: Login to Docker Hub
if: ${{ steps.registries.outputs.dockerhub == 'true' }}
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
@@ -204,9 +235,7 @@ jobs:
id: meta
uses: docker/metadata-action@v6
with:
images: |
${{ env.GHCR_IMAGE }}
${{ env.DOCKER_IMAGE }}
images: ${{ steps.registries.outputs.images }}
tags: |
type=sha,prefix=sha-
type=raw,value=canary-${{ github.run_id }}-${{ github.run_attempt }},enable=${{ needs.mode.outputs.canary == 'true' }}
@@ -241,14 +270,17 @@ jobs:
--annotation "index:org.opencontainers.image.documentation=https://docs.rxresu.me" \
--annotation "index:org.opencontainers.image.source=https://github.com/${{ github.repository }}" \
--annotation "index:org.opencontainers.image.version=${{ steps.version.outputs.version }}" \
$(printf '${{ env.GHCR_IMAGE }}@sha256:%s ' *)
$(printf '${{ steps.registries.outputs.ghcr_image }}@sha256:%s ' *)
# Get the digest of the multi-arch manifest
GHCR_DIGEST=$(docker buildx imagetools inspect ${{ env.GHCR_IMAGE }}:${FINAL_TAG} --format '{{json .Manifest.Digest}}' | tr -d '"')
DOCKER_DIGEST=$(docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}:${FINAL_TAG} --format '{{json .Manifest.Digest}}' | tr -d '"')
GHCR_DIGEST=$(docker buildx imagetools inspect ${{ steps.registries.outputs.ghcr_image }}:${FINAL_TAG} --format '{{json .Manifest.Digest}}' | tr -d '"')
echo "final_tag=$FINAL_TAG" >> "$GITHUB_OUTPUT"
echo "ghcr_digest=$GHCR_DIGEST" >> "$GITHUB_OUTPUT"
echo "docker_digest=$DOCKER_DIGEST" >> "$GITHUB_OUTPUT"
if [[ "${{ steps.registries.outputs.dockerhub }}" == "true" ]]; then
DOCKER_DIGEST=$(docker buildx imagetools inspect ${{ steps.registries.outputs.docker_image }}:${FINAL_TAG} --format '{{json .Manifest.Digest}}' | tr -d '"')
echo "docker_digest=$DOCKER_DIGEST" >> "$GITHUB_OUTPUT"
fi
- name: Install Cosign
uses: sigstore/cosign-installer@v3
@@ -256,15 +288,19 @@ jobs:
- name: Sign images with Cosign
run: |
# Sign GHCR image
cosign sign --yes ${{ env.GHCR_IMAGE }}@${{ steps.manifest.outputs.ghcr_digest }}
cosign sign --yes ${{ steps.registries.outputs.ghcr_image }}@${{ steps.manifest.outputs.ghcr_digest }}
# Sign Docker Hub image
cosign sign --yes ${{ env.DOCKER_IMAGE }}@${{ steps.manifest.outputs.docker_digest }}
if [[ "${{ steps.registries.outputs.dockerhub }}" == "true" ]]; then
# Sign Docker Hub image
cosign sign --yes ${{ steps.registries.outputs.docker_image }}@${{ steps.manifest.outputs.docker_digest }}
fi
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.GHCR_IMAGE }}:${{ steps.manifest.outputs.final_tag }}
docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}:${{ steps.manifest.outputs.final_tag }}
docker buildx imagetools inspect ${{ steps.registries.outputs.ghcr_image }}:${{ steps.manifest.outputs.final_tag }}
if [[ "${{ steps.registries.outputs.dockerhub }}" == "true" ]]; then
docker buildx imagetools inspect ${{ steps.registries.outputs.docker_image }}:${{ steps.manifest.outputs.final_tag }}
fi
- name: Verify anonymous pulls on both architectures
run: |
@@ -273,7 +309,11 @@ jobs:
trap 'rm -rf "$registry_config"' EXIT
# Prevent Docker from discovering a system credential helper.
printf '%s\n' '{"auths":{"ghcr.io":{},"https://index.docker.io/v1/":{}}}' > "$registry_config/config.json"
for image in "$GHCR_IMAGE" "$DOCKER_IMAGE"; do
images=("${{ steps.registries.outputs.ghcr_image }}")
if [[ "${{ steps.registries.outputs.dockerhub }}" == "true" ]]; then
images+=("${{ steps.registries.outputs.docker_image }}")
fi
for image in "${images[@]}"; do
for platform in linux/amd64 linux/arm64; do
docker --config "$registry_config" pull --quiet --platform "$platform" \
"$image:${{ steps.manifest.outputs.final_tag }}"
@@ -281,7 +321,7 @@ jobs:
done
- name: Redeploy Stack
if: ${{ needs.mode.outputs.release == 'true' }}
if: ${{ needs.mode.outputs.release == 'true' && env.DEPLOY == 'true' }}
uses: appleboy/ssh-action@v1
with:
key: ${{ secrets.SSH_KEY }}
@@ -292,7 +332,7 @@ jobs:
./manage_stack.sh up reactive_resume
- name: Purge Cloudflare cache
if: ${{ needs.mode.outputs.release == 'true' }}
if: ${{ needs.mode.outputs.release == 'true' && env.PURGE_CLOUDFLARE == 'true' }}
env:
CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+2 -7
View File
@@ -20,7 +20,7 @@ env:
jobs:
e2e:
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ vars.CI_RUNNER_X64 || 'ubuntu-latest' }}
timeout-minutes: 30
services:
@@ -58,12 +58,7 @@ jobs:
- name: Install Playwright Browser
timeout-minutes: 10
run: |
# The runner's Ubuntu archive/security mirrors time out during dependency installation.
printf '%s\n' 'https://mirrors.edge.kernel.org/ubuntu/' | sudo tee /etc/apt/blacksmith-ubuntu-mirrors.txt > /dev/null
sudo find /etc/apt -type f \( -name '*.list' -o -name '*.sources' \) \
-exec sed -i -E 's#https?://(archive|us\.archive|security)\.ubuntu\.com/ubuntu#https://mirrors.edge.kernel.org/ubuntu#g' {} +
pnpm exec playwright install --with-deps chromium
run: pnpm exec playwright install --with-deps chromium
- name: Generate Test Secrets
run: |
+1 -1
View File
@@ -10,7 +10,7 @@ permissions:
jobs:
label:
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ vars.CI_RUNNER_X64 || 'ubuntu-latest' }}
steps:
- name: Checkout Repository
+1 -1
View File
@@ -10,7 +10,7 @@ permissions:
jobs:
stale:
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ vars.CI_RUNNER_X64 || 'ubuntu-latest' }}
steps:
- name: Close Inactive Issues Awaiting Information
+99
View File
@@ -0,0 +1,99 @@
name: Vercel compatibility
on:
pull_request:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
artifact:
runs-on: ${{ vars.CI_RUNNER_X64 || 'ubuntu-latest' }}
timeout-minutes: 20
services:
postgres:
image: postgres:17-alpine
env:
POSTGRES_PASSWORD: postgres
ports: [5432:5432]
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s --health-timeout 5s --health-retries 10
env:
APP_URL: http://localhost:3000
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/postgres
AUTH_SECRET: isolated-ci-auth-secret-32-characters
ENCRYPTION_SECRET: isolated-ci-encryption-secret-32-characters
REDIS_URL: redis://localhost:6379
STORAGE_BACKEND: blob
BLOB_READ_WRITE_TOKEN: vercel_blob_rw_ci_fake_build_only
VERCEL: "1"
VERCEL_ENV: production
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install --frozen-lockfile
# Local project settings avoid authentication and API calls. Forks receive no cloud credentials.
- name: Build Vercel artifact against isolated PostgreSQL
run: |
mkdir -p .vercel
node --input-type=module - <<'JS'
import { writeFileSync } from 'node:fs';
writeFileSync('.vercel/project.json', JSON.stringify({
projectId: 'prj_ci', orgId: 'team_ci', projectName: 'reactive-resume-ci',
settings: { framework: null, nodeVersion: '24.x', createdAt: 0 }
}));
JS
pnpm dlx --allow-build=esbuild vercel@60.0.1 build --prod --yes --global-config "$RUNNER_TEMP/vercel-offline"
- name: Check Lambda module loading and function budget
run: |
node --no-experimental-require-module --input-type=module - <<'JS'
import assert from 'node:assert/strict';
import { readFileSync, readdirSync } from 'node:fs';
const config = JSON.parse(readFileSync('.vercel/output/functions/api/index.func/.vc-config.json'));
assert.equal(config.runtime, 'nodejs24.x');
assert.equal(config.maxDuration, 300);
const tracedFiles = Object.keys(config.filePathMap ?? {});
assert.ok(tracedFiles.some((path) => path.endsWith('/pdfkit/js/standard-fonts/Helvetica.cjs')));
assert.ok(tracedFiles.some((path) => path.endsWith('/pdfkit/js/data/Helvetica.afm')));
for (const name of readdirSync('apps/server/dist')) {
if (name.endsWith('.mjs') && !['index.mjs', 'prepare-deployment.mjs'].includes(name)) {
await import(`./apps/server/dist/${name}`);
}
}
const { default: app } = await import('./apps/server/dist/vercel.mjs');
const response = await app.fetch(new Request('http://localhost:3000/api/storage/stage', { method: 'POST', body: '{}' }));
assert.equal(response.status, 401);
process.exit(0);
JS
live-smoke:
if: github.event_name == 'workflow_dispatch'
runs-on: ${{ vars.CI_RUNNER_X64 || 'ubuntu-latest' }}
environment: vercel-smoke
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
- name: Smoke-test dedicated deployment
env:
SMOKE_URL: ${{ vars.VERCEL_SMOKE_URL }}
SMOKE_AI_BASE_URL: ${{ vars.VERCEL_SMOKE_AI_BASE_URL }}
SMOKE_AI_API_KEY: ${{ secrets.VERCEL_SMOKE_AI_API_KEY }}
run: node tooling/deployment/smoke.mjs
-17
View File
@@ -1,17 +0,0 @@
// @ts-check
const betaPackages = ["drizzle-zod"];
const rcPackages = ["drizzle-orm", "drizzle-kit"];
/** @type {import('npm-check-updates').RunOptions} */
module.exports = {
upgrade: true,
workspaces: true,
install: "always",
packageManager: "pnpm",
target: (packageName) => {
if (betaPackages.includes(packageName)) return "@beta";
if (rcPackages.includes(packageName)) return "@rc";
return "latest";
},
};
+27
View File
@@ -0,0 +1,27 @@
.env*
!.env.example
.git
.codegraph
.superpowers
.agents
.codex
.claude
.turbo
**/node_modules
**/dist
**/coverage
**/reports
data
apps/web/data
screenshots
.vercel
.wrangler
.tanstack
.worktrees
.migration
.supermemory
.cache
tmp
temp
**/test-results
**/playwright-report
+5 -7
View File
@@ -27,16 +27,13 @@ Auto-Clarity: drop caveman for security warnings, irreversible actions, user con
Boundaries: code/commits/PRs written normal.
<!-- caveman-end -->
<!-- graphify-begin -->
## Agent skills
- Issues and specs: GitHub Issues for `reactive-resume/reactive-resume`. See `docs/agents/issue-tracker.md`.
- Domain docs use a multi-context layout. See `docs/agents/domain.md`.
## Overview
Reactive Resume is a pnpm monorepo (Turborepo) with two deployable apps: `apps/web` (TanStack Start / React 19 / Vite) and `apps/server` (Hono / Node.js). The production Docker image runs a single Node.js process on port 3000; `apps/server` mounts the API/auth/MCP/static routes and serves the built web app.
Reactive Resume is a pnpm monorepo (Turborepo) with two deployable apps: `apps/web` (React 19 SPA with TanStack Router and Vite) and `apps/server` (Hono / Node.js). The production Docker image runs a single Node.js process on port 3000; `apps/server` mounts the API/auth/MCP/static routes and serves the built web app.
Internal packages are source-consumed through `package.json` export maps pointing at `src` files. Do not assume package-local `dist` output exists unless a package explicitly adds it.
@@ -69,9 +66,10 @@ Narrow cross-cutting helpers go in `packages/utils` only after checking no domai
## Web app conventions
- `apps/web/src/router.tsx` initializes router context with `queryClient`, `orpc`, `theme`, `locale`, `session`, and `flags`. Reuse route context instead of refetching these ad hoc.
- Builder shell: `apps/web/src/routes/builder/$resumeId`. Its nested preview route is client-only (`ssr: false`); the public resume route `apps/web/src/routes/$username/$slug.tsx` uses `ssr: "data-only"`.
- Browser-only preview code: `apps/web/src/features/resume/preview`. Public PDF viewer: `apps/web/src/features/resume/public`. Keep PDF.js/canvas/browser APIs out of SSR paths.
- Isomorphic oRPC client: `apps/web/src/libs/orpc/client.ts` — server calls use an in-process router client, browser calls use `/api/rpc` with credentials included.
- The web app is a client-rendered SPA. `apps/server` serves `index.html` and injects page metadata (OpenGraph, canonical, JSON-LD) in `apps/server/src/static/web.ts`; there is no React SSR.
- Builder shell: `apps/web/src/routes/builder/$resumeId`. Public resume route: `apps/web/src/routes/$username/$slug.tsx`.
- Browser-only preview code: `apps/web/src/features/resume/preview`. Public PDF viewer: `apps/web/src/features/resume/public`. Keep PDF.js/canvas code in these features, not in `packages/pdf`.
- oRPC client: `apps/web/src/libs/orpc/client.ts` calls `/api/rpc` with credentials included. `apps/web/src/libs/orpc/fetch.ts` stages large request bodies through Blob on Vercel.
- For React components with explicit props, use a named props type (e.g. `type FooProps = {...}` with `function Foo(props: FooProps)`) rather than inline object annotations, especially with more than one field or with generics.
## Package boundaries
-3
View File
@@ -1,3 +0,0 @@
# Domain contexts
- [Resume](packages/resume/CONTEXT.md): authored resume content and presentation concepts shared by the builder and exporters.
+11 -5
View File
@@ -165,7 +165,7 @@ For detailed setup instructions, environment configuration, and self-hosting gui
| Category | Technology |
| ---------------- | ------------------------------- |
| Framework | TanStack Start (React 19, Vite) |
| Framework | TanStack Router (React 19, Vite) |
| Runtime | Node.js |
| Language | TypeScript |
| Database | PostgreSQL with Drizzle ORM |
@@ -189,7 +189,13 @@ The full documentation lives at [docs.rxresu.me](https://docs.rxresu.me):
## Self-Hosting
Reactive Resume can be self-hosted using Docker. The stack includes:
Reactive Resume supports Docker and Vercel Hobby.
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Freactive-resume%2Freactive-resume&project-name=reactive-resume&repository-name=reactive-resume&env=AUTH_SECRET%2CENCRYPTION_SECRET&envDescription=Generate+two+independent+secrets+with+openssl+rand+-hex+32.+Keep+these+values+across+deployments.&envLink=https%3A%2F%2Fdocs.rxresu.me%2Fself-hosting%2Fvercel&stores=%5B%7B%22type%22%3A%22integration%22%2C%22protocol%22%3A%22storage%22%2C%22integrationSlug%22%3A%22neon%22%2C%22productSlug%22%3A%22neon%22%7D%2C%7B%22type%22%3A%22integration%22%2C%22protocol%22%3A%22storage%22%2C%22integrationSlug%22%3A%22upstash%22%2C%22productSlug%22%3A%22upstash-kv%22%7D%2C%7B%22type%22%3A%22blob%22%2C%22access%22%3A%22private%22%7D%5D)
Vercel provisions Neon PostgreSQL, private Blob storage, and Upstash Redis through its deployment wizard. Supply two persistent secrets, then deploy. See the [Vercel guide](docs/self-hosting/vercel.mdx) for setup, limits, and optional SMTP/OAuth configuration.
For Docker, the stack includes:
- **PostgreSQL** — Database for storing user data and resumes
- **SeaweedFS** (optional) — S3-compatible storage for file uploads
@@ -237,9 +243,9 @@ Other ways to support:
<a href="https://www.star-history.com/?repos=reactive-resume%2Freactive-resume&type=date&legend=top-left">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=reactive-resume/reactive-resume&type=date&theme=dark&legend=top-left&sealed_token=QmaOn4Ech499R6kpQe8ONn911UjGUaJfQBT0MXlQLU9hTo-Ie7lTxIILWbBvmtzDGHk7ziWKN_N5iM5mgP8widn_FGHd9-PHNokPtSji8XLgbFpqatgyqIDPnOys-IhO40W3J0HeH07FL-Q8Bq6ArRk3LDtJDwjh4m0ya-2L59ULb7BaqxkSDuCytkCr" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=reactive-resume/reactive-resume&type=date&legend=top-left&sealed_token=QmaOn4Ech499R6kpQe8ONn911UjGUaJfQBT0MXlQLU9hTo-Ie7lTxIILWbBvmtzDGHk7ziWKN_N5iM5mgP8widn_FGHd9-PHNokPtSji8XLgbFpqatgyqIDPnOys-IhO40W3J0HeH07FL-Q8Bq6ArRk3LDtJDwjh4m0ya-2L59ULb7BaqxkSDuCytkCr" />
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=reactive-resume/reactive-resume&type=date&legend=top-left&sealed_token=QmaOn4Ech499R6kpQe8ONn911UjGUaJfQBT0MXlQLU9hTo-Ie7lTxIILWbBvmtzDGHk7ziWKN_N5iM5mgP8widn_FGHd9-PHNokPtSji8XLgbFpqatgyqIDPnOys-IhO40W3J0HeH07FL-Q8Bq6ArRk3LDtJDwjh4m0ya-2L59ULb7BaqxkSDuCytkCr" />
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=reactive-resume/reactive-resume&type=date&theme=dark&legend=top-left" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=reactive-resume/reactive-resume&type=date&legend=top-left" />
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=reactive-resume/reactive-resume&type=date&legend=top-left" />
</picture>
</a>
+1
View File
@@ -0,0 +1 @@
export { default } from "../apps/server/dist/vercel.mjs";
+27 -23
View File
@@ -18,20 +18,20 @@
"#react-pdf-renderer": "@react-pdf/renderer"
},
"dependencies": {
"@ai-sdk/anthropic": "^4.0.54",
"@ai-sdk/cerebras": "^3.0.49",
"@ai-sdk/cohere": "^4.0.42",
"@ai-sdk/deepseek": "^3.0.45",
"@ai-sdk/fireworks": "^3.0.52",
"@ai-sdk/google": "^4.0.72",
"@ai-sdk/groq": "^4.0.42",
"@ai-sdk/mistral": "^4.0.44",
"@ai-sdk/openai": "^4.0.67",
"@ai-sdk/openai-compatible": "^3.0.49",
"@ai-sdk/perplexity": "^4.0.44",
"@ai-sdk/togetherai": "^3.0.50",
"@ai-sdk/xai": "^5.0.0",
"@aws-sdk/client-s3": "^3.1133.0",
"@ai-sdk/anthropic": "^4.0.58",
"@ai-sdk/cerebras": "^3.0.53",
"@ai-sdk/cohere": "^4.0.46",
"@ai-sdk/deepseek": "^3.0.49",
"@ai-sdk/fireworks": "^3.0.56",
"@ai-sdk/google": "^4.0.76",
"@ai-sdk/groq": "^4.0.46",
"@ai-sdk/mistral": "^4.0.48",
"@ai-sdk/openai": "^4.0.71",
"@ai-sdk/openai-compatible": "^3.0.53",
"@ai-sdk/perplexity": "^4.0.48",
"@ai-sdk/togetherai": "^3.0.54",
"@ai-sdk/xai": "^5.0.4",
"@aws-sdk/client-s3": "^3.1136.0",
"@better-auth/api-key": "^1.7.5",
"@better-auth/drizzle-adapter": "^1.7.5",
"@better-auth/infra": "^0.4.9",
@@ -40,12 +40,12 @@
"@bramus/specificity": "^2.4.2",
"@hono/node-server": "^2.1.1",
"@modelcontextprotocol/sdk": "^1.30.0",
"@orpc/client": "^1.15.1",
"@orpc/experimental-ratelimit": "^1.15.1",
"@orpc/json-schema": "^1.15.1",
"@orpc/openapi": "^1.15.1",
"@orpc/server": "^1.15.1",
"@orpc/zod": "^1.15.1",
"@orpc/client": "^1.15.2",
"@orpc/experimental-ratelimit": "^1.15.2",
"@orpc/json-schema": "^1.15.2",
"@orpc/openapi": "^1.15.2",
"@orpc/server": "^1.15.2",
"@orpc/zod": "^1.15.2",
"@react-pdf/hyphenate": "0.1.0",
"@react-pdf/renderer": "^4.9.0",
"@reactive-resume/api": "workspace:*",
@@ -58,7 +58,9 @@
"@sindresorhus/slugify": "^3.0.1",
"@t3-oss/env-core": "^0.13.11",
"@uiw/color-convert": "^2.10.3",
"ai": "^7.0.102",
"@vercel/blob": "^2.8.0",
"@vercel/functions": "^3.9.9",
"ai": "^7.0.107",
"bcrypt": "^6.0.0",
"better-auth": "1.7.5",
"cjk-regex": "^3.5.0",
@@ -70,6 +72,8 @@
"fast-json-patch": "^3.1.1",
"fast-png": "^8.0.0",
"hono": "^4.13.8",
"ioredis": "^6.0.0",
"jose": "^6.2.12",
"jsonrepair": "^3.15.0",
"node-html-parser": "^9.0.4",
"nodemailer": "^10.0.10",
@@ -79,7 +83,7 @@
"react": "^19.3.0",
"react-email": "^6.9.5",
"react-pdf-html": "^2.1.5",
"resumable-stream": "^2.2.12",
"resumable-stream": "^2.2.13",
"sanitize-html": "^2.17.7",
"sharp": "^0.35.4",
"tokenx": "^2.1.0",
@@ -90,7 +94,7 @@
},
"devDependencies": {
"@reactive-resume/config": "workspace:*",
"@types/node": "^26.6.1",
"@types/node": "^26.6.2",
"@types/pg": "^8.23.1",
"@types/react": "^19.3.0",
"@typescript/native-preview": "7.0.0-dev.20260707.2",
+15 -7
View File
@@ -3,6 +3,7 @@ import type { Context } from "hono";
import { isIP } from "node:net";
import { getConnInfo } from "@hono/node-server/conninfo";
import { Hono } from "hono";
import { prepareStagedBody, withStagedBody } from "@reactive-resume/api/features/storage/transport";
import { handleMcp } from "../mcp/handler";
import { handleOpenApi } from "../openapi/handler";
import {
@@ -33,8 +34,14 @@ const getTrustedClient = (context: Context<ServerEnvironment>): string => {
}
};
export function createApp() {
type AppOptions = {
serveStatic?: boolean;
trustedClient?: (request: Request) => string;
};
export function createApp(options: AppOptions = {}) {
const app = new Hono<ServerEnvironment>();
const client = (c: Context<ServerEnvironment>) => options.trustedClient?.(c.req.raw) ?? getTrustedClient(c);
app.use("/auth/*", async (c, next) => {
await next();
@@ -44,15 +51,16 @@ export function createApp() {
c.header("Cache-Control", "no-store");
});
app.all("/api/rpc", (c) => handleRpc(c.req.raw, getTrustedClient(c)));
app.all("/api/rpc/*", (c) => handleRpc(c.req.raw, getTrustedClient(c)));
app.all("/api/openapi", (c) => handleOpenApi(c.req.raw, getTrustedClient(c)));
app.all("/api/openapi/*", (c) => handleOpenApi(c.req.raw, getTrustedClient(c)));
app.post("/api/storage/stage", (c) => prepareStagedBody(c.req.raw));
app.all("/api/rpc", (c) => withStagedBody(c.req.raw, (request) => handleRpc(request, client(c))));
app.all("/api/rpc/*", (c) => withStagedBody(c.req.raw, (request) => handleRpc(request, client(c))));
app.all("/api/openapi", (c) => handleOpenApi(c.req.raw, client(c)));
app.all("/api/openapi/*", (c) => handleOpenApi(c.req.raw, client(c)));
app.get("/api/auth/oauth", (c) => handleOAuth(c.req.raw));
app.all("/api/auth/*", (c) => handleAuth(c.req.raw));
app.get("/api/health", () => handleHealth());
app.get("/api/resumes/:username/:slug/pdf", (c) =>
handlePublicResumePdf(c.req.raw, c.req.param("username"), c.req.param("slug"), getTrustedClient(c)),
handlePublicResumePdf(c.req.raw, c.req.param("username"), c.req.param("slug"), client(c)),
);
app.get("/api/resumes/:id/pdf", (c) => handleResumePdfDownload(c.req.raw, c.req.param("id")));
app.get("/api/uploads/*", (c) => handleUpload(c.req.raw));
@@ -76,7 +84,7 @@ export function createApp() {
// Must precede the static middleware: serveStatic resolves "/" to dist/index.html and would
// return it verbatim, skipping the OpenGraph/Twitter/canonical/JSON-LD injection in handleWebApp.
app.on(["GET", "HEAD"], "/", (c) => handleWebApp(c.req.raw));
app.use("/*", serveWebDistStatic);
if (options.serveStatic !== false) app.use("/*", serveWebDistStatic);
app.on(["GET", "HEAD"], "/*", (c) => handleWebApp(c.req.raw));
return app;
+16 -4
View File
@@ -2,6 +2,7 @@ import { sql } from "drizzle-orm";
import { withTimeout } from "es-toolkit";
import { getStorageService } from "@reactive-resume/api/features/storage";
import { db } from "@reactive-resume/db/client";
import { getRedis } from "@reactive-resume/db/redis";
import { appVersion } from "../app-version";
const HEALTHCHECK_TIMEOUT_MS = 1_500;
@@ -32,13 +33,13 @@ async function runCheck(check: () => Promise<object>): Promise<CheckResult> {
}
}
function publicCheck(check: CheckResult, name: "Database" | "Storage"): CheckResult {
function publicCheck(check: CheckResult, name: "Database" | "Storage" | "Redis"): CheckResult {
if (check.status === "healthy") return check;
return {
status: check.status,
latencyMs: check.latencyMs,
error: `${name} health check failed.`,
...(check.type === "local" || check.type === "s3" ? { type: check.type } : {}),
...(check.type === "local" || check.type === "s3" || check.type === "blob" ? { type: check.type } : {}),
};
}
@@ -51,8 +52,18 @@ async function checkDatabase() {
const checkStorage = () => getStorageService().healthcheck();
export async function handleHealth() {
const [database, storage] = await Promise.all([runCheck(checkDatabase), runCheck(checkStorage)]);
const status = [database, storage].some((check) => check.status === "unhealthy") ? "unhealthy" : "healthy";
const redisClient = getRedis();
const [database, storage, redis] = await Promise.all([
runCheck(checkDatabase),
runCheck(checkStorage),
redisClient
? runCheck(async () => {
await redisClient.ping();
return { status: "healthy" };
})
: undefined,
]);
const status = [database, storage, redis].some((check) => check?.status === "unhealthy") ? "unhealthy" : "healthy";
const checks = {
service: "reactive-resume",
@@ -62,6 +73,7 @@ export async function handleHealth() {
uptime: `${process.uptime().toFixed(2)}s`,
database: publicCheck(database, "Database"),
storage: publicCheck(storage, "Storage"),
...(redis ? { redis: publicCheck(redis, "Redis") } : {}),
};
if (status === "unhealthy") {
@@ -35,6 +35,7 @@ export async function handlePublicResumePdf(
});
} catch (error) {
const status = errorStatus(error);
if (status === 500) console.error("Public resume PDF generation failed", error);
return noStoreResponse(
status === 500 ? "Failed to generate public resume PDF" : "Public resume PDF unavailable",
status,
+7 -1
View File
@@ -16,6 +16,12 @@ vi.mock("./http/app", () => {
},
};
});
vi.mock("@reactive-resume/auth/config", () => ({
initializeAuth: async () => {
await Promise.resolve();
events.push("auth ready");
},
}));
vi.mock("@hono/node-server", () => ({
serve: () => {
events.push("server listening");
@@ -30,6 +36,6 @@ describe("server startup", () => {
const entry = await import("./index");
expect(events).toEqual([]);
await entry.main();
expect(events).toEqual(["migrations complete", "auth imported", "app created", "server listening"]);
expect(events).toEqual(["migrations complete", "auth imported", "auth ready", "app created", "server listening"]);
});
});
+3 -2
View File
@@ -6,9 +6,10 @@ import { runStartupChecks } from "./startup/checks";
export async function main() {
await runStartupChecks();
// OAuth resource seeding starts when auth is imported, so load the app only
// after migrations have created the provider tables.
// Load and initialize auth only after migrations have created the provider tables.
const { createApp } = await import("./http/app");
const { initializeAuth } = await import("@reactive-resume/auth/config");
await initializeAuth();
// Safety net: Node 24 crashes the whole process on an unhandled rejection. One request's
// stray promise must not take the server down for everyone, so log and keep serving.
+20 -36
View File
@@ -3,7 +3,13 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { onError } from "@orpc/client";
import { createRouterClient } from "@orpc/server";
import router from "@reactive-resume/api/routers";
import { MCP_TOOL_NAME, registerPrompts, registerResources, registerTools } from "@reactive-resume/mcp";
import {
buildMcpServerInfo,
MCP_TOOL_NAME,
registerPrompts,
registerResources,
registerTools,
} from "@reactive-resume/mcp";
import { appVersion } from "../app-version";
import { getRequestLocale } from "../rpc/locale";
@@ -23,41 +29,19 @@ function createRequestClient(request: Request): RouterClient<typeof router> {
}
export function createMcpServer(request: Request) {
const server = new McpServer(
{
name: "reactive-resume",
version: appVersion,
title: "Reactive Resume",
websiteUrl: "https://rxresu.me",
description:
"Reactive Resume is a free and open-source resume builder. Use this MCP server to interact with your resume using an LLM of your choice.",
icons: [
{
src: "https://rxresu.me/icon/light.svg",
mimeType: "image/svg+xml",
theme: "light",
},
{
src: "https://rxresu.me/icon/dark.svg",
mimeType: "image/svg+xml",
theme: "dark",
},
],
},
{
instructions: [
"You are connected to Reactive Resume over MCP.",
"Authenticate with OAuth (recommended) or an API key (`x-api-key`).",
`Discover resume IDs with \`${MCP_TOOL_NAME.listResumes}\` (not \`resources/list\`).`,
`List distinct tags with \`${MCP_TOOL_NAME.listResumeTags}\`.`,
`Read schema at \`resume://_meta/schema\`; read resume JSON via \`resume://{id}\` or \`${MCP_TOOL_NAME.getResume}\`.`,
`Apply body edits with JSON Patch through \`${MCP_TOOL_NAME.patchResume}\`.`,
`Change name, slug, tags, or public visibility with \`${MCP_TOOL_NAME.updateResume}\` (returns canonical share URL; anonymous access only when \`isPublic\` is true; passwords are managed in the web app only).`,
`Create short-lived authenticated PDF download URLs with \`${MCP_TOOL_NAME.downloadResumePdf}\`; set target to \`cover-letter\` to export a visible cover letter separately.`,
`Import full ResumeData JSON with \`${MCP_TOOL_NAME.importResume}\`.`,
].join(" "),
},
);
const server = new McpServer(buildMcpServerInfo(appVersion), {
instructions: [
"You are connected to Reactive Resume over MCP.",
"Authenticate with OAuth (recommended) or an API key (`x-api-key`).",
`Discover resume IDs with \`${MCP_TOOL_NAME.listResumes}\` (not \`resources/list\`).`,
`List distinct tags with \`${MCP_TOOL_NAME.listResumeTags}\`.`,
`Read schema at \`resume://_meta/schema\`; read resume JSON via \`resume://{id}\` or \`${MCP_TOOL_NAME.getResume}\`.`,
`Apply body edits with JSON Patch through \`${MCP_TOOL_NAME.patchResume}\`.`,
`Change name, slug, tags, or public visibility with \`${MCP_TOOL_NAME.updateResume}\` (returns canonical share URL; anonymous access only when \`isPublic\` is true; passwords are managed in the web app only).`,
`Create short-lived authenticated PDF download URLs with \`${MCP_TOOL_NAME.downloadResumePdf}\`; set target to \`cover-letter\` to export a visible cover letter separately.`,
`Import full ResumeData JSON with \`${MCP_TOOL_NAME.importResume}\`.`,
].join(" "),
});
const client = createRequestClient(request);
registerResources(server, client);
+1 -1
View File
@@ -1,7 +1,7 @@
import { readFile, writeFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
export async function generateOpenApiDocumentation(
async function generateOpenApiDocumentation(
target = fileURLToPath(new URL("../../../../docs/spec.json", import.meta.url)),
) {
const packageJson = JSON.parse(await readFile(new URL("../../../../package.json", import.meta.url), "utf8")) as {
+20
View File
@@ -0,0 +1,20 @@
import { initializeAuth } from "@reactive-resume/auth/config";
import { getPool } from "@reactive-resume/db/client";
import { env } from "@reactive-resume/env/server";
import { runDatabaseMigrations } from "./startup/checks";
if (process.env.VERCEL_ENV === "preview" && process.env.ALLOW_PREVIEW_MIGRATIONS !== "true") {
throw new Error(
"Preview deployment needs an isolated database. Set ALLOW_PREVIEW_MIGRATIONS=true only after connecting one.",
);
}
if (process.env.VERCEL === "1") {
if (env.STORAGE_BACKEND !== "blob")
throw new Error("Vercel requires private Blob storage for direct uploads. Docker supports local, S3, and Blob.");
if (!env.REDIS_URL || !env.ENCRYPTION_SECRET) throw new Error("Vercel requires Redis and ENCRYPTION_SECRET.");
}
await runDatabaseMigrations();
await initializeAuth();
await getPool().end();
+39 -9
View File
@@ -7,6 +7,7 @@ import { migrate } from "drizzle-orm/node-postgres/migrator";
import { Pool } from "pg";
import { env } from "@reactive-resume/env/server";
import { getLocalDataDirectory } from "@reactive-resume/utils/monorepo.node";
import { verifyMigratedSchema } from "./schema-check";
function resolveFromCurrentModule(relativePath: string) {
return fileURLToPath(new URL(relativePath, import.meta.url));
@@ -24,25 +25,54 @@ function resolveWorkspaceFolder(folderName: string): string {
throw new Error(`Could not locate ${folderName} folder relative to ${resolveFromCurrentModule(".")}`);
}
async function runDatabaseMigrations() {
export async function runDatabaseMigrations() {
console.info("Running database migrations...");
const pool = new Pool({ connectionString: env.DATABASE_URL });
const db = drizzle({ client: pool });
const pool = new Pool({
connectionString: env.DATABASE_MIGRATION_URL ?? env.DATABASE_URL,
max: 1,
connectionTimeoutMillis: 10_000,
});
try {
await migrate(db, { migrationsFolder: resolveWorkspaceFolder("migrations") });
console.info("Database migrations completed");
} catch (error) {
console.error("Database migrations failed", { error });
throw error;
const client = await pool.connect();
try {
await client.query("SELECT pg_advisory_lock(721830451)");
const db = drizzle({ client });
try {
await migrate(db, { migrationsFolder: resolveWorkspaceFolder("migrations") });
console.info("Database migrations completed");
} catch (error) {
console.error("Database migrations failed", { error });
throw error;
}
// Post-migration verification is not a migration failure, so it gets its own log
// message. A drifted schema still lets the server boot; STRICT_SCHEMA_CHECK=true
// makes the drift fatal instead.
try {
await verifyMigratedSchema(client);
} catch (error) {
console.error("Database schema verification failed", { error });
if (env.STRICT_SCHEMA_CHECK) throw error;
console.error(
"Continuing with a drifted database schema; set STRICT_SCHEMA_CHECK=true to refuse startup instead.",
);
}
} finally {
try {
await client.query("SELECT pg_advisory_unlock(721830451)");
} finally {
client.release();
}
}
} finally {
await pool.end();
}
}
async function validateLocalStoragePath() {
if (env.S3_ACCESS_KEY_ID && env.S3_SECRET_ACCESS_KEY && env.S3_BUCKET) return;
if (env.STORAGE_BACKEND !== "local") return;
const dataDirectory = getLocalDataDirectory(env.LOCAL_STORAGE_PATH);
console.info(`Validating local storage path: ${dataDirectory}`);
@@ -0,0 +1,50 @@
import { describe, expect, it } from "vitest";
import { collectExpectedColumns, verifyMigratedSchema } from "./schema-check";
describe("collectExpectedColumns", () => {
it("collects every column of every schema table", () => {
const expected = collectExpectedColumns();
expect(expected.length).toBeGreaterThan(0);
expect(expected).toContainEqual({ tableName: "ai_providers", columnName: "user_id" });
expect(expected).toContainEqual({ tableName: "user", columnName: "id" });
});
});
describe("verifyMigratedSchema", () => {
it("passes when the catalog reports nothing missing", async () => {
const queryable = { query: async () => ({ rows: [] }) };
await expect(verifyMigratedSchema(queryable)).resolves.toBeUndefined();
});
it("fails with the table name when every column of a table is missing", async () => {
const rows = collectExpectedColumns()
.filter((e) => e.tableName === "ai_providers")
.map((e) => ({ table_name: e.tableName, column_name: e.columnName }));
const queryable = { query: async () => ({ rows }) };
await expect(verifyMigratedSchema(queryable)).rejects.toThrow('table "ai_providers"');
});
it("fails with the qualified column name when only some columns are missing", async () => {
const queryable = { query: async () => ({ rows: [{ table_name: "user", column_name: "role" }] }) };
await expect(verifyMigratedSchema(queryable)).rejects.toThrow('"user"."role"');
});
it("passes the expected table and column lists to the catalog query", async () => {
let captured: unknown[] | undefined;
const queryable = {
query: (_text: string, values?: unknown[]) => {
captured = values;
return Promise.resolve({ rows: [] });
},
};
await verifyMigratedSchema(queryable);
const [tables, columns] = captured as [string[], string[]];
// The query relies on $1/$2 being index-aligned, so each table name must pair
// with its own column name at the same index.
const pairs = tables.map((table, index) => `${table}.${columns[index]}`);
expect(pairs).toContain("ai_providers.user_id");
});
});
+71
View File
@@ -0,0 +1,71 @@
import { is } from "drizzle-orm";
import { getTableConfig, PgTable } from "drizzle-orm/pg-core";
import * as schema from "@reactive-resume/db/schema";
interface SchemaQueryable {
query(text: string, values?: unknown[]): Promise<{ rows: { table_name: string; column_name: string }[] }>;
}
export function collectExpectedColumns() {
const expected: { tableName: string; columnName: string }[] = [];
for (const value of Object.values(schema)) {
if (!is(value, PgTable)) continue;
const config = getTableConfig(value);
for (const column of config.columns) expected.push({ tableName: config.name, columnName: column.name });
}
return expected;
}
// The migration ledger (drizzle.__drizzle_migrations) only records that a migration ran; it
// cannot detect objects that were dropped or lost outside the migrator (a partial restore,
// a manual DROP TABLE, or a recreated "public" schema while the "drizzle" schema survives).
// Comparing the live catalog with the declared schema turns that silent drift into a startup
// failure instead of runtime "relation does not exist" (42P01) errors. The comparison covers
// tables and columns only — indexes, constraints, and enums are intentionally out of scope.
export async function verifyMigratedSchema(queryable: SchemaQueryable): Promise<void> {
const expected = collectExpectedColumns();
if (expected.length === 0) return;
// $1 and $2 are index-aligned: $1[i] is the name of the table expected to contain $2[i].
// Names are qualified as "public.<table>" so the lookup does not follow the connection's
// search_path — migrations always create these tables in the public schema.
const result = await queryable.query(
`select e.table_name, e.column_name
from unnest($1::text[], $2::text[]) as e(table_name, column_name)
where to_regclass('public.' || e.table_name) is null
or not exists (
select 1 from pg_catalog.pg_attribute a
where a.attrelid = to_regclass('public.' || e.table_name)
and a.attname = e.column_name
and a.attnum > 0 and not a.attisdropped
)
order by e.table_name, e.column_name`,
[expected.map((e) => e.tableName), expected.map((e) => e.columnName)],
);
if (result.rows.length === 0) return;
const expectedPerTable = new Map<string, number>();
for (const e of expected) expectedPerTable.set(e.tableName, (expectedPerTable.get(e.tableName) ?? 0) + 1);
const missingByTable = new Map<string, Set<string>>();
for (const row of result.rows) {
const columns = missingByTable.get(row.table_name) ?? new Set<string>();
columns.add(row.column_name);
missingByTable.set(row.table_name, columns);
}
const missing = [...missingByTable.entries()].map(([table, columns]) =>
columns.size === expectedPerTable.get(table)
? `table "${table}"`
: `column(s) ${[...columns].map((column) => `"${table}"."${column}"`).join(", ")}`,
);
throw new Error(
`Database schema does not match the migration ledger: ${missing.join(", ")} ` +
"missing even though all migrations are marked as applied. This usually means the database was " +
"restored from a backup that did not include these objects, or they were dropped outside of " +
"migrations. Restore a consistent backup or recreate the missing objects, then restart the server.",
);
}
+99
View File
@@ -0,0 +1,99 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { TRUSTED_IP_HEADERS } from "@reactive-resume/utils/rate-limit";
const mocks = vi.hoisted(() => ({
ipAddress: vi.fn<(request: Request) => string | undefined>(),
waitUntil: vi.fn(),
initializeAuth: vi.fn(),
attachDatabasePool: vi.fn(),
configureAgentStreamLifetime: vi.fn(),
pool: {},
getPool: vi.fn(),
createApp:
vi.fn<
(options: { serveStatic: boolean; trustedClient: (request: Request) => string }) => {
fetch: (request: Request) => Promise<Response>;
}
>(),
handle: vi.fn<(request: Request) => Promise<Response>>(),
}));
vi.mock("@vercel/functions", () => ({
ipAddress: mocks.ipAddress,
waitUntil: mocks.waitUntil,
attachDatabasePool: mocks.attachDatabasePool,
}));
vi.mock("@reactive-resume/api/features/agent/streams", () => ({
configureAgentStreamLifetime: mocks.configureAgentStreamLifetime,
}));
vi.mock("@reactive-resume/auth/config", () => ({ initializeAuth: mocks.initializeAuth }));
vi.mock("@reactive-resume/db/client", () => ({ getPool: mocks.getPool }));
vi.mock("./http/app", () => ({ createApp: mocks.createApp }));
function spoofedRequest() {
return new Request("https://resume.test/api/rpc?batch=1", {
method: "POST",
body: "original RPC body",
headers: {
...Object.fromEntries(TRUSTED_IP_HEADERS.map((header) => [header, "192.0.2.66"])),
"x-forwarded-for": "192.0.2.66, 192.0.2.77",
cookie: "session=original",
authorization: "Bearer original",
"content-type": "application/json",
},
});
}
beforeEach(() => {
vi.resetModules();
vi.clearAllMocks();
mocks.getPool.mockReturnValue(mocks.pool);
mocks.handle.mockResolvedValue(new Response("handled"));
mocks.createApp.mockReturnValue({ fetch: mocks.handle });
});
describe("Vercel adapter", () => {
it("registers platform lifetime hooks and disables filesystem static serving", async () => {
await import("./vercel");
expect(mocks.configureAgentStreamLifetime).toHaveBeenCalledExactlyOnceWith(mocks.waitUntil);
expect(mocks.attachDatabasePool).toHaveBeenCalledExactlyOnceWith(mocks.pool);
expect(mocks.createApp).toHaveBeenCalledExactlyOnceWith({
serveStatic: false,
trustedClient: expect.any(Function),
});
});
it.each(["203.0.113.9", "2001:db8::9"])("replaces all spoofed IP headers with platform IP %s", async (ip) => {
mocks.ipAddress.mockReturnValue(ip);
const { default: adapter } = await import("./vercel");
const request = spoofedRequest();
expect(await (await adapter.fetch(request)).text()).toBe("handled");
expect(mocks.ipAddress).toHaveBeenCalledExactlyOnceWith(request);
const forwarded = mocks.handle.mock.calls[0]?.[0];
if (!forwarded) throw new Error("Expected forwarded request");
for (const header of TRUSTED_IP_HEADERS) {
const expected = ["x-real-ip", "x-forwarded-for"].includes(header.toLowerCase()) ? ip : null;
expect(forwarded.headers.get(header)).toBe(expected);
}
expect(mocks.createApp.mock.calls[0]?.[0].trustedClient(forwarded)).toBe(ip);
expect(forwarded.url).toBe(request.url);
expect(forwarded.method).toBe("POST");
expect(await forwarded.text()).toBe("original RPC body");
expect(forwarded.headers.get("cookie")).toBe("session=original");
expect(forwarded.headers.get("authorization")).toBe("Bearer original");
expect(forwarded.headers.get("content-type")).toBe("application/json");
});
it.each([undefined, "", "invalid-ip", "203.0.113.9, 192.0.2.66"])(
"clears attacker headers when platform IP is missing or invalid: %s",
async (ip) => {
mocks.ipAddress.mockReturnValue(ip);
const { default: adapter } = await import("./vercel");
await adapter.fetch(spoofedRequest());
const forwarded = mocks.handle.mock.calls[0]?.[0];
if (!forwarded) throw new Error("Expected forwarded request");
for (const header of TRUSTED_IP_HEADERS) expect(forwarded.headers.has(header)).toBe(false);
expect(mocks.createApp.mock.calls[0]?.[0].trustedClient(forwarded)).toBe("unknown");
},
);
});
+29
View File
@@ -0,0 +1,29 @@
import { isIP } from "node:net";
import { attachDatabasePool, ipAddress, waitUntil } from "@vercel/functions";
import { configureAgentStreamLifetime } from "@reactive-resume/api/features/agent/streams";
import { initializeAuth } from "@reactive-resume/auth/config";
import { getPool } from "@reactive-resume/db/client";
import { TRUSTED_IP_HEADERS } from "@reactive-resume/utils/rate-limit";
import { createApp } from "./http/app";
configureAgentStreamLifetime(waitUntil);
attachDatabasePool(getPool());
const app = createApp({
serveStatic: false,
trustedClient: (request) => request.headers.get("x-real-ip") ?? "unknown",
});
export default {
async fetch(request: Request) {
await initializeAuth();
const ip = ipAddress(request);
const headers = new Headers(request.headers);
for (const name of TRUSTED_IP_HEADERS) headers.delete(name);
headers.delete("x-real-ip");
if (ip && isIP(ip)) {
headers.set("x-real-ip", ip);
headers.set("x-forwarded-for", ip);
}
return app.fetch(new Request(request, { headers }));
},
};
+32 -3
View File
@@ -8,8 +8,35 @@ const rootPackageJson = JSON.parse(readFileSync(new URL("../../package.json", im
version?: string;
};
// Lambda disables require(ESM) and uses stricter CJS export detection than standalone Node.
const bundledInteropPackages = new Set([
"@uiw/color-convert",
"@babel/runtime",
"sanitize-html",
"htmlparser2",
"domhandler",
"domutils",
"domelementtype",
"dom-serializer",
"entities",
"deepmerge",
"escape-string-regexp",
"is-plain-object",
"parse-srcset",
"postcss",
"nanoid",
"picocolors",
"source-map-js",
"launder",
"dayjs",
]);
const shouldExternalizeThirdParty = (id: string) => {
if (id.startsWith("@reactive-resume/")) return false;
const packageName = id
.split("/")
.slice(0, id.startsWith("@") ? 2 : 1)
.join("/");
if (id.startsWith("@reactive-resume/") || bundledInteropPackages.has(packageName)) return false;
if (id.startsWith("@/") || id.startsWith(".") || id.startsWith("/") || id.startsWith("\0")) return false;
return true;
@@ -33,7 +60,9 @@ const promptAssetsPlugin: TsdownPlugin = {
};
export default defineConfig({
entry: { index: "src/index.ts" },
entry: { index: "src/index.ts", vercel: "src/vercel.ts", "prepare-deployment": "src/prepare-deployment.ts" },
// Keep import.meta.url-based asset lookup adjacent to the entrypoints.
outputOptions: { chunkFileNames: "[name]-[hash].mjs" },
format: "esm",
platform: "node",
target: "node24",
@@ -47,7 +76,7 @@ export default defineConfig({
suppressWarnings: [/dynamic import will not move module into another chunk/],
outExtensions: () => ({ js: ".mjs" }),
deps: {
alwaysBundle: [/^@reactive-resume\//],
alwaysBundle: [/^@reactive-resume\//, ...bundledInteropPackages],
neverBundle: shouldExternalizeThirdParty,
},
plugins: [promptAssetsPlugin],
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Daar is geen skakel na 'n profiel, portefeulje of bewaarplek nie."
msgid "There is no summary paragraph."
msgstr "Daar is geen opsommingsparagraaf nie."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Daar was nie genoeg inligting om hierdie toets uit te voer nie."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Hierdie toetse loop terwyl jy tik en verlaat nooit jou blaaier nie. Hulle toets of sagteware jou CV kan lees, nie hoe goed dit geskryf is nie."
@@ -6168,14 +6164,6 @@ msgstr "Hierdie handeling kan nie ongedaan gemaak word nie. Dit vee die draad se
msgid "This assistant could not be opened."
msgstr "Hierdie assistent kon nie oopgemaak word nie."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Hierdie toets is nie van toepassing op hierdie lêer nie."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Hierdie toets word slegs op CV's in Engels uitgevoer."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Hierdie koppelingsversoek is ongeldig of het verval."
@@ -6260,10 +6248,6 @@ msgstr "Hierdie lêer gebruik baie verskillende lettertipes."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Hierdie lêer gebruik Tipe 3-lettertipes, wat tekeninge eerder as karakters dra."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Hierdie lêer se bladsyinhoud kon nie betyds ondersoek word nie."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Hierdie opskrif is nie een waarna ontleders soek nie."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "ወደ መገለጫ፣ ፖርትፎሊዮ ወይም ማከማቻ የሚ
msgid "There is no summary paragraph."
msgstr "ምንም የማጠቃለያ አንቀጽ የለም።"
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "ይህን ቼክ ለማካሄድ በቂ መረጃ አልነበረም።"
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "እነዚህ ምርመራዎች እርስዎ በሚተይቡበት ጊዜ ይሠራሉ፤ ከአሳሽዎም ፈጽሞ አይወጡም። የሚፈትኑት ሶፍትዌር የስራ ልምድ ማስረጃዎን ማንበብ ይችል እንደሆነ እንጂ ምን ያህል በጥሩ ሁኔታ እንደተጻፈ አይደለም።"
@@ -6168,14 +6164,6 @@ msgstr "ይህ እርምጃ ሊቀለበስ አይችልም። የውይይቱ
msgid "This assistant could not be opened."
msgstr "ይህ ረዳት ሊከፈት አልቻለም።"
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "ይህ ቼክ በዚህ ፋይል ላይ አይተገበርም።"
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "ይህ ቼክ የሚሰራው በእንግሊዝኛ በተጻፉ የስራ ልምድ ማስረጃዎች ላይ ብቻ ነው።"
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "ይህ የግንኙነት ጥያቄ ልክ ያልሆነ ወይም ጊዜው አልፎበታል።"
@@ -6260,10 +6248,6 @@ msgstr "ይህ ፋይል ብዙ የተለያዩ ፊደላትን ይጠቀማል
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "ይህ ፋይል ከፊደላት ይልቅ ስዕሎችን የሚያሸክሙ Type 3 ፊደላትን ይጠቀማል።"
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "የዚህ ፋይል የገጽ ይዘቶች በጊዜው ሊመረመሩ አልቻሉም።"
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "ይህ ርዕስ አንድ ተንታኞች የሚፈልጉት አይደለም።"
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "لا يوجد رابط لملف تعريف أو ملف أعمال أو
msgid "There is no summary paragraph."
msgstr "لا توجد فقرة ملخّص."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "لم تتوفر معلومات كافية لتشغيل هذا الفحص."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "تعمل هذه الفحوصات أثناء الكتابة ولا تغادر متصفحك أبدًا. وهي تختبر ما إذا كانت البرامج تستطيع قراءة سيرتك الذاتية، لا مدى جودة كتابتها."
@@ -6168,14 +6164,6 @@ msgstr "لا يمكن التراجع عن هذا الإجراء. سيحذف رس
msgid "This assistant could not be opened."
msgstr "تعذر فتح هذا المساعد."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "لا ينطبق هذا الفحص على هذا الملف."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "يعمل هذا الفحص فقط على السير الذاتية المكتوبة بالإنجليزية."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "طلب الاتصال هذا غير صالح أو انتهت صلاحيته."
@@ -6260,10 +6248,6 @@ msgstr "يستخدم هذا الملف عددًا كبيرًا من الخطوط
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "يستخدم هذا الملف خطوط Type 3، التي تحمل رسومات بدلاً من أحرف."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "تعذّر فحص محتوى صفحات هذا الملف في الوقت المحدد."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "هذا العنوان ليس واحدًا يبحث عنه المحللون."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Profilə, portfolioya və ya repozitoriyaya keçid yoxdur."
msgid "There is no summary paragraph."
msgstr "Xülasə paraqrafı yoxdur."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Bu yoxlamanı aparmaq üçün kifayət qədər məlumat yox idi."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Bu yoxlamalar siz yazdıqca işləyir və heç vaxt brauzerinizdən çıxmır. Onlar CV-nizin nə qədər yaxşı yazıldığını deyil, proqramın onu oxuya bilib-bilmədiyini yoxlayır."
@@ -6168,14 +6164,6 @@ msgstr "Bunu geri qaytarmaq mümkün deyil. Mövzunun mesajlarını və yüklən
msgid "This assistant could not be opened."
msgstr "Bu köməkçi açıla bilmədi."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Bu yoxlama bu fayla aid deyil."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Bu yoxlama yalnız ingilis dilində yazılmış CV-lər üzərində işləyir."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Bu əlaqə sorğusu etibarsızdır və ya vaxtı keçib."
@@ -6260,10 +6248,6 @@ msgstr "Bu fayl çoxlu müxtəlif şrift istifadə edir."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Bu fayl simvollar əvəzinə şəkillər daşıyan Type 3 şriftlərindən istifadə edir."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Bu faylın səhifə məzmunu vaxtında yoxlanıla bilmədi."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Bu başlıq təhlilçilərin axtardığı bir başlıq deyil."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Няма връзка към профил, портфолио или х
msgid "There is no summary paragraph."
msgstr "Няма абзац с резюме."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Нямаше достатъчно информация за изпълнение на тази проверка."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Тези проверки се извършват, докато пишете, и никога не напускат браузъра ви. Те проверяват дали софтуерът може да прочете автобиографията ви, а не колко добре е написана."
@@ -6168,14 +6164,6 @@ msgstr "Това действие не може да бъде отменено.
msgid "This assistant could not be opened."
msgstr "Този асистент не можа да бъде отворен."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Тази проверка не важи за този файл."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Тази проверка се изпълнява само за автобиографии, написани на английски език."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Тази заявка за връзка е невалидна или е изтекла."
@@ -6260,10 +6248,6 @@ msgstr "Този файл използва много различни шриф
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Този файл използва шрифтове Type 3, които съдържат рисунки вместо знаци."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Съдържанието на страниците на този файл не можа да бъде прегледано навреме."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Това заглавие не е това, което анализаторите търсят."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "কোনো প্রোফাইল, পোর্টফোলিও
msgid "There is no summary paragraph."
msgstr "কোনো সারাংশ অনুচ্ছেদ নেই।"
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "এই চেক চালানোর জন্য পর্যাপ্ত তথ্য ছিল না।"
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "এই পরীক্ষাগুলো আপনি টাইপ করার সঙ্গে সঙ্গেই চলে এবং কখনও আপনার ব্রাউজারের বাইরে যায় না। এগুলো যাচাই করে সফটওয়্যার আপনার জীবনবৃত্তান্ত পড়তে পারে কি না, সেটি কতটা ভালো লেখা তা নয়।"
@@ -6168,14 +6164,6 @@ msgstr "এই কাজটি ফিরিয়ে নেওয়া যা
msgid "This assistant could not be opened."
msgstr "এই সহকারীকে খোলা যায়নি।"
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "এই চেকটি এই ফাইলের ক্ষেত্রে প্রযোজ্য নয়।"
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "এই চেকটি শুধুমাত্র ইংরেজিতে লেখা জীবনবৃত্তান্তে চলে।"
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "এই সংযোগ অনুরোধটি অবৈধ বা মেয়াদোত্তীর্ণ।"
@@ -6260,10 +6248,6 @@ msgstr "এই ফাইলে অনেকগুলো ভিন্ন ফন
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "এই ফাইলে Type 3 ফন্ট ব্যবহার করা হয়েছে, যা অক্ষরের বদলে অঙ্কন বহন করে।"
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "এই ফাইলের পৃষ্ঠার বিষয়বস্তু সময়মতো পরীক্ষা করা যায়নি।"
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "এই শিরোনামটি এক পার্সারের জন্য নয়।"
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "No hi ha cap enllaç a un perfil, portafoli o repositori."
msgid "There is no summary paragraph."
msgstr "No hi ha cap paràgraf de resum."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "No hi havia prou informació per executar aquesta comprovació."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Aquestes comprovacions s'executen mentre escrius i no surten mai del teu navegador. Comproven si un programa pot llegir el teu currículum, no com de ben escrit està."
@@ -6168,14 +6164,6 @@ msgstr "Aquesta acció no es pot desfer. Suprimeix els missatges del fil i els f
msgid "This assistant could not be opened."
msgstr "No s'ha pogut obrir aquest assistent."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Aquesta comprovació no s'aplica a aquest fitxer."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Aquesta comprovació només s'executa en currículums escrits en anglès."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Aquesta sol·licitud de connexió no és vàlida o ha caducat."
@@ -6260,10 +6248,6 @@ msgstr "Aquest fitxer utilitza molts tipus de lletra diferents."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Aquest fitxer utilitza tipus de lletra Type 3, que porten dibuixos en lloc de caràcters."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "El contingut de les pàgines d'aquest fitxer no s'ha pogut inspeccionar a temps."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Aquest encapçalament no és un dels que busquen els analitzadors sintàctics."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Chybí odkaz na profil, portfolio nebo repozitář."
msgid "There is no summary paragraph."
msgstr "Chybí souhrnný odstavec."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Nebylo dostatek informací ke spuštění této kontroly."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Tyto kontroly běží během psaní a nikdy neopustí váš prohlížeč. Testují, zda software dokáže váš životopis přečíst, ne jak dobře je napsaný."
@@ -6168,14 +6164,6 @@ msgstr "Tuto akci nelze vrátit zpět. Odstraní zprávy vlákna a nahrané př
msgid "This assistant could not be opened."
msgstr "Tohoto asistenta se nepodařilo otevřít."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Tato kontrola se na tento soubor nevztahuje."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Tato kontrola se spouští pouze u životopisů psaných v angličtině."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Tento požadavek na připojení je neplatný nebo jeho platnost vypršela."
@@ -6260,10 +6248,6 @@ msgstr "Tento soubor používá mnoho různých písem."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Tento soubor používá písma typu 3, která obsahují kresby místo znaků."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Obsah stránek tohoto souboru se nepodařilo včas zkontrolovat."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Tento nadpis nehledají analyzátory."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Der er intet link til en profil, portfolio eller et repository."
msgid "There is no summary paragraph."
msgstr "Der er ikke noget resuméafsnit."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Der var ikke nok oplysninger til at køre dette tjek."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Disse tjek kører, mens du skriver, og forlader aldrig din browser. De tester, om software kan læse dit CV, ikke hvor godt det er skrevet."
@@ -6168,14 +6164,6 @@ msgstr "Dette kan ikke fortrydes. Det sletter trådens beskeder og de uploadede
msgid "This assistant could not be opened."
msgstr "Denne assistent kunne ikke åbnes."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Dette tjek gælder ikke for denne fil."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Dette tjek kører kun på CV'er skrevet på engelsk."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Denne forbindelsesanmodning er ugyldig eller udløbet."
@@ -6260,10 +6248,6 @@ msgstr "Denne fil bruger mange forskellige skrifttyper."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Denne fil bruger Type 3-skrifttyper, som indeholder tegninger i stedet for tegn."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Denne fils sideindhold kunne ikke undersøges i tide."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Denne overskrift er ikke én, som parsere leder efter."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Es gibt keinen Link zu einem Profil, Portfolio oder Repository."
msgid "There is no summary paragraph."
msgstr "Es gibt keinen zusammenfassenden Absatz."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Es gab nicht genug Informationen, um diese Prüfung durchzuführen."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Diese Prüfungen laufen während der Eingabe und verlassen Ihren Browser nie. Sie testen, ob Software Ihren Lebenslauf lesen kann, nicht wie gut er geschrieben ist."
@@ -6168,14 +6164,6 @@ msgstr "Diese Aktion kann nicht rückgängig gemacht werden. Sie löscht die Nac
msgid "This assistant could not be opened."
msgstr "Dieser Assistent konnte nicht geöffnet werden."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Diese Prüfung gilt nicht für diese Datei."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Diese Prüfung läuft nur bei Lebensläufen, die auf Englisch verfasst sind."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Diese Verbindungsanfrage ist ungültig oder abgelaufen."
@@ -6260,10 +6248,6 @@ msgstr "Diese Datei verwendet viele verschiedene Schriftarten."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Diese Datei verwendet Type-3-Schriftarten, die Zeichnungen statt Zeichen enthalten."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Die Seiteninhalte dieser Datei konnten nicht rechtzeitig untersucht werden."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Diese Überschrift ist nicht diejenige, nach der Parser suchen."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Δεν υπάρχει σύνδεσμος προς προφίλ, portfoli
msgid "There is no summary paragraph."
msgstr "Δεν υπάρχει παράγραφος περίληψης."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Δεν υπήρχαν αρκετές πληροφορίες για την εκτέλεση αυτού του ελέγχου."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Αυτοί οι έλεγχοι εκτελούνται καθώς πληκτρολογείτε και δεν φεύγουν ποτέ από το πρόγραμμα περιήγησής σας. Ελέγχουν αν το λογισμικό μπορεί να διαβάσει το βιογραφικό σας, όχι πόσο καλά είναι γραμμένο."
@@ -6168,14 +6164,6 @@ msgstr "Αυτή η ενέργεια δεν μπορεί να αναιρεθεί
msgid "This assistant could not be opened."
msgstr "Δεν ήταν δυνατό το άνοιγμα αυτού του βοηθού."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Αυτός ο έλεγχος δεν ισχύει για αυτό το αρχείο."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Αυτός ο έλεγχος εκτελείται μόνο σε βιογραφικά γραμμένα στα αγγλικά."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Αυτό το αίτημα σύνδεσης δεν είναι έγκυρο ή έχει λήξει."
@@ -6260,10 +6248,6 @@ msgstr "Αυτό το αρχείο χρησιμοποιεί πολλές δια
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Αυτό το αρχείο χρησιμοποιεί γραμματοσειρές Type 3, οι οποίες περιέχουν σχέδια αντί για χαρακτήρες."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Το περιεχόμενο των σελίδων αυτού του αρχείου δεν μπόρεσε να επιθεωρηθεί εγκαίρως."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Αυτή η επικεφαλίδα δεν αναζητείται από τους αναλυτές."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "There is no link to a profile, portfolio or repository."
msgid "There is no summary paragraph."
msgstr "There is no summary paragraph."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "There was not enough information to run this check."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
@@ -6168,14 +6164,6 @@ msgstr "This action cannot be undone. It deletes the thread's messages and uploa
msgid "This assistant could not be opened."
msgstr "This assistant could not be opened."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "This check does not apply to this file."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "This check only runs on resumes written in English."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "This connection request is invalid or has expired."
@@ -6260,10 +6248,6 @@ msgstr "This file uses a lot of different fonts."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "This file uses Type 3 fonts, which carry drawings instead of characters."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "This file's page contents could not be inspected in time."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "This heading is not one parsers look for."
-16
View File
@@ -6126,10 +6126,6 @@ msgstr "There is no link to a profile, portfolio or repository."
msgid "There is no summary paragraph."
msgstr "There is no summary paragraph."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "There was not enough information to run this check."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
@@ -6163,14 +6159,6 @@ msgstr "This action cannot be undone. It deletes the thread's messages and uploa
msgid "This assistant could not be opened."
msgstr "This assistant could not be opened."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "This check does not apply to this file."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "This check only runs on resumes written in English."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "This connection request is invalid or has expired."
@@ -6255,10 +6243,6 @@ msgstr "This file uses a lot of different fonts."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "This file uses Type 3 fonts, which carry drawings instead of characters."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "This file's page contents could not be inspected in time."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "This heading is not one parsers look for."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "No hay ningún enlace a un perfil, portafolio o repositorio."
msgid "There is no summary paragraph."
msgstr "No hay ningún párrafo de resumen."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "No hubo suficiente información para ejecutar esta comprobación."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Estas comprobaciones se ejecutan mientras escribes y nunca salen de tu navegador. Comprueban si un programa puede leer tu currículum, no lo bien escrito que está."
@@ -6168,14 +6164,6 @@ msgstr "Esta acción no se puede deshacer. Elimina los mensajes del hilo y los a
msgid "This assistant could not be opened."
msgstr "No se pudo abrir este asistente."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Esta comprobación no se aplica a este archivo."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Esta comprobación solo se ejecuta en currículums escritos en inglés."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Esta solicitud de conexión no es válida o ha caducado."
@@ -6260,10 +6248,6 @@ msgstr "Este archivo utiliza muchas fuentes distintas."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Este archivo utiliza fuentes Type 3, que contienen dibujos en lugar de caracteres."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "No se pudo inspeccionar a tiempo el contenido de las páginas de este archivo."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Este encabezado no es el que buscan los analizadores."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "هیچ لینکی به پروفایل، پورتفولیو یا مخزن
msgid "There is no summary paragraph."
msgstr "هیچ پاراگراف خلاصه‌ای وجود ندارد."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "اطلاعات کافی برای اجرای این بررسی وجود نداشت."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "این بررسی‌ها همزمان با تایپ اجرا می‌شوند و هرگز از مرورگر شما خارج نمی‌شوند. آن‌ها می‌سنجند که آیا نرم‌افزار می‌تواند رزومهٔ شما را بخواند، نه اینکه چقدر خوب نوشته شده است."
@@ -6168,14 +6164,6 @@ msgstr "این کار قابل بازگشت نیست. پیام‌های تاپی
msgid "This assistant could not be opened."
msgstr "این دستیار قابل باز شدن نیست."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "این بررسی برای این فایل قابل اجرا نیست."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "این بررسی فقط روی رزومه‌های نوشته‌شده به زبان انگلیسی اجرا می‌شود."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "این درخواست اتصال نامعتبر است یا منقضی شده است."
@@ -6260,10 +6248,6 @@ msgstr "این فایل از فونت‌های متفاوت زیادی استف
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "این فایل از فونت‌های Type 3 استفاده می‌کند که به‌جای نویسه، تصویر حمل می‌کنند."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "محتوای صفحات این فایل به‌موقع قابل بازرسی نبود."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "این عنوان از عنوان‌هایی نیست که تجزیه‌گرها به دنبال آن هستند."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Linkkiä profiiliin, portfolioon tai koodivarastoon ei ole."
msgid "There is no summary paragraph."
msgstr "Yhteenvetokappaletta ei ole."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Tietoa ei ollut riittävästi tämän tarkistuksen suorittamiseen."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Nämä tarkistukset suoritetaan kirjoittaessasi eivätkä ne poistu selaimestasi. Ne testaavat, pystyykö ohjelmisto lukemaan ansioluettelosi, eivät sitä, miten hyvin se on kirjoitettu."
@@ -6168,14 +6164,6 @@ msgstr "Tätä toimintoa ei voi perua. Se poistaa viestiketjun viestit ja ladatu
msgid "This assistant could not be opened."
msgstr "Tätä avustajaa ei voitu avata."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Tämä tarkistus ei koske tätä tiedostoa."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Tämä tarkistus suoritetaan vain englanniksi kirjoitetuille ansioluetteloille."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Tämä yhteyspyyntö on virheellinen tai vanhentunut."
@@ -6260,10 +6248,6 @@ msgstr "Tämä tiedosto käyttää paljon eri fontteja."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Tämä tiedosto käyttää Type 3 -fontteja, jotka sisältävät piirroksia merkkien sijaan."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Tämän tiedoston sivujen sisältöä ei voitu tarkastaa ajoissa."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Tämä otsikko ei ole jäsentäjien etsimä."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Il n'y a aucun lien vers un profil, un portfolio ou un dépôt."
msgid "There is no summary paragraph."
msgstr "Il n'y a pas de paragraphe de résumé."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Il n'y avait pas assez d'informations pour exécuter cette vérification."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Ces vérifications s'exécutent au fur et à mesure que vous écrivez et ne quittent jamais votre navigateur. Elles testent si un logiciel peut lire votre CV, pas la qualité de sa rédaction."
@@ -6168,14 +6164,6 @@ msgstr "Cette action est irréversible. Elle supprime les messages de la discuss
msgid "This assistant could not be opened."
msgstr "Impossible d'ouvrir cet assistant."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Cette vérification ne s'applique pas à ce fichier."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Cette vérification ne s'exécute que sur les CV rédigés en anglais."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Cette demande de connexion est invalide ou a expiré."
@@ -6260,10 +6248,6 @@ msgstr "Ce fichier utilise beaucoup de polices différentes."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Ce fichier utilise des polices Type 3, qui contiennent des dessins au lieu de caractères."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Le contenu des pages de ce fichier n'a pas pu être inspecté à temps."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Cet en-tête n'est pas celui que recherchent les analyseurs."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "אין קישור לפרופיל, לתיק עבודות או למאגר
msgid "There is no summary paragraph."
msgstr "אין פסקת תקציר."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "לא היה מספיק מידע כדי להריץ את הבדיקה הזו."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "הבדיקות האלה רצות תוך כדי הקלדה ולעולם אינן עוזבות את הדפדפן שלך. הן בודקות אם תוכנה מסוגלת לקרוא את קורות החיים שלך, לא עד כמה הם כתובים היטב."
@@ -6168,14 +6164,6 @@ msgstr "לא ניתן לבטל פעולה זו. היא מוחקת את הודע
msgid "This assistant could not be opened."
msgstr "לא ניתן היה לפתוח את העוזר הזה."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "הבדיקה הזו לא רלוונטית לקובץ הזה."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "הבדיקה הזו רצה רק על קורות חיים שכתובים באנגלית."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "בקשת חיבור זו אינה חוקית או שפג תוקפו."
@@ -6260,10 +6248,6 @@ msgstr "הקובץ הזה משתמש בהרבה גופנים שונים."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "הקובץ הזה משתמש בגופני Type 3, שנושאים ציורים במקום תווים."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "לא ניתן היה לבדוק את תוכן העמודים של הקובץ הזה בזמן."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "זו אינה כותרת שמנתחים מחפשים."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "किसी प्रोफ़ाइल, पोर्टफ़ोलि
msgid "There is no summary paragraph."
msgstr "कोई सारांश पैराग्राफ नहीं है।"
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "यह जांच चलाने के लिए पर्याप्त जानकारी नहीं थी।"
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "ये जाँचें आपके टाइप करते ही चलती हैं और कभी आपके ब्राउज़र से बाहर नहीं जातीं। ये यह परखती हैं कि सॉफ़्टवेयर आपका रेज़्यूमे पढ़ पाता है या नहीं, यह नहीं कि वह कितना अच्छा लिखा गया है।"
@@ -6168,14 +6164,6 @@ msgstr "इस कार्रवाई को पूर्ववत नही
msgid "This assistant could not be opened."
msgstr "इस सहायक को खोला नहीं जा सका।"
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "यह जांच इस फ़ाइल पर लागू नहीं होती।"
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "यह जांच केवल अंग्रेज़ी में लिखे बायोडाटा पर चलती है।"
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "यह कनेक्शन अनुरोध अमान्य है या समाप्त हो चुका है."
@@ -6260,10 +6248,6 @@ msgstr "इस फ़ाइल में कई अलग-अलग फ़ॉन
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "यह फ़ाइल Type 3 फ़ॉन्ट का उपयोग करती है, जो अक्षरों के बजाय चित्र रखते हैं।"
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "इस फ़ाइल की पेज सामग्री समय पर जांची नहीं जा सकी।"
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "यह शीर्षक वह नहीं है जिसे पार्सर्स ढूंढते हैं।"
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Nincs link egy profilra, portfólióra vagy tárolóra (repository)."
msgid "There is no summary paragraph."
msgstr "Nincs összefoglaló bekezdés."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Nem volt elég információ ennek az ellenőrzésnek a lefuttatásához."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Ezek az ellenőrzések gépelés közben futnak, és soha nem hagyják el a böngészőjét. Azt vizsgálják, hogy a szoftver el tudja-e olvasni az önéletrajzát, nem azt, hogy mennyire jól van megírva."
@@ -6168,14 +6164,6 @@ msgstr "Ez a művelet nem vonható vissza. Törli a szál üzeneteit és a felt
msgid "This assistant could not be opened."
msgstr "Ez az asszisztens nem nyitható meg."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Ez az ellenőrzés nem vonatkozik erre a fájlra."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Ez az ellenőrzés csak angol nyelvű önéletrajzokon fut."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Ez a csatlakozási kérelem érvénytelen vagy lejárt."
@@ -6260,10 +6248,6 @@ msgstr "Ez a fájl sok különböző betűtípust használ."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Ez a fájl Type 3 betűtípusokat használ, amelyek karakterek helyett rajzokat hordoznak."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Ennek a fájlnak az oldaltartalmát nem sikerült időben megvizsgálni."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Ezt a címsort nem az elemzők keresik."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Tidak ada tautan ke profil, portofolio, atau repositori."
msgid "There is no summary paragraph."
msgstr "Tidak ada paragraf ringkasan."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Informasi tidak cukup untuk menjalankan pemeriksaan ini."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Pemeriksaan ini berjalan saat Anda mengetik dan tidak pernah keluar dari peramban Anda. Pemeriksaan menguji apakah perangkat lunak dapat membaca resume Anda, bukan seberapa baik tulisannya."
@@ -6168,14 +6164,6 @@ msgstr "Tindakan ini tidak dapat dibatalkan. Tindakan ini menghapus pesan-pesan
msgid "This assistant could not be opened."
msgstr "Asisten ini tidak dapat dibuka."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Pemeriksaan ini tidak berlaku untuk file ini."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Pemeriksaan ini hanya berjalan pada resume yang ditulis dalam bahasa Inggris."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Permintaan koneksi ini tidak valid atau telah kedaluwarsa."
@@ -6260,10 +6248,6 @@ msgstr "File ini menggunakan banyak font yang berbeda."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "File ini menggunakan font Type 3, yang memuat gambar, bukan karakter."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Isi halaman file ini tidak dapat diperiksa tepat waktu."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Judul ini bukan yang dicari parser."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Non c'è alcun link a un profilo, portfolio o repository."
msgid "There is no summary paragraph."
msgstr "Non c'è un paragrafo di riepilogo."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Non c'erano informazioni sufficienti per eseguire questo controllo."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Questi controlli vengono eseguiti mentre scrivi e non escono mai dal tuo browser. Verificano se un software riesce a leggere il tuo curriculum, non quanto è scritto bene."
@@ -6168,14 +6164,6 @@ msgstr "L'operazione non può essere annullata. Elimina i messaggi del thread e
msgid "This assistant could not be opened."
msgstr "Impossibile aprire questo assistente."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Questo controllo non si applica a questo file."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Questo controllo viene eseguito solo su curriculum scritti in inglese."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Questa richiesta di connessione non è valida o è scaduta."
@@ -6260,10 +6248,6 @@ msgstr "Questo file usa molti font diversi."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Questo file usa font Type 3, che contengono disegni anziché caratteri."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Non è stato possibile analizzare in tempo il contenuto delle pagine di questo file."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Questa intestazione non è quella cercata dai parser."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "プロフィール、ポートフォリオ、リポジトリへのリン
msgid "There is no summary paragraph."
msgstr "概要の段落がありません。"
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "このチェックを実行するための情報が不足していました。"
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "これらのチェックは入力中に実行され、ブラウザの外に出ることはありません。文章の出来ではなく、ソフトウェアが履歴書を読めるかどうかを確認します。"
@@ -6168,14 +6164,6 @@ msgstr "この操作は元に戻せません。スレッドのメッセージと
msgid "This assistant could not be opened."
msgstr "このアシスタントを開くことができませんでした。"
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "このチェックはこのファイルには適用されません。"
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "このチェックは英語で書かれた履歴書にのみ実行されます。"
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "この接続リクエストは無効か、有効期限が切れています。"
@@ -6260,10 +6248,6 @@ msgstr "このファイルは多くの異なるフォントを使用していま
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "このファイルはType 3フォントを使用しています。これは文字ではなく図形データを保持します。"
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "このファイルのページ内容を時間内に検査できませんでした。"
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "この見出しはパーサーが探すものではありません。"
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "គ្មានតំណភ្ជាប់ទៅកាន់ប្រវ
msgid "There is no summary paragraph."
msgstr "គ្មានកថាខណ្ឌសង្ខេបទេ។"
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "គ្មានព័ត៌មានគ្រប់គ្រាន់ដើម្បីដំណើរការការត្រួតពិនិត្យនេះទេ។"
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "ការត្រួតពិនិត្យទាំងនេះដំណើរការនៅពេលអ្នកវាយបញ្ចូល ហើយមិនដែលចេញពីកម្មវិធីរុករករបស់អ្នកឡើយ។ វាសាកល្បងថាតើកម្មវិធីអាចអានប្រវត្តិរូបសង្ខេបរបស់អ្នកបានឬអត់ មិនមែនថាវាត្រូវបានសរសេរល្អប៉ុណ្ណានោះទេ។"
@@ -6168,14 +6164,6 @@ msgstr "សកម្មភាពនេះមិនអាចត្រឡប់វ
msgid "This assistant could not be opened."
msgstr "មិនអាចបើកជំនួយការនេះបានទេ។"
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "ការត្រួតពិនិត្យនេះមិនអនុវត្តចំពោះឯកសារនេះទេ។"
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "ការត្រួតពិនិត្យនេះដំណើរការតែលើប្រវត្តិរូបសង្ខេបដែលសរសេរជាភាសាអង់គ្លេសប៉ុណ្ណោះ។"
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "សំណើ​តភ្ជាប់​នេះ​មិន​ត្រឹមត្រូវ ឬ​បាន​ផុត​កំណត់។"
@@ -6260,10 +6248,6 @@ msgstr "ឯកសារនេះប្រើពុម្ពអក្សរផ្
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "ឯកសារនេះប្រើពុម្ពអក្សរ Type 3 ដែលផ្ទុករូបគូរជំនួសឱ្យតួអក្សរ។"
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "មាតិកាទំព័ររបស់ឯកសារនេះមិនអាចត្រូវបានពិនិត្យទាន់ពេលទេ។"
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "ចំណងជើងនេះមិនមែនជាអ្នកវិភាគស្វែងរកទេ។"
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "ಪ್ರೊಫೈಲ್, ಪೋರ್ಟ್‌ಫೋಲಿಯೊ ಅಥ
msgid "There is no summary paragraph."
msgstr "ಯಾವುದೇ ಸಾರಾಂಶ ಪ್ಯಾರಾಗ್ರಾಫ್ ಇಲ್ಲ."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "ಈ ಪರಿಶೀಲನೆಯನ್ನು ನಡೆಸಲು ಸಾಕಷ್ಟು ಮಾಹಿತಿ ಇರಲಿಲ್ಲ."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "ನೀವು ಟೈಪ್ ಮಾಡುತ್ತಿರುವಾಗಲೇ ಈ ಪರಿಶೀಲನೆಗಳು ನಡೆಯುತ್ತವೆ ಮತ್ತು ಅವು ನಿಮ್ಮ ಬ್ರೌಸರ್ ಅನ್ನು ಎಂದಿಗೂ ಬಿಟ್ಟು ಹೋಗುವುದಿಲ್ಲ. ನಿಮ್ಮ ರೆಸ್ಯೂಮ್ ಅನ್ನು ತಂತ್ರಾಂಶ ಓದಬಲ್ಲದೇ ಎಂಬುದನ್ನಷ್ಟೇ ಅವು ಪರೀಕ್ಷಿಸುತ್ತವೆ, ಅದು ಎಷ್ಟು ಚೆನ್ನಾಗಿ ಬರೆದಿದೆ ಎಂಬುದನ್ನಲ್ಲ."
@@ -6168,14 +6164,6 @@ msgstr "ಈ ಕ್ರಿಯೆಯನ್ನು ಹಿಂತಿರುಗಿಸಲ
msgid "This assistant could not be opened."
msgstr "ಈ ಸಹಾಯಕವನ್ನು ತೆರೆಯಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "ಈ ಪರಿಶೀಲನೆ ಈ ಫೈಲ್‌ಗೆ ಅನ್ವಯಿಸುವುದಿಲ್ಲ."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "ಈ ಪರಿಶೀಲನೆ ಇಂಗ್ಲಿಷ್‌ನಲ್ಲಿ ಬರೆದ ರೆಸ್ಯೂಮೆಗಳಲ್ಲಿ ಮಾತ್ರ ನಡೆಯುತ್ತದೆ."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "ಈ ಸಂಪರ್ಕ ವಿನಂತಿಯು ಅಮಾನ್ಯವಾಗಿದೆ ಅಥವಾ ಅವಧಿ ಮೀರಿದೆ."
@@ -6260,10 +6248,6 @@ msgstr "ಈ ಫೈಲ್ ಹಲವಾರು ವಿಭಿನ್ನ ಫಾಂಟ
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "ಈ ಫೈಲ್ Type 3 ಫಾಂಟ್‌ಗಳನ್ನು ಬಳಸುತ್ತದೆ, ಇವು ಅಕ್ಷರಗಳ ಬದಲು ಚಿತ್ರಗಳನ್ನು ಹೊಂದಿರುತ್ತವೆ."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "ಈ ಫೈಲ್‌ನ ಪುಟದ ವಿಷಯವನ್ನು ಸಮಯಕ್ಕೆ ಪರಿಶೀಲಿಸಲಾಗಲಿಲ್ಲ."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "ಈ ಶಿರೋನಾಮೆ ಒಂದು ಪಾರ್ಸರ್‌ಗಳು ಹುಡುಕುತ್ತಿಲ್ಲ."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "프로필, 포트폴리오 또는 저장소로 연결되는 링크가
msgid "There is no summary paragraph."
msgstr "요약 문단이 없습니다."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "이 점검을 실행할 충분한 정보가 없었습니다."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "이 점검은 입력하는 동안 실행되며 브라우저를 벗어나지 않습니다. 글이 얼마나 잘 쓰였는지가 아니라, 소프트웨어가 이력서를 읽을 수 있는지를 확인합니다."
@@ -6168,14 +6164,6 @@ msgstr "이 작업은 되돌릴 수 없습니다. 스레드의 메시지와 업
msgid "This assistant could not be opened."
msgstr "이 도우미를 열 수 없습니다."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "이 점검은 이 파일에 해당하지 않습니다."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "이 점검은 영어로 작성된 이력서에서만 실행됩니다."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "이 연결 요청이 유효하지 않거나 만료되었습니다."
@@ -6260,10 +6248,6 @@ msgstr "이 파일이 매우 다양한 폰트를 사용하고 있습니다."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "이 파일은 문자 대신 그림 정보를 담는 Type 3 폰트를 사용하고 있습니다."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "이 파일의 페이지 내용을 시간 내에 검사하지 못했습니다."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "이 제목은 파서가 찾는 항목이 아닙니다."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Nėra nuorodos į profilį, portfolio ar saugyklą."
msgid "There is no summary paragraph."
msgstr "Nėra apibendrinančios pastraipos."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Nepakako informacijos šiai patikrai atlikti."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Šios patikros vyksta jums rašant ir niekada nepalieka jūsų naršyklės. Jos tikrina, ar programinė įranga gali perskaityti jūsų gyvenimo aprašymą, o ne kaip gerai jis parašytas."
@@ -6168,14 +6164,6 @@ msgstr "Šio veiksmo atšaukti negalima. Jis ištrina temos žinutes ir įkeltus
msgid "This assistant could not be opened."
msgstr "Šio asistento atidaryti nepavyko."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Ši patikra šiam failui netaikoma."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Ši patikra atliekama tik angliškai parašytiems gyvenimo aprašymams."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Ši ryšio užklausa neteisinga arba pasibaigė."
@@ -6260,10 +6248,6 @@ msgstr "Šiame faile naudojama daug skirtingų šriftų."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Šiame faile naudojami Type 3 šriftai, kurie vietoje simbolių saugo piešinius."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Nepavyko laiku patikrinti šio failo puslapių turinio."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Ši antraštė nėra ta, kurios analizatoriai ieško."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Nav saites uz profilu, portfolio vai repozitoriju."
msgid "There is no summary paragraph."
msgstr "Nav kopsavilkuma rindkopas."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Nebija pietiekami daudz informācijas, lai veiktu šo pārbaudi."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Šīs pārbaudes notiek jums rakstot un nekad nepamet jūsu pārlūkprogrammu. Tās pārbauda, vai programmatūra spēj izlasīt jūsu CV, nevis to, cik labi tas ir uzrakstīts."
@@ -6168,14 +6164,6 @@ msgstr "Šo darbību nevar atsaukt. Tā izdzēš tēmas ziņas un augšupielād
msgid "This assistant could not be opened."
msgstr "Šo palīgu nevarēja atvērt."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Šī pārbaude neattiecas uz šo failu."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Šī pārbaude tiek veikta tikai angļu valodā rakstītiem CV."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Šis savienojuma pieprasījums nav derīgs vai ir beidzies."
@@ -6260,10 +6248,6 @@ msgstr "Šis fails izmanto daudzus dažādus fontus."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Šis fails izmanto Type 3 fontus, kas satur zīmējumus, nevis rakstzīmes."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Šī faila lapu saturu neizdevās pārbaudīt laikā."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Šis virsraksts nav tas, ko parsētāji meklē."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "പ്രൊഫൈൽ, പോർട്ട്‌ഫോളിയോ അല
msgid "There is no summary paragraph."
msgstr "സംഗ്രഹ ഖണ്ഡിക ഇല്ല."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "ഈ പരിശോധന നടത്താൻ ആവശ്യമായ വിവരങ്ങൾ ഇല്ലായിരുന്നു."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "നിങ്ങൾ ടൈപ്പ് ചെയ്യുന്നതിനൊപ്പം ഈ പരിശോധനകൾ നടക്കുന്നു, അവ ഒരിക്കലും നിങ്ങളുടെ ബ്രൗസർ വിട്ടുപോകുന്നില്ല. നിങ്ങളുടെ റിസ്യൂം സോഫ്റ്റ്‌വെയറിന് വായിക്കാനാകുമോ എന്നാണ് അവ പരിശോധിക്കുന്നത്, അത് എത്ര നന്നായി എഴുതിയിരിക്കുന്നു എന്നല്ല."
@@ -6168,14 +6164,6 @@ msgstr "ഈ പ്രവൃത്തി പഴയപടിയാക്കാൻ
msgid "This assistant could not be opened."
msgstr "ഈ അസിസ്റ്റന്റ് തുറക്കാൻ കഴിഞ്ഞില്ല."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "ഈ പരിശോധന ഈ ഫയലിന് ബാധകമല്ല."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "ഇംഗ്ലീഷിൽ എഴുതിയ റിസ്യൂമുകളിൽ മാത്രമേ ഈ പരിശോധന പ്രവർത്തിക്കൂ."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "ഈ കണക്ഷൻ അഭ്യർത്ഥന അസാധുവാണ് അല്ലെങ്കിൽ കാലഹരണപ്പെട്ടു."
@@ -6260,10 +6248,6 @@ msgstr "ഈ ഫയൽ ധാരാളം വ്യത്യസ്ത ഫോണ
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "ഈ ഫയൽ Type 3 ഫോണ്ടുകൾ ഉപയോഗിക്കുന്നു, അവ അക്ഷരങ്ങൾക്ക് പകരം ഡ്രോയിംഗുകൾ വഹിക്കുന്നു."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "ഈ ഫയലിന്റെ പേജ് ഉള്ളടക്കം സമയബന്ധിതമായി പരിശോധിക്കാൻ കഴിഞ്ഞില്ല."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "ഈ തലക്കെട്ട് പാഴ്‌സർമാർ തിരയുന്ന ഒന്നല്ല."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "प्रोफाइल, पोर्टफोलिओ किंवा
msgid "There is no summary paragraph."
msgstr "सारांश परिच्छेद नाही."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "ही तपासणी चालवण्यासाठी पुरेशी माहिती नव्हती."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "या तपासण्या तुम्ही टाइप करताच चालतात आणि कधीही तुमच्या ब्राउझरबाहेर जात नाहीत. सॉफ्टवेअर तुमचा रेझ्युमे वाचू शकते का हे त्या तपासतात, तो किती चांगला लिहिला आहे हे नाही."
@@ -6168,14 +6164,6 @@ msgstr "ही क्रिया उलट करता येणार ना
msgid "This assistant could not be opened."
msgstr "हा असिस्टंट उघडता आला नाही."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "ही तपासणी या फाइलला लागू होत नाही."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "ही तपासणी फक्त इंग्रजीत लिहिलेल्या रेझ्युमेंवर चालते."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "हा कनेक्शन विनंती अमान्य आहे किंवा कालबाह्य झाली आहे."
@@ -6260,10 +6248,6 @@ msgstr "ही फाइल अनेक वेगवेगळे फाँट
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "ही फाइल Type 3 फाँट्स वापरते, जे अक्षरांऐवजी रेखाचित्रे वाहून नेतात."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "या फाइलच्या पानाची सामग्री वेळेत तपासता आली नाही."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "हे शीर्षक एक विश्लेषक शोधत नाही."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Tiada pautan ke profil, portfolio atau repositori."
msgid "There is no summary paragraph."
msgstr "Tiada perenggan ringkasan."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Tidak cukup maklumat untuk menjalankan semakan ini."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Pemeriksaan ini berjalan semasa anda menaip dan tidak pernah keluar daripada pelayar anda. Ia menguji sama ada perisian boleh membaca resume anda, bukan sebaik mana ia ditulis."
@@ -6168,14 +6164,6 @@ msgstr "Tindakan ini tidak boleh dibatalkan. Ia memadam mesej thread dan lampira
msgid "This assistant could not be opened."
msgstr "Pembantu ini tidak dapat dibuka."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Semakan ini tidak terpakai kepada fail ini."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Semakan ini hanya berjalan pada resume yang ditulis dalam Bahasa Inggeris."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Permintaan sambungan ini tidak sah atau telah tamat tempoh."
@@ -6260,10 +6248,6 @@ msgstr "Fail ini menggunakan banyak fon yang berbeza."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Fail ini menggunakan fon Type 3, yang membawa lukisan dan bukannya aksara."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Kandungan halaman fail ini tidak dapat diperiksa dalam masa yang ditetapkan."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Tajuk ini bukan satu yang dicari oleh penghurai."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "प्रोफाइल, पोर्टफोलियो वा र
msgid "There is no summary paragraph."
msgstr "कुनै सारांश अनुच्छेद छैन।"
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "यो चेक चलाउन पर्याप्त जानकारी थिएन।"
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "यी जाँचहरू तपाईंले टाइप गर्दै जाँदा चल्छन् र कहिल्यै तपाईंको ब्राउजरबाहिर जाँदैनन्। यिनले सफ्टवेयरले तपाईंको बायोडाटा पढ्न सक्छ कि सक्दैन भनेर जाँच्छन्, त्यो कति राम्रो लेखिएको छ भनेर होइन।"
@@ -6168,14 +6164,6 @@ msgstr "यो कार्य उल्ट्याउन सकिँदैन
msgid "This assistant could not be opened."
msgstr "यो सहायक खोल्न सकिएन।"
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "यो चेक यो फाइलमा लागू हुँदैन।"
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "यो चेक अङ्ग्रेजीमा लेखिएका बायोडाटामा मात्र चल्छ।"
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "यो जडान अनुरोध अमान्य छ वा म्याद सकिएको छ।"
@@ -6260,10 +6248,6 @@ msgstr "यो फाइलले धेरै फरक फन्ट प्र
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "यो फाइलले Type 3 फन्ट प्रयोग गर्छ, जसमा अक्षरको सट्टा चित्र हुन्छ।"
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "यो फाइलको पृष्ठ सामग्री समयमै जाँच गर्न सकिएन।"
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "यो हेडिङ एउटै पार्र्सले खोजेको होइन।"
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Er is geen link naar een profiel, portfolio of repository."
msgid "There is no summary paragraph."
msgstr "Er is geen samenvattende alinea."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Er was niet genoeg informatie om deze controle uit te voeren."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Deze controles draaien terwijl je typt en verlaten je browser nooit. Ze testen of software je cv kan lezen, niet hoe goed het geschreven is."
@@ -6168,14 +6164,6 @@ msgstr "Deze actie kan niet ongedaan worden gemaakt. Hiermee worden de berichten
msgid "This assistant could not be opened."
msgstr "Deze assistent kon niet worden geopend."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Deze controle is niet van toepassing op dit bestand."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Deze controle werkt alleen voor cv's die in het Engels zijn geschreven."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Dit koppelingsverzoek is ongeldig of verlopen."
@@ -6260,10 +6248,6 @@ msgstr "Dit bestand gebruikt veel verschillende lettertypen."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Dit bestand gebruikt Type 3-lettertypen, die tekeningen bevatten in plaats van tekens."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "De paginainhoud van dit bestand kon niet op tijd worden geïnspecteerd."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Deze link mist het protocol."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Det finnes ingen lenke til en profil, portefølje eller et kodearkiv."
msgid "There is no summary paragraph."
msgstr "Det finnes ikke noe sammendragsavsnitt."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Det var ikke nok informasjon til å kjøre denne kontrollen."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Disse kontrollene kjører mens du skriver og forlater aldri nettleseren din. De tester om programvare kan lese CV-en din, ikke hvor godt den er skrevet."
@@ -6168,14 +6164,6 @@ msgstr "Dette kan ikke angres. Det sletter trådens meldinger og de opplastede v
msgid "This assistant could not be opened."
msgstr "Denne assistenten kunne ikke åpnes."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Denne kontrollen gjelder ikke denne filen."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Denne kontrollen kjører kun på CV-er skrevet på engelsk."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Denne tilkoblingsforespørselen er ugyldig eller har utløpt."
@@ -6260,10 +6248,6 @@ msgstr "Denne filen bruker mange forskjellige skrifter."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Denne filen bruker Type 3-skrifter, som inneholder tegninger i stedet for tegn."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Sideinnholdet i denne filen kunne ikke inspiseres i tide."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Denne overskriften er ikke en parserne ser etter."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "ଏକ ପ୍ରୋଫାଇଲ୍, ପୋର୍ଟଫୋଲିଓ କ
msgid "There is no summary paragraph."
msgstr "କୌଣସି ସାରାଂଶ ଅନୁଚ୍ଛେଦ ନାହିଁ।"
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "ଏହି ଯାଞ୍ଚ ଚଲାଇବା ପାଇଁ ଯଥେଷ୍ଟ ସୂଚନା ନଥିଲା।"
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "ଆପଣ ଟାଇପ୍ କରୁଥିବା ସମୟରେ ହିଁ ଏହି ଯାଞ୍ଚଗୁଡିକ ଚାଲେ ଏବଂ ସେଗୁଡିକ କେବେ ବି ଆପଣଙ୍କ ବ୍ରାଉଜର ଛାଡ଼ି ଯାଏ ନାହିଁ। ଆପଣଙ୍କ ରେଜ୍ୟୁମେକୁ ସଫ୍ଟୱେୟାର ପଢ଼ିପାରିବ କି ନାହିଁ ତାହା ହିଁ ସେଗୁଡିକ ପରୀକ୍ଷା କରେ, ଏହା କେତେ ଭଲ ଭାବରେ ଲେଖାଯାଇଛି ତାହା ନୁହେଁ।"
@@ -6168,14 +6164,6 @@ msgstr "ଏହି କାର୍ଯ୍ୟକୁ ପୂର୍ବାବସ୍ଥା
msgid "This assistant could not be opened."
msgstr "ଏହି ସହାୟକକୁ ଖୋଲାଯାଇପାରିଲା ନାହିଁ।"
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "ଏହି ଯାଞ୍ଚ ଏହି ଫାଇଲ ପାଇଁ ପ୍ରଯୁଜ୍ୟ ନୁହେଁ।"
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "ଏହି ଯାଞ୍ଚ କେବଳ ଇଂରାଜୀରେ ଲେଖାଯାଇଥିବା ରେଜ୍ୟୁମେ ଉପରେ ଚାଲେ।"
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "ଏହି ସଂଯୋଗ ଅନୁରୋଧ ଅବ alid ଧ କିମ୍ବା ମିଆଦ ପୂର୍ଣ୍ଣ ହୋଇଛି |"
@@ -6260,10 +6248,6 @@ msgstr "ଏହି ଫାଇଲ୍ ଅନେକ ଭିନ୍ନ ଫଣ୍ଟ ବ
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "ଏହି ଫାଇଲ୍ Type 3 ଫଣ୍ଟ ବ୍ୟବହାର କରେ, ଯାହା ଅକ୍ଷର ପରିବର୍ତ୍ତେ ଚିତ୍ର ବହନ କରେ।"
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "ଏହି ଫାଇଲର ପୃଷ୍ଠା ବିଷୟବସ୍ତୁକୁ ସମୟ ମଧ୍ୟରେ ନିରୀକ୍ଷଣ କରାଯାଇ ପାରିଲା ନାହିଁ।"
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "ପାର୍ସର୍‌ଗୁଡ଼ିକ ଖୋଜୁଥିବା ଶିରୋନାମା ମଧ୍ୟରୁ ଏହା ଗୋଟିଏ ନୁହେଁ।"
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Brak odnośnika do profilu, portfolio lub repozytorium."
msgid "There is no summary paragraph."
msgstr "Brak akapitu podsumowania."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Za mało informacji, aby przeprowadzić tę kontrolę."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Te kontrole działają w trakcie pisania i nigdy nie opuszczają Twojej przeglądarki. Sprawdzają, czy oprogramowanie potrafi odczytać Twoje CV, a nie jak dobrze jest napisane."
@@ -6168,14 +6164,6 @@ msgstr "Tej akcji nie można cofnąć. Usuwa wiadomości wątku i przesłane za
msgid "This assistant could not be opened."
msgstr "Nie udało się otworzyć tego asystenta."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Ta kontrola nie dotyczy tego pliku."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Ta kontrola działa tylko dla CV napisanych w języku angielskim."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "To żądanie połączenia jest nieprawidłowe lub wygasło."
@@ -6260,10 +6248,6 @@ msgstr "Ten plik używa wielu różnych czcionek."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Ten plik używa czcionek Type 3, które zawierają rysunki zamiast znaków."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Nie udało się zbadać treści stron tego pliku w wyznaczonym czasie."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Tego nagłówka nie szukają parsery."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Não há nenhum link para um perfil, portfólio ou repositório."
msgid "There is no summary paragraph."
msgstr "Não há um parágrafo de resumo."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Não havia informações suficientes para executar esta verificação."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Estas verificações rodam enquanto você digita e nunca saem do seu navegador. Elas testam se um programa consegue ler seu currículo, não a qualidade da escrita."
@@ -6168,14 +6164,6 @@ msgstr "Esta ação não pode ser desfeita. Ela exclui as mensagens do tópico e
msgid "This assistant could not be opened."
msgstr "Não foi possível abrir este assistente."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Esta verificação não se aplica a este arquivo."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Esta verificação só é executada em currículos escritos em inglês."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Esta solicitação de conexão é inválida ou expirou."
@@ -6260,10 +6248,6 @@ msgstr "Este arquivo usa muitas fontes diferentes."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Este arquivo usa fontes Type 3, que carregam desenhos em vez de caracteres."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "O conteúdo das páginas deste arquivo não pôde ser inspecionado a tempo."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Este título não é um dos que os analisadores procuram."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Não há nenhum link para um perfil, portefólio ou repositório."
msgid "There is no summary paragraph."
msgstr "Não há nenhum parágrafo de resumo."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Não havia informação suficiente para executar esta verificação."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Estas verificações são executadas enquanto escreve e nunca saem do seu navegador. Testam se um programa consegue ler o seu currículo, não a qualidade da escrita."
@@ -6168,14 +6164,6 @@ msgstr "Esta ação não pode ser anulada. Elimina as mensagens do tópico e os
msgid "This assistant could not be opened."
msgstr "Não foi possível abrir este assistente."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Esta verificação não se aplica a este ficheiro."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Esta verificação só é executada em currículos escritos em inglês."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Este pedido de ligação é inválido ou expirou."
@@ -6260,10 +6248,6 @@ msgstr "Este ficheiro usa muitas fontes diferentes."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Este ficheiro usa fontes Type 3, que transportam desenhos em vez de caracteres."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "O conteúdo das páginas deste ficheiro não pôde ser inspecionado a tempo."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Este título não é o que os analisadores procuram."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Nu există niciun link către un profil, portofoliu sau repozitoriu."
msgid "There is no summary paragraph."
msgstr "Nu există niciun paragraf de rezumat."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Nu au existat suficiente informații pentru a rula această verificare."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Aceste verificări rulează pe măsură ce scrieți și nu părăsesc niciodată browserul dumneavoastră. Ele testează dacă programele pot citi CV-ul, nu cât de bine este scris."
@@ -6168,14 +6164,6 @@ msgstr "Această acțiune nu poate fi anulată. Șterge mesajele firului și ata
msgid "This assistant could not be opened."
msgstr "Acest asistent nu a putut fi deschis."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Această verificare nu se aplică acestui fișier."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Această verificare rulează doar pe CV-uri scrise în engleză."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Această cerere de conectare este invalidă sau a expirat."
@@ -6260,10 +6248,6 @@ msgstr "Acest fișier folosește foarte multe fonturi diferite."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Acest fișier folosește fonturi Type 3, care conțin desene în loc de caractere."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Conținutul paginilor acestui fișier nu a putut fi inspectat la timp."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Acest titlu nu este unul pe care îl caută analizatorii."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Нет ссылки на профиль, портфолио или ре
msgid "There is no summary paragraph."
msgstr "Нет вводного абзаца."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Недостаточно информации для выполнения этой проверки."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Эти проверки выполняются по мере набора текста и не покидают ваш браузер. Они проверяют, сможет ли программа прочитать ваше резюме, а не то, насколько хорошо оно написано."
@@ -6168,14 +6164,6 @@ msgstr "Это действие нельзя отменить. Оно удаля
msgid "This assistant could not be opened."
msgstr "Не удалось открыть этого помощника."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Эта проверка неприменима к этому файлу."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Эта проверка выполняется только для резюме на английском языке."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Этот запрос на подключение недействителен или срок его действия истек."
@@ -6260,10 +6248,6 @@ msgstr "В этом файле используется много разных
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "В этом файле используются шрифты Type 3, которые содержат рисунки вместо символов."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Не удалось вовремя изучить содержимое страниц этого файла."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Этот заголовок не тот заголовок, который ищут парсеры."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Chýba odkaz na profil, portfólio alebo repozitár."
msgid "There is no summary paragraph."
msgstr "Chýba súhrnný odsek."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Nebolo dostatok informácií na spustenie tejto kontroly."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Tieto kontroly bežia počas písania a nikdy neopustia váš prehliadač. Testujú, či softvér dokáže váš životopis prečítať, nie ako dobre je napísaný."
@@ -6168,14 +6164,6 @@ msgstr "Túto akciu nemožno vrátiť späť. Odstráni správy vlákna a nahran
msgid "This assistant could not be opened."
msgstr "Tohto asistenta sa nepodarilo otvoriť."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Táto kontrola sa na tento súbor nevzťahuje."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Táto kontrola sa spúšťa iba pri životopisoch napísaných v angličtine."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Táto žiadosť o pripojenie je neplatná alebo jej platnosť vypršala."
@@ -6260,10 +6248,6 @@ msgstr "Tento súbor používa veľa rôznych písiem."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Tento súbor používa písma Type 3, ktoré nesú kresby namiesto znakov."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Obsah strán tohto súboru sa nepodarilo včas preskúmať."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Tento nadpis nehľadajú analyzátori."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Ni povezave do profila, portfelja ali repozitorija."
msgid "There is no summary paragraph."
msgstr "Ni povzetka."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Za izvedbo tega preverjanja ni bilo dovolj podatkov."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Ta preverjanja tečejo, medtem ko tipkate, in nikoli ne zapustijo vašega brskalnika. Preizkušajo, ali programska oprema lahko prebere vaš življenjepis, ne pa, kako dobro je napisan."
@@ -6168,14 +6164,6 @@ msgstr "Tega dejanja ni mogoče razveljaviti. Izbriše sporočila niti in nalož
msgid "This assistant could not be opened."
msgstr "Tega pomočnika ni bilo mogoče odpreti."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "To preverjanje ne velja za to datoteko."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "To preverjanje se izvaja le za življenjepise, napisane v angleščini."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Ta zahteva za povezavo je neveljavna ali je potekla."
@@ -6260,10 +6248,6 @@ msgstr "Ta datoteka uporablja veliko različnih pisav."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Ta datoteka uporablja pisave Type 3, ki namesto znakov vsebujejo risbe."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Vsebine strani te datoteke ni bilo mogoče pravočasno pregledati."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Tega naslova razčlenjevalci ne iščejo."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Nuk ka lidhje me një profil, portofol apo depo kodi."
msgid "There is no summary paragraph."
msgstr "Nuk ka paragraf përmbledhës."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Nuk kishte informacion të mjaftueshëm për të kryer këtë kontroll."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Këto kontrolle ekzekutohen ndërsa shkruani dhe nuk dalin kurrë nga shfletuesi juaj. Ato testojnë nëse programet mund ta lexojnë CV-në tuaj, jo sa mirë është shkruar."
@@ -6168,14 +6164,6 @@ msgstr "Ky veprim nuk mund të zhbëhet. Ai fshin mesazhet e fijes dhe bashkëng
msgid "This assistant could not be opened."
msgstr "Ky asistent nuk mund të hapej."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Ky kontroll nuk zbatohet për këtë skedar."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Ky kontroll ekzekutohet vetëm në CV të shkruara në anglisht."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Kjo kërkesë për lidhje është e pavlefshme ose ka skaduar."
@@ -6260,10 +6248,6 @@ msgstr "Ky skedar përdor shumë fonte të ndryshme."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Ky skedar përdor fonte Type 3, të cilat mbajnë vizatime në vend të shkronjave."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Përmbajtja e faqeve të këtij skedari nuk mundi të inspektohej në kohë."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Ky titull nuk është një analizues që kërkojnë."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Не постоји веза ка профилу, портфолију
msgid "There is no summary paragraph."
msgstr "Не постоји пасус са сажетком."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Није било довољно информација за покретање ове провере."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Ове провере се извршавају док куцате и никада не напуштају ваш прегледач. Оне испитују да ли софтвер може да прочита ваш резиме, а не колико је добро написан."
@@ -6168,14 +6164,6 @@ msgstr "Ова радња се не може опозвати. Она брише
msgid "This assistant could not be opened."
msgstr "Овај помоћник није могао бити отворен."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Ова провера се не примењује на ову датотеку."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Ова провера се покреће само на биографијама написаним на енглеском."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Овај захтев за повезивање је неважећи или је истекао."
@@ -6260,10 +6248,6 @@ msgstr "Ова датотека користи много различитих
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Ова датотека користи Type 3 фонтове, који носе цртеже уместо знакова."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Садржај странице ове датотеке није могао да се прегледа на време."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Овај наслов није онај који парсери траже."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Det finns ingen länk till en profil, portfölj eller kodförvar."
msgid "There is no summary paragraph."
msgstr "Det finns inget sammanfattande stycke."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Det fanns inte tillräckligt med information för att köra denna kontroll."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Dessa kontroller körs medan du skriver och lämnar aldrig din webbläsare. De testar om programvara kan läsa ditt CV, inte hur väl det är skrivet."
@@ -6168,14 +6164,6 @@ msgstr "Detta går inte att ångra. Det tar bort trådens meddelanden och de upp
msgid "This assistant could not be opened."
msgstr "Den här assistenten kunde inte öppnas."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Denna kontroll gäller inte för denna fil."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Denna kontroll körs endast på CV:n skrivna på engelska."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Den här anslutningsbegäran är ogiltig eller har upphört att gälla."
@@ -6260,10 +6248,6 @@ msgstr "Denna fil använder många olika typsnitt."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Denna fil använder Type 3-typsnitt, som innehåller teckningar istället för tecken."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Denna fils sidinnehåll kunde inte inspekteras i tid."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Denna rubrik är inte en tolkare letar efter."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "சுயவிவரம், போர்ட்ஃபோலியோ அ
msgid "There is no summary paragraph."
msgstr "சுருக்கப் பத்தி எதுவும் இல்லை."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "இந்த சோதனையை இயக்க போதுமான தகவல் இல்லை."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "நீங்கள் தட்டச்சு செய்யும்போதே இந்தச் சோதனைகள் இயங்குகின்றன, உங்கள் உலாவியை விட்டு வெளியே செல்வதே இல்லை. உங்கள் ரெஸ்யூமை மென்பொருளால் படிக்க முடியுமா என்பதைத்தான் இவை சோதிக்கின்றன, அது எவ்வளவு நன்றாக எழுதப்பட்டுள்ளது என்பதை அல்ல."
@@ -6168,14 +6164,6 @@ msgstr "இந்தச் செயலை மீட்டெடுக்க ம
msgid "This assistant could not be opened."
msgstr "இந்த உதவியாளரைத் திறக்க முடியவில்லை."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "இந்த சோதனை இந்தக் கோப்புக்குப் பொருந்தாது."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "ஆங்கிலத்தில் எழுதப்பட்ட ரெஸ்யூம்களில் மட்டுமே இந்த சோதனை இயங்கும்."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "இந்த இணைப்பு கோரிக்கை செல்லாதது அல்லது காலாவதியானது."
@@ -6260,10 +6248,6 @@ msgstr "இந்தக் கோப்பு நிறைய வெவ்வே
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "இந்தக் கோப்பு Type 3 எழுத்துருக்களைப் பயன்படுத்துகிறது, அவை எழுத்துக்களுக்குப் பதிலாக வரைபடங்களைக் கொண்டுள்ளன."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "இந்தக் கோப்பின் பக்க உள்ளடக்கத்தை சரியான நேரத்தில் ஆய்வு செய்ய முடியவில்லை."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "இந்த தலைப்பு ஒரு பாகுபடுத்தி பார்க்கவில்லை."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "ప్రొఫైల్, పోర్ట్‌ఫోలియో లే
msgid "There is no summary paragraph."
msgstr "సారాంశ పేరాగ్రాఫ్ లేదు."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "ఈ చెక్‌ను నడపడానికి తగినంత సమాచారం లేదు."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "మీరు టైప్ చేస్తుండగానే ఈ తనిఖీలు నడుస్తాయి, అవి మీ బ్రౌజర్‌ను ఎప్పుడూ దాటి వెళ్లవు. మీ రెజ్యూమ్‌ను సాఫ్ట్‌వేర్ చదవగలదా అన్నదే అవి పరీక్షిస్తాయి, అది ఎంత బాగా రాశారన్నది కాదు."
@@ -6168,14 +6164,6 @@ msgstr "ఈ చర్యను వెనక్కి తీసుకోలేర
msgid "This assistant could not be opened."
msgstr "ఈ సహాయకుడిని తెరవలేకపోయింది."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "ఈ చెక్ ఈ ఫైల్‌కు వర్తించదు."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "ఈ చెక్ ఇంగ్లీష్‌లో రాసిన రెజ్యూమ్‌లపై మాత్రమే నడుస్తుంది."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "ఈ కనెక్షన్ అభ్యర్థన చెల్లనిది లేదా గడువు ముగిసింది."
@@ -6260,10 +6248,6 @@ msgstr "ఈ ఫైల్ చాలా వేర్వేరు ఫాంట్
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "ఈ ఫైల్ Type 3 ఫాంట్‌లను ఉపయోగిస్తుంది, ఇవి అక్షరాలకు బదులు చిత్రాలను కలిగి ఉంటాయి."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "ఈ ఫైల్ పేజీ కంటెంట్‌లను సకాలంలో పరిశీలించలేకపోయాం."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "ఈ హెడ్డింగ్ పార్సర్‌లు వెతకడం కాదు."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "ไม่มีลิงก์ไปยังโปรไฟล์ พ
msgid "There is no summary paragraph."
msgstr "ไม่มีย่อหน้าสรุป"
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "มีข้อมูลไม่เพียงพอที่จะรันการตรวจสอบนี้"
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "การตรวจสอบเหล่านี้ทำงานขณะที่คุณพิมพ์ และไม่ออกไปนอกเบราว์เซอร์ของคุณ โดยทดสอบว่าซอฟต์แวร์อ่านเรซูเม่ของคุณได้หรือไม่ ไม่ใช่ว่าเขียนได้ดีแค่ไหน"
@@ -6168,14 +6164,6 @@ msgstr "การกระทำนี้ย้อนกลับไม่ได
msgid "This assistant could not be opened."
msgstr "ไม่สามารถเปิดผู้ช่วยนี้ได้"
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "การตรวจสอบนี้ไม่เกี่ยวข้องกับไฟล์นี้"
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "การตรวจสอบนี้ทำงานเฉพาะกับเรซูเม่ที่เขียนเป็นภาษาอังกฤษ"
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "คำขอเชื่อมต่อนี้ไม่ถูกต้องหรือหมดอายุแล้ว"
@@ -6260,10 +6248,6 @@ msgstr "ไฟล์นี้ใช้ฟอนต์ที่แตกต่า
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "ไฟล์นี้ใช้ฟอนต์ Type 3 ซึ่งบรรจุภาพวาดแทนตัวอักษร"
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "ไม่สามารถตรวจสอบเนื้อหาหน้าของไฟล์นี้ได้ทันเวลา"
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "หัวข้อนี้ไม่ใช่สิ่งที่ parsers มองหา"
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Bir profile, portföye veya depoya bağlantı yok."
msgid "There is no summary paragraph."
msgstr "Bir özet paragrafı yok."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Bu kontrolü çalıştırmak için yeterli bilgi yoktu."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Bu kontroller siz yazarken çalışır ve tarayıcınızdan asla dışarı çıkmaz. Özgeçmişinizin ne kadar iyi yazıldığını değil, yazılımın onu okuyup okuyamadığını test ederler."
@@ -6168,14 +6164,6 @@ msgstr "Bu işlem geri alınamaz. Konudaki mesajları ve yüklenen ekleri siler.
msgid "This assistant could not be opened."
msgstr "Bu asistan açılamadı."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Bu kontrol bu dosya için geçerli değil."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Bu kontrol yalnızca İngilizce yazılmış özgeçmişlerde çalışır."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Bu bağlantı isteği geçersiz veya süresi dolmuş."
@@ -6260,10 +6248,6 @@ msgstr "Bu dosya çok sayıda farklı yazı tipi kullanıyor."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Bu dosya, karakter yerine çizim taşıyan Type 3 yazı tiplerini kullanıyor."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Bu dosyanın sayfa içerikleri zamanında incelenemedi."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Bu başlık ayrıştırıcıların aradığı bir başlık değil."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Немає посилання на профіль, портфоліо ч
msgid "There is no summary paragraph."
msgstr "Немає абзацу з підсумком."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Було недостатньо інформації, щоб запустити цю перевірку."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Ці перевірки виконуються під час введення тексту й не залишають ваш браузер. Вони перевіряють, чи зможе програма прочитати ваше резюме, а не те, наскільки добре воно написане."
@@ -6168,14 +6164,6 @@ msgstr "Цю дію неможливо скасувати. Вона видаля
msgid "This assistant could not be opened."
msgstr "Цей помічник не вдалося відкрити."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Ця перевірка не стосується цього файлу."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Ця перевірка виконується лише для резюме, написаних англійською мовою."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Цей запит на підключення недійсний або термін дії минув."
@@ -6260,10 +6248,6 @@ msgstr "Цей файл використовує багато різних шр
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Цей файл використовує шрифти Type 3, які містять малюнки замість символів."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Вміст сторінок цього файлу не вдалося перевірити вчасно."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Цей заголовок не шукає аналізатор."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Profil, portfolio yoki repozitoriyga havola yoʻq."
msgid "There is no summary paragraph."
msgstr "Qisqacha ma'lumot abzatsi yoʻq."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Bu tekshiruvni ishga tushirish uchun ma'lumot yetarli emas edi."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Bu tekshiruvlar siz yozayotganda ishlaydi va hech qachon brauzeringizdan chiqmaydi. Ular rezyumengiz qanchalik yaxshi yozilganini emas, balki dastur uni o'qiy oladimi-yo'qmi shuni sinaydi."
@@ -6168,14 +6164,6 @@ msgstr "Bu amalni ortga qaytarib bo'lmaydi. U mavzu xabarlarini va yuklangan bir
msgid "This assistant could not be opened."
msgstr "Bu yordamchini ochib bo'lmadi."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Bu tekshiruv ushbu faylga taalluqli emas."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Bu tekshiruv faqat ingliz tilida yozilgan rezyumelarda ishlaydi."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Bu ulanish so‘rovi yaroqsiz yoki muddati tugagan."
@@ -6260,10 +6248,6 @@ msgstr "Bu faylda juda koʻp turli shriftlar ishlatilgan."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Bu faylda belgilar oʻrniga chizmalarni tashuvchi Type 3 shriftlari ishlatilgan."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Bu faylning sahifa mazmunini vaqtida tekshirib boʻlmadi."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Bu sarlavha tahlilchilar qidiradigan birorta emas."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "Không có liên kết đến hồ sơ, portfolio hoặc kho lưu trữ.
msgid "There is no summary paragraph."
msgstr "Không có đoạn tóm tắt nào."
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "Không đủ thông tin để chạy kiểm tra này."
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "Các kiểm tra này chạy khi bạn gõ và không bao giờ rời khỏi trình duyệt của bạn. Chúng kiểm tra xem phần mềm có đọc được sơ yếu lý lịch của bạn hay không, chứ không phải nó được viết hay đến mức nào."
@@ -6168,14 +6164,6 @@ msgstr "Không thể hoàn tác hành động này. Nó xóa các tin nhắn c
msgid "This assistant could not be opened."
msgstr "Không thể mở trình trợ lý này."
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "Kiểm tra này không áp dụng cho tệp này."
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "Kiểm tra này chỉ chạy trên sơ yếu lý lịch được viết bằng tiếng Anh."
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "Yêu cầu kết nối này không hợp lệ hoặc đã hết hạn."
@@ -6260,10 +6248,6 @@ msgstr "Tệp này sử dụng rất nhiều font khác nhau."
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "Tệp này sử dụng font Type 3, loại font chứa hình vẽ thay vì ký tự."
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "Nội dung trang của tệp này không thể được kiểm tra kịp thời."
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "Tiêu đề này không phải là tiêu đề mà các trình phân tích cú pháp tìm kiếm."
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "没有指向个人主页、作品集或代码仓库的链接。"
msgid "There is no summary paragraph."
msgstr "没有个人简介段落。"
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "信息不足,无法运行此项检查。"
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "这些检查在你输入时运行,且从不离开你的浏览器。它们检测的是软件能否读懂你的简历,而不是它写得好不好。"
@@ -6168,14 +6164,6 @@ msgstr "此操作无法撤销。它会删除该会话的消息和已上传的附
msgid "This assistant could not be opened."
msgstr "此助手无法打开。"
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "此项检查不适用于该文件。"
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "此项检查仅适用于以英文撰写的简历。"
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "此连接请求无效或已过期。"
@@ -6260,10 +6248,6 @@ msgstr "该文件使用了许多不同的字体。"
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "该文件使用了 Type 3 字体,这种字体携带的是图形而非字符。"
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "未能及时检查完该文件的页面内容。"
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "这个标题不是解析器寻找的。"
-16
View File
@@ -6131,10 +6131,6 @@ msgstr "沒有指向個人檔案、作品集或程式碼庫的連結。"
msgid "There is no summary paragraph."
msgstr "沒有個人簡介段落。"
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr "資訊不足,無法執行此項檢查。"
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr "這些檢查會在您輸入時執行,而且不會離開您的瀏覽器。它們檢測的是軟體能否讀懂您的履歷,而不是它寫得好不好。"
@@ -6168,14 +6164,6 @@ msgstr "此操作無法復原。它會刪除該對話串的訊息與已上傳的
msgid "This assistant could not be opened."
msgstr "此助手無法打開。"
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr "此項檢查不適用於該檔案。"
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr "此項檢查僅適用於以英文撰寫的履歷。"
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr "此連線請求無效或已過期。"
@@ -6260,10 +6248,6 @@ msgstr "該檔案使用了許多不同的字體。"
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr "該檔案使用了 Type 3 字體,這種字體攜帶的是圖形而非字元。"
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr "未能及時檢查完該檔案的頁面內容。"
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr "這個標題不是解析器尋找的。"
-16
View File
@@ -6126,10 +6126,6 @@ msgstr ""
msgid "There is no summary paragraph."
msgstr ""
#: src/features/ats-checker/messages.ts
msgid "There was not enough information to run this check."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "These checks run as you type and never leave your browser. They test whether software can read your resume, not how well it is written."
msgstr ""
@@ -6163,14 +6159,6 @@ msgstr ""
msgid "This assistant could not be opened."
msgstr ""
#: src/features/ats-checker/messages.ts
msgid "This check does not apply to this file."
msgstr ""
#: src/features/ats-checker/messages.ts
msgid "This check only runs on resumes written in English."
msgstr ""
#: src/features/auth/pages/consent.tsx
msgid "This connection request is invalid or has expired."
msgstr ""
@@ -6255,10 +6243,6 @@ msgstr ""
msgid "This file uses Type 3 fonts, which carry drawings instead of characters."
msgstr ""
#: src/features/ats-checker/messages.ts
msgid "This file's page contents could not be inspected in time."
msgstr ""
#: src/libs/resume/ats.ts
msgid "This heading is not one parsers look for."
msgstr ""
+9 -13
View File
@@ -16,7 +16,7 @@
"lingui:extract": "lingui extract --clean --overwrite"
},
"dependencies": {
"@ai-sdk/react": "^4.0.105",
"@ai-sdk/react": "^4.0.110",
"@base-ui/react": "^1.8.0",
"@better-auth/api-key": "^1.7.5",
"@better-auth/infra": "^0.4.9",
@@ -36,9 +36,9 @@
"@fontsource-variable/manrope": "^5.3.0",
"@lingui/core": "^6.7.0",
"@lingui/react": "^6.7.0",
"@orpc/client": "^1.15.1",
"@orpc/server": "^1.15.1",
"@orpc/tanstack-query": "^1.15.1",
"@orpc/client": "^1.15.2",
"@orpc/server": "^1.15.2",
"@orpc/tanstack-query": "^1.15.2",
"@phosphor-icons/react": "^2.1.10",
"@react-pdf/renderer": "^4.9.0",
"@reactive-resume/ai": "workspace:*",
@@ -56,7 +56,7 @@
"@tanstack/react-form": "^1.33.5",
"@tanstack/react-hotkeys": "^0.10.0",
"@tanstack/react-query": "^5.103.1",
"@tanstack/react-router": "^1.170.36",
"@tanstack/react-router": "^1.170.38",
"@tiptap/extension-color": "^3.31.3",
"@tiptap/extension-heading": "^3.31.3",
"@tiptap/extension-highlight": "^3.31.3",
@@ -70,19 +70,16 @@
"@types/js-cookie": "^3.0.6",
"@uiw/color-convert": "^2.10.3",
"@uiw/react-color-colorful": "^2.10.3",
"ai": "^7.0.102",
"ai": "^7.0.107",
"better-auth": "1.7.5",
"buffer": "^6.0.3",
"cmdk": "^1.1.1",
"drizzle-orm": "1.0.0-rc.4",
"es-toolkit": "^1.52.0",
"fuse.js": "^7.5.0",
"immer": "^11.1.18",
"js-cookie": "^3.0.8",
"motion": "^13.4.0",
"pdfjs-dist": "6.3.289",
"pg": "^8.23.0",
"prettier": "^3.9.7",
"prettier": "^3.9.8",
"qrcode.react": "^4.2.0",
"react": "^19.3.0",
"react-dom": "^19.3.0",
@@ -98,7 +95,7 @@
"zustand": "^5.0.15"
},
"devDependencies": {
"@babel/core": "^8.0.5",
"@babel/core": "^8.0.6",
"@lingui/babel-plugin-lingui-macro": "^6.7.0",
"@lingui/cli": "^6.7.0",
"@lingui/format-po": "^6.7.0",
@@ -110,9 +107,8 @@
"@tanstack/react-devtools": "^0.10.12",
"@tanstack/react-query-devtools": "^5.103.1",
"@tanstack/react-router-devtools": "^1.167.2",
"@tanstack/router-plugin": "^1.168.38",
"@tanstack/router-plugin": "^1.168.40",
"@types/babel__core": "^7.20.5",
"@types/pg": "^8.23.1",
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"@typescript/native-preview": "7.0.0-dev.20260707.2",
@@ -1,47 +0,0 @@
// @vitest-environment happy-dom
import { fireEvent, render } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { TextMaskEffect } from "./text-mask";
const renderMask = (props: React.ComponentProps<typeof TextMaskEffect>) => render(<TextMaskEffect {...props} />);
describe("TextMaskEffect", () => {
it("renders the supplied text in all visible text layers", () => {
const { container } = renderMask({ text: "Hello World" });
const texts = container.querySelectorAll("text");
expect(texts.length).toBeGreaterThanOrEqual(2);
for (const el of texts) {
expect(el.textContent).toBe("Hello World");
}
});
it("forwards aria-hidden onto the root svg", () => {
const { container } = renderMask({ text: "X", "aria-hidden": "true" });
const svg = container.querySelector("svg") as SVGSVGElement;
expect(svg.getAttribute("aria-hidden")).toBe("true");
});
it("renders an aria-label on the root svg", () => {
const { container } = renderMask({ text: "X" });
const svg = container.querySelector("svg") as SVGSVGElement;
expect(svg.getAttribute("aria-label")).toBe("Text mask effect");
});
it("does not throw on mouse-enter / mouse-move / mouse-leave interactions", () => {
const { container } = renderMask({ text: "X" });
const svg = container.querySelector("svg") as SVGSVGElement;
expect(() => {
fireEvent.mouseEnter(svg);
fireEvent.mouseMove(svg, { clientX: 50, clientY: 25 });
fireEvent.mouseLeave(svg);
}).not.toThrow();
});
it("merges custom className into the svg", () => {
const { container } = renderMask({ text: "X", className: "custom-class" });
const svg = container.querySelector("svg") as SVGSVGElement;
expect(svg.getAttribute("class") ?? "").toContain("custom-class");
});
});
@@ -1,110 +0,0 @@
import { m } from "motion/react";
import { useRef, useState } from "react";
import { cn } from "@reactive-resume/utils/style";
const textClassName = cn("fill-transparent font-bold text-3xl leading-none tracking-tight");
type TextMaskEffectProps = {
text: string;
duration?: number;
className?: string;
"aria-hidden"?: boolean | "true" | "false";
};
export const TextMaskEffect = ({ text, duration = 6, className, "aria-hidden": ariaHidden }: TextMaskEffectProps) => {
const svgRef = useRef<SVGSVGElement>(null);
const [hovered, setHovered] = useState(false);
const [maskPosition, setMaskPosition] = useState({ cx: "50%", cy: "50%" });
return (
<svg
ref={svgRef}
width="100%"
height="100%"
viewBox="0 0 300 40"
aria-hidden={ariaHidden}
aria-label="Text mask effect"
className={cn("select-none", className)}
xmlns="http://www.w3.org/2000/svg"
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
onMouseMove={(e) => {
if (!svgRef.current) return;
const svgRect = svgRef.current.getBoundingClientRect();
const cxPercentage = ((e.clientX - svgRect.left) / svgRect.width) * 100;
const cyPercentage = ((e.clientY - svgRect.top) / svgRect.height) * 100;
setMaskPosition({ cx: `${cxPercentage}%`, cy: `${cyPercentage}%` });
}}
>
<defs>
<linearGradient id="textGradient" gradientUnits="userSpaceOnUse" cx="50%" cy="50%" r="25%">
{hovered && (
<>
<stop offset="0%" stopColor="#eab308" />
<stop offset="25%" stopColor="#ef4444" />
<stop offset="50%" stopColor="#3b82f6" />
<stop offset="75%" stopColor="#06b6d4" />
<stop offset="100%" stopColor="#8b5cf6" />
</>
)}
</linearGradient>
<m.radialGradient
r="20%"
id="revealMask"
animate={maskPosition}
gradientUnits="userSpaceOnUse"
initial={{ cx: "50%", cy: "50%" }}
transition={{ duration: 0, ease: "easeOut" }}
>
<stop offset="0%" stopColor="white" />
<stop offset="100%" stopColor="black" />
</m.radialGradient>
<mask id="textMask">
<rect x="0" y="0" width="100%" height="100%" fill="url(#revealMask)" />
</mask>
</defs>
<text
x="50%"
y="50%"
strokeWidth="0.3"
textAnchor="middle"
dominantBaseline="middle"
style={{ opacity: hovered ? 0.7 : 0 }}
className={cn(textClassName, "stroke-zinc-300 dark:stroke-zinc-700")}
>
{text}
</text>
<m.text
x="50%"
y="50%"
strokeWidth="0.3"
textAnchor="middle"
dominantBaseline="middle"
transition={{ duration, ease: "easeInOut" }}
initial={{ strokeDashoffset: 1000, strokeDasharray: 1000 }}
whileInView={{ strokeDashoffset: 0, strokeDasharray: 1000 }}
className={cn(textClassName, "stroke-zinc-300 dark:stroke-zinc-700")}
>
{text}
</m.text>
<text
x="50%"
y="50%"
strokeWidth="0.3"
textAnchor="middle"
mask="url(#textMask)"
dominantBaseline="middle"
stroke="url(#textGradient)"
className={cn(textClassName)}
>
{text}
</text>
</svg>
);
};
+1 -1
View File
@@ -1,4 +1,4 @@
import type { AnyDialogRendererEntry } from "../renderer-registry";
import type { AnyDialogRendererEntry } from "../schemas";
import { CreateApiKeyDialog } from "./create";
export const apiKeyDialogRenderers: readonly AnyDialogRendererEntry[] = [
@@ -21,6 +21,7 @@ import { FormControl, FormItem, FormLabel, FormMessage } from "@reactive-resume/
import { Input } from "@reactive-resume/ui/components/input";
import { OTPField } from "@reactive-resume/ui/components/otp-field";
import { toast } from "@reactive-resume/ui/components/toast";
import { downloadWithAnchor } from "@reactive-resume/utils/file";
import { useFormBlocker } from "@/hooks/use-form-blocker";
import { authClient } from "@/libs/auth/client";
import { getReadableErrorMessage } from "@/libs/error-message";
@@ -164,16 +165,7 @@ export function EnableTwoFactorDialog(_: DialogProps<"auth.two-factor.enable">)
const handleDownloadBackupCodes = () => {
if (!backupCodes) return;
const content = backupCodes.join("\n");
const blob = new Blob([content], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "reactive-resume_backup-codes.txt";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
downloadWithAnchor(new Blob([backupCodes.join("\n")], { type: "text/plain" }), "reactive-resume_backup-codes.txt");
};
return (
+1 -1
View File
@@ -1,4 +1,4 @@
import type { AnyDialogRendererEntry } from "../renderer-registry";
import type { AnyDialogRendererEntry } from "../schemas";
import { ChangePasswordDialog } from "./change-password";
import { DisableTwoFactorDialog } from "./disable-two-factor";
import { EnableTwoFactorDialog } from "./enable-two-factor";
-12
View File
@@ -1,12 +0,0 @@
import type { ReactNode } from "react";
import type { DialogSchema, DialogType } from "./schemas";
// ponytail: defineDialogRenderer/defineDialogRendererRegistry were identity fns; inlined
type DialogRendererEntry<T extends DialogType = DialogType> = {
type: T;
render: (dialog: Extract<DialogSchema, { type: T }>) => ReactNode;
};
export type AnyDialogRendererEntry = {
[T in DialogType]: DialogRendererEntry<T>;
}[DialogType];
+9 -3
View File
@@ -334,12 +334,18 @@ export function ImportResumeDialog(_: DialogProps<"resume.import">) {
<FormLabel>
<Trans>File</Trans>
</FormLabel>
<FormControl>
<Input type="file" className="hidden" ref={inputRef} onChange={onUploadFile} />
<FormControl className="group/upload relative">
<Input
type="file"
className="absolute inset-0 z-1 h-full w-full cursor-pointer opacity-0"
tabIndex={-1}
ref={inputRef}
onChange={onUploadFile}
/>
<Button
variant="outline"
className="h-auto w-full flex-col border-dashed py-8 font-normal"
className="h-auto w-full flex-col border-dashed py-8 font-normal group-hover/upload:bg-muted group-hover/upload:text-foreground"
onClick={onSelectFile}
>
{field.state.value ? (
+1 -1
View File
@@ -1,4 +1,4 @@
import type { AnyDialogRendererEntry } from "../renderer-registry";
import type { AnyDialogRendererEntry } from "../schemas";
import { CreateResumeDialog, DuplicateResumeDialog, UpdateResumeDialog } from ".";
import { ImportResumeDialog } from "./import";
import { CreateAwardDialog, UpdateAwardDialog } from "./sections/award";
+10
View File
@@ -1,4 +1,5 @@
import type { CoverLetterItem, CustomSection, SectionItem, SummaryItem } from "@reactive-resume/schema/resume/data";
import type { ReactNode } from "react";
type EmptyDialog<T extends string> = { [K in T]: { type: K; data?: undefined } }[T];
@@ -55,6 +56,15 @@ export type DialogSchema =
export type DialogType = DialogSchema["type"];
type DialogRendererEntry<T extends DialogType = DialogType> = {
type: T;
render: (dialog: Extract<DialogSchema, { type: T }>) => ReactNode;
};
export type AnyDialogRendererEntry = {
[T in DialogType]: DialogRendererEntry<T>;
}[DialogType];
export type DialogData<T extends DialogType> = Extract<DialogSchema, { type: T }>["data"];
type DialogPropsData<T extends DialogType> =
@@ -3,24 +3,10 @@
import { beforeAll, describe, expect, it } from "vitest";
import { i18n } from "@lingui/core";
import { PDF_ATS_RULE_CODES } from "@reactive-resume/resume/ats-pdf";
import {
getPdfCategoryDescription,
getPdfCategoryLabel,
getPdfFindingMessage,
getPdfSeverityLabel,
getPdfSkipReasonLabel,
} from "./messages";
import { getPdfCategoryDescription, getPdfCategoryLabel, getPdfFindingMessage, getPdfSeverityLabel } from "./messages";
const CATEGORIES = ["parseability", "layout", "sections", "contact", "dates", "content"] as const;
const SEVERITIES = ["blocker", "warning", "tip"] as const;
const SKIP_REASONS = [
"no-text",
"no-operators",
"not-english",
"not-applicable",
"encrypted",
"insufficient-data",
] as const;
beforeAll(() => {
i18n.load("en", {});
@@ -60,8 +46,4 @@ describe("labels", () => {
for (const severity of SEVERITIES) expect(getPdfSeverityLabel(severity).length).toBeGreaterThan(0);
});
it("explains every reason a check can be skipped", () => {
for (const reason of SKIP_REASONS) expect(getPdfSkipReasonLabel(reason).length).toBeGreaterThan(0);
});
});
+1 -12
View File
@@ -1,4 +1,4 @@
import type { PdfCategory, PdfRuleCode, PdfSeverity, PdfSkipReason } from "@reactive-resume/resume/ats-pdf";
import type { PdfCategory, PdfRuleCode, PdfSeverity } from "@reactive-resume/resume/ats-pdf";
import { t } from "@lingui/core/macro";
import { match } from "ts-pattern";
@@ -370,14 +370,3 @@ export function getPdfSeverityLabel(severity: PdfSeverity): string {
.with("tip", () => t`Tip`)
.exhaustive();
}
export function getPdfSkipReasonLabel(reason: PdfSkipReason): string {
return match(reason)
.with("no-text", () => t`No text could be read from this file.`)
.with("no-operators", () => t`This file's page contents could not be inspected in time.`)
.with("not-english", () => t`This check only runs on resumes written in English.`)
.with("not-applicable", () => t`This check does not apply to this file.`)
.with("encrypted", () => t`This file is encrypted.`)
.with("insufficient-data", () => t`There was not enough information to run this check.`)
.exhaustive();
}
@@ -67,16 +67,6 @@ describe("useCommandPaletteStore", () => {
expect(useCommandPaletteStore.getState().peekPage()).toBe("b");
});
it("popPage removes the last page and clears search", () => {
useCommandPaletteStore.setState({ pages: ["a", "b"], search: "x" });
useCommandPaletteStore.getState().popPage();
const state = useCommandPaletteStore.getState();
expect(state.pages).toEqual(["a"]);
expect(state.search).toBe("");
});
it("reset clears every state field", () => {
useCommandPaletteStore.setState({ open: true, search: "x", pages: ["a"] });
@@ -11,7 +11,6 @@ type CommandPaletteActions = {
setSearch: (search: string) => void;
pushPage: (page: string) => void;
peekPage: () => string | undefined;
popPage: () => void;
reset: () => void;
goBack: () => void;
};
@@ -38,8 +37,6 @@ export const useCommandPaletteStore = create<CommandPaletteStore>((set, get) =>
pushPage: (page) => set((state) => ({ pages: [...state.pages, page], search: "" })),
popPage: () => set((state) => ({ pages: state.pages.slice(0, -1), search: "" })),
reset: () => set(initialState),
goBack: () => {
@@ -10,7 +10,8 @@ import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@r
import { Button } from "@reactive-resume/ui/components/button";
import { Separator } from "@reactive-resume/ui/components/separator";
import { useCurrentBuilderResumeSelector, useUpdateResumeData } from "@/features/resume/builder/draft";
import { getSectionTitle, leftSidebarSections } from "@/libs/resume/section";
import { leftSidebarSections } from "@/libs/resume/section";
import { resolveLayoutSectionTitle } from "@/routes/builder/$resumeId/-sidebar/right/sections/layout/title";
export function getVisibleLeftSidebarSections(data: ResumeData): LeftSidebarSection[] {
const hiddenSectionIds = new Set(
@@ -80,18 +81,6 @@ export function SectionEditorList({ renderSection }: SectionEditorListProps) {
);
}
function getRecoverySectionTitle(data: ResumeData, sectionId: string): string {
if (sectionId === "summary") return data.summary.title || getSectionTitle("summary");
if (Object.hasOwn(data.sections, sectionId)) {
const type = sectionId as SectionType;
return data.sections[type].title || getSectionTitle(type);
}
const customSection = data.customSections.find((section) => section.id === sectionId);
return customSection?.title || (customSection ? getSectionTitle(customSection.type) : sectionId);
}
export function SectionRecovery() {
const data = useCurrentBuilderResumeSelector((resume) => resume.data);
const updateResumeData = useUpdateResumeData();
@@ -132,7 +121,7 @@ export function SectionRecovery() {
<AccordionContent className="pb-3">
<ul className="space-y-2">
{hiddenSections.map(({ sectionId }) => {
const title = getRecoverySectionTitle(data, sectionId);
const title = resolveLayoutSectionTitle(data, sectionId);
return (
<li
@@ -34,44 +34,40 @@ function walk(root: SemanticNode): SemanticNode[] {
return nodes;
}
function unique(values: readonly string[]): string[] {
return [...new Set(values)];
}
function selectorLabels(metadata: SemanticCssEditorMetadata): string[] {
const nodes = walk(metadata.semanticTree);
const attributes = unique([
"id",
"role",
...Object.values(SEMANTIC_REGISTRY_V1).flatMap(({ attributes }) => attributes),
]);
const roles = unique(Object.values(SEMANTIC_REGISTRY_V1).flatMap(({ roles }) => roles));
return unique([
...SEMANTIC_NODE_KINDS,
"*",
...nodes.flatMap((node) => (node.id ? [`#${escapeCssIdentifier(node.id)}`] : [])),
...attributes.map((attribute) => `[${escapeCssIdentifier(attribute)}]`),
...nodes.flatMap((node) =>
Object.entries(node.attributes).map(
([name, value]) => `[${escapeCssIdentifier(name)}=${escapeCssString(value)}]`,
const attributes = [
...new Set(["id", "role", ...Object.values(SEMANTIC_REGISTRY_V1).flatMap(({ attributes }) => attributes)]),
];
const roles = [...new Set(Object.values(SEMANTIC_REGISTRY_V1).flatMap(({ roles }) => roles))];
return [
...new Set([
...SEMANTIC_NODE_KINDS,
"*",
...nodes.flatMap((node) => (node.id ? [`#${escapeCssIdentifier(node.id)}`] : [])),
...attributes.map((attribute) => `[${escapeCssIdentifier(attribute)}]`),
...nodes.flatMap((node) =>
Object.entries(node.attributes).map(
([name, value]) => `[${escapeCssIdentifier(name)}=${escapeCssString(value)}]`,
),
),
),
...roles.map((role) => `[role~=${escapeCssString(role)}]`),
...metadata.templateParts.map((name) => `template-part[name=${escapeCssString(name)}]`),
":root",
":first-child",
":last-child",
":only-child",
":nth-child()",
":nth-of-type()",
":is()",
":where()",
":not()",
]);
...roles.map((role) => `[role~=${escapeCssString(role)}]`),
...metadata.templateParts.map((name) => `template-part[name=${escapeCssString(name)}]`),
":root",
":first-child",
":last-child",
":only-child",
":nth-child()",
":nth-of-type()",
":is()",
":where()",
":not()",
]),
];
}
function userVariables(source: string): string[] {
return unique([...source.matchAll(/(--(?!resume-)[-_a-zA-Z0-9]+)\s*:/g)].map((match) => match[1] as string));
return [...new Set([...source.matchAll(/(--(?!resume-)[-_a-zA-Z0-9]+)\s*:/g)].map((match) => match[1] as string))];
}
function completionKind(source: string, position: number): "directive" | "property" | "selector" | "system" | "value" {
@@ -110,12 +106,14 @@ function completionLabels(source: string, position: number, metadata: SemanticCs
case "value": {
const property = declarationProperty(source, position);
const definition = property ? PROPERTY_REGISTRY_V1[property] : undefined;
return unique([
...(definition?.values ?? []),
...(definition?.units ?? []),
...userVariables(source),
...Object.keys(SYSTEM_VARIABLE_REGISTRY_V1),
]);
return [
...new Set([
...(definition?.values ?? []),
...(definition?.units ?? []),
...userVariables(source),
...Object.keys(SYSTEM_VARIABLE_REGISTRY_V1),
]),
];
}
}
}

Some files were not shown because too many files have changed in this diff Show More