Legendary Arena Lab

Node Runtime

wiki

Node Runtime

Migration in progress. api.legendary-arena.com and its PostgreSQL are moving off Render onto a self-hosted DigitalOcean Ubuntu droplet fronted by Cloudflare, per docs/PLAN.md . Until decommission, Render stays warm as the rollback target.

Summary

This page provisions the Node.js toolchain the game server runs on. It installs fnm into a fixed location, pins Node to the exact version the app expects, and activates pnpm through corepack so builds and the systemd service resolve one deterministic runtime.

Mechanics

The owning artifact is infra/scripts/10-node.ps1 . It requires root and runs under Set-StrictMode with stop-on-error, so a failed step aborts the whole provision. Behaviour, in order:

  1. Prereqs. Confirms the operator user exists and installs the base packages needed to fetch and unpack the runtime:

    OPERATOR_USER = operator   # env override
    packages      = curl, ca-certificates, unzip
    
  2. fnm. Installs Fast Node Manager by downloading the latest Linux release from GitHub into a fixed path. Idempotent — it skips the download if the binary is already present:

    /opt/fnm/fnm   # skipped if this file already exists
    
  3. Profile init. Writes an fnm init line into the operator’s PowerShell profile so interactive shells resolve the managed Node:

    ~operator/.config/powershell/profile.ps1
    
  4. Node + pnpm. Installs the pinned Node, sets it default, then enables corepack and activates the pinned pnpm:

    NODE_VERSION = 24.18.0     # fnm install 24.18.0 ; set default
    PNPM_VERSION = 10.32.1     # corepack enable ; corepack prepare pnpm@10.32.1 --activate
    
  5. Verify. Prints node -v and pnpm -v for a provision-time sanity check.

The pinned 24.18.0 matches .node-version and is the runtime named in docs/PLAN.md (D-24205); pnpm 10.32.1 is likewise the version the plan pins.

Interactions

  • Deploy Server — builds and runs the app through the fnm binary at /opt/fnm/fnm, so this must complete first or the deploy has no toolchain.
  • Provision Droplet — creates the operator user this script depends on; run it before this page.
  • Systemd Service — the unit’s ExecStart calls /opt/fnm/fnm exec 24.18.0, binding the service to the exact path and version installed here.

Edge Cases

  • Version must match .node-version. Per docs/PLAN.md (D-24205), a newer Node is a different system, not a compatible upgrade — leave NODE_VERSION at 24.18.0 unless the plan changes.
  • The fnm path is load-bearing. The binary lives at /opt/fnm/fnm and is referenced by that absolute path in the systemd unit’s ExecStart and in the deploy script. Relocating it breaks both.
  • corepack owns the pnpm version. pnpm is pinned through corepack and the project’s packageManager field; changing PNPM_VERSION without matching that field drifts the toolchain.
  • GitHub fetch at provision time. The fnm download hits GitHub’s release API, so network outages or rate limits can fail the install — re-run once connectivity is back (the step is idempotent).

Execute

# Default provision (operator user, Node 24.18.0, pnpm 10.32.1)
sudo pwsh -File infra/scripts/10-node.ps1

# With explicit version overrides (documented defaults shown)
sudo NODE_VERSION=24.18.0 PNPM_VERSION=10.32.1 pwsh -File infra/scripts/10-node.ps1

Verify

/opt/fnm/fnm exec 24.18.0 node -v
# Expected: v24.18.0

/opt/fnm/fnm exec 24.18.0 pnpm -v
# Expected: 10.32.1

References