Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
efa9fd5
Update C++ module bindings to RawModuleDefV10
JasonAtClockwork Feb 25, 2026
6f8639a
Merge branch 'master' into jlarabie/cpp-v10
JasonAtClockwork Feb 25, 2026
5f3fa0b
Merge branch 'master' into jlarabie/cpp-v10
JasonAtClockwork Feb 26, 2026
bab6691
Fix for linting
JasonAtClockwork Feb 26, 2026
aa566a8
Make event tables inaccessible from views
JasonAtClockwork Feb 27, 2026
f71513b
Unreal SDK update to websocket 2.0 for core sdk and tests
JasonAtClockwork Feb 26, 2026
f824ab0
Add multi-module support
JasonAtClockwork Feb 26, 2026
db20a12
Update Unreal Blackholio
JasonAtClockwork Feb 28, 2026
e135234
Lint + CLI fixes
JasonAtClockwork Feb 28, 2026
b6045fc
Merge origin/master into unreal-sdk-2.0
JasonAtClockwork Mar 2, 2026
7b67fd0
Repairs after testing Blakcholio tutorial and multi-module heavy testing
JasonAtClockwork Mar 4, 2026
59d348d
Linting fix that didn't pop up locally
JasonAtClockwork Mar 4, 2026
a8170a6
Merge branch 'master' into jlarabie/unreal-sdk-2.0
JasonAtClockwork Mar 4, 2026
5790ba4
Small codegen fixes to treat unknown request ids as a protocol violation
JasonAtClockwork Mar 5, 2026
e51165b
Merge branch 'master' into jlarabie/unreal-sdk-2.0
JasonAtClockwork Mar 10, 2026
3cc7206
Reworked Unreal Blackholio tutorial for pathing issues
JasonAtClockwork Mar 10, 2026
14bcde1
Update for sender to sender() for C++ module bindings
JasonAtClockwork Mar 12, 2026
ef6f648
Merge branch 'master' into jlarabie/unreal-sdk-2.0
JasonAtClockwork Mar 12, 2026
527dda9
Documentation update and final change for upgrade-version to update C…
JasonAtClockwork Mar 13, 2026
1b13683
Update docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md
JasonAtClockwork Mar 13, 2026
60ef612
Update docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00…
JasonAtClockwork Mar 13, 2026
1d00844
Merge branch 'master' into jlarabie/unreal-sdk-2.0
JasonAtClockwork Mar 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/bindings-cpp/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ SPACETIMEDB_REDUCER(create_user, ReducerContext ctx, std::string name) {
}

// Success path
ctx.db[user].insert(User{ctx.sender, name, false});
ctx.db[user].insert(User{ctx.sender(), name, false});
return Ok(); // No value needed - just success
}
```
Expand Down Expand Up @@ -638,4 +638,4 @@ SpacetimeDB loading → Server-side validation and error reporting
- [Type System Details](README.md#features)
- [Constraint Validation Tests](tests/type-isolation-test/)
- [API Reference](REFERENCE.md)
- [Quick Start Guide](QUICKSTART.md)
- [Quick Start Guide](QUICKSTART.md)
12 changes: 6 additions & 6 deletions crates/bindings-cpp/QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ SPACETIMEDB_REDUCER(set_name, ReducerContext ctx, std::string name) {
}

// Find and update the user by identity (primary key)
auto user_row = ctx.db[user_identity].find(ctx.sender);
auto user_row = ctx.db[user_identity].find(ctx.sender());
if (user_row.has_value()) {
auto user = user_row.value();
user.name = validated.value();
Expand All @@ -127,7 +127,7 @@ SPACETIMEDB_REDUCER(send_message, ReducerContext ctx, std::string text) {
return Err(validated.error());
}

Message msg{ctx.sender, ctx.timestamp, validated.value()};
Message msg{ctx.sender(), ctx.timestamp, validated.value()};
ctx.db[message].insert(msg);
return Ok();
}
Expand All @@ -140,21 +140,21 @@ Lifecycle reducers are special functions called automatically by SpacetimeDB:
```cpp
// Called when a client connects
SPACETIMEDB_CLIENT_CONNECTED(client_connected, ReducerContext ctx) {
auto user_row = ctx.db[user_identity].find(ctx.sender);
auto user_row = ctx.db[user_identity].find(ctx.sender());
if (user_row.has_value()) {
auto user = user_row.value();
user.online = true;
ctx.db[user_identity].update(user);
} else {
User new_user{ctx.sender, std::nullopt, true};
User new_user{ctx.sender(), std::nullopt, true};
ctx.db[user].insert(new_user);
}
return Ok();
}

// Called when a client disconnects
SPACETIMEDB_CLIENT_DISCONNECTED(client_disconnected, ReducerContext ctx) {
auto user_row = ctx.db[user_identity].find(ctx.sender);
auto user_row = ctx.db[user_identity].find(ctx.sender());
if (user_row.has_value()) {
auto user = user_row.value();
user.online = false;
Expand Down Expand Up @@ -291,4 +291,4 @@ For more complex examples, see:

---

Ready to learn more? Check out the [C++ Reference Documentation](REFERENCE.md) for detailed API information.
Ready to learn more? Check out the [C++ Reference Documentation](REFERENCE.md) for detailed API information.
10 changes: 5 additions & 5 deletions crates/bindings-cpp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,15 @@ SPACETIMEDB_NAMESPACE(UserRole, "Auth") // Will be "Auth.UserRole" in client co

// User-defined reducer
SPACETIMEDB_REDUCER(add_user, ReducerContext ctx, std::string name, std::string email) {
User user{ctx.sender, name, email}; // id will be auto-generated
User user{ctx.sender(), name, email}; // id will be auto-generated
ctx.db[users].insert(user);
LOG_INFO("Added user: " + name);
return Ok();
}

// Delete user by id (using primary key)
SPACETIMEDB_REDUCER(delete_user, ReducerContext ctx) {
ctx.db[users_identity].delete_by_key(ctx.sender);
ctx.db[users_identity].delete_by_key(ctx.sender());
return Ok();
}

Expand All @@ -121,19 +121,19 @@ SPACETIMEDB_INIT(init, ReducerContext ctx) {
}

SPACETIMEDB_CLIENT_CONNECTED(on_connect, ReducerContext ctx) {
LOG_INFO("Client connected: " + ctx.sender.to_hex_string());
LOG_INFO("Client connected: " + ctx.sender().to_hex_string());
return Ok();
}

SPACETIMEDB_CLIENT_DISCONNECTED(on_disconnect, ReducerContext ctx) {
LOG_INFO("Client disconnected: " + ctx.sender.to_hex_string());
LOG_INFO("Client disconnected: " + ctx.sender().to_hex_string());
return Ok();
}

// Define a view for querying data (finds the calling user)
SPACETIMEDB_VIEW(std::optional<User>, find_my_user, Public, ViewContext ctx) {
// Use indexed field to find user by their identity
return ctx.db[users_identity].find(ctx.sender);
return ctx.db[users_identity].find(ctx.sender());
}

// Define a procedure (pure function with return value)
Expand Down
20 changes: 10 additions & 10 deletions crates/bindings-cpp/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ SPACETIMEDB_INIT(init, ReducerContext ctx) {
// Called when a client connects
SPACETIMEDB_CLIENT_CONNECTED(on_connect, ReducerContext ctx) {
LOG_INFO("Client connected");
// ctx.sender contains the client's Identity
// ctx.sender() contains the client's Identity
return Ok();
}

Expand All @@ -213,7 +213,7 @@ SPACETIMEDB_REDUCER(example, ReducerContext ctx, /* params */) {
ctx.db[table_name].insert(record);

// Client identity
Identity client = ctx.sender;
Identity client = ctx.sender();

// Current timestamp
Timestamp now = ctx.timestamp;
Expand Down Expand Up @@ -893,7 +893,7 @@ SPACETIMEDB_TABLE(User, user, Public);
FIELD_PrimaryKey(user, id);

SPACETIMEDB_REDUCER(create_user, ReducerContext ctx, std::string name) {
User user{ctx.sender, name}; // ctx.sender is the calling client's identity
User user{ctx.sender(), name}; // ctx.sender() is the calling client's identity
ctx.db[user_id].insert(user);
return Ok();
}
Expand Down Expand Up @@ -1138,20 +1138,20 @@ FIELD_Index(user, active);
// Register new user
SPACETIMEDB_REDUCER(register_user, ReducerContext ctx, std::string username, std::string email) {
// Check if user already exists
auto user_opt = ctx.db[user_identity].find(ctx.sender);
auto user_opt = ctx.db[user_identity].find(ctx.sender());
if (user_opt && user_opt->active) {
return Err("User already registered");
}

User new_user{0, ctx.sender, username, email, ctx.timestamp, true};
User new_user{0, ctx.sender(), username, email, ctx.timestamp, true};
ctx.db[user].insert(new_user);
LOG_INFO("User registered: " + username);
return Ok();
}

// Update user profile
SPACETIMEDB_REDUCER(update_profile, ReducerContext ctx, std::string new_username) {
auto user_opt = ctx.db[user_identity].find(ctx.sender);
auto user_opt = ctx.db[user_identity].find(ctx.sender());
if (user_opt && user_opt->active) {
User updated_user = *user_opt;
updated_user.username = new_username;
Expand All @@ -1164,7 +1164,7 @@ SPACETIMEDB_REDUCER(update_profile, ReducerContext ctx, std::string new_username

// Deactivate user
SPACETIMEDB_REDUCER(deactivate_user, ReducerContext ctx) {
auto user_opt = ctx.db[user_identity].find(ctx.sender);
auto user_opt = ctx.db[user_identity].find(ctx.sender());
if (user_opt && user_opt->active) {
User updated_user = *user_opt;
updated_user.active = false;
Expand Down Expand Up @@ -1227,7 +1227,7 @@ FIELD_Index(messages, sender);

// Create channel
SPACETIMEDB_REDUCER(create_channel, ReducerContext ctx, std::string name, std::string description, bool is_public) {
Channel channel{0, name, description, ctx.sender, is_public};
Channel channel{0, name, description, ctx.sender(), is_public};
ctx.db[channels].insert(channel);
LOG_INFO("Channel created: " + name);
return Ok();
Expand All @@ -1249,7 +1249,7 @@ SPACETIMEDB_REDUCER(send_message, ReducerContext ctx, uint32_t channel_id, std::
return Err("Channel not found");
}

Message message{0, channel_id, ctx.sender, content, ctx.timestamp};
Message message{0, channel_id, ctx.sender(), content, ctx.timestamp};
ctx.db[messages].insert(message);
return Ok();
}
Expand Down Expand Up @@ -1281,4 +1281,4 @@ SPACETIMEDB_REDUCER(update_age, ReducerContext ctx, uint32_t new_age) {

---

This completes the C++ reference documentation. For more examples and advanced patterns, see the working modules in [`modules/sdk-test-cpp`](../../modules/sdk-test-cpp) and [`modules/module-test-cpp`](../../modules/module-test-cpp).
This completes the C++ reference documentation. For more examples and advanced patterns, see the working modules in [`modules/sdk-test-cpp`](../../modules/sdk-test-cpp) and [`modules/module-test-cpp`](../../modules/module-test-cpp).
20 changes: 13 additions & 7 deletions crates/bindings-cpp/include/spacetimedb/procedure_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,18 @@ namespace SpacetimeDB {
* @endcode
*/
struct ProcedureContext {
private:
// Caller's identity - who invoked this procedure
Identity sender;

Identity sender_;

public:
// Timestamp when the procedure was invoked
Timestamp timestamp;

// Connection ID for the caller
// Used to track which client connection initiated this procedure
ConnectionId connection_id;

#ifdef SPACETIMEDB_UNSTABLE_FEATURES
// HTTP client for making external requests
// IMPORTANT: HTTP calls are NOT allowed inside transactions!
Expand All @@ -81,7 +83,11 @@ struct ProcedureContext {
ProcedureContext() = default;

ProcedureContext(Identity s, Timestamp t, ConnectionId conn_id)
: sender(s), timestamp(t), connection_id(conn_id) {}
: sender_(s), timestamp(t), connection_id(conn_id) {}

Identity sender() const {
return sender_;
}

/**
* @brief Read the current module's Identity
Expand Down Expand Up @@ -197,7 +203,7 @@ struct ProcedureContext {
// Create a ReducerContext for this transaction
// Note: connection_id converted to std::optional
ReducerContext reducer_ctx(
sender,
sender(),
std::optional<ConnectionId>(connection_id),
Timestamp::from_micros_since_epoch(tx_timestamp)
);
Expand Down Expand Up @@ -260,7 +266,7 @@ struct ProcedureContext {

// Create a ReducerContext for this transaction
ReducerContext reducer_ctx(
sender,
sender(),
std::optional<ConnectionId>(connection_id),
Timestamp::from_micros_since_epoch(tx_timestamp)
);
Expand Down
13 changes: 10 additions & 3 deletions crates/bindings-cpp/include/spacetimedb/reducer_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ namespace SpacetimeDB {

// Enhanced ReducerContext with database access - matches Rust pattern
struct ReducerContext {
// Core fields - directly accessible like in Rust
Identity sender;
private:
Identity sender_;

public:
// Core fields - sender is exposed via sender() like Rust, other fields remain directly accessible
std::optional<ConnectionId> connection_id;
Timestamp timestamp;

Expand All @@ -37,6 +40,10 @@ struct ReducerContext {
mutable uint32_t counter_uuid_ = 0;

public:
Identity sender() const {
return sender_;
}

// Returns the authorization information for the caller of this reducer
const AuthCtx& sender_auth() const {
return sender_auth_;
Expand Down Expand Up @@ -110,7 +117,7 @@ struct ReducerContext {
ReducerContext() : sender_auth_(AuthCtx::internal()) {}

ReducerContext(Identity s, std::optional<ConnectionId> cid, Timestamp ts)
: sender(s), connection_id(cid), timestamp(ts),
: sender_(s), connection_id(cid), timestamp(ts),
sender_auth_(AuthCtx::from_connection_id_opt(cid, s)) {}
};

Expand Down
4 changes: 2 additions & 2 deletions crates/bindings-cpp/include/spacetimedb/reducer_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
* @usage
* ```cpp
* SPACETIMEDB_CLIENT_CONNECTED(on_connect, ReducerContext ctx) {
* LOG_INFO("Client connected: " + ctx.sender.to_hex());
* LOG_INFO("Client connected: " + ctx.sender().to_hex());
* return Ok();
* }
* ```
Expand All @@ -149,7 +149,7 @@
* @usage
* ```cpp
* SPACETIMEDB_CLIENT_DISCONNECTED(on_disconnect, ReducerContext ctx) {
* LOG_INFO("Client disconnected: " + ctx.sender.to_hex());
* LOG_INFO("Client disconnected: " + ctx.sender().to_hex());
* return Ok();
* }
* ```
Expand Down
6 changes: 3 additions & 3 deletions crates/bindings-cpp/include/spacetimedb/tx_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,21 @@ struct TxContext {
public:
// Public references to ReducerContext fields for consistent API with Rust
// In Rust, Deref makes tx.db work the same as ctx.db
// In C++, we explicitly expose references to achieve the same ergonomics
// In C++, we explicitly expose references where possible and provide
// accessors for fields exposed as methods on ReducerContext.
DatabaseContext& db;
const Identity& sender;
const Timestamp& timestamp;
const std::optional<ConnectionId>& connection_id;

// Constructor - initializes all reference members
explicit TxContext(ReducerContext& ctx)
: ctx_(ctx),
db(ctx.db),
sender(ctx.sender),
timestamp(ctx.timestamp),
connection_id(ctx.connection_id) {}

// Access to ReducerContext methods
Identity sender() const { return ctx_.sender(); }
const AuthCtx& sender_auth() const { return ctx_.sender_auth(); }
Identity identity() const { return ctx_.identity(); }
StdbRng& rng() const { return ctx_.rng(); }
Expand Down
12 changes: 8 additions & 4 deletions crates/bindings-cpp/include/spacetimedb/view_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,29 @@ namespace SpacetimeDB {
* SPACETIMEDB_VIEW(std::vector<Item>, get_my_items, Public, ViewContext ctx) {
* std::vector<Item> my_items;
* // Filter by caller's identity using indexed field
* for (const auto& item : ctx.db[item_owner].filter(ctx.sender)) {
* for (const auto& item : ctx.db[item_owner].filter(ctx.sender())) {
* my_items.push_back(item);
* }
* return Ok(my_items);
* }
* @endcode
*/
struct ViewContext {
private:
// Caller's identity - who invoked this view
Identity sender;

Identity sender_;

public:
// Read-only database access - no mutations allowed
ReadOnlyDatabaseContext db;

// Constructors
ViewContext() = default;

explicit ViewContext(Identity s)
: sender(s) {}
: sender_(s) {}

Identity sender() const { return sender_; }
};

/**
Expand Down
Loading
Loading