connect: expose light mode and confirmed reads #22

Closed
opened 2026-08-19 15:19:38 +00:00 by yuris · 0 comments
Owner

connect accepts no equivalent of the official SDKs' withLightMode and withConfirmedReads. Both are single query parameters on the subscribe URL, and both are supported on v1.json.spacetimedb.

What they do

Verified in SpacetimeDB v2.8.2 source:

  • ?light=true → ClientConfig.tx_update_full = !light (crates/client-api/src/routes/subscribe.rs:204-208). The server then sends TransactionUpdateLight — rows only, no status, timestamp, caller identity or reducer info — for transactions the client did not itself call. The caller always receives a full update regardless (module_subscription_manager.rs:1962-1964), so a client's own reducer callbacks are unaffected.
  • ?confirmed=true|false → holds updates until they are durable (subscribe.rs:107-114). Default is false on the v1 protocol.

The SDK already handles TransactionUpdateLight (stdb/connection.lua:324), so light mode needs no new message handling — only the ability to ask for it.

Why light mode is worth having here

It is a bandwidth and parse win, and parse cost is the one that bites in Lua: every non-caller transaction currently carries caller_identity, caller_connection_id, reducer_call (name, id, args, request_id), energy_quanta_used and total_host_execution_duration that most games read none of. On a busy module with many players, that is per-message JSON a pure-Lua decoder pays for on the main thread, on mobile, every frame a transaction lands.

confirmed is the narrower one: it trades latency for durability, which matters for anything the player perceives as committed (a purchase, a match result) and is wrong for high-frequency position updates.

Proposed change

Two connect options threaded onto the URL, defaulting to current behaviour so nothing changes for existing callers:

Option Default Effect
light false Appends ?light=true
confirmed_reads nil Appends ?confirmed=true / false when set; omitted otherwise

The URL assembly belongs next to stdb.with_token, which already knows how to append a parameter and is unit-tested (dev/test/test_init.lua:24-25).

Watch two things:

  • Ordering with with_token. The token is appended as ?token= on HTML5; a second parameter must use &. The existing helper handles one parameter, not composition — that is the actual work in this issue.
  • confirmed is tri-state. Absent, true, and false are three distinct requests; a boolean default of false would silently start sending ?confirmed=false where the SDK currently sends nothing. Keep nil meaning "do not mention it".

Acceptance

Unit tests in dev/test/test_init.lua covering: light alone, confirmed alone, both, both plus a token (proving ?/& composition), and the default case emitting a byte-identical URL to today's.

Light mode also wants one conformance assertion, since it is the only way to prove the server actually honoured it: with light = true, a transaction caused by another connection should arrive as TransactionUpdateLight. That needs a second client in the harness, so it may be worth deferring the conformance half and shipping the option with unit coverage only — say so explicitly rather than leaving it ambiguous.

Priority

Medium. Neither is required for correctness, light is a real cost saving for the exact platform this SDK targets, and both are cheap. Good 1.0 material, not a blocker.

`connect` accepts no equivalent of the official SDKs' `withLightMode` and `withConfirmedReads`. Both are single query parameters on the subscribe URL, and both are supported on `v1.json.spacetimedb`. ## What they do Verified in SpacetimeDB v2.8.2 source: - **`?light=true`** → `ClientConfig.tx_update_full = !light` (`crates/client-api/src/routes/subscribe.rs:204-208`). The server then sends `TransactionUpdateLight` — rows only, no status, timestamp, caller identity or reducer info — for transactions the client did not itself call. **The caller always receives a full update regardless** (`module_subscription_manager.rs:1962-1964`), so a client's own reducer callbacks are unaffected. - **`?confirmed=true|false`** → holds updates until they are durable (`subscribe.rs:107-114`). Default is `false` on the v1 protocol. The SDK already handles `TransactionUpdateLight` (`stdb/connection.lua:324`), so light mode needs no new message handling — only the ability to ask for it. ## Why light mode is worth having here It is a bandwidth and parse win, and parse cost is the one that bites in Lua: every non-caller transaction currently carries `caller_identity`, `caller_connection_id`, `reducer_call` (name, id, args, request_id), `energy_quanta_used` and `total_host_execution_duration` that most games read none of. On a busy module with many players, that is per-message JSON a pure-Lua decoder pays for on the main thread, on mobile, every frame a transaction lands. `confirmed` is the narrower one: it trades latency for durability, which matters for anything the player perceives as committed (a purchase, a match result) and is wrong for high-frequency position updates. ## Proposed change Two `connect` options threaded onto the URL, defaulting to current behaviour so nothing changes for existing callers: | Option | Default | Effect | |---|---|---| | `light` | `false` | Appends `?light=true` | | `confirmed_reads` | `nil` | Appends `?confirmed=true` / `false` when set; omitted otherwise | The URL assembly belongs next to `stdb.with_token`, which already knows how to append a parameter and is unit-tested (`dev/test/test_init.lua:24-25`). Watch two things: - **Ordering with `with_token`.** The token is appended as `?token=` on HTML5; a second parameter must use `&`. The existing helper handles one parameter, not composition — that is the actual work in this issue. - **`confirmed` is tri-state.** Absent, `true`, and `false` are three distinct requests; a boolean default of `false` would silently start sending `?confirmed=false` where the SDK currently sends nothing. Keep `nil` meaning "do not mention it". ## Acceptance Unit tests in `dev/test/test_init.lua` covering: light alone, confirmed alone, both, both plus a token (proving `?`/`&` composition), and the default case emitting a byte-identical URL to today's. Light mode also wants one conformance assertion, since it is the only way to prove the server actually honoured it: with `light = true`, a transaction caused by *another* connection should arrive as `TransactionUpdateLight`. That needs a second client in the harness, so it may be worth deferring the conformance half and shipping the option with unit coverage only — say so explicitly rather than leaving it ambiguous. ## Priority Medium. Neither is required for correctness, `light` is a real cost saving for the exact platform this SDK targets, and both are cheap. Good 1.0 material, not a blocker.
yuris closed this issue 2026-08-19 16:22:17 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
yuris/spacetimedb-defold#22
No description provided.