Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
4069eaa
fix(web-shell): allow session refresh with daemon auth
Aug 3, 2026
dea7b29
test(web-shell): cover SPA fallback shell branch for non-session navi…
Aug 3, 2026
0ac2f01
Merge branch 'main' into agent/fix-web-shell-session-refresh-auth
qwen-code-dev-bot Aug 3, 2026
516dca1
Merge branch 'main' into agent/fix-web-shell-session-refresh-auth
wenshao Aug 3, 2026
572c9e9
test(web-shell): retarget sec-fetch SPA fallback test to non-session …
qwen-code-dev-bot Aug 4, 2026
af38a40
fix(web-shell): serve pre-auth navigations during the deferred runtim…
qwen-code-dev-bot Aug 4, 2026
56e620e
Merge branch 'main' into agent/fix-web-shell-session-refresh-auth
qwen-code-dev-bot Aug 4, 2026
91c3f0f
fix(cli): align deferred pre-auth web shell gate with warm routing (#…
qwen-code-dev-bot Aug 4, 2026
c257d65
fix(cli): report daemon startup failure to pre-auth web shell navigat…
qwen-code-dev-bot Aug 4, 2026
451ac12
Merge branch 'main' into agent/fix-web-shell-session-refresh-auth
qwen-code-dev-bot Aug 4, 2026
3f27d53
fix(cli): exempt bare /assets from the deferred pre-auth gate (#8445)
qwen-code-dev-bot Aug 5, 2026
31b8f09
refactor(cli): dedupe runtime failure envelopes and deferred-window t…
qwen-code-dev-bot Aug 5, 2026
729af2d
refactor(cli): rename startup envelope helper and pin query-string de…
qwen-code-dev-bot Aug 5, 2026
2a68383
fix(cli): serve the // root alias pre-auth and fail-close the deferre…
qwen-code-dev-bot Aug 5, 2026
2e90b9e
docs(cli): record the pre-auth %2F session deep-link invariant (#8445)
qwen-code-dev-bot Aug 6, 2026
3440313
Merge branch 'main' into agent/fix-web-shell-session-refresh-auth
qwen-code-dev-bot Aug 6, 2026
d796703
fix(test): isolate serve streaming suite from stray workspace setting…
qwen-code-dev-bot Aug 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/cli/src/serve/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3030,6 +3030,36 @@ describe('createServeApp', () => {
expect(res.text).toContain('<div id="root">');
});

it('serves session document deep links before bearer auth without exposing APIs', async () => {
const app = createServeApp({ ...baseOpts, token: 'secret' }, undefined, {
webShellDir,
});
const shell = await request(app)
.get('/session/abc123')
.set('Host', host)
.set('Accept', 'text/html');
expect(shell.status).toBe(200);
expect(shell.text).toContain('<div id="root">');

const head = await request(app)
.head('/session/abc123')
.set('Host', host)
.set('Accept', 'text/html');
expect(head.status).toBe(200);

const nonNavigation = await request(app)
.get('/session/abc123')
.set('Host', host)
.set('Accept', 'application/json');
expect(nonNavigation.status).toBe(401);

const api = await request(app)
.get('/session/abc123/status')
.set('Host', host)
.set('Accept', 'text/html');
expect(api.status).toBe(401);
});

it('leaves non-navigation API misses as JSON 404s', async () => {
const app = createServeApp(baseOpts, undefined, { webShellDir });
const res = await request(app)
Expand Down
4 changes: 3 additions & 1 deletion packages/cli/src/serve/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1181,7 +1181,9 @@ export function createServeApp(
// API calls still carry the bearer (getDaemonAuthHeaders) and every API
// route below stays token-gated. The SPA deep-link fallback is registered
// LATER (after all API routes, see mountWebShellSpaFallback) so authed
// routes win over the shell. The assets dir is resolved by the caller
// routes win over the shell. Exact `/session/:id` document navigations are
// mounted here too because a browser refresh cannot attach the bearer header
// before the shell loads. The assets dir is resolved by the caller
// (runQwenServe) and injected via deps.webShellDir; `--no-web` sets
// opts.serveWebShell=false to opt out.
const webShellDir =
Expand Down
8 changes: 7 additions & 1 deletion packages/cli/src/serve/web-shell-static.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ function createSendIndex(
*
* - `GET /assets/*` — hashed, immutable build chunks (long-cache).
* - `GET /` — the HTML shell, always (so `curl /` shows the UI too).
* - `GET /session/:id` document navigations — the HTML shell, so a browser
* refresh can load before the front-end adds its bearer header.
*
* Caller must have already verified `webShellDir` exists.
*/
Expand Down Expand Up @@ -183,10 +185,14 @@ export function mountWebShellAssets(
res.status(404).type('text/plain').send('Not found');
});
app.get('/', (_req: Request, res: Response) => sendIndex(res));
app.get('/session/:id', (req: Request, res: Response, next: NextFunction) => {
if (!isDocumentNavigation(req)) return next();
sendIndex(res);
});
}

/**
* Mount the SPA deep-link fallback (for navigations like `/session/<id>`).
* Mount the SPA deep-link fallback for routes not explicitly mounted above.
* Registered AFTER all API routes — just before the error handler — so real
* routes, INCLUDING their `bearerAuth` 401s, always win and only genuine 404
* misses fall through to the shell.
Expand Down
Loading