Refresh expired CLI session instead of dropping to none auth#184
Conversation
When a session's access token expired, resolveConfig fell through to authMode: 'none' and silently dropped session.activeWorkspace. The HTTP client then built `/api/v1/workspaces//documents` (empty segment) and the backend returned 404, making expired sessions surface as missing routes — even though the refresh token was still valid and the existing 401 -> refresh -> retry path in HttpClient was waiting to handle exactly this case. Adopt the saved session whenever both tokens are present and let the HTTP client decide if the access token still works. If the refresh token is also dead, the existing SESSION_EXPIRED error path surfaces a clear "run `wafflebase login`" message. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
📝 WalkthroughWalkthroughThis PR fixes a CLI issue where an expired access token would cause a 404 error even with a valid refresh token. The ChangesSession Token Handling in Config Resolution
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/cli/test/config.test.ts (1)
60-112: ⚡ Quick winAdd one negative session-token edge test to lock guard behavior.
You already cover valid and expired access-token paths. Please also assert that when either token is missing,
resolveConfig({})does not selectauthMode: 'jwt'(protects the newsession.accessToken && session.refreshTokencontract at Line 112).🧪 Suggested test addition
describe('session-backed JWT auth', () => { @@ it('keeps JWT auth and workspace when access token is expired but refresh token exists', () => { writeSessionFile({ expiresAt: new Date(Date.now() - 60_000).toISOString() }); const config = resolveConfig({}); expect(config.authMode).toBe('jwt'); expect(config.workspace).toBe('ws-from-session'); expect(config.accessToken).toBe('access-token'); expect(config.refreshToken).toBe('refresh-token'); }); + + it('does not use JWT auth when refresh token is missing', () => { + writeSessionFile({ refreshToken: '' }); + const config = resolveConfig({}); + expect(config.authMode).not.toBe('jwt'); + }); });As per coding guidelines, "
**/*.{test,spec}.{js,ts,jsx,tsx}: Write tests for critical business logic and edge cases".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/test/config.test.ts` around lines 60 - 112, Add a negative test in the 'session-backed JWT auth' describe block that uses writeSessionFile to create a session missing either accessToken or refreshToken (e.g., omit accessToken and/or refreshToken in overrides), calls resolveConfig({}), and asserts that config.authMode is not 'jwt' and that workspace/accessToken/refreshToken are not taken from the session; this protects the new session.accessToken && session.refreshToken contract checked in resolveConfig.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/tasks/archive/2026/05/20260505-cli-expired-session-404-todo.md`:
- Around line 13-15: Add explicit fenced code block languages to the two code
fences: change the block containing { "error": { "code": "ERROR", "message":
"HTTP 404" } } to a ```json fence, and change the block containing the GET
https://api.wafflebase.io/api/v1/workspaces//documents request to a ```http
fence so the JSON and HTTP examples are properly annotated for markdown linting.
---
Nitpick comments:
In `@packages/cli/test/config.test.ts`:
- Around line 60-112: Add a negative test in the 'session-backed JWT auth'
describe block that uses writeSessionFile to create a session missing either
accessToken or refreshToken (e.g., omit accessToken and/or refreshToken in
overrides), calls resolveConfig({}), and asserts that config.authMode is not
'jwt' and that workspace/accessToken/refreshToken are not taken from the
session; this protects the new session.accessToken && session.refreshToken
contract checked in resolveConfig.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7398a161-86bb-4ecf-9f87-3e9cb2148a54
📒 Files selected for processing (5)
docs/tasks/README.mddocs/tasks/archive/2026/05/20260505-cli-expired-session-404-todo.mddocs/tasks/archive/README.mdpackages/cli/src/config/config.tspackages/cli/test/config.test.ts
| ``` | ||
| { "error": { "code": "ERROR", "message": "HTTP 404" } } | ||
| ``` |
There was a problem hiding this comment.
Specify fenced code block languages to satisfy markdown lint.
Line 13 and Line 27 should include language identifiers (json, http) to clear MD040 warnings.
📝 Suggested markdown fix
-```
+```json
{ "error": { "code": "ERROR", "message": "HTTP 404" } }@@
- +http
GET https://api.wafflebase.io/api/v1/workspaces//documents
Also applies to: 27-29
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 13-13: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/tasks/archive/2026/05/20260505-cli-expired-session-404-todo.md` around
lines 13 - 15, Add explicit fenced code block languages to the two code fences:
change the block containing { "error": { "code": "ERROR", "message": "HTTP 404"
} } to a ```json fence, and change the block containing the GET
https://api.wafflebase.io/api/v1/workspaces//documents request to a ```http
fence so the JSON and HTTP examples are properly annotated for markdown linting.
Verification: verify:selfResult: ✅ PASS in 138.5s
Verification: verify:integrationResult: ✅ PASS |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Adds @wafflebase/slides as a third surface alongside Sheets and Docs, plus 53-shape library (Phase 1+2), adjustment handles for 9 pilot shapes (P3-A.1), live snap guides, align/distribute toolbar, themed authoring, and layout-change UI. Also ships Sheets cell comments (Phase B), docs peer-avatar caret jump, yorkie-js-sdk 0.7.8 upgrade, and CLI/REST API improvements (docs export imageFetcher, expired session refresh, REST docs split). Minor bump because slides is a new top-level package. Highlights: #184 #185 #186 #187 #188 #189 #190 #191 #192 #197 #198 #201 #202 #203 #204 #205 #206 #207 #209 #210
Summary
wafflebase docs list(and other CLI subcommands) returningHTTP 404once the session's access token expires, even when a valid refresh token is sitting in~/.wafflebase/session.json.resolveConfiginpackages/cli/src/config/config.tsonly adopted the saved session when!isSessionExpired(session). With an expired access token it fell through toauthMode: 'none'and droppedsession.activeWorkspace, so the HTTP client builtGET /api/v1/workspaces//documents(empty segment) and the backend rejected it with a 404. The HttpClient's existing 401 → refresh → retry path requiresauthMode === 'jwt', so it was effectively dead code in exactly the scenario it was designed for.accessTokenandrefreshTokenare present. The HttpClient now actually gets to refresh the access token on 401; if the refresh token is also dead, the existingSESSION_EXPIREDpath still surfaces a clear "runwafflebase login" message.wafflebase statuskeeps usingisSessionExpiredfor its "valid" / "expired" UX hint — only config resolution is changed.Test plan
pnpm --filter @wafflebase/cli test— new regression case inpackages/cli/test/config.test.tsfails before the fix, passes after.~/.wafflebase/session.jsonexpiresAtinto the past, ran the installed CLI →HTTP 404. Then ran the patched CLI from source (pnpm --filter @wafflebase/cli dev docs list) → auto-refresh fired, document list returned,expiresAtrotated forward.pnpm -w run verify:fast— exit 0.🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
Bug Fixes
Tests