Pre-launch.NetCraftGames is not accepting customers yet. Launch happens only after its public checks pass.See launch statusJoin the waitlist

AI prompt

Node.js socket.io server for NetCraftGames

A copy-paste prompt that makes your AI get a socket.io server ready for NetCraftGames: WebSocket only, a fixed path in the manifest, health page, clean stop and packaging with ncg pack. Copy it, paste it into your AI coding assistant, and read what it changes.

By Charging Bull SoftwareLast updated:

When to use this prompt

Your game server is written in JavaScript with socket.io (version 3 or 4) and your browser game connects to it with the socket.io client.

socket.io normally starts with plain web requests (long polling) and upgrades to a WebSocket later. Our gateway passes WebSocket connections only, so the game has to connect with WebSocket from the first byte. The prompt makes that change on both sides and writes the path our gateway uses into the manifest.

If your game uses Colyseus or python-socketio, this is not the right prompt: use the check to find the one that is.

The prompt

Status: Draft. The manifest is checked; the engine steps are not yet proven.

Node.js with socket.io (WebSocket only)Click inside the box to select it all, then copy.
You are preparing an existing multiplayer game so a hosting service (NetCraftGames) can run its dedicated server on a Linux machine.
Rules for you:
- Make ONLY the changes listed below. Do not redesign game logic. Do not add multiplayer to a game that has none. If something below cannot be done without a redesign, stop and tell me instead of improvising.
- Never put a password, key or token in code or in any file. Read secrets from environment variables.
- Run every proof step at the end and show me the real output. If a proof step fails, fix it or tell me exactly why you cannot.
- If a step needs a tool you do not have, say so and stop at that step. Do not invent a substitute and do not pretend the step passed.

Facts about the host (exact):
- Linux x86-64, glibc 2.39 or older for every compiled program in the upload.
- The server starts as an unprivileged user in /game. Writable places: /game/saves and a 256 MB /tmp. Nothing is installed, downloaded or compiled on the host. The start command is a fixed list of arguments, not a shell string.
- The host (Ubuntu 24.04 LTS) provides these programs: sh, bash, dash, python3, node, node24 (Python 3.12, Node.js 24.21.0). There is no Java, .NET, Deno or Bun on the host unless you ship it inside the upload.
- Nothing is installed or downloaded on the host: packages travel inside the upload, built for Linux x64 on the owner's own computer.
- A game server cannot look up other websites by name (DNS is closed to it on purpose), so do not make the server depend on calling an outside address by name.
- The host does not set a PORT variable. The port your server uses by default must be the port written in the manifest.
- The host stops the server with SIGTERM and waits up to the number of seconds in the manifest (between 1 and 300).
- The upload is one .tar.gz of at most 512 MiB with at most 10,000 files, no symlinks and no setuid files.
- The host checks your server from outside with a 3 second timeout per request.

TASK: Make this socket.io game server ready for NetCraftGames. The gateway passes WebSocket connections only, to one fixed path, so socket.io must use WebSocket only and the manifest names its path.
1. Server: create an http server, then new Server(httpServer, { transports: ['websocket'] }). Keep socket.io's default path "/socket.io/" (if the code sets another path, put that path into "wsPath" below instead). Listen on 0.0.0.0, port Number(process.env.PORT ?? 8080).
2. Client: connect with io('<gateway address from the connection config>', { path: '/play/<gameId>', transports: ['websocket'], addTrailingSlash: false }). HTTP long polling is NOT supported and the query string a client sends is NOT passed on, so do not use the "query" client option and do not rely on the polling-to-WebSocket upgrade. Send tokens in the "auth" option: it travels inside the first packet, not in the address. Read the address and game id from the connection config, never hard-code them.
3. Serve /health and /join-probe from the same http server (they are not under "/socket.io/", so they do not collide), then add R4 and R5.
4. Packaging: our servers provide Node.js 24.21.0 and install nothing, so the upload carries your code and its packages, built for Linux x64 on the owner's computer, not by you and not on the host.
   - Prefer pure JavaScript packages (ws needs no add-on: leave out the optional bufferutil and utf-8-validate). Stop and ask before adding a package that has a native add-on (a .node file).
   - package.json: "engines": { "node": ">=24" }, a "start" script that runs your entry file (for example "node server.js"), and only the packages the game needs under "dependencies".
   - Make sure package-lock.json exists (the owner runs npm install once to create it). Do not edit anything inside node_modules.
   - If the project is TypeScript, compile it to JavaScript first and tell the owner to pass the built file with --entry <file>.
   - Do NOT write a start script and do NOT pack anything yourself. The owner runs  ncg pack . --node --install  which builds .ncg/build (your code under app/, the production packages for Linux x64 and a start script named server that runs node with --max-old-space-size=2048), then  ncg check .ncg/build  and fixes everything it lists.

Server requirements (all exact):
R1  Listen on 0.0.0.0 (never 127.0.0.1 only, never a random port). Read the port from the PORT environment variable and default to 8080.
R2  Health probe: an HTTP GET /health on TCP port 8080 answers HTTP 200 with the body exactly "ok" within 3 seconds. It must not touch a database or game state. Return 503 if the server loop is stalled or shutting down.
R3  Join probe: an HTTP GET /join-probe on the same port answers 200 with a body that contains "joinable" while a new player could be admitted, otherwise 503 with the body "full" or "stopping". It needs no login and exposes nothing private.
R4  Player count: a second HTTP listener bound to 127.0.0.1 only, port 9090. GET /players answers 200 with JSON {"players": N}, where N is the number of connected players, a whole number from 0 to 10,000, in a body under 4 KB. Do not count a health probe, a join probe or a player who is only in a reconnect grace window.
R5  Shutdown: on SIGTERM (and SIGINT) stop admitting players, tell connected clients, write the save atomically (write a temporary file in the same folder, flush it, then rename it) under /game/saves, close sockets and exit with code 0 within the grace seconds.
R6  Saves and every other file the server writes live under /game/saves only. Read the folder from an environment variable SAVE_DIR and default to /game/saves (use ./saves when running on your own computer).
R7  Log events (join, leave, error), not every tick. The host drops log lines above its rate limit.

5. Write ncg.json with exactly this content. "wsPath" is the path the gateway uses to reach socket.io, including the query Engine.IO needs; the owner fixes it here and nothing a player sends can change it:

----- ncg.json (start) -----
{
  "ncg": 1,
  "game": {
    "name": "My Game"
  },
  "version": "0.1.0",
  "build": {
    "dir": ".ncg/build"
  },
  "manifest": {
    "engine": "browser-wss",
    "transport": "wss",
    "platforms": [
      "web"
    ],
    "mode": "dedicated",
    "networkingImplemented": true,
    "os": "linux",
    "arch": "x64",
    "command": [
      "/game/server"
    ],
    "ports": [
      {
        "port": 8080,
        "protocol": "tcp"
      }
    ],
    "profile": "standard",
    "savePath": "/game/saves",
    "health": {
      "type": "http",
      "port": 8080,
      "path": "/health",
      "expected": "ok"
    },
    "playerProbe": {
      "type": "http",
      "port": 9090,
      "path": "/players"
    },
    "joinProbe": {
      "type": "http",
      "port": 8080,
      "path": "/join-probe",
      "expected": "joinable"
    },
    "shutdown": {
      "signal": "SIGTERM",
      "graceSeconds": 30
    },
    "idleSupported": true,
    "wsPath": "/socket.io/?EIO=4&transport=websocket"
  }
}
----- ncg.json (end) -----

About ncg.json (the project file the ncg tool reads; it is never packed into the upload):
- Write it in the project root with exactly the content shown. Change only: "game.name" (the real name of the game, 1 to 100 characters), "manifest.platforms" (the platforms the game's players really use) and, if your server uses another port, the port numbers in "manifest.ports", "manifest.health" and "manifest.joinProbe".
- "build.dir" is ".ncg/build": the folder that "ncg pack . --node --install" (or "--python --install") builds for you from this project: your code under app/, the packages for Linux x64, and a start script named "server" that the manifest starts as "/game/server". Do not write that script yourself.
- Run "ncg pack" again after every change: it rebuilds .ncg/build from scratch and never changes your own files.

Proof (run these and show me the real output):
P1  Start the finished server the way the host will: the exact command from ncg.json, in a Linux shell (WSL or an ubuntu:24.04 container if you are on Windows or Mac), with no environment variables set except PATH, LANG and HOME.
P2  curl -s -w " %{http_code}" http://127.0.0.1:8080/health  must print ok and 200.
P3  curl -s http://127.0.0.1:9090/players  must print {"players":0}. Connect one real client: it must become {"players":1}.
P4  Send SIGTERM (kill -TERM <pid>). The process must exit with code 0 inside the grace seconds and the save file must exist and parse.
P5  If the ncg tool is installed, run "ncg check" in the project folder and fix everything it lists. If it is not installed, say so; do not write a substitute.

After your AI finishes

  1. Read what it changed. It was told to change only what the prompt lists and to stop and ask when something needs a redesign.
  2. Run the game with two real players. A prompt cannot prove your game plays well.
  3. Come back to the check and answer again, or run the local check the prompt ends with when you have the ncg tool.