Skip to content

finding(app-shell): the injected <base href>'s trailing slash is an unstated invariant of the console-mount resolver family #5678

Description

@os-sales

Measured while folding AiChatPage's publicShareBase into the shared resolver (#4482, PR #5677). Observation-class: nothing reachable is broken today, and no fix is proposed here.

What

consoleRoot() in packages/app-shell/src/console/organizations/resolveHomeUrl.ts is the single mount source for resolveHomeUrl / resolveRootUrl / resolveConsoleUrl, and now also for the share-link base. It resolves relative paths against the <base href> verbatim:

constbaseHref=document.querySelector('base')?.getAttribute('href');returnbaseHref ? newURL(baseHref,window.location.origin) : newURL('/',window.location.origin);

Every one of those helpers therefore silently depends on the injected href ending in /. Given <base href="/_console"> (no trailing slash), new URL('home', 'https://host/_console') resolves to https://host/home — HTML base-URL semantics drop the last segment — so org switching, the /home landing, resolveConsoleUrl('apps/…') and the share base would all leave the console mount at once.

Nothing in the tree asserts or normalizes that trailing slash.

Why it is only an observation

The single injector is packages/cli/src/utils/console.ts, which writes `<base href="${CONSOLE_PATH}/">` — the slash is a literal in the template, so today the invariant holds by construction. objectui ships no <base> tag in any HTML of its own (checked across apps/** and packages/**), and the CLI's injection is idempotent: it bails if the build already shipped one, which is the seam where a differently-shaped href could arrive from a host.

Note also that a slashless href would already break the SPA's relative asset URLs (./assets/…), so such a deployment is broken before it reaches these helpers. That is the argument for leaving consoleRoot() alone rather than adding normalization — the resolver following browser semantics is arguably correct, and "correct" here is a judgement call, not an obvious repair.

Two smaller shapes in the same family, recorded for completeness:

What could be done, if triage decides it is worth anything

Cheapest option is a one-line normalization in consoleRoot() (append / when the resolved pathname lacks one), which would make the family robust to a host-injected href of either shape. That is a behaviour change to /home and org-switch navigation, which is why PR #5677 did not smuggle it in under a share-link card. The alternative is to leave the code alone and write the invariant down where the CLI injects it.

Filed unassigned for triage.


Generated by Claude Code


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions