|
|
|
@@ -1,5 +1,21 @@
|
|
|
|
|
// White-label branding configuration
|
|
|
|
|
// Configure via environment variables for different deployments
|
|
|
|
|
// White-label branding — runtime-resolved, brand-neutral source.
|
|
|
|
|
//
|
|
|
|
|
// This module knows ONE brand: bootnode's own neutral defaults (the built-in
|
|
|
|
|
// fallback). Every real brand (lux / zoo / pars / hanzo / …) is supplied at
|
|
|
|
|
// RUNTIME from an external catalog injected per-deploy — bootnode the app ships
|
|
|
|
|
// no brand names, domains, or links in source.
|
|
|
|
|
//
|
|
|
|
|
// Mechanism (mirrors the @hanzo/id SPA's runtime config loader):
|
|
|
|
|
// 1. The deploy serves `/config.json` and/or injects a `window.__BRAND_CATALOG__`
|
|
|
|
|
// global (a host->BrandConfig map, or a string of one) into the page.
|
|
|
|
|
// 2. `applyBrandCatalog()` ingests it; `getBrandKey()` resolves the active
|
|
|
|
|
// brand by `window.location.hostname` against the catalog.
|
|
|
|
|
// 3. `getBrand()` returns the resolved BrandConfig, falling back to the
|
|
|
|
|
// built-in neutral `bootnode` defaults when no catalog entry matches.
|
|
|
|
|
//
|
|
|
|
|
// The full multi-brand catalog lives in the DEPLOY config (universe / CF-Pages),
|
|
|
|
|
// NOT in this repo. See `public/config.json` for the contract + the README note
|
|
|
|
|
// in the PR for where the per-host catalog is provisioned.
|
|
|
|
|
|
|
|
|
|
export type BrandConfig = {
|
|
|
|
|
name: string
|
|
|
|
@@ -45,265 +61,138 @@ export type BrandConfig = {
|
|
|
|
|
}[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Brand presets
|
|
|
|
|
const brands: Record<string, BrandConfig> = {
|
|
|
|
|
bootnode: {
|
|
|
|
|
name: "Bootnode",
|
|
|
|
|
tagline: "Blockchain Infrastructure for Developers",
|
|
|
|
|
description: "The complete blockchain development platform. Multi-chain RPC, Token APIs, NFT APIs, Smart Wallets, Webhooks, and more.",
|
|
|
|
|
logo: "/logo/bootnode-logo.svg",
|
|
|
|
|
logoIcon: "/logo/bootnode-icon.svg",
|
|
|
|
|
logoWhite: "/logo/bootnode-logo-white.svg",
|
|
|
|
|
favicon: "/logo/bootnode-icon.svg",
|
|
|
|
|
domain: "bootno.de",
|
|
|
|
|
apiUrl: "https://api.bootno.de",
|
|
|
|
|
wsUrl: "wss://ws.bootno.de",
|
|
|
|
|
statusUrl: "https://status.bootno.de",
|
|
|
|
|
defaultTheme: "light",
|
|
|
|
|
colors: {
|
|
|
|
|
primary: "#000000",
|
|
|
|
|
primaryForeground: "#ffffff",
|
|
|
|
|
accent: "#3b82f6", // blue-500
|
|
|
|
|
accentEnd: "#06b6d4", // cyan-500
|
|
|
|
|
},
|
|
|
|
|
social: {
|
|
|
|
|
twitter: "https://twitter.com/bootnode",
|
|
|
|
|
github: "https://github.com/bootnode",
|
|
|
|
|
},
|
|
|
|
|
iam: {
|
|
|
|
|
url: "https://hanzo.id",
|
|
|
|
|
clientId: "bootnode-platform",
|
|
|
|
|
domain: "hanzo.id",
|
|
|
|
|
},
|
|
|
|
|
footerLinks: [
|
|
|
|
|
{ name: "GitHub", href: "https://github.com/bootnode", external: true },
|
|
|
|
|
{ name: "Twitter", href: "https://twitter.com/bootnode", external: true },
|
|
|
|
|
],
|
|
|
|
|
ecosystemApps: [],
|
|
|
|
|
},
|
|
|
|
|
hanzo: {
|
|
|
|
|
name: "Hanzo Web3",
|
|
|
|
|
tagline: "Enterprise Blockchain Infrastructure",
|
|
|
|
|
description: "Enterprise blockchain infrastructure powered by Hanzo AI. Multi-chain RPC, Token APIs, NFT APIs, Smart Wallets, and more.",
|
|
|
|
|
logo: "/logo/hanzo-logo.svg",
|
|
|
|
|
logoIcon: "/logo/hanzo-icon.svg",
|
|
|
|
|
logoWhite: "/logo/hanzo-logo-white.svg",
|
|
|
|
|
favicon: "/logo/hanzo-icon.svg",
|
|
|
|
|
domain: "web3.hanzo.ai",
|
|
|
|
|
apiUrl: "https://api.cloud.hanzo.ai",
|
|
|
|
|
wsUrl: "wss://ws.cloud.hanzo.ai",
|
|
|
|
|
statusUrl: "https://status.hanzo.ai",
|
|
|
|
|
defaultTheme: "dark",
|
|
|
|
|
colors: {
|
|
|
|
|
primary: "#fd4444",
|
|
|
|
|
primaryForeground: "#ffffff",
|
|
|
|
|
accent: "#fd4444", // hanzo red
|
|
|
|
|
accentEnd: "#ff6b6b", // lighter red
|
|
|
|
|
},
|
|
|
|
|
social: {
|
|
|
|
|
twitter: "https://twitter.com/hanaboratory",
|
|
|
|
|
github: "https://github.com/hanzoai",
|
|
|
|
|
discord: "https://discord.gg/hanzo",
|
|
|
|
|
},
|
|
|
|
|
iam: {
|
|
|
|
|
url: "https://hanzo.id",
|
|
|
|
|
clientId: "hanzo-web3",
|
|
|
|
|
domain: "hanzo.id",
|
|
|
|
|
},
|
|
|
|
|
footerLinks: [
|
|
|
|
|
{ name: "Hanzo AI", href: "https://hanzo.ai", external: true },
|
|
|
|
|
{ name: "Hanzo Cloud", href: "https://cloud.hanzo.ai", external: true },
|
|
|
|
|
{ name: "Hanzo Chat", href: "https://chat.hanzo.ai", external: true },
|
|
|
|
|
{ name: "Hanzo Network", href: "https://hanzo.network", external: true },
|
|
|
|
|
{ name: "GitHub", href: "https://github.com/hanzoai", external: true },
|
|
|
|
|
],
|
|
|
|
|
ecosystemApps: [
|
|
|
|
|
{ name: "Hanzo Chat", href: "https://chat.hanzo.ai", description: "AI chat with 100+ models", icon: "MessageSquare", category: "tools" },
|
|
|
|
|
{ name: "Hanzo Console", href: "https://console.hanzo.ai", description: "LLM observability & evaluation", icon: "BarChart3", category: "tools" },
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
lux: {
|
|
|
|
|
name: "Lux Cloud",
|
|
|
|
|
tagline: "Next-Gen Blockchain Infrastructure",
|
|
|
|
|
description: "High-performance blockchain infrastructure for the Lux Network ecosystem.",
|
|
|
|
|
logo: "/logo/lux-wordmark-dark.svg",
|
|
|
|
|
logoIcon: "/logo/lux-icon.svg",
|
|
|
|
|
logoWhite: "/logo/lux-wordmark-white.svg",
|
|
|
|
|
favicon: "/logo/lux-icon.svg",
|
|
|
|
|
domain: "cloud.lux.network",
|
|
|
|
|
apiUrl: "https://api.cloud.lux.network",
|
|
|
|
|
wsUrl: "wss://ws.cloud.lux.network",
|
|
|
|
|
statusUrl: "https://status.lux.network",
|
|
|
|
|
defaultTheme: "dark",
|
|
|
|
|
colors: {
|
|
|
|
|
primary: "#ffffff",
|
|
|
|
|
primaryForeground: "#000000",
|
|
|
|
|
accent: "#a8a8a8", // monochrome silver
|
|
|
|
|
accentEnd: "#ffffff", // white
|
|
|
|
|
},
|
|
|
|
|
social: {
|
|
|
|
|
twitter: "https://twitter.com/luxdefi",
|
|
|
|
|
github: "https://github.com/luxfi",
|
|
|
|
|
},
|
|
|
|
|
iam: {
|
|
|
|
|
url: "https://lux.id",
|
|
|
|
|
clientId: "lux-cloud",
|
|
|
|
|
domain: "lux.id",
|
|
|
|
|
},
|
|
|
|
|
footerLinks: [
|
|
|
|
|
{ name: "Lux Network", href: "https://lux.network", external: true },
|
|
|
|
|
{ name: "Lux Explorer", href: "https://explore.lux.network", external: true },
|
|
|
|
|
{ name: "Lux Bridge", href: "https://bridge.lux.network", external: true },
|
|
|
|
|
{ name: "Lux Wallet", href: "https://wallet.lux.network", external: true },
|
|
|
|
|
{ name: "Lux Exchange", href: "https://exchange.lux.network", external: true },
|
|
|
|
|
{ name: "GitHub", href: "https://github.com/luxfi", external: true },
|
|
|
|
|
],
|
|
|
|
|
ecosystemApps: [
|
|
|
|
|
{ name: "Explorer", href: "https://explore.lux.network", description: "Block explorer for all Lux chains", icon: "Search", category: "explore" },
|
|
|
|
|
{ name: "Bridge", href: "https://bridge.lux.network", description: "Cross-chain asset bridge", icon: "ArrowLeftRight", category: "defi" },
|
|
|
|
|
{ name: "Exchange", href: "https://exchange.lux.network", description: "Decentralized exchange (DEX)", icon: "ArrowUpDown", category: "defi" },
|
|
|
|
|
{ name: "Markets", href: "https://markets.lux.network", description: "NFT marketplace", icon: "ShoppingBag", category: "defi" },
|
|
|
|
|
{ name: "Wallet", href: "https://wallet.lux.network", description: "Multi-chain wallet", icon: "Wallet", category: "tools" },
|
|
|
|
|
{ name: "Safe", href: "https://safe.lux.network", description: "Multisig wallet (FROST)", icon: "Shield", category: "tools" },
|
|
|
|
|
{ name: "Faucet", href: "https://faucet.lux.network", description: "Testnet token faucet", icon: "Droplets", category: "tools" },
|
|
|
|
|
{ name: "Staking", href: "https://stake.lux.network", description: "Validator staking", icon: "Coins", category: "defi" },
|
|
|
|
|
{ name: "Governance", href: "https://vote.lux.network", description: "On-chain governance", icon: "Vote", category: "governance" },
|
|
|
|
|
{ name: "Status", href: "https://status.lux.network", description: "Network status & uptime", icon: "Activity", category: "explore" },
|
|
|
|
|
{ name: "Lux Build", href: "https://lux.build", description: "Developer portal & docs", icon: "Code", category: "tools" },
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
pars: {
|
|
|
|
|
name: "Pars Cloud",
|
|
|
|
|
tagline: "Sovereign L1 Infrastructure",
|
|
|
|
|
description: "Sovereign L1 blockchain infrastructure for the Pars Network. Post-quantum secure, SessionVM messaging, native DEX, and more.",
|
|
|
|
|
logo: "/logo/pars-logo.svg",
|
|
|
|
|
logoIcon: "/logo/pars-icon.svg",
|
|
|
|
|
logoWhite: "/logo/pars-logo-white.svg",
|
|
|
|
|
favicon: "/logo/pars-icon.svg",
|
|
|
|
|
domain: "cloud.pars.network",
|
|
|
|
|
apiUrl: "https://api.cloud.pars.network",
|
|
|
|
|
wsUrl: "wss://ws.cloud.pars.network",
|
|
|
|
|
statusUrl: "https://status.pars.network",
|
|
|
|
|
defaultTheme: "dark",
|
|
|
|
|
colors: {
|
|
|
|
|
primary: "#00abff",
|
|
|
|
|
primaryForeground: "#ffffff",
|
|
|
|
|
accent: "#00abff", // persian blue
|
|
|
|
|
accentEnd: "#F59E0B", // gold accent
|
|
|
|
|
},
|
|
|
|
|
social: {
|
|
|
|
|
twitter: "https://twitter.com/parsnetwork",
|
|
|
|
|
github: "https://github.com/pars-network",
|
|
|
|
|
},
|
|
|
|
|
iam: {
|
|
|
|
|
url: "https://pars.id",
|
|
|
|
|
clientId: "pars-app-client-id",
|
|
|
|
|
domain: "pars.id",
|
|
|
|
|
},
|
|
|
|
|
footerLinks: [
|
|
|
|
|
{ name: "Pars Network", href: "https://pars.network", external: true },
|
|
|
|
|
{ name: "Pars Explorer", href: "https://explore.pars.network", external: true },
|
|
|
|
|
{ name: "Pars Wallet", href: "https://wallet.pars.network", external: true },
|
|
|
|
|
{ name: "SessionVM", href: "https://session.pars.network", external: true },
|
|
|
|
|
{ name: "GitHub", href: "https://github.com/pars-network", external: true },
|
|
|
|
|
],
|
|
|
|
|
ecosystemApps: [
|
|
|
|
|
{ name: "Explorer", href: "https://explore.pars.network", description: "Pars block explorer", icon: "Search", category: "explore" },
|
|
|
|
|
{ name: "Wallet", href: "https://wallet.pars.network", description: "Pars wallet", icon: "Wallet", category: "tools" },
|
|
|
|
|
{ name: "SessionVM", href: "https://session.pars.network", description: "Private messaging VM", icon: "MessageCircle", category: "tools" },
|
|
|
|
|
{ name: "Faucet", href: "https://faucet.pars.network", description: "Testnet tokens", icon: "Droplets", category: "tools" },
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
zoo: {
|
|
|
|
|
name: "Zoo Labs",
|
|
|
|
|
tagline: "Decentralized AI Infrastructure",
|
|
|
|
|
description: "Blockchain infrastructure for decentralized AI and science research.",
|
|
|
|
|
logo: "/logo/zoo-logo.svg",
|
|
|
|
|
logoIcon: "/logo/zoo-icon.svg",
|
|
|
|
|
logoWhite: "/logo/zoo-logo-white.svg",
|
|
|
|
|
favicon: "/logo/zoo-icon.svg",
|
|
|
|
|
domain: "web3.zoo.ngo",
|
|
|
|
|
apiUrl: "https://api.web3.zoo.ngo",
|
|
|
|
|
wsUrl: "wss://ws.web3.zoo.ngo",
|
|
|
|
|
statusUrl: "https://status.zoo.ngo",
|
|
|
|
|
defaultTheme: "dark",
|
|
|
|
|
colors: {
|
|
|
|
|
primary: "#00cc66",
|
|
|
|
|
primaryForeground: "#ffffff",
|
|
|
|
|
accent: "#00cc66", // emerald green
|
|
|
|
|
accentEnd: "#10b981", // lighter green
|
|
|
|
|
},
|
|
|
|
|
social: {
|
|
|
|
|
twitter: "https://twitter.com/zoolabs",
|
|
|
|
|
github: "https://github.com/zoolabs",
|
|
|
|
|
},
|
|
|
|
|
iam: {
|
|
|
|
|
url: "https://zoolabs.id",
|
|
|
|
|
clientId: "zoo-app-client-id",
|
|
|
|
|
domain: "zoolabs.id",
|
|
|
|
|
},
|
|
|
|
|
footerLinks: [
|
|
|
|
|
{ name: "Zoo Labs", href: "https://zoo.ngo", external: true },
|
|
|
|
|
{ name: "Zoo AI Chat", href: "https://ai.zoo.ngo", external: true },
|
|
|
|
|
{ name: "Zoo Network", href: "https://zoo.network", external: true },
|
|
|
|
|
{ name: "Zen LM", href: "https://zenlm.ai", external: true },
|
|
|
|
|
{ name: "GitHub", href: "https://github.com/zooai", external: true },
|
|
|
|
|
],
|
|
|
|
|
ecosystemApps: [
|
|
|
|
|
{ name: "Zoo AI Chat", href: "https://ai.zoo.ngo", description: "Decentralized AI chat", icon: "Bot", category: "tools" },
|
|
|
|
|
{ name: "Zen LM", href: "https://zenlm.ai", description: "Open frontier models", icon: "Brain", category: "tools" },
|
|
|
|
|
{ name: "Explorer", href: "https://explore.zoo.ngo", description: "Zoo chain explorer", icon: "Search", category: "explore" },
|
|
|
|
|
{ name: "Faucet", href: "https://faucet.zoo.ngo", description: "Testnet tokens", icon: "Droplets", category: "tools" },
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
// Runtime catalog: host substring -> brand key, plus key -> BrandConfig.
|
|
|
|
|
// Both are empty in source. Populated at runtime by `applyBrandCatalog()` from
|
|
|
|
|
// the deploy-injected config (see public/config.json for the shape).
|
|
|
|
|
export type BrandCatalog = {
|
|
|
|
|
// Ordered host matchers. First whose `match` is a substring of the hostname wins.
|
|
|
|
|
hosts?: { match: string; key: string }[]
|
|
|
|
|
// Brand definitions, keyed by brand key (e.g. "lux", "zoo").
|
|
|
|
|
brands?: Record<string, BrandConfig>
|
|
|
|
|
// Default brand key for unknown hosts (defaults to "bootnode").
|
|
|
|
|
defaultKey?: string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get brand from domain auto-detection or environment fallback
|
|
|
|
|
// The ONE built-in brand: bootnode's neutral defaults. Used for dev, SSG, and
|
|
|
|
|
// any host with no catalog entry. Intentionally generic — no third-party brand.
|
|
|
|
|
const BOOTNODE_DEFAULT: BrandConfig = {
|
|
|
|
|
name: "Bootnode",
|
|
|
|
|
tagline: "Blockchain Infrastructure for Developers",
|
|
|
|
|
description:
|
|
|
|
|
"The complete blockchain development platform. Multi-chain RPC, Token APIs, NFT APIs, Smart Wallets, Webhooks, and more.",
|
|
|
|
|
logo: "/logo.svg",
|
|
|
|
|
logoIcon: "/logo.svg",
|
|
|
|
|
logoWhite: "/logo.svg",
|
|
|
|
|
favicon: "/logo.svg",
|
|
|
|
|
domain: "bootno.de",
|
|
|
|
|
apiUrl: "https://api.bootno.de",
|
|
|
|
|
wsUrl: "wss://ws.bootno.de",
|
|
|
|
|
statusUrl: "https://status.bootno.de",
|
|
|
|
|
defaultTheme: "light",
|
|
|
|
|
colors: {
|
|
|
|
|
primary: "#000000",
|
|
|
|
|
primaryForeground: "#ffffff",
|
|
|
|
|
accent: "#3b82f6",
|
|
|
|
|
accentEnd: "#06b6d4",
|
|
|
|
|
},
|
|
|
|
|
social: {},
|
|
|
|
|
iam: {
|
|
|
|
|
url: "https://hanzo.id",
|
|
|
|
|
clientId: "bootnode-web",
|
|
|
|
|
domain: "hanzo.id",
|
|
|
|
|
},
|
|
|
|
|
footerLinks: [],
|
|
|
|
|
ecosystemApps: [],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const DEFAULT_KEY = "bootnode"
|
|
|
|
|
|
|
|
|
|
// Active runtime catalog. Starts empty (source ships no brands). The deploy
|
|
|
|
|
// fills it via `applyBrandCatalog()` before/at hydration.
|
|
|
|
|
let catalog: BrandCatalog = {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parse a raw catalog value (object or JSON string) into a BrandCatalog.
|
|
|
|
|
* Returns {} on any error — never throws (mirrors id SPA's `parseCatalog`).
|
|
|
|
|
*/
|
|
|
|
|
export function parseBrandCatalog(raw: unknown): BrandCatalog {
|
|
|
|
|
if (!raw) return {}
|
|
|
|
|
try {
|
|
|
|
|
const obj = typeof raw === "string" ? JSON.parse(raw) : raw
|
|
|
|
|
if (!obj || typeof obj !== "object") return {}
|
|
|
|
|
return obj as BrandCatalog
|
|
|
|
|
} catch {
|
|
|
|
|
return {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Install the runtime brand catalog. Idempotent — safe to call repeatedly
|
|
|
|
|
* (e.g. once from the inline boot script, once after the /config.json fetch).
|
|
|
|
|
* Accepts either a parsed object or a raw JSON string.
|
|
|
|
|
*/
|
|
|
|
|
export function applyBrandCatalog(raw: unknown): void {
|
|
|
|
|
const next = parseBrandCatalog(raw)
|
|
|
|
|
if (Object.keys(next).length > 0) catalog = next
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read the catalog injected as a global by the deploy
|
|
|
|
|
* (`window.__BRAND_CATALOG__`). Synchronous — available before the first
|
|
|
|
|
* render when the deploy inlines it in the document head.
|
|
|
|
|
*/
|
|
|
|
|
function readInjectedCatalog(): BrandCatalog {
|
|
|
|
|
if (typeof window === "undefined") return {}
|
|
|
|
|
const w = window as unknown as { __BRAND_CATALOG__?: unknown }
|
|
|
|
|
return parseBrandCatalog(w.__BRAND_CATALOG__)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function activeCatalog(): BrandCatalog {
|
|
|
|
|
if (catalog.brands || catalog.hosts) return catalog
|
|
|
|
|
return readInjectedCatalog()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resolve the active brand key from the hostname against the runtime catalog.
|
|
|
|
|
* No hardcoded host switches — the host->key table is data, supplied at deploy.
|
|
|
|
|
*/
|
|
|
|
|
function getBrandKey(): string {
|
|
|
|
|
// Client-side: detect from domain (highest priority)
|
|
|
|
|
if (typeof window !== "undefined") {
|
|
|
|
|
const hostname = window.location.hostname
|
|
|
|
|
if (hostname.includes("lux.cloud") || hostname.includes("lux.network")) return "lux"
|
|
|
|
|
if (hostname.includes("pars.network") || hostname.includes("pars.id")) return "pars"
|
|
|
|
|
if (hostname.includes("zoo.ngo") || hostname.includes("zoo.network") || hostname.includes("zoo.cloud")) return "zoo"
|
|
|
|
|
if (hostname.includes("hanzo.ai")) return "hanzo"
|
|
|
|
|
if (hostname.includes("bootno.de") || hostname.includes("bootnode.io")) return "bootnode"
|
|
|
|
|
const cat = activeCatalog()
|
|
|
|
|
const fallback = cat.defaultKey || DEFAULT_KEY
|
|
|
|
|
if (typeof window === "undefined") return fallback
|
|
|
|
|
const hostname = window.location.hostname.toLowerCase()
|
|
|
|
|
for (const rule of cat.hosts ?? []) {
|
|
|
|
|
if (rule.match && hostname.includes(rule.match.toLowerCase())) return rule.key
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Server-side: BRAND env var (runtime, not baked by Next.js unlike NEXT_PUBLIC_*)
|
|
|
|
|
const runtimeBrand = process.env.BRAND?.toLowerCase()
|
|
|
|
|
if (runtimeBrand && brands[runtimeBrand]) {
|
|
|
|
|
return runtimeBrand
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fall back to build-time NEXT_PUBLIC_BRAND
|
|
|
|
|
const envBrand = process.env.NEXT_PUBLIC_BRAND?.toLowerCase()
|
|
|
|
|
if (envBrand && brands[envBrand]) {
|
|
|
|
|
return envBrand
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "bootnode"
|
|
|
|
|
return fallback
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Export the active brand configuration
|
|
|
|
|
// Export the active brand configuration. Synchronous so module-level callers
|
|
|
|
|
// (`const brand = getBrand()`) keep working; resolves against the injected
|
|
|
|
|
// catalog when present, else the built-in neutral default.
|
|
|
|
|
export function getBrand(): BrandConfig {
|
|
|
|
|
return brands[getBrandKey()]
|
|
|
|
|
const cat = activeCatalog()
|
|
|
|
|
const key = getBrandKey()
|
|
|
|
|
return cat.brands?.[key] ?? cat.brands?.[DEFAULT_KEY] ?? BOOTNODE_DEFAULT
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Export brand key for conditional rendering
|
|
|
|
|
// Export brand key for conditional rendering / per-brand local maps
|
|
|
|
|
// (SDK package names, region data, localStorage namespacing).
|
|
|
|
|
export function getBrandKey_(): string {
|
|
|
|
|
return getBrandKey()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if using Hanzo branding
|
|
|
|
|
// Check if the active brand is the Hanzo brand.
|
|
|
|
|
export function isHanzoBrand(): boolean {
|
|
|
|
|
return getBrandKey() === "hanzo"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get all available brands (for admin/testing)
|
|
|
|
|
// Get all brands currently known at runtime (for admin/testing). Empty until a
|
|
|
|
|
// catalog is injected — source ships no brands.
|
|
|
|
|
export function getAllBrands(): Record<string, BrandConfig> {
|
|
|
|
|
return brands
|
|
|
|
|
return activeCatalog().brands ?? { [DEFAULT_KEY]: BOOTNODE_DEFAULT }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Default export for convenience
|
|
|
|
|
// Default export for convenience (neutral default at module-eval / SSG time;
|
|
|
|
|
// the BrandProvider re-resolves client-side once the runtime catalog loads).
|
|
|
|
|
export const brand = getBrand()
|
|
|
|
|