@indiegems/gem-web-sdk 9.1.2 → 9.1.4

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.
package/docs/changelog.md CHANGED
@@ -16,6 +16,18 @@ Its entries are grouped under up to five headings:
16
16
  - **Rebuild**: a type changed. Recompile against the new version; code that compiles today keeps compiling unless the entry says otherwise.
17
17
  - **New capability**: something a game can now do. Nothing changes unless you use it.
18
18
 
19
+ ## 9.1.4
20
+
21
+ Upgrading from 9.1.3. Impact: none.
22
+
23
+ Nothing in this release asks anything of a game.
24
+
25
+ ## 9.1.3
26
+
27
+ Upgrading from 9.1.2. Impact: none.
28
+
29
+ Nothing in this release asks anything of a game.
30
+
19
31
  ## 9.1.2
20
32
 
21
33
  Upgrading from 9.1.1. Impact: none.
@@ -50,7 +50,7 @@ either way.
50
50
  ```jsonc
51
51
  // package.json
52
52
  "dependencies": {
53
- "@indiegems/gem-web-sdk": "9.1.2"
53
+ "@indiegems/gem-web-sdk": "9.1.4"
54
54
  }
55
55
  ```
56
56
 
@@ -248,12 +248,12 @@ Once it is open:
248
248
  - **Fullscreen covers it.** Leave fullscreen to see it again.
249
249
 
250
250
  The panel is also reachable from inside your game — see
251
- [GemDevTools.open](https://gemarcade.com/developer/api/game#gemdevtools-open), which answers
251
+ [GemDevTools.open](api/api-reference-game.md#gemdevtools-open), which answers
252
252
  `false` for a session that was not granted it rather than throwing — though it does reject if a
253
253
  panel it _is_ allowed to open fails to load, so catch it either way.
254
254
 
255
255
  If you put your own button on it, gate the button on
256
- [`onDevToolsPermissionChange`](https://gemarcade.com/developer/api/game#gemoptions-ondevtoolspermissionchange)
256
+ [`onDevToolsPermissionChange`](api/api-reference-game.md#gemoptions-ondevtoolspermissionchange)
257
257
  rather than checking anything at boot:
258
258
 
259
259
  ```js
@@ -559,5 +559,5 @@ credential made for a build pipeline can upload and promote, and cannot delete.
559
559
  items, shops or loot. Start with **[the shop tutorial](game-economy-tutorial.md)** to build one.
560
560
  - **[Rooms and the match lifecycle](rooms-and-matches.md)** — if it is multiplayer.
561
561
 
562
- The [API reference](https://gemarcade.com/developer/api) has every symbol the SDK publishes,
563
- with signatures and descriptions.
562
+ The [API reference](api/api-reference-game.md) has every symbol the SDK publishes, with
563
+ signatures and descriptions; the [server half](api/api-reference-server.md) is beside it.
@@ -33,8 +33,8 @@
33
33
  },
34
34
  {
35
35
  "file": "changelog.md",
36
- "sha256": "97c84086804c395ca9674cb0dc0bc5336ac1c49adcfc68d85c144655659c6898",
37
- "updated": "2026-10-09T01:13:28Z"
36
+ "sha256": "6333e652b2c3ffade4ced6759436b8ab3dcb95b25a43c1bd82fe9a6f23fd8a7d",
37
+ "updated": "2026-10-10T01:45:03Z"
38
38
  },
39
39
  {
40
40
  "file": "cross-promotion.md",
@@ -68,8 +68,8 @@
68
68
  },
69
69
  {
70
70
  "file": "getting-started.md",
71
- "sha256": "0559be6739add079acf5677c369ff84e93e6f16411e477dac9971ce678d6f4f8",
72
- "updated": "2026-10-09T01:13:28Z"
71
+ "sha256": "22fab7f0fd67966239c38541a8620ac7fe614f100b96df3e94570b573d4a9f61",
72
+ "updated": "2026-10-10T01:45:03Z"
73
73
  },
74
74
  {
75
75
  "file": "inventory-and-catalogs.md",
@@ -93,8 +93,8 @@
93
93
  },
94
94
  {
95
95
  "file": "platform-rules.md",
96
- "sha256": "76fa088b27d27f7e5c936540a65ed5dc7c9f957334d0db650135173672ffba4d",
97
- "updated": "2026-10-09T00:14:06Z"
96
+ "sha256": "b259bcebc6ae12b1db9c7279a6e2adb174af9d60090bf31001e23616f6423fbf",
97
+ "updated": "2026-10-10T00:12:33Z"
98
98
  },
99
99
  {
100
100
  "file": "player-sign-in.md",
@@ -123,13 +123,13 @@
123
123
  },
124
124
  {
125
125
  "file": "server-bundles.md",
126
- "sha256": "02f13ee28d1c1d95f16fe23f3a68464bee6e449c635ec1492595e911ad436d3f",
127
- "updated": "2026-10-09T01:13:28Z"
126
+ "sha256": "bc59062fefb7c17986671e2a8b6b86b714d1c7e9774956a3df98adcef38a7fd2",
127
+ "updated": "2026-10-10T01:45:03Z"
128
128
  },
129
129
  {
130
130
  "file": "serverless-functions-js.md",
131
- "sha256": "8d5bda66dfebd93e80fe97b2f09c0651c26dc83b16827bdae7aa25f198f89e0b",
132
- "updated": "2026-10-03T00:26:43Z"
131
+ "sha256": "56588d50d5a59f066164565470663f8f9da03fe85d98a96d3754e6ec14eb9fac",
132
+ "updated": "2026-10-10T00:12:33Z"
133
133
  },
134
134
  {
135
135
  "file": "serverless-functions.md",
@@ -295,12 +295,12 @@ them to do something is.
295
295
  Both of these are working code in this repository. Neither was linked from anywhere until this page
296
296
  existed, which is how integrators end up rebuilding them.
297
297
 
298
- - **[`examples/e2e/`](../examples/e2e/README.md) — the bridge, end to end, in a real browser.** A real
298
+ - **`examples/e2e/` — the bridge, end to end, in a real browser.** A real
299
299
  parent page and a real game frame, served from two different origins, exchanging a real
300
300
  `MessagePort`. `pnpm e2e` builds the artifacts and serves it. This is the thing to run when a
301
301
  handshake is not landing and you need to know whether the problem is the SDK or your page:
302
302
  `?sandbox=strict` reproduces the sandbox failure on demand.
303
- - **[`examples/server-bundle/echo.mjs`](../examples/server-bundle/echo.mjs) — a complete dedicated
303
+ - **`examples/server-bundle/echo.mjs` — a complete dedicated
304
304
  server for a match, in one file.** The lifecycle a bundle implements and the first message on the
305
305
  channel, running. Its contract is [`server-bundles.md`](server-bundles.md).
306
306
 
@@ -80,8 +80,8 @@ To check the download yourself: the package npm serves is, byte for byte, the fi
80
80
  also publishes on its download host, with the hash beside it:
81
81
 
82
82
  ```bash
83
- curl -fsSL -O https://downloads.gemarcade.com/sdk/v9.1.2/gem-web-sdk.tgz
84
- curl -fsSL https://downloads.gemarcade.com/sdk/v9.1.2/gem-web-sdk.tgz.sri
83
+ curl -fsSL -O https://downloads.gemarcade.com/sdk/v9.1.4/gem-web-sdk.tgz
84
+ curl -fsSL https://downloads.gemarcade.com/sdk/v9.1.4/gem-web-sdk.tgz.sri
85
85
  openssl dgst -sha384 -binary gem-web-sdk.tgz | openssl base64 -A
86
86
  ```
87
87
 
@@ -261,7 +261,7 @@ other version-skew member on `host`:
261
261
  | `leave` | `cause` — why the connection ended, as the runtime saw it; `superseded` means the same player is already back on a newer connection and the `join` that says so follows at once |
262
262
  | `message` | `reliable` / `ordered` — [the delivery class the sender asked for](#delivery-classes-the-flags-are-the-senders-request); `sessionId`; `playerNumber` |
263
263
 
264
- A complete working example is [`examples/server-bundle/echo.mjs`](../examples/server-bundle/echo.mjs)
264
+ A complete working example is `examples/server-bundle/echo.mjs`
265
265
  — a chat relay in one file, exercising every lifecycle method, the startup reads and most of the
266
266
  runtime surface. This repo's suite drives it against the contract below, so it is a starting point
267
267
  rather than a sketch.
@@ -493,7 +493,7 @@ and inherits none of that, which is why the example above loops around it.
493
493
 
494
494
  A complete, runnable version of this — with the slot's access rules, the room template that makes a
495
495
  dedicated server exist at all, and a real match's logs — is
496
- [`examples/server-saves/`](../examples/server-saves/README.md) in the SDK repository. It refuses the
496
+ `examples/server-saves/` in the SDK repository. It refuses the
497
497
  upload outright where the snippet above merely skips an unexpected header, because a grant naming
498
498
  something else is a platform bug worth surfacing rather than working around.
499
499
 
@@ -1,6 +1,8 @@
1
1
  # Serverless functions in JavaScript
2
2
 
3
- <!-- gem-web: unpublished — the platform does not run JavaScript functions yet -->
3
+ **The platform does not run JavaScript functions yet.** This page describes how one is written
4
+ and how it behaves; today a function you publish is a WebAssembly component, as
5
+ [serverless-functions.md](serverless-functions.md) describes.
4
6
 
5
7
  A serverless function can be written in JavaScript or TypeScript instead of Rust: the language your
6
8
  game is already written in, so the verification code in your browser game moves into a function
@@ -12,6 +14,32 @@ what it may change, its limits, channels, and calling it from your game holds he
12
14
  page covers only what is different: how you write one, how the SDK behaves inside it, and how
13
15
  publishing checks it.
14
16
 
17
+ **JavaScript suits light work; heavy computation belongs in a component.** The platform's engine
18
+ runs JavaScript without a JIT, so the same work takes many times longer than in a WebAssembly
19
+ component, and the gap is smallest on a call that does little and widest on sustained computation.
20
+ Checking a claim, looking a record up or making a small state update finishes well inside a call's
21
+ limits in either language. Replaying a run to verify it, or ranking a large board, is where the gap
22
+ decides whether the call finishes: the CPU limit is the same for both, so JavaScript runs out of it
23
+ on work a component finishes many times over, and the call fails with `function_failed` and
24
+ `cpu_budget_exceeded`. A game has one function per channel, so the heaviest thing it does decides
25
+ the language. Measured with each running as the platform runs it, the same algorithm in JavaScript
26
+ and in Rust:
27
+
28
+ | The work | The component was faster by |
29
+ | --------------------------------------------------------------------------------- | --------------------------------- |
30
+ | A function that only returns its input, which measures the engine's cost per call | about 20 times |
31
+ | A loop of 20,000 integer steps | about 20 times |
32
+ | Ranking a daily leaderboard of 10,000 players | about 60 times |
33
+ | Numeric benchmarks: n-body, spectral-norm, fannkuch-redux and binary-trees | from about 30 to nearly 200 times |
34
+ | The numeric benchmarks and the leaderboard, on average | about 80 times |
35
+
36
+ **Your game's speed in a browser is no guide.** The same JavaScript under V8, the engine in Chrome,
37
+ measured with Node.js on the numeric benchmarks and the leaderboard, ran about 100 times faster than
38
+ on the platform's engine once its JIT had warmed up, which is a little faster than the component,
39
+ and about 7 times faster on its first call. With its JIT switched off it was still about 5 times
40
+ faster. Before you rely on a heavy check, invoke it on `dev` with input as large as a real
41
+ player's.
42
+
15
43
  ## 1. The contract
16
44
 
17
45
  The same as a component's: bytes in, bytes out, one fresh instance per call, nothing kept between
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indiegems/gem-web-sdk",
3
- "version": "9.1.2",
3
+ "version": "9.1.4",
4
4
  "description": "postMessage bridge contract between gem-web and browser-playable games",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",