Something went wrong. Try again.
a tool for shared writing and social publishing
Something went wrong. Try again.
TypeScript
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576// Hosts that serve the main app rather than a single publication's custom// domain. A publication only owns the root of its hosted domain, so// per-publication root files (sitemap.xml, robots.txt) are only served when the// request arrives on a custom domain — never on the main site.export function isMainSiteHost(hostname: string): boolean { return ( hostname === "leaflet.pub" || hostname.startsWith("localhost") || hostname.startsWith("127.0.0.1") || hostname.endsWith(".vercel.app") );}
export const MAIN_SITE_URL = process.env.NEXT_PUBLIC_APP_URL || "https://leaflet.pub";
// Base URL for auth endpoints that must run on the main site, where the// canonical auth_token cookie lives. Returns "" on the main site (use a relative// path) and the absolute main-site origin from a custom domain, so oauth/email// login always completes first-party there and hands the session back via the// custom domain's receive_auth_callback. Pass the Host header server-side; falls// back to window on the client.export function mainSiteAuthBase(hostname?: string): string { let host = hostname ?? (typeof window !== "undefined" ? window.location.hostname : ""); // Vercel preview hosts serve the main app, but OAuth can't complete on them // (deployment protection blocks the PDS's client-metadata fetch), so their // logins run on the main site and receive the session back through the // cross-site handoff like any other external host. if (!host || (isMainSiteHost(host) && !host.endsWith(".vercel.app"))) return ""; return MAIN_SITE_URL;}
// Single assembly point for the main-site oauth login URL. Encodes every param// through URLSearchParams so call sites can't drift on ad-hoc escaping. `action`// is the already-encoded value from encodeActionToSearchParam. Pass the Host// header server-side; falls back to window on the client (see mainSiteAuthBase).export function buildOauthLoginUrl( params: { handle?: string; redirect?: string; action?: string; link?: boolean; signup?: boolean; autoMerge?: boolean; reauth?: boolean; addAccount?: boolean; }, hostname?: string,): string { let base = mainSiteAuthBase(hostname); let redirect = params.redirect; // Off the main site the OAuth callback completes on MAIN_SITE_URL, where a // relative redirect would resolve — stranding the user there — so anchor it // to the originating host. if (base && redirect && !/^https?:\/\//.test(redirect)) { let origin = hostname ? `https://${hostname}` : typeof window !== "undefined" ? window.location.origin : ""; if (origin) redirect = new URL(redirect, origin).toString(); } let q = new URLSearchParams(); if (params.handle) q.set("handle", params.handle); if (redirect) q.set("redirect_url", redirect); if (params.action) q.set("action", params.action); if (params.link) q.set("link", "true"); if (params.signup) q.set("signup", "true"); if (params.autoMerge) q.set("autoMerge", "true"); if (params.reauth) q.set("reauth", "true"); if (params.addAccount) q.set("addAccount", "true"); return `${base}/api/oauth/login?${q}`;}