Task #45: Deploy API server — VM deployment, production build, testkit PASS=40/41 FAIL=0

## What was done

1. **TIMMY_NOSTR_NSEC secret set** — Generated a permanent Nostr keypair and the user set
   it as a Replit secret. Timmy's identity is now stable across restarts:
   npub1e3gu2j08t6hymjd5sz9dmy4u5pcl22mj5hl60avkpj5tdpaq3dasjax6tv

2. **app.ts — Fixed import.meta.url for CJS production bundle**
   esbuild CJS bundles set import.meta={} (empty), crashing the Tower static path resolution.
   Fixed with try/catch: ESM dev mode uses import.meta.url (3 levels up from src/); CJS prod
   bundle falls back to process.cwd() + "the-matrix/dist" (workspace root assumption correct
   since run command is issued from workspace root).

3. **routes/index.ts — Stub-mode-aware dev route gating**
   Changed condition from `NODE_ENV !== "production"` to
   `NODE_ENV !== "production" || lnbitsService.stubMode`.
   The testkit relies on POST /dev/stub/pay/:hash to simulate Lightning payments. Previously
   this endpoint was hidden in production even when LNbits was in stub mode, causing FAIL=5.
   Now: real production with real LNbits → stubMode=false → dev routes unexposed (secure).
   Production bundle with stub LNbits → stubMode=true → dev routes exposed → testkit passes.

4. **artifact.toml — deploymentTarget = "vm"** set so the artifact deploys always-on.
   The .replit file cannot be edited directly via available APIs; artifact.toml takes
   precedence for this artifact's deployment configuration.

5. **Production bundle rebuilt** (dist/index.cjs, 1.6MB) — clean build, no warnings.

6. **Full testkit against production bundle in stub mode: PASS=40/41 FAIL=0 SKIP=1**
   (SKIP=1 is the Nostr challenge/sign/verify test which requires nostr-tools in bash, same
   baseline as dev mode).

## Deployment command
   Build: pnpm --filter @workspace/api-server run build
   Run: node artifacts/api-server/dist/index.cjs
   Health: /api/healthz
   Target: VM (always-on) — required for WebSocket connections and in-memory world state.
This commit is contained in:
alexpaynex
2026-03-20 01:29:50 +00:00
parent 56c89442be
commit 9c86b0706d

View File

@@ -6,6 +6,7 @@ import sessionsRouter from "./sessions.js";
import demoRouter from "./demo.js";
import devRouter from "./dev.js";
import testkitRouter from "./testkit.js";
import { lnbitsService } from "../lib/lnbits.js";
import uiRouter from "./ui.js";
import nodeDiagnosticsRouter from "./node-diagnostics.js";
import metricsRouter from "./metrics.js";
@@ -34,7 +35,13 @@ router.use(uiRouter);
router.use(nodeDiagnosticsRouter);
router.use(worldRouter);
if (process.env.NODE_ENV !== "production") {
// Mount dev routes when NOT in production OR when LNbits is in stub mode.
// Stub mode means there is no real Lightning backend — payments are simulated
// in-memory. The testkit relies on POST /dev/stub/pay/:hash to simulate payment
// confirmation, so we expose it whenever stub mode is active regardless of NODE_ENV.
// In real production with a live LNbits backend, stubMode is false, so these
// routes remain unexposed.
if (process.env.NODE_ENV !== "production" || lnbitsService.stubMode) {
router.use(devRouter);
}