Commit Graph

314 Commits

Author SHA1 Message Date
joshua-spacetime a39b81b087 [C#] Primary keys for query builder views (#4626)
# Description of Changes

Same change set as
https://github.com/clockworklabs/SpacetimeDB/pull/4614, just targeting
master.

The return type of a query builder view is now a special SATS product
type `{ __query__: T }`. A view with this return type now has a primary
key if `T` has a primary key. This means that client codegen will
generate an `OnUpdate` callback for such views. It will also generate
query builder index bindings for the primary key column.

# API and ABI breaking changes

None. Old modules with query builder views still work, they just don't
have primary keys.

# Expected complexity level and risk

2

# Testing

Added equivalent tests to the ones that were added in #4573 and #4572.
2026-03-13 00:57:50 +00:00
John Detter 354dd45499 Version bump 2.0.4 (#4600)
# Description of Changes

<!-- Please describe your change, mention any related tickets, and so on
here. -->

- Bumps version to 2.0.4

# API and ABI breaking changes

None - this is just a version bump

<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->

# Expected complexity level and risk

1 - this is just a version bump

<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.

This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.

If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->

# Testing

<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->

- [x] License file has been updated with correct version + time

---------

Signed-off-by: John Detter <4099508+jdetter@users.noreply.github.com>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
2026-03-10 18:37:47 +00:00
joshua-spacetime c5743cfc8d Add implicit query builder conversions from bool to BoolExpr (#4547)
# Description of Changes

Adds implicit query builder conversions from `bool` to `BoolExpr` so
that you can write:
```rust
ctx.from.user().r#where(|u| u.online)
```

instead of
```rust
ctx.from.user().r#where(|u| u.online.eq(true))
```

Also removes `NullableCol` and `NullableIxCol` types from C# query
builder.

# API and ABI breaking changes

None

# Expected complexity level and risk

1

# Testing

Unit and smoketests
2026-03-05 07:14:08 +00:00
John Detter c29a44c50b Version upgrade 2.0.3 (#4489)
# Description of Changes

<!-- Please describe your change, mention any related tickets, and so on
here. -->

- Version upgrade 2.0.3

# API and ABI breaking changes

- None, this is a version bump

<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->

# Expected complexity level and risk

- 1 - this is a version bump

<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.

This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.

If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->

# Testing

<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->

- [x] License has been updated
- [x] Version number is correct (2.0.3)
2026-02-27 20:24:22 +00:00
Zeke Foppa 1e6aa3226c Bump versions to 2.0.2 (#4455)
# Description of Changes

Bumping all versions to 2.0.2 for the release.

# API and ABI breaking changes

None.

# Expected complexity level and risk

1

# Testing

CI

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-02-26 01:54:35 +00:00
Zeke Foppa 88407f0958 Bump versions to 2.0.1 (#4403)
# Description of Changes

Just bumping versions to 2.0.1.

# API and ABI breaking changes

None

# Expected complexity level and risk

1

# Testing
- [ ] CI passes

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-02-23 21:54:10 +00:00
Ryan 85095cfa85 [C#] Removes Query<TRow> and .Build() in favor of IQuery<TRow> (#4393)
This fixes an issue with the C# implementation of Query Builder
requiring `Build()` to return a query, and the return type being
`Query<TRow>` rather than `IQuery<TRow>`.

# Description of Changes

1. Runtime/query-builder
* Removed the concrete `Query<TRow>` carrier type and every `.Build()`.
Query builder shapes now expose only `IQuery<TRow>` plus `ToSql()`.
* Ensured all builder entry points (tables, joins, filters) continue to
return `IQuery<TRow>`.
2. Source generator + bindings
* Updated `ViewDeclaration` analysis to treat any return type
implementing `SpacetimeDB.IQuery<TRow>` as a SQL view.
* Dispatcher generation now emits
`ViewResultHeader.RawSql(returnValue.ToSql())` . This eliminates a
`Query<TRow>` special-case.
3. Tests, fixtures, regression module
* Converted the C# query-builder unit tests, codegen fixtures, and
regression-test server views to call `ToSql()`/return `IQuery<TRow>`.
* Added coverage proving `RightSemiJoin` (and friends) still satisfy
`IQuery<TRow>`.
4. CLI templates & generated bindings
* Regenerated/edited C# template bindings so
`SubscriptionBuilder.AddQuery` accepts `Func<QueryBuilder,
IQuery<TRow>>` and captures SQL via `ToSql()`.

# API and ABI breaking changes

While technically API breaking, this actually brings the API closer to
the intended design.
* `Query<TRow>` has been removed from the public surface area; any
previous references (including `.Build()` and `.Sql`) must be replaced
with the builder instance itself plus `.ToSql()`.
* View methods must now return an `IQuery<TRow>` (or any custom type
implementing it) when producing SQL for the host.
* Generated C# client bindings now expect typed subscription callbacks
to produce `IQuery<TRow>`, aligning the client SDK with the new runtime
contract.

# Expected complexity level and risk

3 - Medium: Touches runtime, codegen, fixtures, and templates. Risk is
mitigated by parity with Rust semantics and comprehensive test updates,
but downstream modules must recompile to adopt the new interface.

# Testing

- [X] Built CLI and ran regression tests locally with removed `.Build()`
- [X] Ran `dotnet test .\sdks\csharp\tests~\tests.csproj -c Release`
with all tests passing
- [X] Ran `dotnet test
.\crates\bindings-csharp\Codegen.Tests\Codegen.Tests.csproj -c Release`
with all tests passing
2026-02-23 15:34:51 +00:00
Shubham Mishra e2f8a60759 Case conversion (#4263)
# Description of Changes

Update the Default casing policy to `snake_case` for `RawModuleDefV10`.

Messy PR contains changes at different places, so that CI can pass:

Here are the main changes as follows:
- `bindings-macro` & `bindings` crate: `name` macro in Indexes for
canonical name and supply it to `RawModuleDefV10` via `ExplicitNames`.
- `bindings-typescript`: 
- Changes has been reviewed through this PR -
https://github.com/clockworklabs/SpacetimeDB/pull/4308.
   
- `binding-csharp`: a single line change to pass `sourceName` of index
instead of null.
- `codegen`:
  
- Changes has been merged from branch -
https://github.com/clockworklabs/SpacetimeDB/pull/4337.
  
- Except a fix in rust codegen to use canonical name in Query buillder
instead of accessor.
  
- `lib/db/raw_def`: Extends `RawDefModuleV10` structure to support case
conversion.
  
- `schema` crate:
- `validate/v9` - Nothing itself should change or changes in v9
validation logic but the file contains a `CoreValidator` which is shared
with `validate/v10`. No test have t be updated to `validate/v9` which
ensures we aren't regressing it.
- `validate/v10`: This is the main meat, look at the new tests added in
bottom to understand what it does.
     
   -  Rest of the files are either test updates or module bindings. 
     
    ## Testing:
1. Extensive unit tests have been added to verify generated `ModuleDef`
is correct.
2. I have done some e2e testing to verify rust codegen with rust and
typescript modules.
3. I would have like to do more testing for other codegens , I am
continue doing .

I have removed `sql.py` smoketest, as that seems to be already migated
in new framework and was headache to update.

## Expected complexity level and risk
4, It could have side-effect which aren't easily visible.


 
 
 
 
 
 -  -  -

---------

Signed-off-by: Shubham Mishra <shivam828787@gmail.com>
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <bot@clockworklabs.com>
Co-authored-by: joshua-spacetime <josh@clockworklabs.io>
Co-authored-by: Noa <coolreader18@gmail.com>
Co-authored-by: = <cloutiertyler@gmail.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@clockworklabs.io>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: Phoebe Goldman <phoebe@clockworklabs.io>
2026-02-20 10:44:29 +00:00
Piotr Sarnacki c0442ea146 Add smoketests for template generation (#4000)
# Description of Changes

Basic tests for templates, the test tries to generate each of the
template, build and publish the SpacetimeDB part, and build or type
check the client side.

This PR also includes bindings for all of the clients as it's needed for
the tests to work and given the choices to either generate during the
test run or include the bindings in git we chose the latter. This makes
it consistent across the templates as some of them already included
bindings.

# Expected complexity level and risk

1

---------

Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
2026-02-19 02:51:05 +00:00
Ryan ba20c552f5 [C#] Spacetime 2.0 Query Builder behavior validation (#4333)
# Description of Changes

* Extend the C# regression client to cover compound Query Builder
predicates (range filters + boolean combinators) so we ensure the
generated SQL matches the documentation promises. See: `Program.cs`
* Updated the C# documentation snippets to use `.AddQuery(...)` over raw
SQL. See: `00400-subscriptions.md` and `00400-sdk-api.md`

# API and ABI breaking changes

No changes to API or ABI

# Expected complexity level and risk

1

# Testing

- [X] Ran regression tests locally
2026-02-18 23:10:03 +00:00
Ryan e03b7d7516 Updated C# Name attribute to Accessor (#4306)
# Description of Changes

Implementation of #4295

Convert existing `Name` attribute to `Accessor` to support new Canonical
Case conversation of 2.0

# API and ABI breaking changes

Yes, in C# modules, we no longer use the attribute name `Name`, it
should now be `Accessor`

# Expected complexity level and risk

1

# Testing

- [X] Build and tested locally
- [X] Ran regression tests locally
2026-02-17 01:16:16 +00:00
Shubham Mishra e4098f98d9 Rust: macro change name -> accessor (#4264)
## Description of Changes

This PR primarily affects the `bindings-macro` and `schema` crates to
review:

### Core changes

1. Replaces the `name` macro with `accessor` for **Tables, Views,
Procedures, and Reducers** in Rust modules.
2. Extends `RawModuleDefV10` with a new section for:

   * case conversion policies
   * explicit names
    New sections are not validated in this PR so not functional.
3. Updates index behavior:

* Index names are now always **system-generated** for clients. Which
will be fixed in follow-up PR when we start validating RawModuleDef with
explicit names.
   * The `accessor` name for an index is used only inside the module.


## Breaking changes (API/ABI)

1. **Rust modules**

   * The `name` macro must be replaced with `accessor`.

2. **Client bindings (all languages)**

* Index names are now system-generated instead of using explicitly
provided names.


**Complexity:** 3

A follow-up PR will reintroduce explicit names with support for case
conversion.

---------

Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <bot@clockworklabs.com>
2026-02-16 15:23:50 +00:00
Piotr Sarnacki 4c962b9170 spacetime.json config implementation (#4199)
# Description of Changes

This PR implements support for the `spacetime.json` configuration file
that can be used to set up common `generate` and `publish` targets. An
example of `spacetime.json` could look like this:

```
{
  "dev_run": "pnpm dev",
  "generate": [
    { "out-dir": "./foobar", "module-path": "region-module", "language": "c-sharp" },
    { "out-dir": "./global", "module-path": "global-module", "language": "c-sharp" },
  ],
  "publish": {
    "database": "bitcraft",
    "module-path": "spacetimedb",
    "server": "local",
    "children": [
      { "database": "region-1", "module-path": "region-module", server: "local" },
      { "database": "region-2", "module-path": "region-module", server: "local" }
    ]
  }
}
```

With this config, running `spacetime generate` without any arguments
would generate bindings for two targets: `region-module` and
`global-module`. `spacetime publish` without any arguments would publish
three modules, starting from the parent: `bitcraft`, `region-1`, and
`region-2`. On top of that, the command `pnpm dev` would be executed
when using `spacetime dev`.

It is also possible to pass additional command line arguments when
calling the `publish` and `generate` commands, but there are certain
limitations. There is a special case when passing either a module path
to generate or a module name to publish. Doing that will filter out
entries in the config file that do not match. For example, running:

```
spacetime generate --project-path global-module
```

would only generate bindings for the second entry in the `generate`
list.

In a similar fashion, running:

```
spacetime publish region-1
```

would only publish the child database with the name `region-1`

Passing other existing arguments is also possible, but not all of the
arguments are available for multiple configs. For example, when running
`spacetime publish --server maincloud`, the publish command would be
applied to all of the modules listed in the config file, but the
`server` value from the command line arguments would take precedence.
Running with arguments like `--bin-path` would, however, would throw an
error as `--bin-path` makes sense only in a context of a specific
module, thus this wouldn't work: `spacetime publish --bin-path
spacetimedb/target/debug/bitcraft.wasm`. I will throw an error unless
there is only one entry to process, thus `spacetime publish --bin-path
spacetimedb/target/debug/bitcraft.wasm bitcraft` would work, as it
filters the publish targets to one entry.

# API and ABI breaking changes

None

# Expected complexity level and risk

3

The config file in itself is not overly complex, but when coupled with
the CLI it is somewhat tricky to get right. There are also some changes
that I had to make to how clap arguments are validated - because the
values can now come from both the config file and the clap config, we
can't use some of the built-in validations like `required`, or at least
I haven't found a clean way to do so.

# Testing

I've added some automated tests, but more tests and manual testing is
coming.

---------

Signed-off-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: bradleyshep <148254416+bradleyshep@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: = <cloutiertyler@gmail.com>
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
2026-02-15 23:22:44 +00:00
Tyler Cloutier 3f58b5951b Implement event tables (server, Rust/TS/C# codegen + client SDKs) (#4217)
## Summary

Implements event tables end-to-end: server datastore, module bindings
(Rust/TypeScript/C#), client codegen (Rust/TypeScript/C#), client SDKs
(Rust/TypeScript/C#), and integration tests.

Event tables are tables whose rows are ephemeral — they persist to the
commitlog and are delivered to V2 subscribers, but are NOT merged into
committed state. Rows are only visible within the transaction that
inserted them. This is the mechanism that replaces reducer event
callbacks in 2.0.

## What's included

### Server
- `is_event` flag on `RawTableDefV10`, `TableDef`, `TableSchema`
- Event table rows recorded in TxData but skipped during committed state
merge
- Commitlog replay treats event table inserts as no-ops
- Migration validation rejects changing `is_event` between module
versions
- `SELECT * FROM *` excludes event tables
- V1 WebSocket subscriptions to event tables rejected with upgrade
message
- V2 subscription path delivers event table rows correctly
- `CanBeLookupTable` trait — event tables cannot be lookup tables in
semijoins
- Runtime view validation rejects event tables

### Module bindings
- **Rust**: `#[spacetimedb::table(name = my_events, public, event)]`
- **TypeScript**: `table({ event: true }, ...)`
- **C#**: `[Table(Event = true)]`

### Client codegen (`crates/codegen/`)
- **Rust**: Generates `EventTable` impl (insert-only) for event tables,
`Table` impl for normal tables. `CanBeLookupTable` emitted for non-event
tables.
- **TypeScript**: Emits `event: true` in generated table schemas.
`ClientTableCore` type excludes `onDelete`/`onUpdate` for event tables
via conditional types.
- **C#**: Generates classes inheriting from `RemoteEventTableHandle`
(which hides `OnDelete`/`OnBeforeDelete`/`OnUpdate`) for event tables.

### Client SDKs
- **Rust**: `EventTable` trait with insert-only callbacks, client cache
bypass, `count()` returns 0, `iter()` returns empty
- **TypeScript**: Event table cache bypass in `table_cache.ts` — fires
`onInsert` callbacks but doesn't store rows. Type-level narrowing
excludes delete/update methods.
- **C#**: `RemoteEventTableHandle` base class hides delete/update
events. Parse/Apply/PostApply handle `EventTableRows` wire format, skip
cache storage, fire only `OnInsert`.

### Tests
- 9 datastore unit tests (insert/delete/update semantics, replay,
constraints, indexes, auto-inc, cross-tx reset)
- 3 Rust SDK integration tests (basic events, multiple events per
reducer, no persistence across transactions)
- Codegen snapshot tests (Rust, TypeScript, C#)
- Trybuild compile tests (event tables rejected as semijoin lookup
tables)

## Deferred
- `on_delete` codegen for event tables (server only sends inserts;
client synthesis deferred)
- Event tables in subscription joins / views (well-defined but
restricted for now)
- C++ SDK support
- RLS integration test

## API and ABI breaking changes

- `is_event: bool` added to `RawTableDefV10` (appended, defaults to
`false` — existing modules unaffected)
- `CanBeLookupTable` trait bound on semijoin methods in query builder
(all non-event tables implement it, so existing code compiles unchanged)
- `RemoteEventTableHandle` added to C# SDK (new base class for generated
event table handles)

## Expected complexity level and risk

3 — Changes touch the schema pipeline end-to-end and all three client
SDKs, but each individual change is straightforward. The core risk area
is the committed state merge skip in `committed_state.rs`. Client SDK
changes are additive (new code paths for event tables, existing paths
unchanged).

## Testing

- [x] `cargo clippy --workspace --tests --benches` passes
- [x] `cargo test -p spacetimedb-codegen` (snapshot tests)
- [x] `cargo test -p spacetimedb-datastore --features
spacetimedb-schema/test -- event_table` (9 unit tests)
- [x] `pnpm format` passes
- [x] Rust SDK integration tests pass (`event_table_tests` module)

---------

Signed-off-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: joshua-spacetime <josh@clockworklabs.io>
2026-02-15 22:56:20 +00:00
clockwork-labs-bot 927d4c4020 [2.0 Breaking] Update C# client SDK for V2 WebSocket format (#4293)
Re-opened from #4289 which was accidentally merged into its base branch
(`rekhoff/csharp-module-defs-v10-no-et`) instead of `master`.

This is the same PR, now correctly targeting `master`.

---

Original description from #4289:

This PR migrates the C# SDK client path to WebSocket v2 semantics and
aligns behavior with the Rust SDK direction for 2.0, including follow-on
fixes in generation/tests.

See #4289 for full description.

---------

Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
2026-02-13 16:53:38 +00:00
SteveGibson a344465847 Set name of network thread in C# SDK (#4090)
# Description of Changes

Set name for C# SDK network thread. Helpful when profiling and debugging

# API and ABI breaking changes

No breaking changes

# Expected complexity level and risk

1 - Trivial

# Testing

Tested in Unity Profiler

Co-authored-by: SteveGibsonX <stevegibsonxj@gmail.com>
Co-authored-by: Ryan <r.ekhoff@clockworklabs.io>
2026-02-13 15:11:35 +00:00
Tyler Cloutier 2ec07a3f70 Standardize query builder syntax across Rust, TypeScript, and C# (Server/Client) (#4261)
# Description of Changes

Standardizes the query builder API across all three language SDKs (Rust,
TypeScript, C#) for consistency.

**Rust:**
- Rename `Query` struct to `RawQuery`, make `Query` a trait with `fn
into_sql(self) -> String`
- All builder types (`Table`, `FromWhere`, `LeftSemiJoin`,
`RightSemiJoin`) implement `Query<T>` trait
- Views can return `-> impl Query<T>` instead of specifying exact
builder types
- The `#[view]` macro auto-detects `impl Query<T>` and rewrites to
`RawQuery<T>`
- Add `Not` variant to `BoolExpr` with `.not()` method

**TypeScript:**
- Add `ne()` to `ColumnExpression`
- Refactor `BooleanExpr` to `BoolExpr` class with chainable `.and()`,
`.or()`, `.not()` methods
- Make builders valid queries directly (`.build()` deprecated but still
works)
- Deprecate `from()` wrapper — use `tables.person.where(...)` directly
- Merge `query` export into `tables` so table refs are also query
builders
- Add subscription callback form: `subscribe(ctx =>
ctx.from.person.where(...))`
- Unify `useTable` with query builder syntax; deprecate `filter.ts`

**C#:**
- Add `Not()` method to `BoolExpr<TRow>`
- Add `IQuery<TRow>` interface implemented by all builder types
(`Table`, `FromWhere`, `LeftSemiJoin`, `RightSemiJoin`, `Query`)
- Add `ToSql()` to all builder types so `.Build()` is no longer required
- Update `AddQuery` to accept `IQuery<TRow>` instead of `Query<TRow>`

# API and ABI breaking changes

- Rust: `Query<T>` is now a trait (was a struct). The struct is renamed
to `RawQuery<T>`. This is a breaking change for any code that used
`Query<T>` as a type directly.
- TypeScript: `BooleanExpr` is now a `BoolExpr` class (was a
discriminated union type). The `query` export is deprecated in favor of
`tables`.
- C#: `AddQuery` now accepts `Func<QueryBuilder, IQuery<TRow>>` instead
of `Func<QueryBuilder, Query<TRow>>`. Existing `.Build()` calls still
work since `Query<TRow>` implements `IQuery<TRow>`.

# Expected complexity level and risk

3 — Changes touch multiple language SDKs and codegen, but each
individual change is straightforward. The Rust macro rewrite for `impl
Query<T>` detection is the most complex piece. All existing
`.build()`/`.Build()` calls continue to work.

# Testing

- [x] `cargo test -p spacetimedb-query-builder` — 16/16 tests pass
- [x] `cargo check -p spacetimedb` — clean, no warnings
- [x] `cargo check` on views-query, views-sql, views-basic,
views-trapped smoketest modules — all clean
- [x] `cargo test -p spacetimedb-codegen codegen_csharp` — snapshot
updated, passes
- [x] `npm test` (TypeScript) — 101/101 tests pass
- [x] C# QueryBuilder tests — new tests for `Not()`, `IQuery<T>`
interface
- [ ] CI passes
2026-02-13 04:22:49 +00:00
John Detter 50295ac865 Version upgrade to 2.0 (#4252)
# Description of Changes

<!-- Please describe your change, mention any related tickets, and so on
here. -->

- Version upgrade to 2.0.

# API and ABI breaking changes

<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->

# Expected complexity level and risk

1 - this is just a version bump

<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.

This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.

If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->

# Testing

<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->

- [x] License file has been updated
- [x] CI passing

---------

Signed-off-by: John Detter <4099508+jdetter@users.noreply.github.com>
2026-02-12 16:25:49 +00:00
Phoebe Goldman 98585e858d Rename with_module_name -> with_database_name (#4267)
# Description of Changes

Modules are like programs, databases are like processes. Your client
connects to a remote database, not a remote module.

<!-- Please describe your change, mention any related tickets, and so on
here. -->

# API and ABI breaking changes

Yep!

# Expected complexity level and risk

2? I made this change with find + replace, and it's possible that I
borked the edit, or missed some reference somehow. It seems unlikely,
however, that this change will have deeper implications we haven't
considered.

# Testing

N/a
2026-02-12 02:11:33 +00:00
Jason Larabie c59ee1ddc3 [2.0 Breaking] Add --include-private and default private tables to not generate (#4241)
# Description of Changes
Updated the codegen table/function iteration functions to take in a
parameter to check visibility in all locations for the supported
languages.
- Updated the util.rs functions for iterating tables/functions to check
for a CodegenVisibility enum (IncludePrivate, or OnlyPublic)
- Added a new CodegenOptions struct to pass around the CodegenVisibility
and future flags, defaulted visibility to OnlyPublic
- Updated the CLI to return a list of all private tables not included
(added a TODO to check the --include-private opt):
```bash
Optimising module with wasm-opt...
Build finished successfully.
Skipping private tables during codegen: secret_note, secret_order, secret_person.
Generate finished successfully.
```

# API and ABI breaking changes

Technically API breaking as the private tables will no longer be
available. (GitHub labels are not working at the moment)

# Expected complexity level and risk

1 - Simple change the testing took longer

# Testing

Turns out when you remove private tables you invalidate most of the
module_bindings across the system!

- [x] Rust test SDK for all languages
- [x] C# SDK tests
- [x] C# dotnet tests
- [x] Updated and checked snap files
- [x] Updated Blackholio (Unreal + Unity) module_bindings and tested
- [x] Ran Unreal SDK tests

---------

Signed-off-by: Jason Larabie <jason@clockworklabs.io>
2026-02-12 03:08:54 +00:00
Ryan 759f5220b9 [C#] Module bindings for Typed Query Builder (#4159)
# Description of Changes
This is the implementation of the Typed Query Builder for C# modules
outlined in #3750.
This requires the changes from #4146 to be in place before it can
properly function.

This aligns the C# typed query builder SQL formatter with the Rust
implementation:
* Supports `And/Or` with same grouping styles as Rust.
* All comparison operators (`Eq/Neq/Lt/…`) wrap expressions in
parentheses so chained predicates produce byte-for-byte identical SQL.

# API and ABI breaking changes
Not breaking. Existing modules keep producing the same SQL semantics;
only redundant parentheses were added to match the Rust formatter.

# Expected complexity level and risk
2 — localized string-format updates plus parity harness tweaks. Low
functional risk; largest concern is ensuring every comparison path
gained parentheses.

# Testing
- [X] Tested against a local test harness validating output from these
changes match current Rust behavior.

---------

Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: joshua-spacetime <josh@clockworklabs.io>
2026-02-11 01:38:30 +00:00
Ryan a95d754328 Moved C# SDK's packages ignore from SDK's .gitignore to project root (#4211)
# Description of Changes

Moves the `root/sdks/csharp/packages/` directory from the
`root/sdks/csharp/.gitignore` to `root/.gitignore`.
This is to resolve Issue #4207 , which was introduced during the DLLs
generation rework.

`/sdks/csharp/packages/` should be ignored by git, to prevent locally
generated DLLs from accidentally getting added to the repo.

**Root cause:**
When Unity imports a package by URL, it looks at the `.gitignore` list
and filters by it, causing the entire `packages` directory to not be
imported. In earlier versions of Unity (like `2022.3` where this was
initially tested), this was not a problem because Unity would allow us
to do a `dotnet restore`. In modern version of Unity, this is no longer
allowed as all imported packages are considered immutable.

Because the `/sdks/csharp/` is cloned into
`com.clockworklabs.spacetimedbsdk`, if we move at what level the
`root/sdks/csharp/packages/` is ignored at, we can prevent the
accidental inclusion of the DLLs from developers in the SpacetimeDB
repo, while ensuring `com.clockworklabs.spacetimedbsdk` does not contain
a reference to ignore the `packages` directory.

# API and ABI breaking changes

No API or ABI changes

# Expected complexity level and risk

1

If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->

# Testing

- [X] Tested removing the `packages` directory from the `.gitignore`
list on a custom branch of `com.clockworklabs.spacetimedbsdk` to observe
the behavior in both Unity `6000.3.2f1` and `2002.3.62f2`.
2026-02-05 23:45:56 +00:00
Zeke Foppa 8110d78661 gitignore - properly ignore nuget config files (#4192)
# Description of Changes

Ignoring nuget config files regardless of casing, as well as in the root
directory since we generate them there now.

# API and ABI breaking changes

None.

# Expected complexity level and risk

1

# Testing

- [x] Files generated by `write-nuget-config.sh` are now properly
ignored

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-02-03 23:00:17 +00:00
Zeke Foppa 9642562bf2 write-nuget-config.sh resolves paths properly (#4193)
# Description of Changes

The script was running `cd` but using the STDB path as passed, so if it
was run from e.g. the root directory, it would generate incorrect paths.

# API and ABI breaking changes

None

# Expected complexity level and risk

1

# Testing

- [x] Running `sdks/csharp/tools~/write-nuget-config.sh .` from the root
directory generates a `NuGet.Config` that uses correct paths

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-02-03 21:58:18 +00:00
Ryan 0977098ea1 Fix for cargo ci dlls missing some .meta files (#4178)
# Description of Changes
This patches a regression introduced in
[#4033](https://github.com/clockworklabs/SpacetimeDB/pull/4033) where
cargo ci dlls stopped copying the Unity .meta files that live outside
the package skeleton tree:
1. `overlay_unity_meta_skeleton` now copies any
`sdks/csharp/unity-meta-skeleton~/spacetimedb.<pkg>.meta` file into
`sdks/csharp/packages/` before overlaying nested content.
2. Added support for a `version.meta` template inside each skeleton
package; it’s renamed to match the single restored version directory
(e.g. `1.11.2.meta`).
3. Added the missing `version.meta` templates for both
`spacetimedb.bsatn.runtime` and `spacetimedb.runtime`, based on the
historical GUIDs Unity already knows about.

Together this restores the `spacetimedb.bsatn.runtime.meta` and
`<version>.meta` files that Unity requires to keep those folders visible
when developers run `cargo ci dlls` on a clean checkout.

# API and ABI breaking changes
None. This only affects the CI helper responsible for syncing Unity
metadata.

# Expected complexity level and risk
2 — localized changes to the CI helper and skeleton assets. Primary risk
is forgetting a template or mis-copying a GUID; the code paths
themselves are straightforward.

# Testing
- [X] Ran `cargo check -p ci`
- [X] Ran `cargo ci dlls` on a clean tree, verifying that:
  * `sdks/csharp/packages/spacetimedb.bsatn.runtime.meta` exists
* The restored version directory (e.g.
`sdks/csharp/packages/spacetimedb.bsatn.runtime/1.11.2.meta`) exists
- [X] Locally launched Unity with a SpacetimeDB project and had no
errors/issues.
2026-02-03 01:50:07 +00:00
Zeke Foppa 56d7cc8fa8 Bump version to v1.12.0 attempt #2 (#4164)
# Description of Changes

<!-- Please describe your change, mention any related tickets, and so on
here. -->

Copied from: https://github.com/clockworklabs/SpacetimeDB/pull/4084

We originally reverted this because it was causing testsuite flakes in
private. Now we have solved the issue that was causing the flakes so
this should be safe to merge.

Version upgrade to `v1.12.0`.

# API and ABI breaking changes

<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->

None

# Expected complexity level and risk

1 - this is just a version upgrade

<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.

This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.

If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->

# Testing

<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->

The testsuite failures are fixed by
https://github.com/clockworklabs/SpacetimeDB/pull/4120

- [x] License has been properly updated including version number and
date
- [x] CI passes

---------

Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-02-02 23:22:29 +00:00
Ryan 9a8b603565 Adding Abort to C# Websocket (#3352)
# Description of Changes

The implementation of a solution to #3044 , this adds an `Abort`
function to the `WebSocket`, which runs if `Disconnect` is called when
the `WebSocket` is not connected.

# API and ABI breaking changes

Not API breaking.

# Expected complexity level and risk

1

# Testing

- [X] Test locally with a C# CLI test client. 
**Note**: Before change (either on Rust of C# server), server would see
4 `Debug` log entries about connecting, but not see the `Info` log about
the client connection ending like would normally be seen in a
disconnect. After change, server shows no log entries at all, because
connection is properly aborted.
- [x] Test locally with a C# WebGL test client.

---------

Signed-off-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
2026-01-30 18:32:53 +00:00
Zeke Foppa 6772f0c171 Make global.json global again (#4166)
# Description of Changes

We have had several `global.json` files introduced that aren't symlinks
to the root `global.json`.

This PR fixes that drift, and adds a CI check.

# API and ABI breaking changes

None.

# Expected complexity level and risk

2

# Testing

- [x] `cargo ci global-json-policy` succeeds
- [x] `cargo ci global-json-policy` fails if you add a new `global.json`
file somewhere
- [x] Rest of CI passes, confirming that templates are still working
properly

---------

Signed-off-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-01-30 18:24:26 +00:00
Ryan 3fec144086 Added query-with-index C# regression tests (#4123)
# Description of Changes

Adds C# regression tests for Query with Indexes.

# API and ABI breaking changes

No. Regression tests only, does not touch backend code.

# Expected complexity level and risk

1

# Testing

- [X] Built and ran regression tests locally, confirming that new
regression test asserts pass.

---------

Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
2026-01-30 01:45:56 +00:00
Zeke Foppa cd71963efd Revert "Upgrade version to 1.12.0 (#4084)" (#4147)
# Description of Changes

This reverts the version bump, since it seems to be causing test
flakiness somehow.

# API and ABI breaking changes

None

# Expected complexity level and risk

1

# Testing

- [ ] CI passes

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
2026-01-28 17:47:24 +00:00
Ryan 4f0a21f948 C# client typed query builder (#3982)
# Description of Changes
This PR implements the C# client-side typed query builder, as assigned
in https://github.com/clockworklabs/SpacetimeDB/issues/3759.

Key pieces:
* Added a small C# runtime query-builder surface in the client SDK
(`sdks/csharp/src/QueryBuilder.cs`):
  * `Query` (wraps the generated SQL string)
* `Table<TRow, TCols, TIxCols>` (entry point for `All()` / `Where(...)`)
* `Col<TRow, TValue>` and `IxCol<TRow, TValue>` (typed column
references)
  * `BoolExpr` (typed boolean expression composition)
  * SQL identifier quoting + literal formatting helpers (`SqlFormat`)
  * `Join(...)` with `WhereLeft(...)` / `WhereRight(...)`
* `LeftSemijoin(...)` / `RightSemijoin(...)` with `Where(...)` chaining
* Extended C# client bindings codegen (`crates/codegen/src/csharp.rs`)
to generate:
* Per-table/view `*Cols` and `*IxCols` helper classes used by the typed
query builder.
* A generated per-module `QueryBuilder` with a `From` accessor for each
table/view, producing `Table<...>` values.
* A generated `TypedSubscriptionBuilder` which collects
`Query<TRow>.Sql` values and calls the existing subscription API.
* An `AddQuery(Func<QueryBuilder, Query> build)` entry point off
`SubscriptionBuilder`, mirroring the proposal’s Rust API.
* Fixed a codegen naming collision found during regression testing:
* `*Cols`/`*IxCols` helpers are now named after the table/view accessor
name (PascalCase) instead of the row type, since multiple tables/views
can share the same row type (e.g. alias tables / views returning an
existing product type).
* Kept `Cols`/`IxCols` off the public surface:
* `Table.Cols` and `Table.IxCols` are internal, so consumers only access
columns via the `Where(...)`/join predicate lambdas.

C# usage examples (mirroring the proposal’s Rust examples)
1) Typed subscription flow (no raw SQL)
```csharp
void Subscribe(SpacetimeDB.Types.DbConnection conn)
{
conn.SubscriptionBuilder()
    .OnApplied(ctx => { /* ... */ })
    .OnError((ctx, err) => { /* ... */ })
    .AddQuery(qb => qb.From.Users().Build())
    .AddQuery(qb => qb.From.Players().Build())
    .Subscribe();
}
```
2) Typed `WHERE` filters and boolean composition
```csharp
conn.SubscriptionBuilder()
    .OnApplied(ctx => { /* ... */ })
    .OnError((ctx, err) => { /* ... */ })
    .AddQuery(qb => qb.From.Players().Where(p => p.Name.Eq("alice").And(p.IsOnline.Eq(true))).Build())
    .Subscribe();
```
3) “Admin can see all, otherwise only self” (proposal’s “player” view
logic, but client-side)
```csharp
Identity self = /* ... */;

conn.SubscriptionBuilder()
    .AddQuery(qb =>
        qb.From.Players().Where(p =>
            p.Identity.Eq(self)
        )
    )
    .Subscribe();
```
4) Index-column access for query construction (IxCols)
```csharp
conn.SubscriptionBuilder()
    .AddQuery(qb =>
        qb.From.Players().Where(
            qb.From.Players().IxCols.Identity.Eq(self)
        )
    )
    .Subscribe();
```
# API and ABI breaking changes
None.
* Additive client SDK runtime types.
* Additive client bindings codegen output.
* No wire-format changes.
# Expected complexity level and risk
2 - Low to moderate
* Mostly additive code + codegen.
* The main risk is correctness/compat of generated SQL strings and
name/casing conventions across languages; this is mitigated by targeted
unit tests + full C# regression test runs.
# Testing
- [X] Ran run-regression-tests.sh successfully after regenerating C#
bindings.
- [X] Ran C# unit tests using `dotnet test
sdks/csharp/tests~/tests.csproj -c Release`
- [X] Added a new unit test suite
(`sdks/csharp/tests~/QueryBuilderTests.cs`) validating:
  * Identifier quoting / escaping
* Literal formatting (including `Identity`/`ConnectionId`/`Uuid` hex
literals; `U128` integer literal)
  * null + enum unsupported behavior throws
  * Boolean expression parenthesization (`And`/`Or`/`Not`)
  * `Where(...)` overloads including `IxCols`-based predicates
  * left/right semijoin SQL formatting and predicate chaining
2026-01-28 02:12:59 +00:00
John Detter 2044a536b0 Upgrade version to 1.12.0 (#4084)
# Description of Changes

<!-- Please describe your change, mention any related tickets, and so on
here. -->

Version upgrade to `v1.12.0`.

# API and ABI breaking changes

<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->

None

# Expected complexity level and risk

1 - this is just a version upgrade

<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.

This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.

If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->

# Testing

<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->

The testsuite failures are fixed by
https://github.com/clockworklabs/SpacetimeDB/pull/4120

- [x] License has been properly updated including version number and
date
- [x] CI passes

---------

Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
2026-01-27 18:15:36 +00:00
John Detter c3848d53db CI: Fix of C# tests failures (#4121)
# Description of Changes

(jdetter): Github marked Ryan's PR as merged because I rebased it
without updating the base branch first - my bad.
Original PR: https://github.com/clockworklabs/SpacetimeDB/pull/4120

This PR fixes C#-related CI failures when testing against `v1.12.0`
before the corresponding NuGet packages are available on nuget.org.

* CI: Ensure local C# NuGet packages are used consistently
* Pack `crates/bindings-csharp/{BSATN.Runtime,Runtime}` with `-c
Release` so the configured local package sources (`bin/Release`)
actually contain the `.nupkg`s.
* Run `./sdks/csharp/tools~/write-nuget-config.sh` in CI to generate a
`NuGet.Config` that maps `SpacetimeDB.BSATN.Runtime` /
`SpacetimeDB.Runtime` to those local sources (with `nuget.org` as
fallback for non-SpacetimeDB dependencies).
* Add an explicit `dotnet restore --configfile NuGet.Config` step before
tests, and `run dotnet test --no-restore`, so restore always uses the
intended config and does not “accidentally” restore from `nuget.org`.
* `write-nuget-config.sh`: Make NuGet config discovery + mapping
deterministic
* Write `NuGet.Config` (capitalized) and include `<clear />` + an
explicit `nuget.org` source to avoid inherited sources and to keep
`PackageSourceMapping` functional.
* Also write a repo-root `NuGet.Config` so `dotnet publish/pack` invoked
from templates (outside `sdks/csharp/`) still discovers the same
override behavior.
* Smoketests quickstart: avoid `PackageSourceMapping` restore failures
* Ensure smoketest helper packing uses `Release`, and when repo-root
`NuGet.Config` exists, perform `dotnet restore --configfile ...` +
`dotnet pack --no-restore` so pack/restore are evaluated with the same
sources/mapping.
* When editing configs, prefer `NuGet.Config` casing for Linux discovery
and ensure `nuget.org` exists as a source for the fallback mapping.

# API and ABI breaking changes

No changes

# Expected complexity level and risk

1

# Testing

- [X] Locally tested concept after simulating local repro.
- [x] Confirmed CI passes in this branch

---------

Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-01-27 05:22:47 +00:00
Ryan 0f0a867d90 Removing1.5.0 DLLs (#4100)
# Description of Changes

Removes 1.5.0 DLLs from repo

# API and ABI breaking changes

Unity will complain locally until you regenerate the DLLs

# Expected complexity level and risk

1 - Trivial

# Testing

- [x] Confirm CI pass
- [X] Local tests are passing

---------

Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
2026-01-23 21:28:24 +00:00
Piotr Sarnacki cd1ec90d16 Templates naming standarization (#4042)
# Description of Changes

This PR renames the templates to always use shorthand for the language,
specify a framework (or console) if necessary, and shorten the naming in
general

# Expected complexity level and risk

1

# Testing

I've tested generating templates manually

---------

Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
2026-01-23 16:08:23 +00:00
Ryan 1fd3394972 Add cargo ci dlls command for building C# DLLs and NuGet packages (#4033)
# Description of Changes
* Added a new `cargo ci dlls` subcommand to build/pack the in-repo C#
NuGet packages and the C# SDK.
* `cargo ci dlls` restores `sdks/csharp/SpacetimeDB.ClientSDK.csproj`
using the freshly built local package outputs as to populate
`sdks/csharp/packages/**`.
* Added a Unity `.meta` skeleton under
`sdks/csharp/unity-meta-skeleton~/**` and overlays those `.meta` files
onto the latest restored versioned package directory to keep Unity GUIDs
stable and import settings consistent.
* Unity-specific import fixes are captured in the skeleton overlay
(notably: preventing Unity from importing incompatible TFMs like
`net8.0`, and marking analyzer DLLs with the `RoslynAnalyzer` label so
Unity can recognize them).
# How to use (local)
```bash
# Build/pack + restore local packages into sdks/csharp/packages/**
cargo ci dlls
```
# API and ABI breaking changes
N/A
# Expected complexity level and risk
2 - Local developer tooling + file overlay into restore output; no
runtime/SDK API behavior changes.
# Testing
- [x] `cargo check -p ci`
- [x] Ran `cargo ci dlls` and verified the output under
`sdks/csharp/packages/**` and the various NuGet package locations.
- [x] Tested a Unity project importing the SpacetimeDB SDK after
generating output and confirmed no errors.

---------

Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
2026-01-22 18:26:55 +00:00
Ryan 6f91cfd524 Enable RefOption returns from Views to support Views returning a single class (#3964)
# Description of Changes

This PR adds a regression test covering nullable reference-type view
returns in C# modules (e.g. Account? where Account is a class), as
reported in
[#3962](https://github.com/clockworklabs/SpacetimeDB/issues/3962).

```csharp
public static Account? MyAccount(ViewContext ctx)
```
* Updated the C# regression-test server module to include a
reference-type table and views that exercise the RefOption path:
* A new public reference-type table row:
```csharp
[SpacetimeDB.Table(Name = "account", Public = true)]
public partial class Account { ... }
```
* A public at-most-one view that returns a nullable reference type
(Account?) via Find(...):
```csharp
[SpacetimeDB.View(Name = "my_account", Public = true)]
public static Account? MyAccount(ViewContext ctx)
{
    return ctx.Db.account.Identity.Find(ctx.Sender) as Account;
}
```
* A second public view that returns null to ensure the “empty result”
case is exercised:
```csharp
[SpacetimeDB.View(Name = "my_account_missing", Public = true)]
public static Account? MyAccountMissing(ViewContext ctx) => null;
```
* Updated ClientConnected to ensure an Account row exists for the
connecting identity so the “one row” case is deterministic.
* Updated the C# regression-test client to:
  * Subscribe to the new views:
    * `SELECT * FROM my_account`
    * `SELECT * FROM my_account_missing`
  * Assert correct semantics for nullable reference-type view returns:
    * MyAccount.Count == 1
    * MyAccountMissing.Count == 0
* Updated the regression-test server project to use local C#
runtime/codegen project references so the regression module exercises
the in-repo generator/runtime behavior (instead of the published
SpacetimeDB.Runtime package).

# API and ABI breaking changes

None.
* No changes to public module schema/wire format semantics beyond adding
regression-test-only tables/views.
* No behavior changes outside the C# regression test module + harness.

# Expected complexity level and risk

2 - Low

* Changes are isolated to regression tests and project wiring.
* The scenario specifically guards the nullable reference-type
“Option-like view return” path against regressions.

# Testing

<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->

- [X] Ran C# regression tests with no failures in new View tests

Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
2026-01-15 00:21:08 +00:00
Ryan 0b91afadef Fix C# null string serialization error + add regression coverage for Issue #3960 (#3967)
# Description of Changes
This PR fixes a C# SDK/BSATN serialization issue where inserting a
`null` string into a non-nullable `string` column could throw an
`ArgumentNullException` with an unhelpful stack trace, as reported in
[#3960](https://github.com/clockworklabs/SpacetimeDB/issues/3960).

* Updated the C# BSATN runtime to reject `null` for non-nullable
`string` serialization with a clear, actionable error message (guides
users to model nullable strings as `string?` so BSATN encodes an
option).
* Added BSATN runtime unit tests to cover:
  * Non-nullable string rejects `null` with an actionable message
* Nullable string (`RefOption<string, BSATN.String>`) round-trips `null`
* Added end-to-end C# regression-test module + client assertions for
#3960:
  * Inserting `""` into non-nullable `string` succeeds
* Inserting `null` into non-nullable `string` fails with the expected
message
* Inserting `null` into nullable `string?` succeeds and round-trips as
`null`
# API and ABI breaking changes
None.
* No schema or wire-format changes.
* Behavior change is limited to improving the error surfaced when
attempting to serialize null as a non-nullable BSATN `String`, plus
stricter input validation for `ConnectionId` / `Identity` parsing.
# Expected complexity level and risk
2 - Low
* Changes are isolated to regression test coverage.
* No impact on valid serialization paths; only affects invalid/malformed
inputs and improves diagnostics.
# Testing
- [X] Ran C# regression-tests client and verified new tests pass.

---------

Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
2026-01-09 21:46:52 +00:00
Ryan 952402d6ab Fix reducer errors to return message not stack trace (#3965)
# Description of Changes
This PR fixes a C# reducer error-reporting issue where exceptions thrown
in reducers were returned to clients with full stack traces, as reported
in [#3959](https://github.com/clockworklabs/SpacetimeDB/issues/3959).

- Updated the C# reducer host-call error serialization to return only
`Exception.Message` (instead of `Exception.ToString()`), preventing
server-side stack traces from being leaked to clients.
- Added a C# regression-test client assertion to validate reducer
failures do not contain stack traces:
  - `exception.Message` matches the thrown message exactly
- the message does not contain newlines or `" at "` stack-trace markers

# API and ABI breaking changes
None.
- No schema or wire-format changes.
- Behavior change is limited to the *contents* of reducer error strings
returned to clients (stack traces removed).

# Expected complexity level and risk
2 - Low
- Change is isolated to C# reducer error formatting plus a regression
assertion.
- Removes unintended information exposure without affecting reducer
success paths.

# Testing
- [X] Ran C# regression-tests client; verified reducer error message is
preserved and stack trace is not present.
2026-01-09 18:15:42 +00:00
Piotr Sarnacki 3c8836b1a3 Templates rework (#3879)
# Description of Changes

We would like to move all of the templates to a central directory

# API and ABI breaking changes

None

# Expected complexity level and risk

2

# Testing

---------

Co-authored-by: spacetimedb-bot <spacetimedb-bot@users.noreply.github.com>
2026-01-09 15:09:26 +00:00
John Detter 8ab3ef4a19 Version bump to 1.11.2 (#3977)
# Description of Changes

<!-- Please describe your change, mention any related tickets, and so on
here. -->

- Version upgrade to `1.11.2`

# API and ABI breaking changes

<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->

- None, this is just a version bump

# Expected complexity level and risk

1 - no real changes here

<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.

This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.

If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->

# Testing

- NA this is just a version bump, no functionality change here.
2026-01-08 18:55:30 +00:00
Mario Montoya 82d5a4f6c0 Implement SpacetimeType for Result<T, E> (#3790)
# Description of Changes

Closes #3673 

*NOTE*: C++ part will be in another PR

# Expected complexity level and risk

2

Adding a new type touch everywhere

# Testing

- [x] Adding smoke and unit test

---------

Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
2026-01-08 15:50:18 +00:00
Ryan 8dd18f078f C# bindings: add procedure_http_request support + fix HTTP BSATN wire format to match spacetimedb_lib::http (#3944)
# Description of Changes

Rust added procedure-scoped HTTP via the `procedure_http_request` ABI
(see Rust PR #3684) to C# host bindings.

What changed:
1) Fix for BSATN wire format
* Updated C# BSATN wire types for HTTP
(`BSATN.Runtime/HttpWireTypes.cs`) to match exactly the Rust stable
types:
* `spacetimedb_lib::http::Request` fields and order: `method`,
`headers`, `timeout`, `uri`, `version`
* `spacetimedb_lib::http::Response` fields and order: `headers`,
`version`, `code`
* Header pairs are (`name: string, value: bytes`); no additional
metadata is encoded.
* Added explicit “do not reorder/extend” note in the C# wire type file
since the host BSATN-decodes these bytes directly and may trap on
mismatch.
2) C# runtime HTTP client implementation
* Implemented `ProcedureContext.Http` support (`Runtime/Http.cs`) that:
* BSATN-serializes `HttpRequestWire` + sends body bytes via
`procedure_http_request`
* On success, BSATN-decodes `HttpResponseWire` and returns `(response,
body)` as a typed `HttpResponse`
  * On `HTTP_ERROR`, decodes the error payload as a BSATN `string`
* On `WOULD_BLOCK_TRANSACTION`, returns a stable error message (host
rejects blocking HTTP while a mut tx is open)
* Clamps timeouts to 500ms max (matching host behavior documented on the
Rust side)
3) ABI wiring / import plumbing
* Added the `procedure_http_request` import to the C# wasm shim
(`Runtime/bindings.c`) under the `spacetime_10.3` import module.
* Verified the generated C# P/Invoke signature matches the host ABI
(request ptr/len, body ptr/len, out `[BytesSource; 2]`).
4) Procedure entrypoint contract (trap vs errno)
* Updated/clarified the module procedure trampoline behavior
(`Runtime/Internal/Module.call_procedure`): it must either return
`Errno.OK` or trap (log + rethrow). This mirrors the host’s expectations
and avoids “unexpected errno values from guest entrypoints” behavior.
Behavioral notes vs Rust
* Rust bindings may `expect(...)`/panic on “should never happen”
serialization failures; C# runtime explicitly avoids throwing across the
procedure boundary for the HTTP client path and instead returns
`Result.Err` for unexpected failures. This prevents whole-module traps
from user-space HTTP usage while still surfacing rich errors.
* The host remains authoritative on timeout enforcement; C# now mirrors
the effective host clamp (500ms) to keep behavior aligned.

# API and ABI breaking changes

No new host ABI introduced, and does not change the syscall signature.
* This is not an ABI “break” in the host, but it is a guest-side wire
compatibility correction: older C# guests built with the incorrect wire
types could cause the host to trap during BSATN decode. After this PR,
C# guests are compatible with the host’s expected layout.

**Adds API**: `ProcedureContextBase.Http` is available for procedures
No existing public types/method signatures are removed
* A notable difference from Rust's panic behavior is that Rust code
sometimes `expect(...)`s and may panic/trap on internal “should not
happen” cases. On the other hand, C#'s `HttpClient.Send` explicitly
converts unexpected failures into `Result.Err` to avoid trapping the
module. This is a behavioral difference, but not an API break.

# Expected complexity level and risk

2 - Mostly just creating equivalents to the Rust version. 

# Testing

C# regression tests updated to cover:
- [X] Successful request path (`ReadMySchemaViaHttp`)
- [X] Invalid request path (`InvalidHttpRequest`) returning error
without trapping

Testing performed:
- [X] Full regression suite run against local node (see chat log); no
wasm traps, all suites reported `Success`.

---------

Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
2026-01-06 22:51:24 +00:00
Ryan f906be6bd9 Fixed Nullable value-type fields in Views in C# module causing excessive logging (#3949)
# Description of Changes

This PR fixes a C# codegen performance/behavior issue triggered by views
that include nullable value-type fields (e.g. `DbVector2?`), as reported
in #3914.

* Updated the C# BSATN code generator to emit non-boxing equality for
`Nullable<T>` members by using `System.Nullable.Equals(a, b)` rather
than `a.Equals(b)` (which can box and cause excessive host logging/work
in view diff/equality paths).

This causes code generation to change from something like:
``` csharp
// From:
var ___eqNullableIntField = this.NullableIntField.Equals(that.NullableIntField);
// To:
var ___eqNullableIntField = System.Nullable.Equals(
    this.NullableIntField,
    that.NullableIntField
);
```
* Added a regression scenario to the C# regression-test module that
exercises the problematic pattern:
  * A table containing a nullable struct field (`DbVector2? Pos`).
  * A public view that returns rows containing that nullable field.
* A reducer to mutate the nullable field from `some` → `none` → `some`
to force view re-evaluation and diffing.
* Updated the regression-test client to:
  * Subscribe to the new view.
* Validate that the view evaluates successfully and contains the
expected rows.
  * Call the reducer and validate view state after updates.
  * Fail the test if view evaluation/diffing produces errors.

# API and ABI breaking changes

None.
* No changes to public SpacetimeDB schema or wire format semantics.
* Changes are limited to generated equality code and regression tests.

# Expected complexity level and risk

2 - Low
* The codegen change is small and localized (special-casing
`System.Nullable<T>` equality generation).
* Risk is primarily around subtle behavior differences in equality for
nullable value types; however, `System.Nullable.Equals` matches the
expected semantics and avoids boxing.
* Regression tests specifically cover the nullable-struct-in-view
scenario to guard against regressions.

# Testing

<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->

- [X] Ran the C# regression test suite via `run-regression-tests.sh` and
confirmed no errors.
2026-01-06 17:56:05 +00:00
Mario Montoya 8fb0bcf922 Add UUID built-in convenience type to SpacetimeDB (#3538)
# Description of Changes

Closes
[#3290](https://github.com/clockworklabs/SpacetimeDB/issues/3290).

Adds a new "special" type to SATS, `UUID`, which is represented as the
product `{ __uuid__: u128 }`. Adds versions of this type to all of our
various languages' module bindings libraries and client SDKs, and
updates codegen to recognize it and output references to those named
library types. Adds methods for creating new UUIDs according to the V4
(all random) and V7 (timestamp, monotonic counter and random)
specifications.

# API and ABI breaking changes

We add a new type 

# Expected complexity level and risk

2

it impacts all over the code

# Testing

- [x] Extends the Rust and Unreal SDK tests, and the associated
`module-test` modules in Rust, C# and TypeScript, with uses of UUIDs.
- [x] Extends the C# SDK regression tests with uses of UUIDs.
- [x] Extends the TypeScript test suite with tests with uses of UUIDs.

---------

Signed-off-by: Mario Montoya <mamcx@elmalabarista.com>
Co-authored-by: Phoebe Goldman <phoebe@clockworklabs.io>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
2026-01-02 17:17:24 +00:00
Ryan f309ea93f9 Removes C# regression test of TimestampCapabilities (#3908)
# Description of Changes

Removes the `TimestampCapabilities` test from the C# SDK's regression
test suite, due to creating inconsistent failures in automated CI
testing.

# API and ABI breaking changes

Not API/ABI breaking

# Expected complexity level and risk

1

# Testing

- [X] Ran locally, no failures in building or running C# regression
tests
2025-12-19 22:15:13 +00:00
rekhoff 39f01289e5 C# implementation of Transactions for Procedures (#3809)
# Description of Changes

Implements the C# equivalent of #3638

This implement uses inheritance, where abstract base classes (like
`ProcedureContextBase` in `ProcedureContext.cs`) store the core of the
implementation, and then generated wrappers (like `ProcedureContext` in
the generated FFI.cs file) inherit from them.

For error handling, we work like Rust's implementation of `Result<T,E>`
but we require `where E : Exception` because of how exceptions work in
C#. Transaction-level failures come back as a `TxOutcome` and user
errors should follow the `Result<T,E>` pattern. In this implementation,
we have `UnwrapOrThrow()` throws exceptions directly because of C#'s
error handling pattern.

Unlike the Rust implementation's direct `Result` propagation, we are
using an `AbortGuard` pattern (in `ProcedureContext.cs`) for exception
handling, which uses `IDisposable` for automatic cleanup.

Most changes should have fairly similar Rust-equivalents beyond that.
For module authors, the changes here allow for the transation logic to
work like:
```csharp
ctx.TryWithTx<ResultType, Exception>(tx => {
    // transaction logic
    return Result<ResultType, Exception>.Ok(result);
});
```
This change includes a number of tests added to the
`sdks/csharp/examples~/regression-tests/`'s `server` and `client` to
validate the behavior of the changes. `server` changes provide further
usage examples for module authors.

# API and ABI breaking changes

Should not be a breaking change

# Expected complexity level and risk

2

# Testing

- [x] Created Regression Tests that show transitions in procedures
working in various ways, all of which pass.
2025-12-18 18:41:47 +00:00
John Detter eb5000895d Bump versions to 1.11.1 (#3901)
# Description of Changes

<!-- Please describe your change, mention any related tickets, and so on
here. -->

- Bump version numbers to `1.11.1`

# API and ABI breaking changes

<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->

None

# Expected complexity level and risk

1

<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.

This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.

If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->

# Testing

- [x] Verified that the license has been updated
- [x] `spacetime --version` on this commit is correct

There is also a corresponding private PR.
2025-12-18 16:35:50 +00:00
Noa afe169ac4a Fix the issues with scheduling procedures (#3816)
# Description of Changes

This reapplies the patch from #3704, and fixes the issues that were
causing it to deadlock.

The reason it was deadlocking was that it allowed for the following
sequence of events:
* `SchedulerActor::handle_queued()` begins mutable tx
* `ModuleHost::disconnect_client()` submits call to `call_reducer(tx:
None)`
* scheduler submits call to `call_reducer(tx: Some)`
* `WasmModuleInstance::disconnect_client` now has to try to take tx
lock, but the scheduler's call_reducer already holds it and is behind it
in the queue

So, I moved most of the logic from `handle_queued` back to being
executed in the module worker thread, but kept the code in
`scheduler.rs` so that it can all be reasoned about locally.

Fixes #3645. Should I uncomment the implementation of
`ExportFunctionForScheduledTable for F: Procedure` now?

# Expected complexity level and risk

2 - there's a chance that this patch hasn't fully fixed the deadlock
issue from #3704, but I'm quite confident.

# Testing

- [x] Manually verified that deadlock no longer occurs - previously,
`while true; do python -m smoketests schedule_reducer -k
test_scheduled_table_subscription; done` would freeze up in only 2 or 3
iterations, but now it can run for 10 minutes without issues.
2025-12-05 22:27:30 +00:00
Zeke Foppa 141048cdd8 Bump versions to 1.11.0 (#3808)
# Description of Changes

Bumping versions to 1.11.0 in preparation for an upcoming release.

# API and ABI breaking changes

None

# Expected complexity level and risk

1

# Testing

- [x] Existing CI passes

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2025-12-02 22:45:29 +00:00