- OpenAI compatibility: emit standard CORS headers on
/v1/responsesfor non-streaming requests, and return400on unsupported non-streaming usage. - Deploy-time SW versioning:
gen:sw-versionwrites/sw-version.json; registrar registers/sw.js?v=…so each deploy gets an isolated cache namespace. - SW shell-cache + deploy-regression test seams (
tests/unit/swShellCache.test.js,tests/SW-TEST-SEAM.md).
bun run check/lintgate onoxlint --deny-warnings.
- SW navigation: network-first (not cache-first) with offline
/offlinefallback; neverResponse.error()on documents/images; drop blindcontrollerchangereload (f1d4861). - Remove redundant
controller.close()inopen-sse/handlers/chatCore.jsfinally block — already closed in the success path. - Canary body-size latency: extend
readBodyTextStream()chunk-by-chunk reads across additional large-body routes to avoid the 9–15scurl/8.xstall. - Redis rate-limit isolation: respect
RATELIMIT_KEY_PREFIXso environments (e.g. canary/prod) keep separate namespaces. - Client disconnect: classify
AbortErroratnode:_http_serveras[ClientDisconnect](not[FATAL]) andcontroller.close()on SSE reader abort — no unhandled rejections, no log spam. - Body size cap raised to 50MB default, env-tunable via
POD_MAX_REQUEST_BODY_BYTESandPOD_MAX_CHAT_BODY_BYTES. /api/monitoring/health*are public reads (auth guard removed); older changelog “+ API key auth” entries are historical only.
- Canary 9-15s body-size-bound latency:
src/sse/handlers/chat.tsnow usesreadBodyTextStream()(chunk-by-chunk body read with explicit size cap) instead ofrequest.text()for large bodies. Added per-request timing instrumentation (t_read,t_parse,t_bypass) for diagnosis. - Redis shared-keyspace risk:
src/lib/rateLimit/redis.tsnow respectsRATELIMIT_KEY_PREFIXenv var so canary can use a separate namespace. Added 1-second per-op timeout wrapper (RATELIMIT_REDIS_TIMEOUT_MSenv) to prevent stalled connections from blocking requests. - Stale semantic cache doc:
.agents/architecture/{03-data,01-app}.mdnow correctly describe the cache as in-process LRU + per-instance SQLite (no Redis involvement), matchingsrc/lib/semanticCache.ts.
- AbortError unhandledRejection spam on client disconnect:
request.text()/request.json()now return{ ok: false, reason: "aborted" }viareadBodyText()helper; routes return 499 cleanly. SSE stream wrappers insrc/sse/handlers/chat.tsusecontroller.close()(notcontroller.error(err)) on reader abort, preventing the abort from re-surfacing in the Next.js response writer. - Hard 10MB body cap raised to 50MB default (env-tunable:
POD_MAX_REQUEST_BODY_BYTES,POD_MAX_CHAT_BODY_BYTES). - Global
unhandledRejection/uncaughtExceptionhandlers inserver-init.tsandinstrumentation.tsnow classifyError: aborted at node:_http_serveras[ClientDisconnect](not[FATAL]) and dedupe log spam (1s window, 5-error threshold). - Abort-safe body parsing applied to 6 sibling routes:
imageGeneration,tts,fetch,embeddings,search,pricing/sync. open-sse/handlers/chatCore.js: catch block now filtersAbortErrorand callscontroller.close()instead ofcontroller.error(e).- Resolve intermittent hang: fix HEALTHCHECK port, SSE counter leak, Redis leak, instrumentation.ts init order, dead code cleanup.
- Redirect root
/to/endpointinstead of nonexistent/dashboard. - Don't block server startup on Redis init failure in
register(). - Cache tailscale binary lookup; show cached API keys immediately.
- Add offline cache to combos page — instant load on revisit.
- Optimize service worker for Zeabur cold-start.
- Resolve remaining
eqeqeqlint warnings acrosssrc/.
- Add API compatibility matrix (
compatibility-matrix.md) with OpenAI/Anthropic endpoint status, error shapes, and SDK verification. - Add API compatibility policy and reference-checking workflow to AGENTS.md.
- Update README and AGENTS.md for regex fix and project scope.
- Update stale JS/no-TS references in architecture docs.
- Escape unterminated regex literal in
logger.tsfor Turbopack. - Set
minimumLockoutMinutes=0in test seeds to avoid 60m default skew. - Anthropic error format compliance: catch blocks now return Anthropic error shape on
/v1/messages. - Add missing error code fields in route handlers.
- Security hardening phase 1: error sanitization across 18+ API routes (
sanitizeError) - Security hardening phase 2: safe JSON body parsing across 45+ routes (
parseJsonBody) - Security hardening phase 3: upstream API body leak patches (13 additional routes)
- Security hardening phase 4: SSE/streaming crash hardening (3 containment points)
- Redis rate limiting with automatic backend selection
- Duck-type backend dispatch (replace constructor.name/instanceof — breaks in minified builds)
- RPM slot release when concurrent check fails after RPM passes
- Variable shadowing fixes in 3 OAuth routes
- Fix Codex tool call response cut-off + reasoning effort normalization
- Security hardening + upstream adoption + race fixes
- Fix CHANGELOG, node:fs imports, .env.example branding
- Fix Codex reasoning token budget + audit findings
- feat: Account Lockout Status section on /health page
- feat: 'Connected only' toggle on /media-providers/web page
- feat: connection-level lockdown with exponential cooldown
- Fix Web Cookie providers showing 'No connections' + filter respect
- Verify combo systemPrompt works for OpenCode Go (both routes)
- Lock-in combo system prompt injection across all 6 provider shapes
- /health page works for dashboard users + fix metrics
- Enrich /api/monitoring/health with cache/sync/runtime metrics + API key auth
- Clean noisy console.log spam in client components
- Fix /api/usage/stats 400 on period=90d
- Silence "no label associated with a form field" warnings — aria-label
- Silence form-field autofill warnings — add id/name/aria-label
- Silence Chrome 'preloaded but not used' CSS warning
- Fix Add OpenAI/Anthropic Compatible modal — 400 silent failure
- Relay function honours x-relay-timeout + Kiro transient retry
- Harden Vercel relay (timeout race, platform 504, retry, healthcheck)
- Perplexity-web perceived TTFT — x-pod-skip-reasoning header
- Render Web Cookie Providers section in /providers
- Remove paid Perplexity API provider
- Harden CodeQL #32-#35 fixes (re-scan still flagged)
- Resolve all 14 open CodeQL alerts
- Sink-level log sanitizer for CodeQL #39
- Fix /usage Details 502 error, replace datetime-local with DatePicker, fix Est. Cost to 2dp
- Fix OAuth: hardcode Codex redirect_uri to localhost:1455, remove dead mitm exports
- Fix tunnel enable 'Unable to connect' error — 3 root causes fixed
- Rename 'System Health' to 'Health' + align page spacing with /memory and /cache
- Persist ReactFlow viewport to sessionStorage + rename Usage title
- Rename 'Providers' to 'LLM Providers' in header, breadcrumbs, page title
- Center-align 'No connected providers' placeholder in /media-providers
- Fix /quota double-click expand bug + add Last Request At column
- Fix /usage Details tab always showing empty — observability config + id propagation
- Fix Codex 502 invalid JSON response, remove disableCodexStreaming workaround
- Add memory pipeline, retrieval, store integration tests (711 tests)
- Fix clearInFlight called in all cache paths, add memory+cache edge case tests (653 tests)
- Fix SQLite TTL datetime format, clearInFlight on large responses, add cache integration tests
- Include memoryOwnerId in cache signature, fix temperature default, bump cache size to 512KB
- Add 26 Vertex AI stream guard tests
- Add missing testClaude stub, fix cloud branding, add 39 cloud tests
- Sanitize browser network errors in tunnel enable, wrap fetchData non-fatal, remove DNS warmup delay
- Add INITIAL_PASSWORD, BASE_URL, CLOUD_URL env vars to README
- Restore hideDisabled toggle behavior in /quota, remove permanent filter
- Ping tunnelUrl instead of publicUrl for faster tunnel health check
- Remove requestTooLargeForCache guard (generateSignature handles large payloads)
- Skip stream field injection for Vertex AI target format
- Fix models.dev sync — read cost from .cost field, fix 0 model count
- Remove Melma from API Key providers
- Replace 9Router branding with Pod across repo
- Add .pi to gitignore
- Fix recheckAndClear re-lock respects backoff multiplier
- Migrate Inter and IBM Plex Mono to next/font, suppress Material Symbols lint
- Add perf-cpu-hotpath tests for SSE hotpath fixes
- Reduce CPU load from SSE hot paths
- Resolve 14 CodeQL security alerts
- Fix: skeleton on initial load across health/usage/cache/memory/endpoint pages
- Fix: model lockout recheck before clear, spinner icon, human-readable duration
- Fix: console logs "Showing x of y logs" below log list
- Fix: combo test uses /api/models/test endpoint, spinner icon
- Feat: quota toolbar toggles with session persistence + logs live state
- Fix provider topology active node border white instead of orange
- Fix providers/media-providers Connected Only filter + remove arrow buttons
- Fix semantic cache always 0% hit rate — temperature/top_p normalization
- Feat: health page SSE live update
- Fix minimum lockout time not applied correctly
- Persist Connected Only toggle state in localStorage
- Resolve remaining 14 CodeQL security alerts
- Update RWX workflows for pod repo
- Feat: configurable minimum lockout time with exponential multiplier
- Fix semantic cache 0% hit rate due to memory injection signature mismatch
- Fix console/request logs height
- Fix quota page toolbar improvements
- Health page improvements
- Exclude disabled models from provider quota progress
- Resolve all 23 CodeQL security alerts
- Feat: drag-to-reorder combos and provider connections
- Multi-account custom providers
- Fix Codex provider freeze during tool calls
- Add CONTRIBUTING.md, SECURITY.md, update README
- Add paseo.json to .gitignore, remove melma-router binary
- Fix memory leaks — reduce RSS from 1.2GB to ~200-400MB
- Fix browser tab title "Pod ✦ Pod ✦ Health" → "Pod ✦ Health"
- Fix semantic cache 0% hit rate — temperature threshold too strict
- Bound usage_history growth, debounce stats SSE
- Add
bun run checkscript — format, lint, type check
- Fix usage chart — linear line instead of curved
- Request logs SSE: detect PENDING→SUCCESS/FAILED, poll 1s when pending
- Fix usage stats Cost/Tokens pill tabs — standardize to SegmentedControl
- Fix usage chart white graph color for Tokens/Cost
- Fix console logs timestamp column width
- Improve upstream error logging — URL, model, status code
- Model test bypasses semantic cache via x-pod-no-cache header
- Request log detail: abort previous fetch on new selection
- Memory extraction: add Indonesian language patterns for preference/decision/habit
- Thundering herd protection for semantic cache via in-flight deduplication
- LRU connection cache, cooldown guard, queue depth metrics, rate limit docs
- Security: API key auth on GET /v1/models endpoints; timing-safe comparison
- Kebab-case URL redirects for web-search/web-fetch
- Move Connected Only toggle to header action slot
- Provider nodes: optional Identifier field
- Adopt upstream fixes — developer role norm, stream stall timeout, Ollama usage, Gemini schema, DATA_DIR fallback, Today period, Blackbox provider, MiniMax TTS
- Standardize Button and Badge usage across app
- Quota page: Collapse All, rename Progress→Quota column
- Console logs: Refresh/Live toggle, Connecting status fix
- Combos page: Test button per combo
- Provider health grouped by provider, show provider icon
- Remove MITM bypass feature entirely
- Settings: remove Migrate to SQLite button
- Replace all browser confirm() with in-app ConfirmModal across all pages
- Fix breadcrumb label alignment
- Fix memory page crash — missing confirmDialog state
- Console logs: toolbar in header, level filter pills
- Request logs: search/filter, SSE live stream, detail payload fix
- Proxy logs: silent refresh, configured count always visible
- Standardize pill tabs with SegmentedControl across /usage and /logs
- Quota page: grouped by provider with 3-level expand/collapse
- Remove close button from sonner toasts
- Add @custom-variant dark for Tailwind v4 dark mode
- Health page: Rate Limit Status, Model Lockout Status, sparklines
- Logs page: multi-tab (Request Logs, Proxy Logs, Console)
- Usage page: ReactFlow topology, metric cards redesign, Details tab
- Replace custom toast with sonner, position bottom-right
- Theme toggle, light theme implementation
- API keys table with pagination (15 per page)
- Sidebar: larger app name, version label, custom SVG logo
- Fork from 9Router — reset version to v0.0.1
- Rebrand: 9Router → Pod across code, branding, Docker image, data dir
- Migrate runtime from Node.js to bun
- Remove
/dashboardprefix from all routes - Replace better-sqlite3 with bun:sqlite (SQLite via bun native)
- Docker image:
lazuardytech/pod - CI/CD: GitHub Actions build + Docker publish on tag push
- OpenSSE imported locally (jsconfig.json alias)
- Core pages adapted: login, endpoint, providers, logs, usage, health, settings, memory, cache