Resolves the slug against the tenant catalog and forwards into the integration detail page's existing add-connection flow. Unknown slugs get a not-found state. Makes the link survive sign-in: reserve connect as an org slug so cloud's callback stops reading it as an org selector, and return self-host's login to the requested path (its gate swaps the page in without ever writing a returnTo).
Showing the changes to packages/core/api/src (2 of 17 files). Show all
Unified · Split
| @@ -57,7 +57,20 @@ describe("isValidOrgSlug", () => { · 56 unmodified lines | |||
| 57 | }); | 57 | }); |
| 58 | 58 | ||
| 59 | it("reserves the segments routing depends on", () => { | 59 | it("reserves the segments routing depends on", () => { |
| 60 | for (const critical of ["api", "mcp", "integrations", "policies", "login", "cdn-cgi"]) { | 60 | for (const critical of [ |
| 61 | "api", | ||
| 62 | "mcp", | ||
| 63 | "integrations", | ||
| 64 | "policies", | ||
| 65 | "login", | ||
| 66 | "cdn-cgi", | ||
| 67 | // The connect deep link's root. Cloud's post-auth callback reads the | ||
| 68 | // first path segment as an org selector, so leaving `connect` claimable | ||
| 69 | // made `/connect/<slug>` look like a request for an org named "connect" | ||
| 70 | // — which suppressed the active-membership fallback and could drop the | ||
| 71 | // deep link into org onboarding after sign-in. | ||
| 72 | "connect", | ||
| 73 | ]) { | ||
| 61 | expect(RESERVED_ORG_SLUGS.has(critical), critical).toBe(true); | 74 | expect(RESERVED_ORG_SLUGS.has(critical), critical).toBe(true); |
| 62 | } | 75 | } |
| 63 | }); | 76 | }); |
| @@ -17,8 +17,8 @@ const ORG_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9])){1,47}$/; · 16 unmodified lines | |||
| 17 | * predictably will): | 17 | * predictably will): |
| 18 | * - App planes: api, mcp, .well-known (cloud `app-paths.ts`, selfhost | 18 | * - App planes: api, mcp, .well-known (cloud `app-paths.ts`, selfhost |
| 19 | * envelope, cloudflare `run_worker_first`) | 19 | * envelope, cloudflare `run_worker_first`) |
| 20 | * - Console routes: integrations, policies, secrets, tools, resume, | 20 | * - Console routes: connect, integrations, policies, secrets, tools, |
| 21 | * plugins (the shared contract), plus host extras: | 21 | * resume, plugins (the shared contract), plus host extras: |
| 22 | * api-keys, org, billing, create-org, setup-mcp (cloud), | 22 | * api-keys, org, billing, create-org, setup-mcp (cloud), |
| 23 | * admin, join, docs (selfhost), login (Better Auth | 23 | * admin, join, docs (selfhost), login (Better Auth |
| 24 | * `mcp({ loginPage })` + cloud/selfhost login UX) | 24 | * `mcp({ loginPage })` + cloud/selfhost login UX) |
| @@ -41,6 +41,7 @@ export const RESERVED_ORG_SLUGS: ReadonlySet<string> = new Set([ · 16 unmodified lines | |||
| 41 | "mcp", | 41 | "mcp", |
| 42 | ".well-known", | 42 | ".well-known", |
| 43 | // console + host routes | 43 | // console + host routes |
| 44 | "connect", | ||
| 44 | "integrations", | 45 | "integrations", |
| 45 | "policies", | 46 | "policies", |
| 46 | "secrets", | 47 | "secrets", |