qwen-code/packages/web-shell/client/utils/sessionPath.ts
ytahdn 2ab3681157
fix(web-shell): preserve token and base path in session URLs (#7926)
* fix(web-shell): preserve session URL context

* fix(web-shell): keep daemon token out of the session URL (#7926)

Restore the daemon token stripping that was dropped alongside the
base-path fix: removeDaemonTokenFromUrl() on startup and the ?token=
delete in replaceStandaloneSessionUrl. The ?token= query path is still
supported for backward compatibility, so without stripping it leaks into
the address bar, history, access logs, and Referer headers.

Also extract the session pathname building into buildSessionPathname()
with unit tests covering root/sub-path deployments, the no-session case,
trailing slashes, and id encoding.

* fix(web-shell): anchor session URL parser to agree with writer (#7926)

Extract parseSessionId() next to buildSessionPathname() and anchor it to the last /session/<id> segment so the parser agrees with the greedy writer. Previously a base path ending in a session segment produced /app/session/session/<id>, which the first-match parser read back as the literal id "session". Add round-trip and trailing-slash coverage.

* test(web-shell): cover parseSessionId malformed-encoding catch branch (#7926)

* fix(web-shell): preserve base path in split-view URL (#7926)

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-29 06:12:37 +00:00

38 lines
1.3 KiB
TypeScript

/**
* @license
* Copyright 2026 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Build the pathname for a standalone session URL while preserving any base
* path the app is deployed under (e.g. `/app/session/<id>` stays under
* `/app` instead of being reset to `/session/<id>`). With no session id,
* returns the base path (or `/` at the root).
*/
export function buildSessionPathname(
currentPathname: string,
sessionId: string | undefined,
): string {
const sessionPath = currentPathname.match(/^(.*)\/session\/[^/]+\/?$/);
const basePath = sessionPath?.[1] ?? currentPathname.replace(/\/$/, '');
return sessionId
? `${basePath}/session/${encodeURIComponent(sessionId)}`
: basePath || '/';
}
/**
* Extract the session id from a standalone pathname. Anchored to the last
* `/session/<id>` segment so it agrees with `buildSessionPathname`'s greedy
* writer; a first-match parse would read the literal `session` segment when
* the base path itself ends in `/session` (e.g. `/app/session/session/<id>`).
*/
export function parseSessionId(pathname: string): string | undefined {
const match = pathname.match(/\/session\/([^/]+)\/?$/);
if (!match) return undefined;
try {
return decodeURIComponent(match[1]);
} catch {
return undefined;
}
}