Commit Graph

61 Commits

Author SHA1 Message Date
Ryan 8a0cd87c4f Adds datastore_index_scan_point_bsatn to C# Runtime (#3909)
# Description of Changes

To resolve #3875, we added exact-match unique index point lookup support
to the C# bindings by introducing and using
`datastore_index_scan_point_bsatn`.

Previously, generated unique index `Find()` was (in at least one
codepath) implemented as:

* A range scan (`datastore_index_scan_range_bsatn`) over a BTree bound,
then
* `SingleOrDefault()` to collapse the results into a single row.
When the scan is empty, `SingleOrDefault()` returns `default(T)`. For
value-type rows this can manifest as a default-initialized row instead
of “missing”, which is what surfaced as “default-ish row” behavior in
views.

Using `datastore_index_scan_point_bsatn` makes the C# implementation
match Rust semantics more closely by performing an exact point lookup
and returning:

* `null` when no rows are found
* the row when exactly one row is found
* (defensively) an error if >1 row is returned (unique index invariant
violation)
Similarly, `datastore_delete_by_index_scan_point_bsatn` was added and
used so deletes-by-unique-key are also exact-match point operations
rather than range deletes.

Runtime updates were made to utilize point scan in `FindSingle(key)` and
in both mutable/read-only unique-index paths.

To keep this non-breaking for existing modules, codegen now detects
whether the table row is a struct or a class and chooses the appropriate
base type:
* Struct rows: `Find()` returns `Row?` (`Nullable<Row>`).
* Class rows: `Find()` returns `Row?` (nullable reference, `null` on
miss).

# API and ABI breaking changes

This change is non-breaking with respect to row type kinds, because
class/record table rows continue to work via
RefUniqueIndex/ReadOnlyRefUniqueIndex while struct rows use
UniqueIndex/ReadOnlyUniqueIndex.

API surface changes:
* Generated `Find()` return type is now nullable (`Row?`) to correctly
represent “missing”.

ABI/runtime:
* Requires the point-scan hostcall import
(`datastore_index_scan_point_bsatn`) to be available; the runtime uses
point-scan for unique lookup (and point delete for unique delete).

# Expected complexity level and risk

Low 2

# Testing

- [X] Local testing: repro module + client validate view and direct
Find() behavior

---------

Signed-off-by: rekhoff <r.ekhoff@clockworklabs.io>
2025-12-20 00:32:37 +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
Cameron Hutchison 62e79fad95 C# Views - Use Name from ViewAttribute instead of Method Name (#3792)
C# Views - Use Name from ViewAttribute instead of Method Name

# Description of Changes

The [documentation for C#
views](https://spacetimedb.com/docs/modules/c-sharp#views) says that
"Views must be declared as Public, **with an explicit Name**, and
[...]". However, the `Name` provided to the `View` attribute is not
being used as the name of the view in the Module or the generated C#
client SDK code. The `ViewDeclaration` actually checks that the `View`
attribute's name is not null or empty, but then proceeds to do nothing
with it.

This PR updates the `ViewDeclaration` to use the `Name` property from
`ViewAttribute`.

For more info - see my bug report in Discord:
https://discord.com/channels/1037340874172014652/1443881580602069043

# API and ABI breaking changes

No breaking change to the API. Though, anyone who has a view name
declared that's different from their method name will have to deal with
that during migration of their modules.

# Expected complexity level and risk

1 - Trivial change

# Testing

I compiled the C# projects under `crates/bindings-csharp`, built the
NuGet packages, and tested them locally with a project using SpacetimeDB
1.10 (CLI and associated packages).

I confirmed that the generated classes now use the value from the `View`
attribute as the `RemoteTableName`. See attached image.

<img width="1429" height="372" alt="Screenshot 2025-11-28 at 3 04 48 PM"
src="https://github.com/user-attachments/assets/1db83c14-b0dc-4bcb-87ac-50e104f4d501"
/>

---------

Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: joshua-spacetime <josh@clockworklabs.io>
2025-12-02 07:42:25 +00:00
rekhoff 60e4a640e8 C# module bindings for Procedures (#3732)
# Description of Changes

Implements the C# module bindings for Procedures (#3510)

# API and ABI breaking changes

None

# Expected complexity level and risk

2

# Testing

- [X] Locally tested against existing C# Procedures regression test
client (minus the Transaction and HTTP portions, as those are not in
this change).
2025-11-25 16:50:54 +00:00
rekhoff cb35104c0f Export __call_view__ in C# (#3691)
# Description of Changes

1. Updates the Replication Tests in
`sdks/csharp/examples~/regression-tests` to include better coverage of
Views
2. Added missing linkage for __call_view__ and __call_view_anon__
3. Updated *ViewDispatcher Invoke to transform BSATN.ValueOption<> into
BSATN.List<>
4. Fixed issues with the indexing of views to match correctly during
__call_view__ and __call_view_anon__

# API and ABI breaking changes

No

# Expected complexity level and risk

2

# Testing

- [x] Running `run-regression-tests.sh` passes.

---------

Signed-off-by: rekhoff <r.ekhoff@clockworklabs.io>
Signed-off-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
Co-authored-by: joshua-spacetime <josh@clockworklabs.io>
2025-11-20 17:17:37 +00:00
rekhoff 4143c15b08 C# bindings for views (#3585)
# Description of Changes

Updates C# bindings to allow module authors to define `View`s and
`AnonymousView`s using the pattern:
```
[SpacetimeDB.View]
public static ExampleData? GetExampleDataById(ViewContext ctx, uint id)
{
    return ctx.Db.ExampleData.Id.Find(id);
}
	
[SpacetimeDB.View]
public static ExampleData? GetAnonymousExampleDataById(AnonymousViewContext ctx, uint id)
{
    return ctx.Db.ExampleData.Id.Find(id);
}
```
During publishing of a C# module, the views data will be converted into
`RawViewDefV9`

# API and ABI breaking changes

No known breaking changes

# Expected complexity level and risk

2

# Testing

- [X] Locally tested locally adding the above sample pattern to the
`sdks\csharp\examples~\regression-tests\server` test and performing a
`dotnet build` and a `spacetime publish test`, both of which succeeded.

---------

Signed-off-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
2025-11-11 12:01:44 -05:00
Jeffrey Dallatezza 9586136db7 Treat a missing aud claim as an empty list (#3542)
# Description of Changes

The `aud` claim is required in the OIDC spec, but the server currently
allows it to be missing, and the spacetime auth tokens we use for the
website don't have an audience.

Previously the module bindings would throw an error if there were no
`aud` claim in a jwt payload (if someone used the `audience` within a
reducer), but this change makes us treat a missing audience as an empty
list.

This also renames the `authCtx` fields to `senderAuth` in the typescript
and csharp module APIs, so they match rust.

# API and ABI breaking changes

This doesn't break any ABIs.

This changes the ReducerContext APIs in typescript and rust, but only by
renaming a field that hasn't been released yet.

# Expected complexity level and risk

1.

# Testing

I've tested accessing the `audience` within a reducer for a token
missing an `aud` claim in Typescript and Rust.
2025-10-31 00:48:40 +00:00
Jeffrey Dallatezza bf37b2947b Add bindings for csharp modules to use JWT claims (#3414)
# Description of Changes

This exposes JWT claims for csharp modules, similar to how they are
exposed to rust modules in
https://github.com/clockworklabs/SpacetimeDB/pull/3288.

This adds the new types `AuthCtx` and `JwtClaims`, and adds an `AuthCtx`
to the `ReducerContext`.

`AuthCtx` represents the credentials associated with the request, and
`JwtClaims` represents a jwt token.

One difference from the rust version is that I didn't create helpers to
build an `AuthCtx` from a jwt payload. The reason is that we would need
to be able to compute the identity from the payload claims, which
requires a blake3 hash implementation. The first two c# libraries I
found had issues at runtime
([Blake3](https://www.nuget.org/packages/Blake3) is wrapping a rust
implementation, and
[HashifyNet](https://github.com/Deskasoft/HashifyNET/tree/main/HashifyNet/Algorithms/Blake3)
seems to be broken by our trimming because it uses reflection heavily).
I can look into taking the implementation from `HashifyNet`, since it is
MIT licensed, but I don't think we need to block merging on that.

# API and ABI breaking changes

This adds the new types `AuthCtx` and `JwtClaims`, and adds an `AuthCtx`
to the `ReducerContext`.

This also adds a csharp wrapper for the get_jwt ABI function added in
https://github.com/clockworklabs/SpacetimeDB/pull/3288.

# Expected complexity level and risk

2.

# Testing

This has a very minimal unit test of JwtClaims.

I manually tested using this locally with the csharp quickstart, and I
was able to print jwt tokens inside the module.
2025-10-21 19:17:33 +00:00
rekhoff a546bc8961 Rekhoff/csharp default field values (#3235)
# Description of Changes

This is the implementation of issue #3191. This adds a Default attribute
to C# module fields.

**Note**: In C#, attribute arguments must be compile-time constants,
which means you can't directly use non-constant expressions like new
expressions, method calls, or dynamic values in attribute constructors.
(Ref:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/attributes#2324-attribute-parameter-types)

For this reason, these default values are limited to primitive types,
enums, and strings.
This includes (shown as `C# Type` (`BSATN type`):

* `bool` (`Bool`)
* `sbyte` (`I8`)
* `byte` (`U8`)
* `short` (`I16`)
* `ushort` (`U16`)
* `int` (`I32`)
* `unit` (`U32`)
* `long` (`I64`)
* `ulong` (`U64`)
* `float` (`F32`)
* `double` (`F64`)
* `enum` (`Enum`)
* `string` (`String`)
* `null` (`RefOption`) <- Nullable type

Because of C# limitations, for nullable and complex data types, such as
a struct, can take use `[Default(null)]` to populate values with null
defaults. This allows things like structs to workaround the non-constant
expressions in attribute constructors limitation by allowing these
complex types to still be able to be added as new column tables.

The `int` type can also be in the form of Hex or Binary literals, such
as `[Default(0x2A)]` or `[Default(0b00101010)]`

Both Decimal (like `[Default(3.14m)]`) and Char (like `[Default('A')]`)
are unsupported types in BSATN and will still return `BSATN0001` errors.

# API and ABI breaking changes

Not API breaking.
This change only adds the `[Default(value)]` attribute logic.
Using the `[Default(value)]` attribute with older versions SpacetimeDB
C# modules will result in an error.

# Expected complexity level and risk

2

# Testing

Local testing of this requires use of CLI changes in #3278 

- [x] Regression test of functionality added.
2025-10-06 16:56:37 +00:00
james gilles 0d2a45b239 Fix fields named 'read' (#2525)
# Description of Changes

Fixes
https://github.com/orgs/clockworklabs/projects/22?pane=issue&itemId=102392974&issue=clockworklabs%7Ccom.clockworklabs.spacetimedbsdk%7C276

by renaming `internal` `static` serializer fields so that they do not
overlap with user-provided names.

Note, however, that some field names still will not work: `ReadFields`,
`WriteFields`, `Equals`, and `GetHashCode`.
This would require a separate fix since the error would happen in a
different place. In this case we would need to change the name of the
generated member to something like `ReadFields_` or `Equals_`, which I'm
not sure is a good idea.

# API and ABI breaking changes

N/A

# Expected complexity level and risk

0

# Testing

SDK tests and `dotnet-verify` tests are passing.

---------

Signed-off-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
2025-08-26 21:17:46 +00:00
james gilles 971ae75b5d Improve serialization speed of enums without data in C# (#2762) 2025-06-20 17:38:29 +00:00
james gilles 0d419afbfa Reduce reflection use in generated C# code (#2725) 2025-05-14 18:36:50 +00:00
james gilles 74ad4a14ce Fix Equals and GetHashCode for types containing Lists and Arrays in C# (#2710) 2025-05-12 18:11:01 +00:00
Mazdak Farrokhzad c39f7fa64c Plain enums as index keys with specialized indices (#2506) 2025-04-09 18:52:15 +00:00
joshua-spacetime aac7894aac Feature gate [ClientVisibilityFilter] in C# (#2556) 2025-04-08 20:42:00 +00:00
james gilles 13dfb03135 Add [ClientVisibilityFilter] to csharp module library (#2481) 2025-03-28 19:03:13 +00:00
james gilles f5e4663cb5 Implement IEquatable<Self> for all [SpacetimeDB.Type]s (#2396) 2025-03-12 18:59:34 +00:00
Mazdak Farrokhzad 668eef0d10 bindings-csharp: use the update ABI (#2269)
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
2025-02-22 17:45:28 +00:00
Phoebe Goldman aedc601145 Rename Address to ConnectionId (#2220)
Signed-off-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: James Gilles <jameshgilles@gmail.com>
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
2025-02-10 00:40:16 +00:00
Phoebe Goldman 91327d585e Make Timestamp a special SATS type (#1836)
Signed-off-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: James Gilles <jameshgilles@gmail.com>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
2025-02-07 18:17:53 +00:00
Ingvar Stepanyan 79a9c712f0 Implement new C# index syntax (#2078) 2025-01-07 20:58:17 +00:00
Ingvar Stepanyan 40faad6e2e Implement ctx.Identity for C# (#2091) 2025-01-07 20:45:27 +00:00
Ingvar Stepanyan c87add7349 C#: fix class names for unique column indices (#2088) 2025-01-06 18:58:07 +00:00
Ingvar Stepanyan 78b48c9a98 Reduce noisy C# compilation errors (#2067) 2024-12-30 23:48:50 +00:00
Ingvar Stepanyan 08a3f3210b Migrate C# ModuleDef to V9 (#1670) 2024-12-16 21:49:42 +00:00
james gilles c657b4f088 Rip useless names out of RawDef (#1918) 2024-11-20 21:02:00 +00:00
Ingvar Stepanyan 0935b7346b Fix Find() with struct-based rows (#1917) 2024-10-29 21:33:59 +00:00
Mazdak Farrokhzad 06cc688885 No Maps for you! (#1770) 2024-10-15 22:34:13 +00:00
Jeremie Pelletier 02b70d5c94 c# client generate (#1707) 2024-10-04 04:12:15 +00:00
Ingvar Stepanyan e3de083d08 [C#] [NFC] Some tweaks to the diagnostic tests (#1792) 2024-10-02 22:49:31 +00:00
Ingvar Stepanyan 5ee077e6d9 [C#] [Reducers] Implement new context fields, enum-based kinds, validation (#1729) 2024-10-01 16:30:32 +00:00
Ingvar Stepanyan 8790abde78 [C#] Mark experimental API (#1769) 2024-09-30 21:42:08 +00:00
Ingvar Stepanyan bcdea5702c [C#] Remove .Query support (#1772) 2024-09-30 21:22:29 +00:00
Ingvar Stepanyan 37ac4a43ee [C#] Fix table view names and duplicate table registration (#1757) 2024-09-30 16:17:12 +00:00
Ingvar Stepanyan 49712bfbdf Add C# diagnostics support (#1688) 2024-09-27 19:07:08 +00:00
Ingvar Stepanyan 6ba91bbfc6 Minor attribute cleanups for C# module (#1753) 2024-09-27 15:43:40 +00:00
Jeremie Pelletier 32349062ec Jeremie/cs module (#1719) 2024-09-27 11:23:50 +00:00
SteveGibson 2b09c8d1f8 Logging API (#1714)
Co-authored-by: Steve Boytsun <steve@clockwokrlabs.io>
2024-09-23 14:04:32 -04:00
Ingvar Stepanyan 9f6239991b [C#] [NFC] Reuse attribute classes from runtime (#1718) 2024-09-23 16:47:30 +00:00
Ingvar Stepanyan 214eb7e047 NFC: enforce more C# code style + enable it in Visual Studio (#1687) 2024-09-16 19:29:33 +00:00
Ingvar Stepanyan c8279e1714 C#: hide ReadGenFields from the public API (#1690) 2024-09-10 17:06:39 +00:00
Ingvar Stepanyan 607f7ce6b8 Auto-generate C# ModuleDef bindings from Rust (#1680) 2024-09-09 18:22:17 +00:00
Ingvar Stepanyan 2cccac4e14 C# module benchmarks (#1679) 2024-09-06 18:08:14 +00:00
Mazdak Farrokhzad da71d0f9b1 WASM ABI: insert -> datastore_insert_bsatn & impl new semantics (#1639) 2024-09-05 19:32:26 +00:00
Ingvar Stepanyan 68e356519e C#: split table codegen logic from type codegen logic (#1573)
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2024-09-05 18:00:40 +00:00
Mazdak Farrokhzad 69e881c38f bindings-csharp: pass address_1 (#1621)
Signed-off-by: Mazdak Farrokhzad <twingoow@gmail.com>
Co-authored-by: Ingvar Stepanyan <me@rreverser.com>
2024-09-04 17:36:43 +00:00
Mazdak Farrokhzad 4c086fef96 [WASM ABI 1.0] impl __call_reducer__ & __describe_module__ using bytes_sink_write (#1615) 2024-08-27 15:48:40 +00:00
Noa c577d509c6 Add volatile_nonatomic_schedule_immediate (#1612) 2024-08-23 18:38:07 +00:00
Ingvar Stepanyan 9f1b6dc254 NFC: enforce style for C# locally and on CI (#1567) 2024-08-21 16:21:45 +00:00
Mazdak Farrokhzad 3be5c83d99 [WASM ABI 1.0] __call_reducer__ receives Identity & Address by value (#1607)
Signed-off-by: Mazdak Farrokhzad <twingoow@gmail.com>
Co-authored-by: Ingvar Stepanyan <me@rreverser.com>
Co-authored-by: Noa <coolreader18@gmail.com>
2024-08-19 22:20:57 +00:00