export const PRODUCTION_HOST = "https://dench.com"; export const STAGING_HOST = "https://staging.dench.com"; export const LOCAL_HOST = "http://localhost:3000"; export const DEFAULT_HOST = PRODUCTION_HOST; /** * Production-only fallbacks baked into the CLI binary so it does the * right thing even when run with no config and no env vars (e.g. in a * sandbox whose `buildSandboxEnvVars` map was assembled while the * Vercel deployment was missing one of these keys). * * If any of these is wrong, EVERY install of @dench.com/cli is broken * until republished — keep them in sync with whichever Convex * deployment + Next.js host backs `https://www.dench.com`. */ export const PRODUCTION_API_URL = "https://www.dench.com"; export const PRODUCTION_CONVEX_URL = "https://beaming-alligator-67.convex.cloud"; export const PRODUCTION_GATEWAY_URL = "https://gateway.merseoriginals.com"; export type BackendAlias = "production" | "prod" | "staging" | "local"; function optionFromArgs(args: string[], name: string) { const index = args.indexOf(name); if (index === -1) return undefined; return args[index + 1]; } function hasFlag(args: string[], name: string) { return args.includes(name); } export function normalizeHost(input: string) { const trimmed = input.trim(); if (/^(localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])(?::|$)/.test(trimmed)) { return new URL(`http://${trimmed}`).origin; } const withProtocol = /^https?:\/\//.test(trimmed) ? trimmed : `https://${trimmed}`; const url = new URL(withProtocol); return url.origin; } export function isLocalHost(input: string) { const hostname = new URL(normalizeHost(input)).hostname; return ( hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1" || hostname.endsWith(".localhost") ); } export function apiHostForDenchHost(input: string | undefined) { if (!input?.trim()) return PRODUCTION_API_URL; const normalized = normalizeHost(input); // `dench.com` redirects to `www.dench.com` in production. Fetch drops the // Authorization header across that redirect, so CLI API calls must start on // the canonical API origin. if (normalized === PRODUCTION_HOST) return PRODUCTION_API_URL; return normalized; } /** * Resolve `local|staging|prod|production|` -> a normalized host * origin. Aliases let `dench backend set ` (and `--backend * `) accept the short forms most agents reach for first. * Returns `undefined` for empty input and throws on values that * neither match an alias nor parse as a URL. */ export function resolveBackendAlias(input: string): string { const value = input.trim(); if (!value) { throw new Error( "Backend value is empty. Pass local, staging, prod, or a URL like https://dench.com.", ); } const normalized = value.toLowerCase(); if (normalized === "prod" || normalized === "production") { return PRODUCTION_HOST; } if (normalized === "staging" || normalized === "stage") { return STAGING_HOST; } if ( normalized === "local" || normalized === "localhost" || normalized === "dev" ) { return LOCAL_HOST; } try { return normalizeHost(value); } catch (_error) { throw new Error( `Unrecognized backend "${value}". Use local, staging, prod, or a URL like https://dench.com.`, ); } } export function resolveHostFromArgs( args: string[], configHost?: string, envHost = process.env.DENCH_HOST, ) { if (hasFlag(args, "--prod")) return PRODUCTION_HOST; if (hasFlag(args, "--staging")) return STAGING_HOST; const explicitBackend = optionFromArgs(args, "--backend"); if (explicitBackend) return resolveBackendAlias(explicitBackend); const explicit = optionFromArgs(args, "--host") ?? envHost; if (explicit) return normalizeHost(explicit); if (configHost) return normalizeHost(configHost); return DEFAULT_HOST; }