Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3c36643
feat(grid-wallet-prod): add vitest + gridUnits (USDB<->cents)
pengying Jul 23, 2026
1b73eab
feat(grid-wallet-prod): browser gridCrypto (TEK/HPKE/stamp) + scripts…
pengying Jul 23, 2026
89efd82
feat(grid-wallet-prod): Grid proxy route + allow-list + gridFetch client
pengying Jul 23, 2026
dcc5f0a
feat(grid-wallet-prod): webhook receiver + P-256 signature verification
pengying Jul 23, 2026
f6acb99
feat(grid-wallet-prod): client gridSession (EMAIL_OTP + passkey regis…
pengying Jul 23, 2026
91d9e3f
feat(grid-wallet-prod): live passkey/OTP sign-in wired to panel
pengying Jul 23, 2026
cad4d5f
fix(grid-wallet-prod): OTP sheet cancel during live passkey bootstrap
pengying Jul 23, 2026
f41c232
feat(grid-wallet-prod): live balance + activity reads on sign-in
pengying Jul 23, 2026
7a52eb9
feat(grid-wallet-prod): add money via sandbox fund + balance refresh
pengying Jul 23, 2026
eb07bde
feat(grid-wallet-prod): phone displays real balance; fund error handling
pengying Jul 24, 2026
d00a79a
fix(grid-wallet-prod): balance reconcile races (double-count, concurr…
pengying Jul 24, 2026
5ea179f
fix(grid-wallet-prod): roll back optimistic add on fund failure
pengying Jul 24, 2026
02989b5
fix(grid-wallet-prod): proportional per-add settle on success and fai…
pengying Jul 24, 2026
5028f0e
feat(grid-wallet-prod): outbound quote/stamp/execute/poll to COMPLETED
pengying Jul 24, 2026
76326dd
fix(grid-wallet-prod): add money via real platform on-ramp (sandbox f…
pengying Jul 24, 2026
a3669ae
fix(grid-wallet-prod): gate completion checkmarks on transaction COMP…
pengying Jul 24, 2026
9a60d4a
fix(grid-wallet-prod): panel shows only real traffic for money flows;…
pengying Jul 24, 2026
eabc9c5
feat(grid-wallet-prod): email-OTP-first sign-in, real funding flows, …
pengying Jul 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions components/grid-wallet-prod/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Build context hygiene — anything here is either rebuilt in the image, secret,
# or irrelevant to the server bundle.
node_modules
.next
.git
.cursor
.playwright-mcp

# Secrets never belong in an image layer; pass them at `docker run` with
# --env-file / -e instead.
.env
.env.local
.env*.local

# Local scratch + verification artefacts.
scripts/.tmp-*
*.png
tsconfig.tsbuildinfo
npm-debug.log*
.DS_Store
56 changes: 56 additions & 0 deletions components/grid-wallet-prod/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Grid wallet production demo — Next 14 standalone server.
#
# docker build -t grid-wallet-prod .
# docker run --rm -p 4001:4001 --env-file .env.local grid-wallet-prod
#
# Then http://localhost:4001, and the webhook receiver at /api/webhooks
# (point ngrok or your platform's webhook config at that path).
#
# NOTE ON ENV: NEXT_PUBLIC_* is INLINED AT BUILD TIME, so the sandbox flag is a
# build arg, not a runtime var — a production image must be built WITHOUT it, or
# it will still offer the "simulate funding" affordance. Everything else
# (GRID_CLIENT_ID / GRID_CLIENT_SECRET / GRID_API_BASE_URL / GRID_CUSTOMER_ID /
# GRID_WEBHOOK_PUBKEY) is read per request and belongs at `docker run` time.

# ── deps ──────────────────────────────────────────────────────────────────────
FROM node:22-alpine AS deps
WORKDIR /app
# Playwright is a devDependency used only by the verification scripts; its
# postinstall would otherwise pull ~400MB of browsers into the build.
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
COPY package.json package-lock.json ./
RUN npm ci

# ── build ─────────────────────────────────────────────────────────────────────
FROM node:22-alpine AS builder
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED=1
# Sandbox keys? Pass --build-arg NEXT_PUBLIC_GRID_SANDBOX=true to bake in the
# simulated-funding button. Omit for a production build.
ARG NEXT_PUBLIC_GRID_SANDBOX
ENV NEXT_PUBLIC_GRID_SANDBOX=$NEXT_PUBLIC_GRID_SANDBOX
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# ── run ───────────────────────────────────────────────────────────────────────
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production \
NEXT_TELEMETRY_DISABLED=1 \
PORT=4001 \
HOSTNAME=0.0.0.0
# Unprivileged: nothing here needs root.
RUN addgroup -g 1001 -S nodejs && adduser -S -u 1001 -G nodejs nextjs
# `standalone` traces in only the server files actually reached, and ships its
# own minimal node_modules; static assets and public/ are copied alongside it.
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
USER nextjs
EXPOSE 4001
# The SSE webhook stream is long-lived; give the container a plain HTTP check
# that doesn't hold a connection open.
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s \
CMD node -e "fetch('http://127.0.0.1:'+(process.env.PORT||4001)+'/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
CMD ["node", "server.js"]
7 changes: 7 additions & 0 deletions components/grid-wallet-prod/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ Differences from the demo:
npm install --ignore-scripts # --ignore-scripts avoids a central-icons license postinstall
npm run dev # http://localhost:4001 (grid-wallet-demo keeps 4000)
```

Sandbox "Add money" runs the real platform on-ramp (fund the platform's USD account, then
quote + execute platform -> your embedded wallet) — a direct sandbox fund of the wallet itself
only mints book balance with no on-chain USDB. Any fee Grid's on-ramp charges comes straight out
of the real quote (observed anywhere from $0 to ~$0.20 on a $5-$20 add across sandbox runs), so
the balance credit can land at or slightly under the amount you added — that's real fee behavior,
not a bug.
13 changes: 10 additions & 3 deletions components/grid-wallet-prod/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));

/** @type {import('next').NextConfig} */
const nextConfig = {
// Self-contained server bundle (.next/standalone) — what the Docker runtime
// stage copies, so the image carries no node_modules of its own.
output: 'standalone',
transpilePackages: ['@lightsparkdev/origin'],
typescript: {
// Origin is source-linked without its own node_modules,
Expand Down Expand Up @@ -33,11 +36,15 @@ const nextConfig = {
];
},
webpack: (config) => {
// Ensure dependencies imported by the local Origin package
// resolve from this project's node_modules
// Ensure dependencies imported by the local Origin package resolve from
// this project's node_modules. The relative 'node_modules' entry comes
// FIRST so webpack's default nested walk-up still wins (e.g. @turnkey/crypto's
// own node_modules/@noble/* pin, which differs from this project's top-level
// @noble/* version and exports different subpaths) — the absolute path is
// only a fallback for imports with no node_modules to walk up from.
config.resolve.modules = [
path.resolve(__dirname, 'node_modules'),
'node_modules',
path.resolve(__dirname, 'node_modules'),
];

// Origin only exports its main barrel — narrow imports for tree-shaken components.
Expand Down
Loading
Loading