Uh oh!
There was an error while loading. Please reload this page.
fix(app-shell): invitation links resolve through the console mount helper instead of rebuilding BASE_URL (#4472) - #4480
Merged
Conversation
…lper instead of rebuilding BASE_URL (#4472) Both copy sites carried their own `buildAcceptUrl`, glueing `${window.location.origin}` to `import.meta.env.BASE_URL`. In the portable build the console ships (`base: './'`) BASE_URL is the literal '.', so the copied link was `http://localhost:8080./accept-invitation/<id>` — a trailing-dot host — and with the dot removed it still skipped the `/_console/` mount, which the server answers with {"error":"Not found"}. Both local copies are deleted; the two sites call `resolveConsoleUrl`, the mount-aware helper WorkspaceSwitcher and OrganizationsPage already use. The invite dialog resolves once so its displayed field and its clipboard cannot drift apart. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
yinlianghui
commented
Aug 12, 2026
CollaboratorAuthor
ACCEPT — step-7 复核 by PM session
Flipping ready + arming auto-merge. Note for the pool: #4474 and #4475 unlock when this lands (shared manage-area surface). Generated by Claude Code Generated by Claude Code |
yinlianghui
marked this pull request as ready for review
August 12, 2026 19:13
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes#4472
The defect
Copying an invitation link from the workspace Invitations tab produced a URL the recipient cannot open:
Both copy sites carried their own
buildAcceptUrl, glueing${window.location.origin}ontoimport.meta.env.BASE_URL:packages/app-shell/src/console/organizations/manage/InvitationsPage.tsx:32— the Invitations tab's per-row copy button;packages/app-shell/src/console/organizations/manage/InviteMemberDialog.tsx:39— the freshly-created invitation's "Accept link" field (and its copy button).In the portable build the console ships (
base: './',apps/console/vite.config.ts)BASE_URLis the literal'.', so the concatenation put a dot straight after the authority — a trailing-dot host. Removing the dot by hand did not rescue the link either: the resulting/accept-invitation/:idskips the deployment mount, and a console served under/_console/answers that path with{"error":"Not found"}. This is precisely the failureresolveHomeUrl.ts's own header records as retired.The fix
Both local copies are deleted. The two sites call
resolveConsoleUrlfrompackages/app-shell/src/console/organizations/resolveHomeUrl.ts— the mount-aware helperWorkspaceSwitcherandOrganizationsPagealready use for full-page navigations. It resolves against the base-href tag (base href="/_console/") the server injects when it serves the console (objectstack packages/cli/src/utils/console.ts), so the copied link carries the mount in every deployment shape. One resolver, one answer: no URL assembly survives in either file. The invite dialog resolves once into a singleacceptUrl, so its displayed field and its clipboard cannot drift apart.No public surface moved: the emitted
.d.tsfor both modules is byte-identical to theorigin/mainbuild (measured, two builds diffed) — hencepatch.Red-first
packages/app-shell/src/console/organizations/__tests__/acceptInvitationLink.mount.test.tsxdrives both copy sites through the real components and asserts the produced URL whole, in both deployment shapes (/_console/mount and root mount).Against the current builder the mount half failed exactly as reported:
The trailing-dot half needed one measurement before it could be trusted, and the finding is worth recording:
vi.stubEnv('BASE_URL', '.')reaches only the exactimport.meta.env.BASE_URLspelling. The retired builders read(import.meta as any).env?.BASE_URL, and Vite inlines a bareimport.meta.envas an object literal at transform time — so that read saw'/'in vitest no matter what was stubbed, and the portable-build condition could not be reproduced through it. Switching only the spelling in the two retired builders (temporarily, then reverted withgit checkout) made the pin produce the bug report's string verbatim:So the shipped pin goes red on a reintroduced local builder via the mount assertion; the trailing-dot assertion is carried alongside it and documented in the test as unable to fail on its own in vitest, rather than left to read as coverage it does not have.
After the fix, all 4 cases green.
Verification
pnpm exec vitest run packages/app-shell/— 357 files, 3420 passed, 1 skippedpnpm --filter @object-ui/app-shell type-check(tsc --noEmitandtsc -p tsconfig.test.json) — exit 0pnpm exec eslinton the three changed files — 0 errors (26 pre-existingset-state-in-effectwarnings in untouched code)node scripts/check-changeset-presence.mjs,check-changeset-no-major.mjs,check-control-bytes.mjs— all greenCopy census
Swept for other
accept-invitation/assembly andBASE_URL-based origin concatenation in console code. No further in-family defects; two sites listed for the record, neither touched here:packages/app-shell/src/console/ai/AiChatPage.tsx:986(publicShareBase) — a third hand-rolled mount resolution, but a correct one: it reads the document's base-href tag and yields${origin}/_console/s. Duplicated mechanism, no user-visible defect; a candidate to fold intoresolveConsoleUrlseparately.apps/console/src/utils/consoleBase.ts:42— readsimport.meta.env.BASE_URLdeliberately and never concatenates an origin; documented for all three mount shapes and covered by its own tests. Not in family.Generated by Claude Code