Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

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

Closed

Description

@hotlong

Moved from objectstack-ai/objectstack#8090 at triage (file-at-destination: the fix is entirely in this repo). Filed 2026-08-12 by @baozhoutao from a multi-org console walkthrough, original grading priority:p1. Batch siblings: objectstack-ai/objectstack#8091 #8092 #8093 #8094 (see that thread).

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 members → Invitations tab → click Copy invitation link.
  4. Paste the clipboard content.

Actual

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

Two defects in one string:

  • trailing-dot host — localhost:8080. (the port is followed by .);
  • the console mount is missing — the console is served under /_console/, and GET /accept-invitation/ (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: <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 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 :. 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 objectui main checkout at filing time.

Activity

  1. self-assigned this
    on Aug 12, 2026
  2. yinlianghui commented on Aug 12, 2026

    @yinlianghui
    Contributor

    CLAIM — session session_017Qqyix2QcnpUC9XeYVDzx3, branch claude/issue-4472-accept-url-mount.

    Ruling: fix as the card proposes — delete BOTH local buildAcceptUrl copies (InvitationsPage.tsx:32, InviteMemberDialog.tsx:39) and route through the existing mount-aware resolveConsoleUrl, the exact failure mode resolveHomeUrl.ts's own header documents as retired. One resolver, one answer: no local URL-building survives in either file. Red-first: pin the copied URL contains no trailing-dot host (:8080.-style) and starts with the console mount — red against the current builder, green through the helper; cover both copy sites (Invitations tab + freshly-created-invitation dialog).

    Grading: patch @object-ui/app-shell (runtime-only; verify emitted .d.ts unmoved).

    Surface (mutual exclusion): packages/app-shell/src/console/organizations/manage/InvitationsPage.tsx + InviteMemberDialog.tsx + tests + one changeset. Disjoint from in-flight #4463 (views/ObjectView), #4473 (apps/console landing), #4431, #4471. Note #4474 (untranslated strings) also touches org/invitation UI and is deliberately NOT dispatched this wave to keep this surface exclusive.


    Generated by Claude Code


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions