diff --git a/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00400-reducer-context.md b/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00400-reducer-context.md index a4d743813d1..06e30fb7b2a 100644 --- a/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00400-reducer-context.md +++ b/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00400-reducer-context.md @@ -272,6 +272,46 @@ The context provides access to a random number generator that is deterministic a Never use external random number generators (like `Random` in C# without using the context). These are non-deterministic and will cause different nodes to produce different results, breaking consensus. ::: +Use the context-provided random API for any reducer logic that needs random values: + + + + +```typescript +const fraction = ctx.random(); // [0.0, 1.0) +const roll = ctx.random.integerInRange(1, 6); // inclusive +const bytes = ctx.random.fill(new Uint8Array(16)); +``` + + + + +```csharp +double fraction = ctx.Rng.NextDouble(); // [0.0, 1.0) +int roll = ctx.Rng.Next(1, 7); // [1, 7) +``` + + + + +```rust +use spacetimedb::rand::Rng; + +let value: u32 = ctx.random(); +let roll: u32 = ctx.rng().gen_range(1..=6); +``` + + + + +```cpp +auto& rng = ctx.rng(); +int32_t roll = rng.gen_range(1, 6); // inclusive +``` + + + + ## Module Identity The context provides access to the module's own identity, which is useful when a reducer needs to refer to the database itself. diff --git a/docs/docs/00200-core-concepts/00600-clients/00200-codegen.md b/docs/docs/00200-core-concepts/00600-clients/00200-codegen.md index f648e17a578..3575377a20a 100644 --- a/docs/docs/00200-core-concepts/00600-clients/00200-codegen.md +++ b/docs/docs/00200-core-concepts/00600-clients/00200-codegen.md @@ -189,10 +189,10 @@ For example, a `create_user` reducer becomes: ```typescript // Call the reducer -conn.reducers.createUser(name, email); +conn.reducers.createUser({ name, email }); // Register a callback to observe reducer invocations -conn.reducers.onCreateUser((ctx, name, email) => { +conn.reducers.onCreateUser((ctx, { name, email }) => { console.log(`User created: ${name}`); }); ``` diff --git a/docs/docs/00200-core-concepts/00600-clients/00300-connection.md b/docs/docs/00200-core-concepts/00600-clients/00300-connection.md index 8882aa3c80d..f1ad4c73d42 100644 --- a/docs/docs/00200-core-concepts/00600-clients/00300-connection.md +++ b/docs/docs/00200-core-concepts/00600-clients/00300-connection.md @@ -26,9 +26,10 @@ Create a connection using the `DbConnection` builder pattern: ```typescript import { DbConnection } from './module_bindings'; -const conn = new DbConnection.builder() +const conn = DbConnection.builder() .withUri("https://maincloud.spacetimedb.com") - .withDatabaseName("my_database"); + .withDatabaseName("my_database") + .build(); ``` @@ -80,9 +81,10 @@ To connect to a database hosted on MainCloud: ```typescript -const conn = new DbConnection.builder() +const conn = DbConnection.builder() .withUri("https://maincloud.spacetimedb.com") - .withDatabaseName("my_database"); + .withDatabaseName("my_database") + .build(); ``` @@ -126,10 +128,11 @@ To authenticate with a token (for example, from [SpacetimeAuth](../00500-authent ```typescript -const conn = new DbConnection.builder() +const conn = DbConnection.builder() .withUri("https://maincloud.spacetimedb.com") .withDatabaseName("my_database") - .withToken("your_auth_token_here"); + .withToken("your_auth_token_here") + .build(); ``` diff --git a/docs/docs/00200-core-concepts/00600-clients/00700-typescript-reference.md b/docs/docs/00200-core-concepts/00600-clients/00700-typescript-reference.md index 759a0f85f10..66abdda2021 100644 --- a/docs/docs/00200-core-concepts/00600-clients/00700-typescript-reference.md +++ b/docs/docs/00200-core-concepts/00600-clients/00700-typescript-reference.md @@ -1088,7 +1088,7 @@ function MyComponent() { return (

Connected as: {identity?.toHexString()}

-
@@ -1136,7 +1136,7 @@ import { useReducer } from 'spacetimedb/react'; import { reducers } from './module_bindings'; const createPlayer = useReducer(reducers.createPlayer); -createPlayer('Alice'); +createPlayer({ name: 'Alice' }); ``` `useReducer` returns a function that calls the generated reducer. Calls made before the connection is ready are queued and flushed once the connection is established. diff --git a/skills/concepts/SKILL.md b/skills/concepts/SKILL.md index 402a1a8ff18..9c4195fc1bd 100644 --- a/skills/concepts/SKILL.md +++ b/skills/concepts/SKILL.md @@ -20,7 +20,7 @@ SpacetimeDB is a relational database that is also a server. It lets you upload a ## Critical Rules 1. **Reducers are transactional.** They do not return data to callers. Use subscriptions to read data. -2. **Reducers must be deterministic.** No filesystem, network, timers, or random. All state must come from tables. +2. **Reducers must be deterministic.** Do not use filesystem, network, external clocks, or external random sources in reducers. Use `ReducerContext` for SpacetimeDB-provided timestamp and deterministic random values. 3. **Read data via tables/subscriptions**, not reducer return values. Clients get data through subscribed queries. 4. **Auto-increment IDs are not sequential.** Gaps are normal, do not use for ordering. Use timestamps or explicit sequence columns. 5. **`ctx.sender` is the authenticated principal.** Never trust identity passed as arguments.