diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 208379ef9..8cfba4090 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -36,7 +36,7 @@ jobs: - name: Build canary run: bun run build:canary env: - VITE_PORTAL_GATEWAY_BASE_URL: 'https://m.longbridge.xyz' + VITE_PORTAL_GATEWAY_BASE_URL: 'https://mr.longbridge.xyz' NODE_OPTIONS: --max-old-space-size=12288 --expose-gc - name: Upload to Aliyun OSS diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 97b3577b2..1fe68db51 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,7 +40,7 @@ jobs: - name: Build release run: bun run build:release env: - VITE_PORTAL_GATEWAY_BASE_URL: 'https://m.lbkrs.com' + VITE_PORTAL_GATEWAY_BASE_URL: 'https://mr.lbkrs.com' - name: Deploy to Cloudflare Pages uses: cloudflare/wrangler-action@v3 diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index b305e26a5..7df44a3c5 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -28,11 +28,17 @@ const oneTapProxy = process.env.PROXY === 'canary' ? 'canary' : 'production' const isReleaseBuild = process.env.PROXY !== 'canary' && process.env.NODE_ENV === 'production' const heloraScriptSrc = 'https://assets.lbkrs.com/h5hub/helora-embed/helora-embed-1.0.1.iife.js' +// Resolve `window.__API_PROXY_URL__` at runtime based on cookie `app_id` (US tenants), +// falling back to the build-time env value. Must run before longport-internal.iife.js loads. +// Aligns with docs/.vitepress/theme/utils/app-id.ts (US_APPID_API_HOST). +const apiProxyDefault = JSON.stringify(process.env.VITE_PORTAL_GATEWAY_BASE_URL) +const apiProxyBootstrap = `(function(){var d=document;function c(n){var m=('; '+d.cookie).split('; '+n+'=');return m.length===2?decodeURIComponent(m.pop().split(';').shift()):undefined;}var a=c('app_id')||c('x-original-app-id');var US={longbridge_us:'https://mr.longbridge.com',longbridge_us_uat:'https://mr.longbridge-staging.com'};window.__API_PROXY_URL__=(a&&US[a])||${apiProxyDefault};})();` + const insertScript = (html: string) => { const $ = cheerio.load(html) $('head').prepend( - ``, - `` + ``, + `` ) return $.html() } @@ -211,7 +217,7 @@ export default defineConfig( rewrite: (path) => path.replace(/^\/api/, ''), }, '/lb-api': { - target: process.env.VITE_PORTAL_API_BASE_URL || 'https://m.longbridge.xyz', + target: process.env.VITE_PORTAL_API_BASE_URL || 'https://mr.longbridge.xyz', changeOrigin: true, rewrite: (path) => path.replace(/^\/lb-api/, '/api'), }, diff --git a/docs/.vitepress/theme/utils/app-id.ts b/docs/.vitepress/theme/utils/app-id.ts new file mode 100644 index 000000000..5cf41c796 --- /dev/null +++ b/docs/.vitepress/theme/utils/app-id.ts @@ -0,0 +1,51 @@ +/** + * Runtime tenant detection via cookie `app_id`. + * Aligns with openapi-website-private: + * - packages/utils/src/normalize.ts:11-17 (US_APP_IDS) + * - packages/services/utils.ts:14-17 (APPID_PROXY_OVERRIDE) + */ + +/** + * API host per US tenant environment. + * Values match openapi-website-private/packages/utils/src/constant.ts DomainsMap: + * us-prod.api = 'https://mr.longbridge.com' + * us-staging.api = 'https://mr.longbridge-staging.com' + */ +export const US_APPID_API_HOST: Record = { + longbridge_us: 'https://mr.longbridge.com', + longbridge_us_uat: 'https://mr.longbridge-staging.com', +} + +/** Read a cookie value on the client. Returns undefined on SSR or missing. */ +function readCookie(name: string): string | undefined { + if (typeof document === 'undefined') return undefined + const target = `${name}=` + for (const part of document.cookie.split(';')) { + const trimmed = part.trim() + if (trimmed.startsWith(target)) { + return decodeURIComponent(trimmed.slice(target.length)) + } + } + return undefined +} + +/** Current tenant app_id from cookie (falls back to `x-original-app-id`). */ +export function getAppIdFromCookie(): string | undefined { + return readCookie('app_id') || readCookie('x-original-app-id') +} + +/** Whether the current user is on a US tenant (either prod or UAT). */ +export function isUsAppId(): boolean { + const appId = getAppIdFromCookie() + return !!appId && appId in US_APPID_API_HOST +} + +/** + * Resolve the API host for the current US tenant. + * Returns the matching host for `longbridge_us` (prod) / `longbridge_us_uat` (staging), + * or undefined when the cookie is not a US app_id. + */ +export function resolveUsApiHost(): string | undefined { + const appId = getAppIdFromCookie() + return appId ? US_APPID_API_HOST[appId] : undefined +} diff --git a/docs/.vitepress/theme/utils/navigate.ts b/docs/.vitepress/theme/utils/navigate.ts index 7079a6922..a1b0e871d 100644 --- a/docs/.vitepress/theme/utils/navigate.ts +++ b/docs/.vitepress/theme/utils/navigate.ts @@ -15,5 +15,6 @@ export function createLoginRedirectPath(ssoParams?: Record> ) { - const API_BASE_URL = endsWith(location.hostname, '.xyz') - ? 'https://openapi.longbridge.xyz' - : endsWith(location.hostname, '.cn') - ? 'https://openapi.longbridge.com' - : 'https://openapi.longbridge.com' + // Prefer runtime cookie `app_id`: + // - longbridge_us → https://mr.longbridge.com (US prod) + // - longbridge_us_uat → https://mr.longbridge-staging.com (US staging) + // Fallback to hostname suffix detection. + const usHost = resolveUsApiHost() + const API_BASE_URL = + usHost || + (endsWith(location.hostname, '.xyz') + ? 'https://openapi.longbridge.xyz' + : endsWith(location.hostname, '.cn') + ? 'https://openapi.longbridge.com' + : 'https://openapi.longbridge.com') const config: ApiConfig = { appKey: authConfig.appKey, diff --git a/package.json b/package.json index 5af03f1f2..aee8f6201 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "dev:cn": "cross-env VITE_REGION=cn VITE_API_BASE_URL=https://openapi.longbridge.cn VITE_SITE_HOSTNAME=https://open.longbridge.cn npx vitepress dev docs", "build:canary": "cross-env \"NODE_OPTIONS=--max-old-space-size=12288 --expose-gc\" PROXY=canary VITE_API_BASE_URL=https://openapi.longbridge.xyz npx vitepress build docs && bun run build:llms && bun run build:copy-routes", "build:release": "cross-env \"NODE_OPTIONS=--max-old-space-size=12288 --expose-gc\" VITE_API_BASE_URL=https://openapi.longbridge.com npx vitepress build docs && bun run build:llms && bun run build:copy-routes", - "build:cn": "cross-env \"NODE_OPTIONS=--max-old-space-size=12288 --expose-gc\" VITE_REGION=cn VITE_API_BASE_URL=https://openapi.longbridge.cn VITE_PORTAL_GATEWAY_BASE_URL=https://m.lbkrs.com VITE_SITE_HOSTNAME=https://open.longbridge.cn npx vitepress build docs && cross-env VITE_REGION=cn bun run build:llms && bun run build:copy-routes", + "build:cn": "cross-env \"NODE_OPTIONS=--max-old-space-size=12288 --expose-gc\" VITE_REGION=cn VITE_API_BASE_URL=https://openapi.longbridge.cn VITE_PORTAL_GATEWAY_BASE_URL=https://mr.lbkrs.com VITE_SITE_HOSTNAME=https://open.longbridge.cn npx vitepress build docs && cross-env VITE_REGION=cn bun run build:llms && bun run build:copy-routes", "build:llms": "bun run scripts/normalize_md.ts && bun run scripts/generate-llms.ts", "build:copy-routes": "bun run scripts/copy-routes.ts", "preview": "vitepress preview docs", diff --git a/region.config.ts b/region.config.ts index 3b19c1207..6b461e0e8 100644 --- a/region.config.ts +++ b/region.config.ts @@ -29,7 +29,7 @@ export interface RegionConfig { export const regionConfig: Record = { cn: { apiBaseUrl: 'https://openapi.longbridge.cn', - portalGatewayBaseUrl: 'https://m.lbkrs.com', + portalGatewayBaseUrl: 'https://mr.lbkrs.com', siteHostname: 'https://open.longbridge.cn', mcpHostname: 'https://mcp.longbridge.cn',