Resolved conflicts taking origin/master (v0.5.55) as canonical, with local
features re-applied:
- runtime log level (LOG_LEVEL env + dashboard Settings → Logging, applied
immediately and persisted across restarts)
- free/noAuth provider enable/disable toggle via providerStrategies.enabled
- parallel model testing (Test All Models / Test Selected Keys)
- Add qmodel_latest to QODER_MODEL_MAP
- Expose qmodel_latest in static Qoder provider catalog (qd)
- Generalize executor comment so model set does not go stale
- Add unit coverage for the new model key + catalog
Closes#1638
Co-authored-by: Cursor <cursoragent@cursor.com>
Move device-flow / poll / userinfo / parseExpiry from src/lib/qoder/auth.js
into a QoderService class at src/lib/oauth/services/qoder.js, matching how
KiroService is organized. Also re-add the QoderService re-export from
services/index.js.
The split now mirrors Kiro:
src/lib/oauth/services/qoder.js OAuth flow (was auth.js)
src/lib/qoder/cosy.js Per-request signing (unchanged)
src/lib/qoder/encoding.js WAF-bypass body (unchanged)
src/lib/qoder/constants.js Endpoints + model map (unchanged)
Behavior is unchanged — same functions, same signatures, just relocated
into a class so the import path lines up with `import { QoderService } from
"@/lib/oauth/services"` like every other OAuth provider. parseExpiry is now
a static method so callers and tests can use it without instantiating.
42 tests still pass; build still clean.
Adds 18 new tests covering the bugs fixed in the previous commit so they
can't silently regress:
- parseExpiry (7 tests): numeric ms-epoch input, numeric strings handled
before Date.parse so "1700000000" doesn't get year-interpreted, RFC3339
strings, expires_in:0 honored as already-expired, 30-day fallback only
when both inputs are missing/invalid
- normalizeMessages (4 tests): system hoisting, multipart text flatten,
multiple system joining, empty input
- wrapQoderSSE (6 tests): the fixed cases — trailing partial line drained
in flush(), no chunks forwarded after [DONE], embedded newlines stripped
from inner body, error envelope produces error chunk + [DONE], non-ok
responses returned unchanged
- expose parseExpiry from auth.js, expose normalizeMessages/wrapQoderSSE
via __test__ from the executor (internals only — not part of the public
API). Marked with comment so the surface is intentional.
42 tests total (24 original + 18 new). Build still clean.