Skip to content

console: copied invitation link is unusable — buildAcceptUrl rebuilds the trailing-dot host that resolveHomeUrl already retired #8090

Description

@baozhoutao

Copying an invitation link from the workspace Invitations tab yields a URL that cannot be opened. The recipient of an invitation therefore has no working way in.

Repro

  1. Multi-org runtime, zh console, sign up and create a workspace (owner).
  2. Users → Invite user → invite lisi@acme-test.com as member.
  3. Workspace switcher → Manage membersInvitations tab → click Copy invitation link.
  4. Paste the clipboard content.

Actual

http://localhost:8080./accept-invitation/bgn1XAfRuCQUS1l9NBqOMGgJDUYm5l56

Two defects in one string:

  • trailing-dot hostlocalhost:8080. (the port is followed by .);
  • the console mount is missing — the console is served under /_console/, and GET /accept-invitation/<id> (dot removed) is answered by the server with {"error":"Not found"}.

The only URL that renders the accept page is http://localhost:8080/_console/accept-invitation/<id> — verified working, the page loads and the invitation can be accepted.

Expected

The copied link is the one the recipient can open: <origin><console mount>accept-invitation/<id>.

Cause

buildAcceptUrl rebuilds the URL from import.meta.env.BASE_URL, which is '.' in a portable (base: './') build:

// packages/app-shell/src/console/organizations/manage/InvitationsPage.tsx:32
function buildAcceptUrl(invitationId: string): string {
  const base = (import.meta as any).env?.BASE_URL ?? '/';
  const normalized = base.endsWith('/') ? base : `${base}/`;
  return `${window.location.origin}${normalized}accept-invitation/${invitationId}`;
}

Duplicated verbatim in packages/app-shell/src/console/organizations/manage/InviteMemberDialog.tsx:39 (the "share link" view of the invite dialog), so the freshly-created-invitation link is broken the same way.

This is the exact failure mode resolveHomeUrl.ts was written to retire — its header documents it:

${origin}${import.meta.env.BASE_URL}home broke portable builds (base: './'), producing https://host./home — trailing-dot host.

Suggested fix

Drop both local buildAcceptUrl copies and call the existing mount-aware helper:

import { resolveConsoleUrl } from '../resolveHomeUrl';
const url = resolveConsoleUrl(`accept-invitation/${invitationId}`);

resolveConsoleUrl resolves against <base href> (the deployment mount), which is what both WorkspaceSwitcher and OrganizationsPage already use for full-page navigations. A regression test asserting the copied URL contains no :<port>. and starts with the console mount would pin it.

Environment

Local dev server http://localhost:8080, multi-org enabled, zh locale, observed 2026-08-12. The server was started by the maintainer and its exact commit is not verified; the source quoted above is the current objectui main checkout.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions