Skip to content

Commit b322348

Browse files
docs: document how to access module owner via init reducer (#4315)
In the `init` reducer, `ctx.sender` is the **module owner** — the identity of the user who published the database. This is the only lifecycle reducer where the owner identity is automatically provided. Added a tip to the lifecycle docs showing: - That `ctx.sender` in `init` is the owner - How to store it in a table for later authorization checks - Examples in TypeScript, C#, and Rust Closes #3229 Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
1 parent 5d9eb7c commit b322348

1 file changed

Lines changed: 59 additions & 0 deletions

File tree

docs/docs/00200-core-concepts/00200-functions/00300-reducers/00500-lifecycle.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,65 @@ The `init` reducer:
113113
- Runs when clearing with `spacetime publish -c`
114114
- Failure prevents publishing or clearing
115115
116+
:::tip Module Owner
117+
In the `init` reducer, `ctx.sender` is the **module owner** — the identity of the user who published the database. This is the only place where the owner identity is automatically provided, so if you need to reference it later (e.g. for authorization), store it in a table during `init`:
118+
119+
<Tabs groupId="server-language" queryString>
120+
<TabItem value="typescript" label="TypeScript">
121+
122+
```typescript
123+
const config = table({ name: 'config' }, {
124+
ownerIdentity: t.identity().primaryKey(),
125+
});
126+
127+
export const init = spacetimedb.init((ctx) => {
128+
ctx.db.config.insert({ ownerIdentity: ctx.sender });
129+
});
130+
```
131+
132+
</TabItem>
133+
<TabItem value="csharp" label="C#">
134+
135+
```csharp
136+
[SpacetimeDB.Table(Name = "Config")]
137+
public partial struct Config
138+
{
139+
[SpacetimeDB.PrimaryKey]
140+
public Identity OwnerIdentity;
141+
}
142+
143+
[SpacetimeDB.Reducer(ReducerKind.Init)]
144+
public static void Init(ReducerContext ctx)
145+
{
146+
ctx.Db.Config.Insert(new Config { OwnerIdentity = ctx.Sender });
147+
}
148+
```
149+
150+
</TabItem>
151+
<TabItem value="rust" label="Rust">
152+
153+
```rust
154+
#[table(accessor = config)]
155+
pub struct Config {
156+
#[primary_key]
157+
pub owner_identity: Identity,
158+
}
159+
160+
#[reducer(init)]
161+
pub fn init(ctx: &ReducerContext) -> Result<(), String> {
162+
ctx.db.config().try_insert(Config {
163+
owner_identity: ctx.sender(),
164+
})?;
165+
Ok(())
166+
}
167+
```
168+
169+
</TabItem>
170+
</Tabs>
171+
172+
You can then check `ctx.sender` against the stored owner identity in other reducers to restrict admin-only operations.
173+
:::
174+
116175
## Client Connected
117176

118177
Runs when a client establishes a connection.

0 commit comments

Comments
 (0)