This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
DeepLX is a serverless translation service optimized for Cloudflare Workers. It provides a free alternative to translation APIs by proxying requests to DeepL and Google Translate services through intelligent load balancing, rate limiting, and caching mechanisms.
npm run dev- Start local development server with Wranglernpm run deploy- Deploy to Cloudflare Workers productionnpm run cf-typegen- Generate TypeScript types for Cloudflare Workers bindings
npm test- Run all testsnpm run test:unit- Run unit tests only (tests in tests/lib/)npm run test:integration- Run integration tests (tests/integration/)npm run test:performance- Run performance tests (tests/performance/)npm run test:coverage- Generate coverage reportnpm run test:watch- Run tests in watch modenpm run test:debug- Run tests with Node debugging enabled
npm run lint- Type-check with TypeScript (no emit, runstsc --noEmit)
- Request arrives at Hono router (src/index.ts)
- CORS preflight handling (if OPTIONS)
- Security middleware validates input and extracts client IP
- Rate limiting checks (two-level: client IP + proxy backend)
- Cache lookup (two-level: in-memory + KV)
- If cache miss:
- Proxy manager selects available proxy endpoint
- Circuit breaker checks if proxy is healthy
- Retry logic with exponential backoff
- Translation query to provider (DeepL or Google)
- Cache successful translation
- Return standardized response
- DeepL Query Engine (src/lib/query.ts): Main translation logic for DeepL using JSONRPC API
- Google Translate Service (src/lib/services/googleTranslate.ts): Google Translate integration
- Two-Level Cache (src/lib/cache.ts): In-memory Map + Cloudflare KV with 1-hour TTL
- Token Bucket Rate Limiter (src/lib/rateLimit.ts): Dual rate limiting (per-client IP + per-proxy) with dynamic limits based on proxy count
- Circuit Breaker (src/lib/circuitBreaker.ts): Prevents cascade failures by temporarily blocking failing proxy endpoints (states: CLOSED/OPEN/HALF_OPEN)
- Proxy Manager (src/lib/proxyManager.ts): Random proxy selection with browser fingerprinting (User-Agent, Accept-Language rotation)
- Retry Logic (src/lib/retryLogic.ts): Exponential backoff retry mechanism (max 3 retries, 1s initial delay, 2x backoff factor)
All configurable constants are centralized in src/lib/config.ts:
- Rate limits:
RATE_LIMIT_CONFIG(dynamic based on proxy count) - Cache TTL:
CACHE_CONFIG - Retry settings:
DEFAULT_RETRY_CONFIG - Payload limits:
PAYLOAD_LIMITS - Request timeout:
REQUEST_TIMEOUT
The application exposes three POST endpoints (defined in src/index.ts):
/deepl- DeepL translation (recommended)/google- Google Translate/translate- Legacy endpoint (uses DeepL for backward compatibility)/debug- Debug endpoint (only available whenDEBUG_MODE=true)
All endpoints use the same handleTranslation() function with a provider parameter.
Required environment variables in wrangler.jsonc:
DEBUG_MODE- Enable debug endpoint (default: "false")PROXY_URLS- Comma-separated list of XDPL proxy endpoints for DeepL
Required KV namespaces:
CACHE_KV- Translation result cacheRATE_LIMIT_KV- Rate limit token buckets
Required bindings:
ANALYTICS- Cloudflare Analytics Engine dataset
The worker includes a scheduled event handler that runs every 5 minutes (configured in wrangler.jsonc triggers):
- Clears in-memory cache to prevent memory leaks
- Called via
handleScheduled()in src/index.ts
- Client-level: Token bucket with dynamic limit =
(proxy_count × 8 requests/sec) × 60 = tokens/minute - Proxy-level: 8 tokens/sec per proxy with 16 token burst capacity
- Uses two-level caching (in-memory 5s TTL + KV 1h TTL) for performance
- See
checkCombinedRateLimit()in src/lib/rateLimit.ts
- In-memory cache: JavaScript Map for fast lookups (cleared every 5 minutes by scheduled task)
- KV cache: Cloudflare KV for persistence (1-hour TTL)
- Cache key generation: hash of
text:source_lang:target_lang:provider - See src/lib/cache.ts
- Opens after 5 consecutive failures
- 30-second recovery timeout
- Requires 3 consecutive successes to close
- One circuit breaker instance per proxy URL
- See src/lib/circuitBreaker.ts
- Input validation and sanitization in src/lib/security.ts and src/lib/validation.ts
- Maximum text length: 5000 characters (configurable in
PAYLOAD_LIMITS) - Language code validation with whitelist
- Client IP extraction from CF-Connecting-IP or X-Forwarded-For headers
- CORS handling via
handleCORSPreflight()
Tests are organized in the tests/ directory:
tests/lib/- Unit tests for individual library modulestests/integration/- Integration tests for API endpointstests/performance/- Performance and load teststests/setup.ts- Jest setup filetests/utils/testHelpers.ts- Shared test utilities
Test configuration in jest.config.js:
- Uses
ts-jestpreset for TypeScript - 30-second test timeout
- Coverage collected from
src/**/*.ts
When writing tests:
- Mock Cloudflare Workers bindings (KV, Analytics)
- Use
testHelpers.tsutilities for creating mock environments - Integration tests should test full request/response cycle
- Performance tests should validate response time constraints
- Target: ES2020 with WebWorker lib
- Module: ESNext with bundler resolution (Cloudflare Workers uses bundling)
- Strict mode: Enabled
- Types:
@cloudflare/workers-types,jest - Entry point: src/index.ts
From CONTRIBUTING.md:
feature/description- New featuresfix/description- Bug fixesdocs/description- Documentationrefactor/description- Code refactoringtest/description- Test improvements
Use conventional commits: type(scope): description
- Types: feat, fix, docs, style, refactor, test, chore
- 2 spaces indentation
- Single quotes for strings
- Trailing commas in multiline structures
- Lines under 100 characters
- Explicit types for function parameters/returns
- Avoid
anytype
- Run
npm test(all tests must pass) - Run
npm run lint(type check) - Add tests for new functionality
- Update documentation if needed
- Ensure code coverage doesn't decrease
Optimized for Cloudflare Workers serverless environment:
- Minimize memory allocations (cache cleanup every 5 minutes)
- Efficient token bucket algorithm (O(1) rate limit checks)
- Two-level caching reduces KV read latency
- Browser fingerprinting uses pre-defined arrays (no runtime generation)
- Async KV writes don't block responses (fire-and-forget pattern in rate limiter)
Set DEBUG_MODE=true in wrangler.jsonc to enable the /debug endpoint for request inspection.
- Check dynamic rate limits with
getDynamicRateLimits(env)in src/lib/rateLimit.ts - Rate limits scale with proxy count: more proxies = higher client limits
- Clear rate limit cache: delete keys matching
rate_limit:*inRATE_LIMIT_KV
- Circuit opens after 5 consecutive proxy failures
- Wait 30 seconds for automatic HALF_OPEN state
- Check proxy health in proxy manager logs
- In-memory cache is cleared every 5 minutes by scheduled task
- KV cache has 1-hour TTL
- Cache key collision: verify
generateCacheKey()produces unique keys for different inputs