Commit Graph
104 Commits
Author SHA1 Message Date
MythEclipseandClaude 6d61dcba8f prioritas langsung baru proxy
Ubah strategi retry di fetchWithRetry dan fetchWithSessionRetry:
- Langsung (direct) sebagai percobaan pertama sebelum proxy pool
- Proxy sebagai fallback jika direct gagal

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-18 01:45:34 +07:00
MythEclipseandClaude ca8de1ba00 feat: migrate deepseek route to aichat.org with all models
- Replace broken deep-seek.ai endpoint with aichat.org relay
- Add AichatSession manager with cookie/CSRF bootstrap and auto-refresh
- Add exponential backoff retry (3 attempts) for session bootstrap
- Add all 9 aichat.org model routes via shared config (zero duplication)
- Session cookies auto-refreshed from Set-Cookie on every API response
- Auto-heal: 401 triggers session re-bootstrap + retry transparently

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-18 00:02:54 +07:00
MythEclipseandClaude 778180a5dc fix: inline test-api.html as TypeScript string export for Vercel
Bun import of .html files returns HTMLBundle (not a string) in Vercel's
serverless environment, and Bun.file() has no filesystem access there.
Copy the HTML content into api/test-api-content.ts as an escaped string
export, then import it in api/relay.ts — Bun bundler inlines it.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 14:14:13 +07:00
MythEclipseandClaude f8fd18612b fix: use Bun.file().text() at module scope to inline test-api.html
Bun HTML import returns HTMLBundle object on Vercel serverless, which
renders as '[object HTMLBundle]'. Using Bun.file().text() at top-level
module scope ensures Bun bundler inlines the raw string at build time.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 13:54:13 +07:00
MythEclipseandClaude bcba2c5386 fix: use text import for test-api.html in Vercel deployment
Bun HTML import returns HTMLBundle object, not a string — Vercel
renders it as '[object HTMLBundle]'. Use 'with { type: "text" }'
to import as raw string so it renders properly.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 13:51:04 +07:00
MythEclipseandClaude bc6edbef3e fix: serve test-api.html at /docs on Vercel and Worker deployments
Update api/relay.ts (Vercel entry point) and src/worker.ts (Cloudflare
Workers entry point) to serve the interactive API test console at /docs
and /test, replacing the old inline docs page.

api/relay.ts uses Bun's HTML import (bundled inline at build time)
since filesystem access is unavailable in Vercel serverless runtime.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 13:37:23 +07:00
MythEclipseandClaude aa3f96ef2d refactor: merge /test into /docs, serve test-api.html publicly
Both /docs and /test now serve the API test console (public/test-api.html),
replacing the old inline docs page.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 13:28:43 +07:00
MythEclipseandClaude e4406b586e feat: add Xiaomi MiMo Free API provider (mimo-auto)
- Add mimo-auth.ts: JWT bootstrap with device fingerprint, cached auto-refresh, 401/403 invalidation
- Add mimo-auto entry to MODEL_ROUTES with anti-abuse system message injection
- Inject JWT auth + x-session-affinity header before Mimo API fetch
- Retry once on 401/403 (invalidate JWT, re-bootstrap)
- Extend SSE passthrough for mimo-free provider
- Strip 'data:' prefix from Mimo non-streaming responses

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 13:22:07 +07:00
MythEclipse 89f0ff0f32 a 2026-06-17 12:29:54 +07:00
MythEclipseandClaude 7cbf6fd817 feat: add per-model proxy cooldown for rate-limit handling
ProxyPool:
- Add cooldowns map (host:port::model -> expiry) and cooldownDuration (60s default)
- Add markRateLimited(model) — puts current proxy in cooldown for a model
- Add isProxyInCooldown, isIndexInCooldown, isCurrentInCooldown checks
- Modify rotate(model?) — skip proxies in cooldown for the given model
- Add setCooldownDuration(ms) for configuration

SessionProxyPool:
- Add markRateLimited(sessionId, model) — delegates to underlying pool
- Modify rotateNow(sessionId, model?) — skip cooldown proxies
- Modify acquire(sessionId, model?) — skip cooldown when picking least-loaded
- Modify pickLeastUsedIndex(model?) — skip cooldown proxies in scan

fetch-utils.ts:
- Add extractModel helper — extracts model from context string
- On HTTP 429: call markRateLimited(model) before markFailed
- Pass model to rotate() / rotateNow() / acquire() throughout

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 04:59:16 +07:00
MythEclipseandClaude 283ed26231 fix: exhaust all proxies then direct fallback before giving up
fetchWithRetry:
- Dynamically calculate maxAttempts = pool.size + 1 (direct fallback)
- Try every proxy in pool via rotation, then direct as last resort
- Only classify as error when even direct produces no response

fetchWithSessionRetry:
- Default maxRetries = sessionPool.size + 1 instead of hardcoded 3
- Try pool.size proxy attempts (each on a different proxy via rotateNow),
  then 1 direct attempt (no proxy) before giving up
- Only classify as error if direct also returns no response

ProxyPool.rotate():
- Skip proxies that have exceeded the failure threshold (isFailed)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 04:45:30 +07:00
MythEclipseandClaude f1943353ef fix: rotate proxy on every failure, return proper HTTP status
- Add rotateNow() to SessionProxyPool — force-rotate session to a
  different proxy immediately (excludes current index to ensure real
  rotation). Uses round-robin scan from oldIndex+1 so all proxies
  get used, not just bouncing between two.

- fetchWithSessionRetry: call rotateNow() on every failure instead of
  markFailed() which only rotated after threshold. Return last HTTP
  response (e.g. 429) instead of classifying as 502 when we have one.

- fetchWithRetry: rotate pool on every failure for consistency.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 04:40:45 +07:00
MythEclipseandClaude 9c2f0a65f0 feat: add request logging to AI proxy routes
- Log session ID, model, pool size, and active session count on every
  POST /v1/chat/completions and POST /v1/messages

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 04:30:07 +07:00
MythEclipseandClaude 45f1b33fb6 feat: add structured logging across proxy pool and fetch utils
- fetch-utils.ts: logProxy() — logs every attempt, proxy used, success/failure
  with sessionId prefix for traceability
- proxy-pool.ts: logPool() — logs acquire/release/rotate/markFailed/markSuccess
  with active session count and proxy host info
- Both use consistent [prefix] HH:MM:SS.mmm key=value format

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 04:29:31 +07:00
MythEclipseandClaude 519fe3af83 fix: proxy pool now actively distributes IPs across sessions
- fetchWithRetry: use proxy on every attempt (not just fallback after direct)
- fetchWithSessionRetry: call acquire() on attempt 0 so new sessions get
  a least-loaded proxy assigned, enabling IP spread across concurrent users
- Update docstrings to reflect new strategy

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 04:26:26 +07:00
MythEclipseandClaude 9bd6acddc5 feat: implement session-based sticky proxy pool with auto-failover
Add SessionProxyPool for per-session sticky proxy allocation with
load-balanced least-used selection and auto-rotation on failure.
Introduce fetchWithSessionRetry for transparent retry with proxy
rotation. Wire into AI proxy handlers (OpenAI + Anthropic) with
stream lifecycle cleanup.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-16 23:50:47 +07:00
MythEclipseandClaude 6c945dcbf4 feat: add API test page at /test endpoint
- New public/test-api.html — browser-based test UI for all proxy endpoints
- Health check, model listing, Chat Completions (stream+non-stream),
  Anthropic Messages (stream+non-stream), and generic HTTP relay
- Server serves /test route from public/test-api.html

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-16 22:58:17 +07:00
MythEclipse b09bca8def feat(core): implement robust fetch utilities and stream management
Introduce a centralized `fetch-utils.ts` to handle retry logic with proxy fallback, SSE line buffering to prevent chunk-boundary corruption, and graceful shutdown via active reader tracking.

Key changes:
- Add `fetchWithRetry` for automatic direct-to-proxy failover.
- Implement `SSELineBuffer` to ensure reliable parsing of split SSE chunks.
- Add `createStreamBodyLimiter` to enforce payload limits on streaming requests.
- Refactor `ProxyPool` to decouple failure marking from rotation.
- Standardize CORS handling and environment variable configuration.
- Clean up documentation and remove obsolete skill files.
2026-06-11 03:56:26 +07:00
MythEclipse db065f788d style(anthropic-proxy): update comment formatting and add SSE utility functions
Standardize comment separators and arrow usage in documentation headers.
Additionally, introduce `accumulateSSEText` and `extractTextFromSSE` to
provide robust parsing for various SSE stream formats, including
Claude Code and OpenAI-compatible deltas.
2026-06-11 01:43:23 +07:00
MythEclipse 261f84a96e refactor(anthropic-proxy): improve SSE stream transformation logic
Refactor the backend-to-Anthropic SSE transformation to use a more robust
state machine approach. This replaces manual string building with a
structured phase-based system (`init`, `block`, `done`) to better
manage the Anthropic streaming protocol, including `message_start` and
`content_block_delta` events.

- Extract `formatContentBlockDelta` helper for consistent event formatting
- Implement phase-based state machine in `transformAnthropicStream`
- Delegate `[DONE]` handling to the stream transformer instead of
  manually emitting `message_stop`
- Improve reliability of message ID generation and event sequencing
2026-06-11 01:24:54 +07:00
MythEclipseandClaude Fable 5 47b85fb396 chore: use hardcoded dummy API key
- Replace env-based API_KEY with sk-dummy-key hardcoded
- All entry points use same key: Authorization: Bearer sk-dummy-key
- Simplifies usage for library/client consumption

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 00:59:01 +07:00
MythEclipseandClaude Fable 5 c0a02279bd feat: add API key authentication for AI proxy endpoints
- Add API_KEY config (env var) to all entry points
- requireAuth helper checks Authorization: Bearer or x-api-key header
- Auth applied to /v1/chat/completions, /v1/messages, /v1/models
- When API_KEY is empty/unset, auth is disabled (backward compatible)
- Update wrangler.toml with API_KEY variable documentation

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 00:56:18 +07:00
MythEclipseandClaude Fable 5 2be57c0838 fix: handle surfsense stream format correctly
Surfsense sends data: {"type":"text-delta","delta":"text"} — use
raw.delta (not raw.content) and filter events by type. Skip non-text
events (thinking steps, start, etc) to produce clean Anthropic SSE.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 00:49:36 +07:00
MythEclipseandClaude Fable 5 2fead57d0f fix: use MODEL_ROUTES directly for Anthropic proxy routing
Remove the ANTHROPIC_MODEL_MAP layer — /v1/messages now uses the
same model names as /v1/chat/completions (deepseek-v4-flash-free,
gpt-5.4-mini-no-login, deepseek/deepseek-v4-flash). This way users
send the original model name and it routes to the correct backend.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 00:42:21 +07:00
MythEclipseandClaude Fable 5 2fca9febe4 fix: pass original model name to backend in Anthropic proxy
Use anthReq.model instead of backendModel so the backend receives
the user-sent model name (e.g. claude-sonnet-4) rather than the
internal mapped name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 00:20:20 +07:00
MythEclipseandClaude Fable 5 5974d31164 fix: avoid double markFailed in AI proxy retry loop
Response handler already calls markFailed() on non-2xx and network
errors (which rotates the proxy). The preamble at attempt >= 2 was
calling markFailed() again, double-rotating and skipping a proxy.
Changed preamble to use rotate() instead of markFailed().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 00:02:40 +07:00
MythEclipseandClaude Fable 5 2dfb87eac6 fix: retry AI proxy with next proxy on HTTP errors too
Previously only retried on network errors (fetch exceptions). Now also
rotates to next proxy when upstream returns non-2xx (429 rate limit,
5xx, etc). Applies to both OpenAI and Anthropic endpoints.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:57:24 +07:00
MythEclipseandClaude Fable 5 38d7a83fe9 feat: add AI proxy routes to Workers and Vercel entry points
- Add /v1/chat/completions, /v1/messages, /v1/models routes to
  src/worker.ts (Cloudflare Workers) and api/relay.ts (Vercel)
- Import handleChatCompletion, handleAnthropicMessages handlers
- Using the same backend routing as the standalone server

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:45:38 +07:00
MythEclipseandClaude Fable 5 4168a087a0 feat: add Anthropic-compatible AI proxy endpoint
- Create src/lib/anthropic-proxy.ts: accepts Anthropic Messages API
  format (POST /v1/messages) and routes to the same backend providers
- Anthropic model names (claude-sonnet-4, claude-3-haiku, claude-opus-4)
  map to backend models with full request/response translation
- Streaming (SSE) via Anthropic protocol: message_start,
  content_block_delta, message_stop events
- Add /v1/messages route to server with CORS and proxy pool fallback
- Reuses MODEL_ROUTES from ai-proxy.ts for consistent backend routing

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:08:32 +07:00
MythEclipseandClaude Fable 5 567ed52db5 feat: add OpenAI-compatible AI proxy endpoint
- Create src/lib/ai-proxy.ts: routes OpenAI chat completions requests
  to backend providers (opencode.ai, surfsense.com, deep-seek.ai)
  based on model name with request/response translation
- Add POST /v1/chat/completions route to server with streaming (SSE)
  support, CORS, and proxy pool fallback on failure
- Add GET /v1/models route returning available model list
- Direct-first strategy: try backend directly, fall back to proxy pool
  on network failure (consistent with relay behavior)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 22:52:45 +07:00
MythEclipseandClaude Fable 5 c61f8d9db6 fix: try direct connection first, fall back to proxy
Change proxy strategy: first attempt goes direct (no proxy).
Only if direct fails, fall back to proxy pool with rotation.
This way healthy upstreams don't pay the proxy latency.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 22:15:47 +07:00
MythEclipseandClaude Fable 5 03427cae8c feat: auto-rotate proxy pool with retry on network failure
- Add src/lib/proxy-pool.ts: round-robin proxy pool that reads
  proxy.txt (host:port:user:pass), tracks consecutive failures,
  and rotates on threshold
- Integrate into src/index.ts: on fetch network error, mark proxy
  as failed, rotate to next, and retry the request once
- proxy.txt loaded from PROXY_FILE/PROXY_LIST env var or ./proxy.txt
- Graceful no-op when proxy.txt doesn't exist (Vercel/Workers)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 22:12:59 +07:00
MythEclipseandClaude Fable 5 3f96d8a6e7 fix: relay requests to / with x-relay-target instead of showing index
When a GET request hits / with an x-relay-target header, it should relay
the request — not display the index page. Fixed in all three entry points
(src/index.ts, api/relay.ts, src/worker.ts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:59:25 +07:00
Asep Haryana SaputraandGitHub a67f9283e3 Update README.md 2026-06-10 21:56:26 +07:00
Asep Haryana SaputraandGitHub 2b58b6cb0f Update README.md 2026-06-10 21:55:49 +07:00
Asep Haryana SaputraandGitHub 1aac993d34 Update README.md 2026-06-10 21:49:17 +07:00
MythEclipseandClaude Fable 5 2ac23f199d chore: configure Cloudflare Workers deployment
- Enable workers_dev deploy to edge-proxy-relay.workers.dev
- Set account_id in wrangler.toml
- Configure CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID as
  GitHub Actions secrets via gh CLI (from .env)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:46:13 +07:00
MythEclipseandClaude Fable 5 7a4df35371 feat: add Cloudflare Workers deployment support
- Create src/worker.ts: Workers-compatible relay handler using env
  bindings instead of process.env, exports { fetch } for Workers runtime
- Update wrangler.toml: point to new src/worker.ts entry point
- Update deploy.yml: add wrangler-action deploy step after tests pass
- The worker reuses the same relay logic from src/lib/ and src/middleware/

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:38:22 +07:00
Asep Haryana SaputraandGitHub 5552ee2118 Update README.md 2026-06-10 21:30:05 +07:00
MythEclipseandClaude Fable 5 58553f936e fix: disable Vercel Next.js framework detection
Add "framework": null to vercel.json so Vercel doesn't try to
run Next.js build flow (looking for .next/routes-manifest.json).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:22:37 +07:00
MythEclipseandClaude Fable 5 9dc32e8b10 fix: correct Vercel Bun runtime config and handler export format
Per Vercel docs (vercel.com/docs/functions/runtimes/bun):
- Use top-level "bunVersion": "1.x" in vercel.json (NOT functions block)
- Export default { async fetch(request) { ... } } — object with fetch method
  (not a bare default function)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:20:16 +07:00
MythEclipseandClaude Fable 5 591c1fa199 fix: add Vercel-compatible relay handler and fix vercel.json runtime
- Create api/relay.ts: Vercel serverless function handler that reuses
  relay logic from src/lib/relay-utils.ts and src/middleware/
- Export default fetch handler (no Bun.serve()) for Vercel Functions
- Fix vercel.json: use @vercel/node@5 runtime with proper routing via
  rewrites to catch all traffic to the relay handler
- Remove stale buildCommand/outputDirectory (Vercel handles function builds)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:17:21 +07:00
MythEclipseandClaude Fable 5 f58a92e2aa feat: migrate from Next.js to pure Bun relay proxy
- Replace Next.js app router with standalone Bun.serve() entry point
- Add middleware stack: rate limiter, body limiter, structured logger, SSRF protection
- Add WebSocket bidirectional relay via x-relay-target header
- Implement error classification (DNS→502, timeouts→504, SSRF→403, rate→429)
- Remove all Next.js dependencies and config files
- Update deploy workflow, tsconfig, wrangler config for Bun deployment

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 19:54:55 +07:00
MythEclipse 124dab98a2 docs: improve README with comprehensive examples and protocol support info 2026-05-08 19:12:18 +07:00
MythEclipse 694f14a316 fix: add node 22 + set secrets to correct repo 2026-05-08 19:03:24 +07:00
MythEclipse eba4fbe00a fix: remove wrong working-directory from workflow 2026-05-08 19:01:49 +07:00
MythEclipse 443ff77be9 ci: add CF Workers deploy workflow + fix relay header forwarding 2026-05-08 18:58:50 +07:00
MythEclipse dfb0f5942f docs: add alternative deployment endpoint to README 2026-05-08 17:32:56 +07:00
MythEclipseandClaude Opus 4.7 75731af9b6 Remove edge runtime directive from route handler
Cloudflare Workers via OpenNext tidak support Next.js edge runtime.
Hapus export const runtime = "edge" agar handler jalan di Workers runtime.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:32:35 +07:00
MythEclipseandClaude Opus 4.7 765bcdca44 Add Cloudflare Workers deploy config via OpenNext
- Fix build:worker script to use opennextjs-cloudflare build
- Add open-next.config.ts required by OpenNext Cloudflare
- Update wrangler.toml main entry to .open-next/worker.js
- Ignore .open-next/ and .wrangler/ build artifacts

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:27:06 +07:00