# Description of Changes
This comes up when doing a fresh `dotnet test`, which causes `dotnet
test -warnaserror` to fail in CI:
```
➜ dotnet test -warnaserror
Determining projects to restore...
Restored /home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/Runtime/Runtime.csproj (in 126 ms).
Restored /home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/BSATN.Runtime/BSATN.Runtime.csproj (in 133 ms).
Restored /home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/BSATN.Runtime.Tests/BSATN.Runtime.Tests.csproj (in 142 ms).
Restored /home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/BSATN.Codegen/BSATN.Codegen.csproj (in 148 ms).
Restored /home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/Codegen/Codegen.csproj (in 148 ms).
Restored /home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/Codegen.Tests/Codegen.Tests.csproj (in 280 ms).
BSATN.Codegen -> /home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/BSATN.Codegen/bin/Debug/netstandard2.0/SpacetimeDB.BSATN.Codegen.dll
BSATN.Runtime -> /home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/BSATN.Runtime/bin/Debug/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
Codegen -> /home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/Codegen/bin/Debug/netstandard2.0/SpacetimeDB.Codegen.dll
/home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/BSATN.Runtime/QueryBuilder.cs(880,9): error CA1510: Use 'ArgumentNullException.ThrowIfNull' instead of explicitly throwing a new exception instance (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1510) [/home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/BSATN.Runtime/BSATN.Runtime.csproj::TargetFramework=net8.0]
/home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/BSATN.Runtime/Builtins.cs(3,1): error IDE0005: Using directive is unnecessary. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0005) [/home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/BSATN.Runtime/BSATN.Runtime.csproj::TargetFramework=net8.0]
BSATN.Runtime -> /home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/BSATN.Runtime/bin/Debug/net8.0/SpacetimeDB.BSATN.Runtime.dll
Codegen.Tests -> /home/work/SpacetimeDBPrivate/public/crates/bindings-csharp/Codegen.Tests/bin/Debug/net8.0/Codegen.Tests.dll
```
The fix is done by AI.
# API and ABI breaking changes
None. Behavior should be the same.
# Expected complexity level and risk
1
# Testing
`git clean -fdx . && dotnet test -warnaserror` no longer fails
---------
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
## Summary
Prevents `spacetime version uninstall <ver>` from showing a confirmation
prompt when the version isn't installed, which previously resulted in a
cryptic "No such file or directory (os error 2)" error after the user
confirmed.
## Changes
### Bug fix
- Check if the version directory exists **before** showing the y/N
prompt
- Return a clear error message: `v{version} is not installed`
### Tests (4 unit tests)
- `test_uninstall_nonexistent_version_errors_before_prompt` — confirms
error fires before prompt for missing versions
- `test_uninstall_current_version_errors` — confirms you can't uninstall
the active version
- `test_uninstall_current_keyword_errors` — confirms the literal string
"current" is rejected
- `test_uninstall_existing_version_with_yes` — confirms normal uninstall
flow works
## Verification
```
cargo check -p spacetimedb-update
cargo clippy -p spacetimedb-update -- -D warnings
cargo test -p spacetimedb-update uninstall
```
## Reproduction
Before this fix:
```
$ spacetime version uninstall 2.0.3
Uninstall v2.0.3? yes
Error: No such file or directory (os error 2)
```
After this fix:
```
$ spacetime version uninstall 2.0.3
Error: v2.0.3 is not installed
```
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
## Summary
- add `ReducerContext::database_identity()` in Rust bindings
- deprecate `ReducerContext::identity()` and keep it as a compatibility
alias
- update reducer docs example to use `ctx.database_identity()`
- add C# reducer-context equivalent: `DatabaseIdentity` and obsolete
`Identity` alias
- update Rust/C# module test callsites to the new API name
- update C# codegen snapshots for generated `ReducerContext` API output
## Why
Issue #3201 reports user confusion between reducer `ctx.identity()`
(database/module identity) and `ctx.sender`. This change clarifies
naming while preserving compatibility.
## Validation
- `cargo check -p spacetimedb -p module-test` (Passed)
- `dotnet test crates/bindings-csharp/Codegen.Tests/Codegen.Tests.csproj
--nologo` (Passed)
- `dotnet test crates/bindings-csharp/Runtime.Tests/Runtime.Tests.csproj
--nologo` (Failed) pre-existing unrelated failure:
- `Runtime.Tests/JwtClaimsTest.cs(10,23): CS1729: 'JwtClaims' does not
contain a constructor that takes 2 arguments`
## Compatibility
- Rust: `identity()` still works but is deprecated in favor of
`database_identity()`.
- C#: `Identity` still works but is marked `[Obsolete]` in favor of
`DatabaseIdentity`.
Closes#3201
# Description of Changes
This patch aims to improve the situation for the need of a generic
function over multiple `ctxs`.
The `DbContext` was introduced for this but due to the associated type
amibguity when trying to implement it another mmethod is needed.
This pr implements a `db_read_only()` method which always results in a
`LocalReadOnly` hence Rust can infer the types of a the returned type
(which prior to this was either `__view , __query and a 3rd one i cent
remember right now 😓`.
I have chosen to be defensive by implementing it as `unstable` but i can
also remove this if that is desired.
It allows the following pattern which has been workig great in my
project so its time to contribute it :>
```rust
pub(crate) trait YourTableNameRead {
// Your methods which only need read access
fn test(&self,args);
}
// The read version is a supertrait to give access to the read methods.
pub(crate) trait YourTableNameWrite: YourTableNameRead {
// Your methods which need read-write access
}
// The read version gets implemented for every DbContext since we can always read.
impl<Db: DbContext> YourTableNameRead for Db {
fn test(&self,args) {
self.db_read_only().table_name().whatever(args);
}
// By constraining the associated type to Local we only get this for writeable ctxs.
impl<Db: DbContext<DbView = Local>> YourTableNameWrite for Db {}
```
These allow you to do on the calling site:
```rust
use YourTableNameRead;
#[view|reducer|procedure]
fn my_func(ctx: Reducer|(Anon)View|Tx, args ) {
ctx.test(args);
}
```
# API and ABI breaking changes
None
# Expected complexity level and risk
1. Minor api and qol adition which is furthermore unstable.
# Testing
- [x] Works in my project
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
<!-- Please describe your change, mention any related tickets, and so on
here. -->
- Bumps version to 2.2.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 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] Version number is correct (`2.2.0`)
- [x] BSL license file has been updated with the new date and version
number
---------
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
As reported in #4886, `metadata.toml` can get get lost if the server
crashes at an unfortunate point in time. To mitigate that, make
`path_type::write` replace the file atomically, and issue `fsync` on the
file and enclosing directory.
# Expected complexity level and risk
1
# Description of Changes
Disclaimer: This description was written by claude:
The two `.leader()` call sites in
[`client-api/src/routes/database.rs`](crates/client-api/src/routes/database.rs)
and
[`client-api/src/routes/subscribe.rs`](crates/client-api/src/routes/subscribe.rs)
pipe `GetLeaderHostError` through `log_and_500`, which:
1. Logs every error variant at `error` level — including `Suspended`,
`Bootstrapping`, `NoLeader`, etc., which are normal operational states.
This produces noisy log lines like:
```
ERROR /app/.../client-api/src/lib.rs:623: internal error: database is
suspended
```
2. Forces every such error into a **500 Internal Server Error**
response, even when the appropriate status code is something else (e.g.
503 Service Unavailable for a suspended database).
`GetLeaderHostError` already implements
`Into<axum::response::ErrorResponse>` with the correct per-variant
mapping:
| Variant | Status |
|---|---|
| `NoSuchDatabase` | 404 Not Found |
| `LaunchError`, `Misdirected` | 500 Internal Server Error |
| `NoNodeId`, `NoLeader`, `ControlConnection`, `Suspended`,
`Bootstrapping` | 503 Service Unavailable |
The standalone implementation already uses `?`-propagation directly.
This PR makes the two client-api call sites match that pattern.
## Result
- Suspended / bootstrapping / no-leader databases now return **503**
instead of 500.
- These expected states no longer produce `error`-level log spam in the
request path. Genuinely unexpected internal errors elsewhere in the
codebase continue to log via `log_and_500` unchanged.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
- [ ] Deploy to staging to see if we still see this error when trying to
access a suspended database
# Description of Changes
Tests for case conversion.
# API and ABI breaking changes
NA
# Expected complexity level and risk
1
---------
Co-authored-by: clockwork-labs-bot <bot@clockworklabs.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
The update version tool sets the
/templates/basic-cpp/spacetimedb/CMakeLists.txt but as we're in the
middle of release this can block the smoketest. This PR changes it to
dynamically change to the `latest` release to allow release night
smoketests to work correctly.
# API and ABI breaking changes
N/A
# Expected complexity level and risk
1 - Small smoketest change
# Testing
- [x] Ran the C++ quickstart smoketest locally
- [x] Updated local template and tested with / without the change
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
When creating or compressing a snapshot, `fsync` all files and
directories, so as to ensure that the snapshot is durable on the local
disk.
This obviously amounts to a large number of `fsync` calls, which may
negatively impact performance of taking a snapshot -- since we hold a
transaction lock while taking a snapshot, this is not to be taken
lightly.
# Expected complexity level and risk
3 -- performance impact
# Testing
I haven't quantified the performance impact.
# Description of Changes
[Some
runtimes](https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream#browser_compatibility)
support brotli for `DecompressionStream`, so I figure we may as
well allow it. Also reorganizes some of the websocket code for better
separation of concerns.
# Expected complexity level and risk
1
# Testing
- [ ] <!-- maybe a test you want to do -->
- [ ] <!-- maybe a test you want a reviewer to do, so they can check it
off when they're satisfied. -->
# Description of Changes
<!-- Please describe your change, mention any related tickets, and so on
here. -->
This was prompted from another request from the discord. Conversation
context:
https://discord.com/channels/1037340874172014652/1138987509834059867/1496964407278698656
We've had the ticket to make `--yes` take an enum value:
https://github.com/clockworklabs/spacetimedb/issues/3784 . Since we can
do this in a non-API/ABI breaking way we're just implementing this
ticket.
*Disclaimer: I used claude to write ~90% of this PR.*
# API and ABI breaking changes
<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->
None. `--yes` now just takes an optional argument string that we parse,
existing CLI commands that use `--yes` will be unaffected.
# Expected complexity level and risk
1 - This is just modifying the `--yes` argument and I've included tests
in the PR.
<!--
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] `spacetime publish --yes` still works as expected
- [x] `spacetime publish --yes=all` does the same thing as `spacetime
publish --yes`
- [x] `spacetime publish --yes=remote` only skips asking if publishing
to a remote server is ok.
- [x] `spacetime publish --yes=remote` only skips asking if publishing
to a remote server is ok.
- [x] `spacetime publish --yes=migrate|remote` skips both the migrate
prompt and the remote server prompt.
- [x] new tests are passing
# Description of Changes
Make Timestamp a FilterableValue in Rust, C#, and Typescript. I'm not
sure this is changing all the places because we have the server and the
client in those 3 languages.
# API and ABI breaking changes
It's an additive change.
# Expected complexity level and risk
3. There are some designs decisions, like comparing timestamp to
strings/numbers.
# Testing
Added unit tests for the 3 languages.
# Description of Changes
This API used to be unimplemented and the SDK tests did not exercise it.
Now it is implemented but while playing with blackholio I noticed the C#
implementation was wrong.
For now I am going to fix blackholio by avoiding use of this API for
now, but we should also correct the implementation and test it.
# API and ABI breaking changes
None
# Expected complexity level and risk
0
# Testing
Working on adding tests. If someone is more familiar with the SDK tests
I would appreciate help amending them.
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
Fix the `spacetime start --listen-addr` help text to match the actual
default value.
The flag already defaults to `0.0.0.0:3000`, but the help text
incorrectly said port 80.
# API and ABI breaking changes
None.
# Expected complexity level and risk
Complexity 1.
# Testing
- [x] `cargo fmt --all --check`
- [x] `cargo check -p spacetimedb-standalone`
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
# Description of Changes
Reapply changes from #4515 after reversion
# API and ABI breaking changes
No API or ABI changes
# Expected complexity level and risk
2 - This PR change itself is trivial, as it just reimplements #4515,
however as #4515 had broken the `quickstart` smoketest, this should be
considered when reviewing this PR.
# Testing
- [X] Tested against `python3 -m smoketests quickstart` locally
---------
Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: Tyler Cloutier <cloutiertyler@aol.com>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
# Description of Changes
See the corresponding commits/PRs for descriptions.
# API and ABI breaking changes
None
# Expected complexity level and risk
1 -- individual PRs already reviewed.
# Testing
No semantic changes.
# Description of Changes
This adds an `enabled` option to the `useTable` hook in the React SDK,
allowing devs to conditionally disable a subscription without having to
wrap it in a component that is conditionally mounted.
With `enabled`, you can control subscription lifecycle as such:
```tsx
const [rows, isReady] = useTable(tables.messages, { enabled: isChatOpen });
```
This is a similar pattern in other data hooks (React Query's `useQuery`,
SWR, Apollo's `useSubscription`, etc).
When `enabled` is `false`:
- `computeSnapshot` returns `[[], true]` immediately (no data, ready
state)
- The subscription effect skips setup and resets `subscribeApplied`
- The event listener callback returns a no-op cleanup
When `enabled` flips back to `true`, the subscription is re-established
automatically via the dependency arrays.
# API and ABI breaking changes
None. The `enabled` field is optional and defaults to `true`, so
existing usage is unaffected.
# Expected complexity level and risk
1 — Single file change, additive only. The `enabled` flag gates existing
behavior behind early returns and is wired into the existing dependency
arrays. No interaction with other components.
# Testing I Did
- [x] Verify `useTable(tables.foo)` works as before (no `enabled` option
passed)
- [x] Verify `useTable(tables.foo, { enabled: false })` returns `[[],
true]` and does not subscribe
- [x] Verify toggling `enabled` from `false` to `true` establishes the
subscription and returns rows
- [x] Verify toggling `enabled` from `true` to `false` clears rows and
unsubscribes
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
# Description of Changes
Users have an odd tendency to overuse this param, which is really meant
for testing and some exceptional circumstances.
This PR hides it from the help so that it is less discoverable.
# API and ABI breaking changes
None.
# Expected complexity level and risk
1
# Testing
- [x] Helptext no longer includes `--server-issued-login`
---------
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
# Description of Changes
`MutTxId::add_columns_to_table` creates new table but only copies
sequences to in-memory state, which causes `autoinc` columns to reset on
module restart.
The existing implementation relies on `create_table_and_update_seq`
helper, which only updates the sequence state in memory. This change
ensures that the `allocation` is also persisted to the system table,
keeping it consistent across restarts.
# API and ABI breaking changes
NA
# Expected complexity level and risk
2
# Testing
Added a test, which migrate table and checks for `autoinc` column value
without and with restart.
---------
Signed-off-by: Shubham Mishra <shivam828787@gmail.com>
Co-authored-by: Mazdak Farrokhzad <twingoow@gmail.com>
# Description of Changes
1. This adds some basic tests of `LockedFile` (which would generally
have also passed before these changes).
2. `LockedFile` can now have contents, which are added to the errors if
we can't aquire the lock. The default metadata has the pid and a
timestamp.
I now see that there is a separate `Lockfile` that doesn't clean up
locks on a crash, so that should probably also be cleaned up (but in a
separate PR).
# Expected complexity level and risk
1.
# Testing
This has unit tests.
# Description of Changes
Revert the following PRs that have caused some breakage:
```
a32cffa76 Finish refactoring out replay (#4850)
d639be0af Replay: some code motion & reuse `ReplayCommittedState` (#4849)
78d6b6f7d Update NativeAOT-LLVM infrastructure to current ABI (#4515)
d5c1738c1 Better module backtraces for panics and whatnot (#577)
6f23b19f3 Wait for database update to become durable (#4846)
81c9eab86 Add `spacetime lock/unlock` to prevent accidental database deletion (#4502)
809aebd7c Move field `replay_table_updated` to `ReplayCommittedState` (#4807)
21b58ef99 Update axum (#2713)
b5cadff7a Extract replay stuff out of `CommittedState`, part 1 (#4804)
```
I also updated the Python smoketests for breakage introduced in
https://github.com/clockworklabs/SpacetimeDB/pull/4502. Reverting that
PR caused conflicts, so this fix is more straightforward.
# API and ABI breaking changes
Maybe kind of, but we haven't released any of these.
# Expected complexity level and risk
1
# Testing
Ask @bfops about testing
---------
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
# Description of Changes
Move the rest of replay logic to `mod replay`.
Closes#4055.
# API and ABI breaking changes
None
# Expected complexity level and risk
2
# Testing
Just code motion.
# Description of Changes
Index code housekeeping: Privatizes `TableIndex` fields, fixes
`insert_index` panic logic, and adds some useful helpers for future
work.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
Covered by existing tests
# Description of Changes
Add support for btree indices where the keys are encoded byte strings
for e.g., multi-column indices of no-unbounded-types (arrays and
strings) that aren't floats.
The main interesting stuff in this PR is in `bytes_key.rs` which defines
`RangeCompatBytesKey`, a type that is derived from `BytesKey`, by
converting little-endian encoded integers to big-endian. Signed integers
are now also supported, but floats are not. `table_index/mod.rs` also
includes a bunch of interesting stuff.
# API and ABI breaking changes
Technically this fixes pre-existing bugs in the handling of `Excluded`
ranges for multi-col indices.
# Expected complexity level and risk
2?
# Testing
- A proptest `order_in_bsatn_is_preserved` is now adjusted and enabled
to exercise the ordering of `RangeCompatBytesKey`.
- A proptest `btree_multi_col_range_scans_work` is added to check the
behavior of range scans on multi-col indices.
---------
Co-authored-by: joshua-spacetime <josh@clockworklabs.io>
This fix is intended to resolve the community reported issue #4659
# Description of Changes
Add handling for `UnaryOperator::Minus` and `UnaryOperator::Plus` in a
new `parse_insert_value()` used during `INSERT` operations. This works
by convert negative unary expressions to signed numeric strings in
INSERT VALUES clauses.
# API and ABI breaking changes
None.
# Expected complexity level and risk
1 (Low). Localized parser fix.
# Testing
- [X] Ran local tests to verify negative numbers work in Rust,
TypeScript, and C# modules
- [X] Confirmed positive numbers and invalid expressions still work
correctly
* Testing involved running `spacetime sql module "INSERT INTO table
(col) VALUES (-100.0);"` from a CLI.
---------
Co-authored-by: joshua-spacetime <josh@clockworklabs.io>
# Description of Changes
Similar to some changes made in
https://github.com/clockworklabs/SpacetimeDB/pull/4269.
Found another smoketest with a name collision which could cause flakes
when running against a remote server.
# 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
# Testing
- [ ] Smoketests pass
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
# Description of Changes
Uses `Isolate::add_near_heap_limit_callback` to prevent unbounded heap
growth. Upon nearing the heap limit, we will now:
1. Call `Isolate::terminate_execution`.
2. Request that v8 double the heap limit.
Then, upon finishing a function call, we lower the heap limit back down.
This should hopefully fix the issue where v8 hits the heap limit and
crashes the whole process.
Also improves the way termination requests are checked for and
processed.
# Expected complexity level and risk
2
# Testing
- [ ] Manual testing with memory-leaky modules
# Description of Changes
First two commits are code motion.
The second commit fixes a mistake I made in a previous PR that made us
use potentially several `ReplayCommittedState`s per
`datastore.replay(..)`.
More to come in terms of PRs; stay tuned.
# API and ABI breaking changes
None
# Expected complexity level and risk
3
# Description of Changes
Similar to https://github.com/clockworklabs/SpacetimeDB/pull/4801, after
we evaluate subscriptions on the main database thread, we send the
results to a worker whose job it is to fan out the updates for the
relevant clients. Hence we want to make sure this worker is not
constantly parked on `recv()` as each `send` on the main thread will
incur overhead waking the task.
To avoid this I've added a utility that wraps an `mpsc`
`UnboundedReceiver` with an adaptive "linger" policy. On each message
`recv`, the worker will now "linger" for a period of time and wait for
any more messages before parking itself on the `recv()` again.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
Manual performance testing for now. Automation to follow.
## Summary
- Update the experimental NativeAOT-LLVM build path
(`EXPERIMENTAL_WASM_AOT=1`) to include all host function imports from
ABI versions 10.0 through 10.4
- Fix the compiler package reference to work on both Windows x64 and
Linux x64 (was hardcoded to Windows only)
- Add a CI smoketest to verify AOT builds work on Linux x64
## Context
See #4514 for the full writeup on the C# AOT situation. The
`wasi-experimental` workload that all C# module builds depend on is
deprecated and removed from .NET 9+. NativeAOT-LLVM is the recommended
path forward for ahead-of-time compilation of C# to WebAssembly.
The existing NativeAOT-LLVM support (added by RReverser in #713) was
stale: missing imports added since then and a Windows-only package
reference.
## Changes
**`SpacetimeDB.Runtime.targets`:**
- Add 10 missing `WasmImport` declarations across spacetime_10.0 through
10.4
- Replace `runtime.win-x64.Microsoft.DotNet.ILCompiler.LLVM` with
`runtime.$(NETCoreSdkPortableRuntimeIdentifier).Microsoft.DotNet.ILCompiler.LLVM`
so it resolves correctly on Linux x64 as well
- Use explicit version strings instead of the `$(SpacetimeNamespace)`
variable
**`ci.yml`:**
- Add AOT build smoketest step in the `csharp-testsuite` job
## Test plan
- [x] CI smoketest passes: `EXPERIMENTAL_WASM_AOT=1 dotnet publish -c
Release` builds successfully on Linux x64
- [ ] Existing C# tests continue to pass (no changes to the default
interpreter path)
---------
Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
Closes#4751
# Description of Changes
- Add `useProcedure` React hook that mirrors `useReducer` which returns
a stable, typed callback that queues calls until the connection is ready
- Add `ProcedureParamsType` and `ProcedureReturnType` utility types to
`type_utils.ts`
- Update TypeScript codegen to emit `export const procedures =
__convertToAccessorMap(proceduresSchema.procedures)` in generated module
bindings, matching the existing pattern for reducers
```ts
import { procedures } from './module_bindings';
import { useProcedure } from 'spacetimedb/react';
const doSomeThing = useProcedure(procedures.doSomeThing);
const result = await doSomeThing({ foo: "..." });
```
# API and ABI breaking changes
None. Additive only — new hook export and new codegen line.
# Expected complexity level and risk
Low. The hook is a near-copy of `useReducer` adapted for procedure
signatures. The codegen change adds one line following the identical
pattern used for reducers.
# Testing
- [x] TypeScript SDK compiles with no new errors (`tsc --noEmit`)
- [x] All 170 existing tests pass (17 test files)
- [x] Tested end-to-end in a React app calling a procedure
---------
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
# Description of Changes
This fixes a bug in TypeScript table default serialization where falsy
defaults like 0, '', false, and explicit undefined were treated as if no
default was provided. I did this as a property check in order to allow
`undefined` which becomes None() as the API allows `T | undefined`.
Closes: #4700
# API and ABI breaking changes
N/A
# Expected complexity level and risk
1 - Simple change to check the default value was added as a property
# Testing
- [x] Reproduced the failing issue in a simple throwaway project
Confirmed reads applies only to subscription clients, calls to the the
HTTP API publish endpoint return a success response before the operation
is confirmed.
While we await scheduling of a new database, updates require to wait for
the update transaction to be confirmed. To allow this, the
`TransactionOffset` channel and the database's `DurableOffset` need to
be returned all the way up to the request handler.
Note that waiting for confirmation is almost always the right choice, so
can't be opted out of at the time of submission of this patch. Callers
may, however, extend the timeout after which waiting for confirmation is
cancelled.
# Description of Changes
Adds a non-repeating scheduled reducer integration test to the existing
Rust and C# integration tests, in order to address #3213
# API and ABI breaking changes
No
# Expected complexity level and risk
1
# Testing
- [X] Ran `cargo test -p spacetimedb-testing` and all tests passed
---------
Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
## Motivation
Feature request: "Is there any way we can lock a module to prevent it
from being deleted? A bit concerned about some fat finger risk of
accidentally deleting prod."
## Solution
Adds a database lock mechanism. A locked database cannot be deleted
until explicitly unlocked.
### New CLI Commands
```bash
# Lock a database to prevent deletion
spacetime lock my-database
# Attempt to delete a locked database (fails with 403)
spacetime delete my-database
# Error: Database is locked and cannot be deleted. Run \`spacetime unlock\` first.
# Unlock when you actually need to delete
spacetime unlock my-database
spacetime delete my-database
```
Both commands support `--server` and `--no-config` flags, and resolve
the database from `spacetime.json` when no argument is given (same as
`spacetime delete`).
### New HTTP API
- `POST /v1/database/:name_or_identity/lock` -- Lock a database
- `POST /v1/database/:name_or_identity/unlock` -- Unlock a database
Both require the same authorization as `DELETE` (owner only).
### Implementation
- Lock state stored in a separate `database_locks` sled tree in the
standalone control DB (avoids changing the `Database` struct and needing
a data migration)
- `ControlStateReadAccess::is_database_locked()` and
`ControlStateWriteAccess::set_database_lock()` added to the trait
- `delete_database` route checks lock state before proceeding; returns
`403 Forbidden` with a descriptive message if locked
- Locking is idempotent (locking an already-locked database is a no-op,
same for unlock)
- Lock only prevents deletion, not publishing updates
### What is NOT locked
- `spacetime publish` (updating module code) still works on locked
databases
- Only `spacetime delete` is blocked
This matches the intent: protect prod from accidental destruction while
allowing normal deployments.
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
While working on #1111 I realised that we have a bug with subscriptions
not being unique when multiple clients with the same identity are
connected. I fixed the bug and only then realised it was already fixed
yesterday in #1121. When working on my changes I created a test for the
issue, so I guess it doesn't hurt to at least submit it.
# Expected complexity level and risk
1
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Fixes#4749.
## Summary
The old report was filed against a `spacetime.toml` path from 1.11-era
CLI flows. On current `master`, the shared TOML config parser already
returns parse failures, but the top-level error does not say which
config file was invalid.
This patch makes the shared TOML config loader add file-path context
while preserving the underlying TOML span details, so users get an error
like `invalid TOML syntax in ...` followed by the parser's line and
column information.
## Testing
- `cargo test -p spacetimedb-core
parse_config_reports_the_invalid_file_path -- --nocapture`
- manual test:
```
➜ cargo run -pspacetimedb-cli -- list
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.33s
Running `target/debug/spacetimedb-cli list`
Error: config file /home/work/.config/spacetime/cli.toml is invalid
Caused by:
TOML parse error at line 5, column 17
|
5 | [[server_configs]
| ^
invalid table header
expected `.`, `]]`
```
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
Shaves another 32 bytes off of `CommittedState` by moving the last
replay only map out of the type.
# API and ABI breaking changes
None
# Expected complexity level and risk
2
# Testing
Covered by existing tests.
# Description of Changes
~~Axum now has what we need out of it for a websocket wrapper, so we no
longer need to duplicate `util/flat_csv.rs` and `util/websocket.rs`,
meaning we have less code to maintain.~~ Nevermind, we know send raw
frames, which axum's wrapper does not support. Makes this PR simpler.
# Expected complexity level and risk
2 - upgrading a dependency is a risk, but looking through the
[changelog](https://github.com/tokio-rs/axum/blob/main/axum/CHANGELOG.md#080)
there isn't anything that should affect us.
# 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] tests pass <!-- maybe a test you want to do -->
- [ ] <!-- maybe a test you want a reviewer to do, so they can check it
off when they're satisfied. -->
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
# Description of Changes
Fixes an issue where running `spacetime dev <database name> --template
chat-react-ts --server maincloud` for an existing database and a new
local project folder would fail with this error:
```sh
Building...
Error: Failed to build project
Caused by:
Module directory does not exist: '/Users/aasoni/./spacetimedb'. Check your --module-path flag or the module-path setting in spacetime.json.
```
Summary of the bug:
- determine_publish_configs was called at line 373 before the project
existed, storing <cwd>/./spacetimedb as the module path
- After init correctly updated spacetimedb_dir to the new project's
path, a later block (lines 454-468) re-read the stale path from the
early publish config and overwrote the correct value
- The rebuild guard at line 498 never triggered because publish_configs
was non-empty (due to the database name CLI argument)
The fix clears publish_configs at the end of the init block, causing the
rebuild at line 498 to run with the correct, post-init spacetimedb_dir.
# API and ABI breaking changes
No
# Expected complexity level and risk
1
# 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] Re-ran `spacetime dev` with various flags to confirm they all
still worked
- [x] Verified that the specific error case was fixed
# Description of Changes
Exports AuthCtx and JwtClaims so that they can be used in helper
functions for checking authentication.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
None, similar to #4567, just adding more exports
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
# Description of Changes
`fetch()` in TypeScript bindings was deserializing the full
`HttpResponse` from BSATN (including headers), but then discarding them
and always returning `new Headers()`. This adds a `deserializeHeaders()`
helper that converts BSATN-deserialized `HttpHeaders` into a
web-standard `Headers` object, so response headers are now correctly
populated on the returned `SyncResponse`.
# API and ABI breaking changes
None. Purely additive — no existing code depended on the (always-empty)
headers.
# Expected complexity level and risk
1 — Single-line behavioral change plus a small helper function. The fix
mirrors the existing request-side encoding pattern.
# Testing
- [x] Unit test: headers survive BSATN serialize/deserialize round-trip
- [x] Unit test: empty headers round-trip correctly
- [x] Verified `deserializeHeaders` uses the same `textDecoder` (UTF-8)
as existing body decoding