mirror of
https://github.com/luxfi/explore.git
synced 2026-07-27 03:13:50 +00:00
feat: multi-brand build matrix + white-label support
Build the same source four ways from one repo:
- ghcr.io/luxfi/explore (lux brand, default)
- ghcr.io/luxfi/explore-hanzo (hanzo brand)
- ghcr.io/luxfi/explore-zoo (zoo brand)
- ghcr.io/luxfi/explore-pars (pars brand)
Each is built for linux/amd64 + linux/arm64 in parallel on hanzo ARC
runners (no QEMU), then merged into a multi-arch manifest.
Brand selection at build time via NEXT_PUBLIC_BRAND, with all
brand-specific assets (logo, favicon, theme, IAM URL) loaded from
NEXT_PUBLIC_* env vars — no hardcoded brand strings in source.
External operators set NEXT_PUBLIC_BRAND=other and supply their own
NEXT_PUBLIC_* env vars (see .env.example.external). The repo carries
no third-party trademarks.
Files:
- lib/white-label.ts brand detection + helpers
- .env.example.{lux,hanzo,zoo,pars,external} deploy templates
- .github/workflows/build-lux.yml 4-brand × 2-arch matrix
- Dockerfile accept NEXT_PUBLIC_BRAND
- configs/app/chainRegistry.ts add SPC + Pars devnet,
chainId fields, white-label
chain builder
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
# External white-label deployment template.
|
||||
#
|
||||
# This file documents the env vars an external operator must set when running
|
||||
# this image with their own brand. The source code is brand-neutral — all
|
||||
# strings below are operator-supplied at deploy time.
|
||||
#
|
||||
# Copy and customize for your deployment:
|
||||
# cp .env.example.external .env.local
|
||||
#
|
||||
# Replace every <PLACEHOLDER> with your own values. NEVER commit a populated
|
||||
# version of this file with third-party trademarks back to this repo.
|
||||
|
||||
NEXT_PUBLIC_BRAND=other
|
||||
|
||||
# Network
|
||||
NEXT_PUBLIC_NETWORK_NAME=<Your Network Name>
|
||||
NEXT_PUBLIC_NETWORK_SHORT_NAME=<SYMBOL>
|
||||
NEXT_PUBLIC_NETWORK_ID=<chain-id-uint64>
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=<Token Name>
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=<TOKEN>
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
|
||||
NEXT_PUBLIC_NETWORK_RPC_URL=https://<your-rpc-host>/rpc
|
||||
|
||||
# API
|
||||
NEXT_PUBLIC_API_HOST=<your-api-host>
|
||||
NEXT_PUBLIC_API_PROTOCOL=https
|
||||
NEXT_PUBLIC_API_BASE_PATH=/
|
||||
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=wss
|
||||
|
||||
# App
|
||||
NEXT_PUBLIC_APP_HOST=<your-explorer-host>
|
||||
NEXT_PUBLIC_APP_PROTOCOL=https
|
||||
NEXT_PUBLIC_IS_TESTNET=false
|
||||
|
||||
# Branding (operator-supplied)
|
||||
NEXT_PUBLIC_NETWORK_ORG_NAME=<Your Org>
|
||||
NEXT_PUBLIC_NETWORK_WEBSITE_URL=https://<your-domain>
|
||||
NEXT_PUBLIC_NETWORK_DESCRIPTION=<one-line description>
|
||||
NEXT_PUBLIC_NETWORK_GITHUB_URL=
|
||||
NEXT_PUBLIC_NETWORK_TWITTER_URL=
|
||||
NEXT_PUBLIC_NETWORK_DISCORD_URL=
|
||||
|
||||
# Auth (IAM) — operator-supplied OIDC provider
|
||||
NEXT_PUBLIC_ACCOUNT_AUTH_PROVIDER=oidc
|
||||
NEXT_PUBLIC_OIDC_SERVER_URL=<https://your-iam-host>
|
||||
NEXT_PUBLIC_OIDC_CLIENT_ID=<your-client-id>
|
||||
|
||||
# Theme
|
||||
NEXT_PUBLIC_COLOR_THEME_DEFAULT=dark
|
||||
@@ -0,0 +1,39 @@
|
||||
# Hanzo Explorer — Hanzo AI brand.
|
||||
# Use: cp .env.example.hanzo .env.local && pnpm build
|
||||
|
||||
NEXT_PUBLIC_BRAND=hanzo
|
||||
|
||||
# Network (Hanzo subnet on Lux mainnet)
|
||||
NEXT_PUBLIC_NETWORK_NAME=Hanzo AI
|
||||
NEXT_PUBLIC_NETWORK_SHORT_NAME=HANZO
|
||||
NEXT_PUBLIC_NETWORK_ID=36963
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=HANZO
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=HANZO
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
|
||||
|
||||
# API
|
||||
NEXT_PUBLIC_API_HOST=api-explore-hanzo.lux.network
|
||||
NEXT_PUBLIC_API_PROTOCOL=https
|
||||
NEXT_PUBLIC_API_BASE_PATH=/
|
||||
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=wss
|
||||
|
||||
# App
|
||||
NEXT_PUBLIC_APP_HOST=explore.hanzo.ai
|
||||
NEXT_PUBLIC_APP_PROTOCOL=https
|
||||
NEXT_PUBLIC_IS_TESTNET=false
|
||||
|
||||
# Branding
|
||||
NEXT_PUBLIC_NETWORK_ORG_NAME=Hanzo Industries Inc.
|
||||
NEXT_PUBLIC_NETWORK_WEBSITE_URL=https://hanzo.ai
|
||||
NEXT_PUBLIC_NETWORK_DESCRIPTION=AI blockchain — decentralized compute and inference.
|
||||
NEXT_PUBLIC_NETWORK_GITHUB_URL=https://github.com/hanzoai
|
||||
NEXT_PUBLIC_NETWORK_TWITTER_URL=https://x.com/hanaboratory
|
||||
NEXT_PUBLIC_NETWORK_DISCORD_URL=https://discord.gg/hanzoai
|
||||
|
||||
# Auth (IAM)
|
||||
NEXT_PUBLIC_ACCOUNT_AUTH_PROVIDER=oidc
|
||||
NEXT_PUBLIC_OIDC_SERVER_URL=https://hanzo.id
|
||||
NEXT_PUBLIC_OIDC_CLIENT_ID=hanzo-explore-client-id
|
||||
|
||||
# Theme
|
||||
NEXT_PUBLIC_COLOR_THEME_DEFAULT=dark
|
||||
@@ -0,0 +1,40 @@
|
||||
# Lux Explorer — default brand.
|
||||
# `pnpm build` with no NEXT_PUBLIC_BRAND override produces a Lux-branded site.
|
||||
|
||||
NEXT_PUBLIC_BRAND=lux
|
||||
|
||||
# Network
|
||||
NEXT_PUBLIC_NETWORK_NAME=Lux Network
|
||||
NEXT_PUBLIC_NETWORK_SHORT_NAME=LUX
|
||||
NEXT_PUBLIC_NETWORK_ID=96369
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=LUX
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=LUX
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
|
||||
NEXT_PUBLIC_NETWORK_RPC_URL=https://api.lux.network/ext/bc/C/rpc
|
||||
|
||||
# API
|
||||
NEXT_PUBLIC_API_HOST=api-explore.lux.network
|
||||
NEXT_PUBLIC_API_PROTOCOL=https
|
||||
NEXT_PUBLIC_API_BASE_PATH=/
|
||||
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=wss
|
||||
|
||||
# App
|
||||
NEXT_PUBLIC_APP_HOST=explore.lux.network
|
||||
NEXT_PUBLIC_APP_PROTOCOL=https
|
||||
NEXT_PUBLIC_IS_TESTNET=false
|
||||
|
||||
# Branding
|
||||
NEXT_PUBLIC_NETWORK_ORG_NAME=Lux Industries Inc.
|
||||
NEXT_PUBLIC_NETWORK_WEBSITE_URL=https://lux.network
|
||||
NEXT_PUBLIC_NETWORK_DESCRIPTION=High-performance blockchain for decentralized applications.
|
||||
NEXT_PUBLIC_NETWORK_GITHUB_URL=https://github.com/luxfi
|
||||
NEXT_PUBLIC_NETWORK_TWITTER_URL=https://x.com/luxdefi
|
||||
NEXT_PUBLIC_NETWORK_DISCORD_URL=https://discord.gg/luxnetwork
|
||||
|
||||
# Auth (IAM)
|
||||
NEXT_PUBLIC_ACCOUNT_AUTH_PROVIDER=oidc
|
||||
NEXT_PUBLIC_OIDC_SERVER_URL=https://lux.id
|
||||
NEXT_PUBLIC_OIDC_CLIENT_ID=lux-explore-client-id
|
||||
|
||||
# Theme
|
||||
NEXT_PUBLIC_COLOR_THEME_DEFAULT=dark
|
||||
@@ -0,0 +1,39 @@
|
||||
# Pars Explorer — Parsis Foundation brand.
|
||||
# Use: cp .env.example.pars .env.local && pnpm build
|
||||
|
||||
NEXT_PUBLIC_BRAND=pars
|
||||
|
||||
# Network (Pars subnet on Lux mainnet)
|
||||
NEXT_PUBLIC_NETWORK_NAME=Pars Network
|
||||
NEXT_PUBLIC_NETWORK_SHORT_NAME=PARS
|
||||
NEXT_PUBLIC_NETWORK_ID=494949
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=PARS
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=PARS
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
|
||||
|
||||
# API
|
||||
NEXT_PUBLIC_API_HOST=api-explore-pars.lux.network
|
||||
NEXT_PUBLIC_API_PROTOCOL=https
|
||||
NEXT_PUBLIC_API_BASE_PATH=/
|
||||
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=wss
|
||||
|
||||
# App
|
||||
NEXT_PUBLIC_APP_HOST=explore.pars.network
|
||||
NEXT_PUBLIC_APP_PROTOCOL=https
|
||||
NEXT_PUBLIC_IS_TESTNET=false
|
||||
|
||||
# Branding
|
||||
NEXT_PUBLIC_NETWORK_ORG_NAME=Parsis Foundation
|
||||
NEXT_PUBLIC_NETWORK_WEBSITE_URL=https://pars.network
|
||||
NEXT_PUBLIC_NETWORK_DESCRIPTION=Pars blockchain — financial infrastructure for the Persian-speaking world.
|
||||
NEXT_PUBLIC_NETWORK_GITHUB_URL=https://github.com/luxfi
|
||||
NEXT_PUBLIC_NETWORK_TWITTER_URL=https://x.com/parsnetwork
|
||||
NEXT_PUBLIC_NETWORK_DISCORD_URL=https://discord.gg/luxnetwork
|
||||
|
||||
# Auth (IAM)
|
||||
NEXT_PUBLIC_ACCOUNT_AUTH_PROVIDER=oidc
|
||||
NEXT_PUBLIC_OIDC_SERVER_URL=https://pars.id
|
||||
NEXT_PUBLIC_OIDC_CLIENT_ID=pars-explore-client-id
|
||||
|
||||
# Theme
|
||||
NEXT_PUBLIC_COLOR_THEME_DEFAULT=dark
|
||||
@@ -0,0 +1,39 @@
|
||||
# Zoo Explorer — Zoo Labs Foundation brand.
|
||||
# Use: cp .env.example.zoo .env.local && pnpm build
|
||||
|
||||
NEXT_PUBLIC_BRAND=zoo
|
||||
|
||||
# Network (Zoo subnet on Lux mainnet)
|
||||
NEXT_PUBLIC_NETWORK_NAME=Zoo Chain
|
||||
NEXT_PUBLIC_NETWORK_SHORT_NAME=ZOO
|
||||
NEXT_PUBLIC_NETWORK_ID=200200
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=ZOO
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ZOO
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
|
||||
|
||||
# API
|
||||
NEXT_PUBLIC_API_HOST=api-explore-zoo.lux.network
|
||||
NEXT_PUBLIC_API_PROTOCOL=https
|
||||
NEXT_PUBLIC_API_BASE_PATH=/
|
||||
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=wss
|
||||
|
||||
# App
|
||||
NEXT_PUBLIC_APP_HOST=explore.zoo.ngo
|
||||
NEXT_PUBLIC_APP_PROTOCOL=https
|
||||
NEXT_PUBLIC_IS_TESTNET=false
|
||||
|
||||
# Branding
|
||||
NEXT_PUBLIC_NETWORK_ORG_NAME=Zoo Labs Foundation
|
||||
NEXT_PUBLIC_NETWORK_WEBSITE_URL=https://zoo.ngo
|
||||
NEXT_PUBLIC_NETWORK_DESCRIPTION=Open AI research network — decentralized AI and science.
|
||||
NEXT_PUBLIC_NETWORK_GITHUB_URL=https://github.com/zooai
|
||||
NEXT_PUBLIC_NETWORK_TWITTER_URL=https://x.com/zoolabs
|
||||
NEXT_PUBLIC_NETWORK_DISCORD_URL=https://discord.gg/zoolabs
|
||||
|
||||
# Auth (IAM)
|
||||
NEXT_PUBLIC_ACCOUNT_AUTH_PROVIDER=oidc
|
||||
NEXT_PUBLIC_OIDC_SERVER_URL=https://zoo.id
|
||||
NEXT_PUBLIC_OIDC_CLIENT_ID=zoo-explore-client-id
|
||||
|
||||
# Theme
|
||||
NEXT_PUBLIC_COLOR_THEME_DEFAULT=dark
|
||||
@@ -21,14 +21,28 @@ concurrency:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: luxfi/explore
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: hanzo-build-linux-amd64
|
||||
name: Build ${{ matrix.brand }} (${{ matrix.arch }})
|
||||
runs-on: hanzo-build-linux-${{ matrix.arch }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
brand: [ lux, hanzo, zoo, pars ]
|
||||
arch: [ amd64, arm64 ]
|
||||
include:
|
||||
- brand: lux
|
||||
image: luxfi/explore
|
||||
- brand: hanzo
|
||||
image: luxfi/explore-hanzo
|
||||
- brand: zoo
|
||||
image: luxfi/explore-zoo
|
||||
- brand: pars
|
||||
image: luxfi/explore-pars
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -47,32 +61,78 @@ jobs:
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
images: ${{ env.REGISTRY }}/${{ matrix.image }}
|
||||
flavor: |
|
||||
latest=false
|
||||
tags: |
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
type=ref,event=branch
|
||||
type=semver,pattern={{version}}
|
||||
type=raw,value=latest-${{ matrix.arch }},enable={{is_default_branch}}
|
||||
type=ref,event=branch,suffix=-${{ matrix.arch }}
|
||||
type=semver,pattern={{version}},suffix=-${{ matrix.arch }}
|
||||
|
||||
- name: Build and push image
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
cache-from: type=gha,scope=${{ matrix.brand }}-${{ matrix.arch }}
|
||||
cache-to: type=gha,mode=max,scope=${{ matrix.brand }}-${{ matrix.arch }}
|
||||
provenance: false
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
GIT_TAG=${{ github.ref_type == 'tag' && github.ref_name || '' }}
|
||||
NEXT_PUBLIC_BRAND=${{ matrix.brand }}
|
||||
|
||||
manifest:
|
||||
name: Multi-arch manifest (${{ matrix.brand }})
|
||||
needs: build
|
||||
if: github.event_name != 'pull_request'
|
||||
runs-on: hanzo-build-linux-amd64
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- brand: lux
|
||||
image: luxfi/explore
|
||||
- brand: hanzo
|
||||
image: luxfi/explore-hanzo
|
||||
- brand: zoo
|
||||
image: luxfi/explore-zoo
|
||||
- brand: pars
|
||||
image: luxfi/explore-pars
|
||||
steps:
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create and push manifest (latest)
|
||||
if: github.ref == 'refs/heads/main'
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t ${{ env.REGISTRY }}/${{ matrix.image }}:latest \
|
||||
${{ env.REGISTRY }}/${{ matrix.image }}:latest-amd64 \
|
||||
${{ env.REGISTRY }}/${{ matrix.image }}:latest-arm64
|
||||
|
||||
- name: Create and push manifest (tag)
|
||||
if: github.ref_type == 'tag'
|
||||
run: |
|
||||
TAG="${GITHUB_REF_NAME#v}"
|
||||
docker buildx imagetools create \
|
||||
-t ${{ env.REGISTRY }}/${{ matrix.image }}:${TAG} \
|
||||
${{ env.REGISTRY }}/${{ matrix.image }}:${TAG}-amd64 \
|
||||
${{ env.REGISTRY }}/${{ matrix.image }}:${TAG}-arm64
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
needs: manifest
|
||||
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
|
||||
runs-on: hanzo-deploy-linux-amd64
|
||||
permissions:
|
||||
|
||||
@@ -56,6 +56,9 @@ ARG GIT_TAG
|
||||
ENV NEXT_PUBLIC_GIT_TAG=$GIT_TAG
|
||||
ARG NEXT_OPEN_TELEMETRY_ENABLED
|
||||
ENV NEXT_OPEN_TELEMETRY_ENABLED=$NEXT_OPEN_TELEMETRY_ENABLED
|
||||
# White-label brand selector (lux | hanzo | zoo | pars | other). Defaults to lux.
|
||||
ARG NEXT_PUBLIC_BRAND=lux
|
||||
ENV NEXT_PUBLIC_BRAND=$NEXT_PUBLIC_BRAND
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV NODE_OPTIONS="--max-old-space-size=8192"
|
||||
|
||||
@@ -39,6 +39,9 @@ export interface ChainEntry {
|
||||
readonly label: string;
|
||||
readonly vm: string;
|
||||
readonly network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
|
||||
|
||||
/** EVM chain ID (uint64). Canonical values tracked in MEMORY.md. */
|
||||
readonly chainId: number;
|
||||
readonly hostnames: ReadonlyArray<string>;
|
||||
readonly explorerUrl: string;
|
||||
readonly apiUrl: string;
|
||||
@@ -220,6 +223,7 @@ export const CHAINS: ReadonlyArray<ChainEntry> = [
|
||||
label: 'Contract Chain',
|
||||
vm: 'EVM',
|
||||
network: 'mainnet',
|
||||
chainId: 96369,
|
||||
// explore.lux.build is a legacy alias — the runtime ingress 301-redirects
|
||||
// it to explore.lux.network, so we only register the canonical host here.
|
||||
hostnames: [ 'explore.lux.network', 'localhost', '127.0.0.1', '0.0.0.0' ],
|
||||
@@ -232,6 +236,7 @@ export const CHAINS: ReadonlyArray<ChainEntry> = [
|
||||
label: 'Zoo Chain',
|
||||
vm: 'L2',
|
||||
network: 'mainnet',
|
||||
chainId: 200200,
|
||||
hostnames: [ 'explore-zoo.lux.network', 'explore.zoo.network', 'explore.zoo.ngo' ],
|
||||
explorerUrl: 'https://explore-zoo.lux.network',
|
||||
apiUrl: 'https://api-explore-zoo.lux.network',
|
||||
@@ -242,6 +247,7 @@ export const CHAINS: ReadonlyArray<ChainEntry> = [
|
||||
label: 'Hanzo AI',
|
||||
vm: 'L2',
|
||||
network: 'mainnet',
|
||||
chainId: 36963,
|
||||
hostnames: [ 'explore-hanzo.lux.network', 'explore.hanzo.network', 'explore.hanzo.ai' ],
|
||||
explorerUrl: 'https://explore-hanzo.lux.network',
|
||||
apiUrl: 'https://api-explore-hanzo.lux.network',
|
||||
@@ -252,6 +258,7 @@ export const CHAINS: ReadonlyArray<ChainEntry> = [
|
||||
label: 'SPC Chain',
|
||||
vm: 'L2',
|
||||
network: 'mainnet',
|
||||
chainId: 36911,
|
||||
hostnames: [ 'explore-spc.lux.network' ],
|
||||
explorerUrl: 'https://explore-spc.lux.network',
|
||||
apiUrl: 'https://api-explore-spc.lux.network',
|
||||
@@ -262,6 +269,7 @@ export const CHAINS: ReadonlyArray<ChainEntry> = [
|
||||
label: 'Pars Network',
|
||||
vm: 'L2',
|
||||
network: 'mainnet',
|
||||
chainId: 494949,
|
||||
hostnames: [ 'explore-pars.lux.network', 'explore.pars.network' ],
|
||||
explorerUrl: 'https://explore-pars.lux.network',
|
||||
apiUrl: 'https://api-explore-pars.lux.network',
|
||||
@@ -273,22 +281,112 @@ export const CHAINS: ReadonlyArray<ChainEntry> = [
|
||||
label: 'Contract Chain',
|
||||
vm: 'EVM',
|
||||
network: 'testnet',
|
||||
chainId: 96368,
|
||||
hostnames: [ 'explore-test.lux.network', 'explore.lux-test.network' ],
|
||||
explorerUrl: 'https://explore-test.lux.network',
|
||||
apiUrl: 'https://api-explore-test.lux.network',
|
||||
branding: LUX_BRANDING,
|
||||
},
|
||||
{
|
||||
name: 'Zoo',
|
||||
label: 'Zoo Chain (Testnet)',
|
||||
vm: 'L2',
|
||||
network: 'testnet',
|
||||
chainId: 200201,
|
||||
hostnames: [ 'explore-zoo-test.lux.network' ],
|
||||
explorerUrl: 'https://explore-zoo-test.lux.network',
|
||||
apiUrl: 'https://api-explore-zoo-test.lux.network',
|
||||
branding: ZOO_BRANDING,
|
||||
},
|
||||
{
|
||||
name: 'Hanzo',
|
||||
label: 'Hanzo AI (Testnet)',
|
||||
vm: 'L2',
|
||||
network: 'testnet',
|
||||
chainId: 36964,
|
||||
hostnames: [ 'explore-hanzo-test.lux.network' ],
|
||||
explorerUrl: 'https://explore-hanzo-test.lux.network',
|
||||
apiUrl: 'https://api-explore-hanzo-test.lux.network',
|
||||
branding: HANZO_BRANDING,
|
||||
},
|
||||
{
|
||||
name: 'SPC',
|
||||
label: 'SPC Chain (Testnet)',
|
||||
vm: 'L2',
|
||||
network: 'testnet',
|
||||
chainId: 36910,
|
||||
hostnames: [ 'explore-spc-test.lux.network' ],
|
||||
explorerUrl: 'https://explore-spc-test.lux.network',
|
||||
apiUrl: 'https://api-explore-spc-test.lux.network',
|
||||
branding: SPC_BRANDING,
|
||||
},
|
||||
{
|
||||
name: 'Pars',
|
||||
label: 'Pars Network (Testnet)',
|
||||
vm: 'L2',
|
||||
network: 'testnet',
|
||||
chainId: 7071,
|
||||
hostnames: [ 'explore-pars-test.lux.network' ],
|
||||
explorerUrl: 'https://explore-pars-test.lux.network',
|
||||
apiUrl: 'https://api-explore-pars-test.lux.network',
|
||||
branding: PARS_BRANDING,
|
||||
},
|
||||
// Devnet chains
|
||||
{
|
||||
name: 'C-Chain',
|
||||
label: 'Contract Chain',
|
||||
vm: 'EVM',
|
||||
network: 'devnet',
|
||||
chainId: 96370,
|
||||
hostnames: [ 'explore-dev.lux.network', 'explore.lux-dev.network' ],
|
||||
explorerUrl: 'https://explore-dev.lux.network',
|
||||
apiUrl: 'https://api-explore-dev.lux.network',
|
||||
branding: LUX_BRANDING,
|
||||
},
|
||||
{
|
||||
name: 'Zoo',
|
||||
label: 'Zoo Chain (Devnet)',
|
||||
vm: 'L2',
|
||||
network: 'devnet',
|
||||
chainId: 200202,
|
||||
hostnames: [ 'explore-zoo-dev.lux.network' ],
|
||||
explorerUrl: 'https://explore-zoo-dev.lux.network',
|
||||
apiUrl: 'https://api-explore-zoo-dev.lux.network',
|
||||
branding: ZOO_BRANDING,
|
||||
},
|
||||
{
|
||||
name: 'Hanzo',
|
||||
label: 'Hanzo AI (Devnet)',
|
||||
vm: 'L2',
|
||||
network: 'devnet',
|
||||
chainId: 36964,
|
||||
hostnames: [ 'explore-hanzo-dev.lux.network' ],
|
||||
explorerUrl: 'https://explore-hanzo-dev.lux.network',
|
||||
apiUrl: 'https://api-explore-hanzo-dev.lux.network',
|
||||
branding: HANZO_BRANDING,
|
||||
},
|
||||
{
|
||||
name: 'SPC',
|
||||
label: 'SPC Chain (Devnet)',
|
||||
vm: 'L2',
|
||||
network: 'devnet',
|
||||
chainId: 36912,
|
||||
hostnames: [ 'explore-spc-dev.lux.network' ],
|
||||
explorerUrl: 'https://explore-spc-dev.lux.network',
|
||||
apiUrl: 'https://api-explore-spc-dev.lux.network',
|
||||
branding: SPC_BRANDING,
|
||||
},
|
||||
{
|
||||
name: 'Pars',
|
||||
label: 'Pars Network (Devnet)',
|
||||
vm: 'L2',
|
||||
network: 'devnet',
|
||||
chainId: 494951,
|
||||
hostnames: [ 'explore-pars-dev.lux.network' ],
|
||||
explorerUrl: 'https://explore-pars-dev.lux.network',
|
||||
apiUrl: 'https://api-explore-pars-dev.lux.network',
|
||||
branding: PARS_BRANDING,
|
||||
},
|
||||
|
||||
// Localnet — chainId 1337. Listing localhost / 127.0.0.1 / 0.0.0.0 here
|
||||
// keeps isWhiteLabelMode() false in local dev so the chain + network
|
||||
@@ -298,6 +396,7 @@ export const CHAINS: ReadonlyArray<ChainEntry> = [
|
||||
label: 'Contract Chain',
|
||||
vm: 'EVM',
|
||||
network: 'localnet',
|
||||
chainId: 1337,
|
||||
hostnames: [ 'explore.localnet', 'explore-local.lux.network' ],
|
||||
explorerUrl: 'http://localhost:3000',
|
||||
apiUrl: 'http://localhost:4000',
|
||||
@@ -368,6 +467,7 @@ function buildWhiteLabelChain(hostname: string): ChainEntry {
|
||||
label: branding.brandName,
|
||||
vm: 'EVM',
|
||||
network: (getEnvValue('NEXT_PUBLIC_IS_TESTNET') === 'true' ? 'testnet' : 'mainnet') as 'mainnet' | 'testnet' | 'devnet' | 'localnet',
|
||||
chainId: Number(getEnvValue('NEXT_PUBLIC_NETWORK_ID')) || 0,
|
||||
hostnames: [ hostname ],
|
||||
explorerUrl: `${ protocol }://${ appHost }`,
|
||||
apiUrl: apiHost ? `${ apiProtocol }://${ apiHost }` : '',
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// White-label brand detection.
|
||||
//
|
||||
// Source code in this repo is brand-neutral. Brand selection happens at
|
||||
// deploy time via `NEXT_PUBLIC_BRAND` env var or by hostname inspection.
|
||||
// All brand-specific assets (logo, title, favicon, color theme, IAM URL)
|
||||
// load from `NEXT_PUBLIC_*` env vars — no hardcoded brand strings here.
|
||||
//
|
||||
// Supported brands:
|
||||
// - lux (default)
|
||||
// - hanzo
|
||||
// - zoo
|
||||
// - pars
|
||||
// - other (any external white-label deploy: branding from env vars)
|
||||
//
|
||||
// External deployments select their brand by setting NEXT_PUBLIC_BRAND in
|
||||
// the runtime environment. They do NOT add their brand here — keeping this
|
||||
// repo free of any third-party trademarks.
|
||||
|
||||
import { getEnvValue } from 'configs/app/utils';
|
||||
|
||||
export type WhiteLabelBrand = 'lux' | 'hanzo' | 'zoo' | 'pars' | 'other';
|
||||
|
||||
const BRAND_HOSTNAME_SUFFIXES: ReadonlyArray<{ readonly suffix: string; readonly brand: WhiteLabelBrand }> = [
|
||||
{ suffix: '.lux.network', brand: 'lux' },
|
||||
{ suffix: '.lux.build', brand: 'lux' },
|
||||
{ suffix: '.hanzo.ai', brand: 'hanzo' },
|
||||
{ suffix: '.hanzo.network', brand: 'hanzo' },
|
||||
{ suffix: '.zoo.ngo', brand: 'zoo' },
|
||||
{ suffix: '.zoo.network', brand: 'zoo' },
|
||||
{ suffix: '.pars.network', brand: 'pars' },
|
||||
];
|
||||
|
||||
export function getWhiteLabelBrand(hostname?: string): WhiteLabelBrand {
|
||||
// 1. Explicit env var wins (CI/CD, k8s ConfigMap)
|
||||
const envBrand = getEnvValue('NEXT_PUBLIC_BRAND');
|
||||
if (envBrand) {
|
||||
const normalized = envBrand.toLowerCase();
|
||||
if (
|
||||
normalized === 'lux' ||
|
||||
normalized === 'hanzo' ||
|
||||
normalized === 'zoo' ||
|
||||
normalized === 'pars' ||
|
||||
normalized === 'other'
|
||||
) {
|
||||
return normalized;
|
||||
}
|
||||
// Any unknown brand string → 'other' (env-driven white-label)
|
||||
return 'other';
|
||||
}
|
||||
|
||||
// 2. Hostname-based detection
|
||||
const host = (hostname || (typeof window !== 'undefined' ? window.location.hostname : '')).toLowerCase();
|
||||
if (host) {
|
||||
for (const entry of BRAND_HOSTNAME_SUFFIXES) {
|
||||
if (host === entry.suffix.slice(1) || host.endsWith(entry.suffix)) {
|
||||
return entry.brand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Default
|
||||
return 'lux';
|
||||
}
|
||||
|
||||
export function isWhiteLabelExternal(brand: WhiteLabelBrand): boolean {
|
||||
return brand === 'other';
|
||||
}
|
||||
Reference in New Issue
Block a user