Files
zeekayandHanzo Dev 6ef181e5d5 fix(wallet): stop shipping a placeholder Reown project id
hanzo.vote served a bundle containing projectId:"dummy-project-id" — the
`|| 'dummy-project-id'` fallback in web3-modal.config.ts. Reown rejects an
unknown project id, so api.web3modal.com/getWallets, /getWalletImage and
pulse.walletconnect.org all answered 403 and "Connect Wallet" — the primary
action of the app — could never populate its wallet list.

This is not an origin-allowlist problem: api.web3modal.com returns
access-control-allow-origin:* and answers 200 for a valid project id sent
with `Origin: https://hanzo.vote`. The id itself was never configured, and
could not have been: the Dockerfile never passed
VITE_APP_WALLET_CONNECT_PROJECT_ID, and Vite inlines it at build time, so a
value provisioned only at runtime can never reach the bundle.

- Drop the placeholder. Absent stays absent, and the WalletConnect connector
  is left unregistered rather than fabricated, so the app degrades to
  injected/EIP-6963/Coinbase wallets instead of emitting doomed 403 traffic.
  createWeb3Modal stays unconditional because useWeb3Modal() throws from its
  hook body when the modal was never created.
- Plumb VITE_APP_WALLET_CONNECT_PROJECT_ID through Dockerfile ARG and CI
  build-args so a provisioned secret actually lands in the bundle.
- Pass VITE_APP_SITE_URL=https://hanzo.vote. It fell through to the .env dev
  default, so production advertised http://localhost:3000 as both the
  WalletConnect dapp origin and og:url.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-26 11:26:31 -07:00

49 lines
2.4 KiB
Docker

# Hanzo Vote — Vite SPA build, served static via hanzoai/spa.
#
# vite build -> dist/ (SPA). Runtime serves it on :3000 via
# ghcr.io/hanzoai/spa (the canonical Hanzo static server, same image used by
# hanzo.id + hanzo.exchange). The wrangler page-function build mode
# (vite build --mode page-function) is for Cloudflare Pages Functions and
# is NOT used in the k8s deploy.
#
# base MUST be '/' (root domain hanzo.vote), so GITHUB_ACTIONS must be UNSET
# at build time — vite.config.mts rewrites base to '/vote/' when it is set,
# and that prefix is only correct for the github.io project-pages URL.
# ─── Build stage ─────────────────────────────────────────────────────
FROM node:24-alpine AS build
RUN apk add --no-cache git python3 make g++
WORKDIR /app
# Manifest first for layer caching. `npm install` (not `ci`): the committed
# lock predates adding `wrangler` (a required peer of
# @torchauth/vite-plugin-wrangler-spa), so `npm ci`'s strict-sync check would
# refuse; install resolves from package.json and updates the tree.
# --legacy-peer-deps: @torchauth/vite-plugin-wrangler-spa@2 declares a too-tight
# peer range wrangler@^3, but the app pins (and runs on) wrangler@^4.
COPY package.json package-lock.json* ./
RUN npm install --no-audit --no-fund --legacy-peer-deps
# Source + SPA build. .git is not in the build context, so the git hash
# is injected explicitly instead of via `git rev-parse`.
COPY . .
ARG GIT_HASH=docker
# Vite inlines these at BUILD time (import.meta.env in the bundle, %VITE_*% in
# index.html), so anything supplied only as a runtime container env is invisible
# to the shipped assets — they must be passed here. Both defaulted wrong before:
# no project id reached the bundle at all, and VITE_APP_SITE_URL fell through to
# the .env dev default, so production served og:url=http://localhost:3000 and
# advertised localhost as the WalletConnect dapp origin.
ARG VITE_APP_WALLET_CONNECT_PROJECT_ID=""
ARG VITE_APP_SITE_URL="https://hanzo.vote"
RUN NODE_OPTIONS=--max-old-space-size=8192 VITE_APP_GIT_HASH="${GIT_HASH}" \
VITE_APP_WALLET_CONNECT_PROJECT_ID="${VITE_APP_WALLET_CONNECT_PROJECT_ID}" \
VITE_APP_SITE_URL="${VITE_APP_SITE_URL}" \
npx vite build
# ─── Runtime: static SPA via hanzoai/spa (serves /public on :3000) ────
FROM ghcr.io/hanzoai/spa:1.4.8
COPY --from=build /app/dist /public