@flayerlabs/gamemode-cli 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,136 @@
1
+ ---
2
+ name: run-a-game-server
3
+ description: Connects a game with its own authoritative multiplayer server to Flaunch Game Mode with @flayerlabs/gamemode-gate. Use when a game runs its own realtime server or region fleet (custom netcode, Colyseus, Socket.IO, raw WebSockets) and needs the gate, /config, join tickets, awards and the platform submission to line up. Do not use for rules-based games with no server — $build-game-mode covers those.
4
+ ---
5
+
6
+ # Run a game server behind a Game Mode gate
7
+
8
+ You have a game whose gameplay lives on your own server. The platform never hosts or relays your
9
+ realtime traffic: you run the server and the gate, and the platform gives your hosted game a strict
10
+ policy that only reaches what you declared. This skill exists because that declaration lives in
11
+ three places that must agree, and because the launch form refuses a gate that does not announce
12
+ itself. Work through the sections in order; each ends with a check you can run.
13
+
14
+ ## Know the three services and who hosts them
15
+
16
+ 1. Your game bundle: static files you zip and submit. The platform hosts these on Moongate and
17
+ serves them from `https://<deploy-id>.games.moongate.com`. The deploy id is derived from the
18
+ bundle's content, so every re-upload changes the hostname. Never hardcode it; never expect it
19
+ to be stable.
20
+ 2. Your gate: one process you deploy (`createGameServerGate()` from `@flayerlabs/gamemode-gate`).
21
+ It owns wallet sessions, the points ledger, spend authorisations and settlement. One process
22
+ serves one chain.
23
+ 3. Your game server(s): your realtime processes, up to four public HTTPS origins. Gameplay,
24
+ scoring decisions and anti-abuse are yours; points move only through the gate's award route.
25
+
26
+ ## Declare the same origins in all three places
27
+
28
+ The reviewed game-server origins must match exactly — same scheme, same host, no path — in:
29
+
30
+ 1. The platform submission form's game server addresses field (one per line). This becomes your
31
+ hosted game's `connect-src`: the browser can only reach origins listed here or your gate.
32
+ 2. `gameServerOrigins` in your `createGameServerGate()` options. This puts each origin into the
33
+ set of valid join-ticket audiences.
34
+ 3. The `joinTicket(origin)` call in your game client and the `audience` your server verifies.
35
+
36
+ A mismatch fails at a different layer each time: missing from (1) and the fetch dies on CSP with
37
+ "Refused to connect"; missing from (2) and the fetch succeeds but the ticket does not verify;
38
+ wrong in (3) and verification rejects every player. At most four origins, exact HTTPS only —
39
+ wildcards, paths and plain HTTP are refused. Rotating regions? Put them behind stable hostnames;
40
+ the list is not meant to churn.
41
+
42
+ ## Serve /config, or the launch form refuses your gate
43
+
44
+ The launch page reads `GET /config` from your gate before it lets anyone launch a coin through
45
+ your game. `startGate()` serves it automatically; `createGameServerGate()` serves it only when
46
+ you pass `announce`. Without it the form reports your server "isn't answering — it may be offline,
47
+ or built before the current Game Mode SDK". Pass it:
48
+
49
+ ```ts
50
+ const app = createGameServerGate({
51
+ // ...pool, sessions, claims, discovery, settlement, gameId, awardToken...
52
+ gameServerOrigins: ['https://us.game.example.com', 'https://eu.game.example.com'],
53
+ announce: () => ({
54
+ chainId: 84532,
55
+ contracts: {
56
+ positionManager: '0x4E7cB1e6800a7B297B38BddcecAF9Ca5b6616FDC',
57
+ spendGatedCalculator: '0x8cbbE6b4cFA5Ccf68399Dbf1429d91A21097ebA5',
58
+ },
59
+ signer: SIGNER_ADDRESS, // the address of your gate's signing key
60
+ settler: SIGNER_ADDRESS,
61
+ walletCapWei: '25000000000000000',
62
+ roundDurationMs: 90_000,
63
+ minLobbyLeadMs: 60_000,
64
+ gateEndsAtGraceS: 10,
65
+ flaunchVariant: 'legacy11',
66
+ requiresEoa: false,
67
+ accepting: true,
68
+ publicLaunchesOpen: true,
69
+ privateLaunches: false,
70
+ }),
71
+ })
72
+ ```
73
+
74
+ The addresses above are Base Sepolia (chain 84532), read back from the chain. `signer` is what a
75
+ launch writes into its pool as the trusted signer — announce an address you do not hold and every
76
+ coin launched through your game is unplayable. `walletCapWei` must cover a flawless round
77
+ (`maxPointsPerPlayer` times the wei value of a point) or boot refuses.
78
+
79
+ Check: `curl https://<your-gate>/config` returns JSON with your `chainId` and `signer`, and
80
+ `curl https://<your-gate>/health` returns `{"ok":true}`.
81
+
82
+ ## Point the gate's environment at the right origins
83
+
84
+ The two origin settings developers most often get backwards:
85
+
86
+ - Allowed origins (browser CORS and the WebSocket `Origin` check) name where your GAME is served
87
+ from — the Moongate origin, not the flaunch page. Because the Moongate hostname changes per
88
+ upload, use the single-label wildcard: `https://*.games.moongate.com`.
89
+ - The sign-in domain names the page the player is looking at — the flaunch site embedding your
90
+ game — not your game and not your gate.
91
+
92
+ Generate the signing key, session secret (32+ characters) and award token (32+ characters,
93
+ `openssl rand -hex 32`) fresh per environment. The award token lives on the gate and your game
94
+ server only; it never reaches a browser or a zip.
95
+
96
+ ## Wire the ticket handshake
97
+
98
+ Browser, after `joinEconomy()`:
99
+
100
+ ```ts
101
+ const gameServerOrigin = 'https://us.game.example.com' // one reviewed origin, chosen by you
102
+ const { ticket } = await gameMode.joinTicket(gameServerOrigin)
103
+ socket.send(JSON.stringify({ type: 'join', ticket })) // first message; never in the URL
104
+ ```
105
+
106
+ Your server, before accepting any gameplay frame:
107
+
108
+ ```ts
109
+ const playerJoin = verifyPlayerJoinTicket(message.ticket, {
110
+ awardToken,
111
+ gameId,
112
+ roundId,
113
+ audience: gameServerOrigin, // the exact origin the browser connected to
114
+ })
115
+ if (!playerJoin || usedTicketIds.has(playerJoin.jti)) return socket.close(4401, 'invalid join ticket')
116
+ usedTicketIds.add(playerJoin.jti)
117
+ ```
118
+
119
+ Also check the WebSocket `Origin` header against the Moongate wildcard, keep one live connection
120
+ per wallet, and treat every later frame as hostile input. Award points only through
121
+ `POST /internal/rounds/:id/awards` with the award token — see the gate README for the routes.
122
+
123
+ ## Strip development fallbacks from the production bundle
124
+
125
+ A production zip that pings `localhost` ports, probes a region list on boot, or falls back to a
126
+ dev wallet endpoint will emit CSP errors on every load and can hang the game on a spinner when the
127
+ fallback wins a race. Gate development-only network paths behind a build flag so the submitted
128
+ bundle contains none of them.
129
+
130
+ ## Submit, then verify against the real policy
131
+
132
+ Submit the zip with the gate option on (your gate origin) and the game server addresses filled in.
133
+ The form live-probes your gate's `/health` at submission, so deploy the gate first. Localhost
134
+ cannot rehearse the deployed CSP: after hosting, open the deployed game and confirm every declared
135
+ origin connects and an undeclared one is blocked. Then launch a fresh test coin through the room
136
+ link — a coin launched before a registration change stays bound to what it was launched with.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Run a Game Server"
3
+ short_description: "Wire an authoritative multiplayer server into Game Mode"
4
+ default_prompt: "Use $run-a-game-server to connect this game's own server to its Game Mode gate, /config, join tickets and platform submission."
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAc5D;AA+BD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAW7D"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAc5D;AA0CD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAW7D"}
package/dist/scaffold.js CHANGED
@@ -37,6 +37,12 @@ async function readCreatorSkill() {
37
37
  async function readCreatorSkillMetadata() {
38
38
  return readAsset('./build-game-mode/agents/openai.yaml', '../../../.agents/skills/build-game-mode/agents/openai.yaml');
39
39
  }
40
+ async function readServerSkill() {
41
+ return readAsset('./run-a-game-server/SKILL.md', '../../../.agents/skills/run-a-game-server/SKILL.md');
42
+ }
43
+ async function readServerSkillMetadata() {
44
+ return readAsset('./run-a-game-server/agents/openai.yaml', '../../../.agents/skills/run-a-game-server/agents/openai.yaml');
45
+ }
40
46
  async function readAsset(packaged, source) {
41
47
  try {
42
48
  return await readFile(new URL(packaged, import.meta.url), 'utf8');
@@ -156,6 +162,8 @@ For the rules and client workflow, read the
156
162
  `,
157
163
  '.agents/skills/build-game-mode/SKILL.md': await readCreatorSkill(),
158
164
  '.agents/skills/build-game-mode/agents/openai.yaml': await readCreatorSkillMetadata(),
165
+ '.agents/skills/run-a-game-server/SKILL.md': await readServerSkill(),
166
+ '.agents/skills/run-a-game-server/agents/openai.yaml': await readServerSkillMetadata(),
159
167
  'src/game/rules.ts': `import { defineGame, type Decision, type PlayerId, type Refusal } from '@flayerlabs/gamemode-spec';
160
168
  import { scheduleWithin } from '@flayerlabs/gamemode-spec/schedule';
161
169
 
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flayerlabs/gamemode-cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Create and validate Flaunch Game Modes",
5
5
  "license": "MIT",
6
6
  "author": "Flayer Labs",
package/src/scaffold.ts CHANGED
@@ -47,6 +47,17 @@ async function readCreatorSkillMetadata(): Promise<string> {
47
47
  );
48
48
  }
49
49
 
50
+ async function readServerSkill(): Promise<string> {
51
+ return readAsset('./run-a-game-server/SKILL.md', '../../../.agents/skills/run-a-game-server/SKILL.md');
52
+ }
53
+
54
+ async function readServerSkillMetadata(): Promise<string> {
55
+ return readAsset(
56
+ './run-a-game-server/agents/openai.yaml',
57
+ '../../../.agents/skills/run-a-game-server/agents/openai.yaml',
58
+ );
59
+ }
60
+
50
61
  async function readAsset(packaged: string, source: string): Promise<string> {
51
62
  try {
52
63
  return await readFile(new URL(packaged, import.meta.url), 'utf8');
@@ -181,6 +192,8 @@ For the rules and client workflow, read the
181
192
 
182
193
  '.agents/skills/build-game-mode/SKILL.md': await readCreatorSkill(),
183
194
  '.agents/skills/build-game-mode/agents/openai.yaml': await readCreatorSkillMetadata(),
195
+ '.agents/skills/run-a-game-server/SKILL.md': await readServerSkill(),
196
+ '.agents/skills/run-a-game-server/agents/openai.yaml': await readServerSkillMetadata(),
184
197
 
185
198
  'src/game/rules.ts': `import { defineGame, type Decision, type PlayerId, type Refusal } from '@flayerlabs/gamemode-spec';
186
199
  import { scheduleWithin } from '@flayerlabs/gamemode-spec/schedule';