# Description of Changes
- [x] : Store "accessor"s names in ModuleDef (for tables, columns, and
indexes for now) and pass them to TableSchema as aliases.
- [x] Create accessor system tables for each of them:
`st_table_accessor`,`st_column_accessor`, `st_index_accessor`
- [x] Update the SQL parsing logic to also consider alias names.
Alias name stored will be same as actual names until we merge
https://github.com/clockworklabs/SpacetimeDB/pull/4263
# API and ABI breaking changes
NA
# Expected complexity level and risk
3
This patch updates SQL name resolution which isn't a very complex change
since table and column name resolution are each handled by their own
helper method.
It also adds new system tables which need to be handle correctly during
restore/replay. We do have regression tests for this that should catch
any incorrect handling or missing steps.
I would say the main risk is that we don't populate cached table and
column schemas with the alias/accessor name. Regression tests have been
added to catch this, but there are edge cases around migrations and
replay that currently aren't covered.
# Testing
Added SQL smoketests that use canonical/accessor table/column names.
They currently fail because we're currently using the accessor name for
both. They should pass once this is updated.
---------
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>
Rewrites the FAQ from 5 basic questions to a comprehensive guide
covering:
- **General** — What is SpacetimeDB, is it only for games, is it
blockchain, licensing, self-hosting
- **Comparisons** — vs Mirror/Photon/networking libs, vs
Firebase/Supabase, vs PostgreSQL
- **Architecture** — Data persistence, real-time sync, reducers vs REST,
module languages, views, procedures
- **Development** — Getting started, `spacetime dev`, SQL usage,
Unity/Unreal/React/framework support, auth
- **Deployment** — Production publishing, hot-swapping modules, schema
migrations, size limits, pricing
- **Troubleshooting** — Global database names (401/403), confusing
generate errors, resetting databases
Content drawn from README, architecture docs, Zen of SpacetimeDB, and
common user questions from GitHub issues and Discord.
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Rewrites the Maincloud deployment guide from a bare-bones stub into a
comprehensive page. Addresses all three points from #3108 plus a
community request for the connection URI.
**New content:**
1. **Finding your module on the dashboard** - Direct URL
(`spacetimedb.com/my-module`) and profile page navigation
2. **Database lifecycle** - Running vs suspended states, automatic
suspension after inactivity, automatic resumption on first request
3. **Next steps section** - Links to dashboard, SpacetimeAuth setup,
quickstart guides, and usage monitoring
**Also added:**
- Prerequisites section (CLI install + `spacetime login` to link web
account)
- Publishing workflow (initial publish, hot-swap updates,
`--delete-data`)
- Client connection code examples for TypeScript, C#, Rust, and C++ with
the Maincloud host URL (`https://maincloud.spacetimedb.com`) - per
community request in #3108
- Database deletion instructions
- Link to pricing page
Closes#3108
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# 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
# Description of Changes
The server upgrade path yells when we upgrade from 1.* to 2.0, but this
upgrade path is confirmed to be good.
# API and ABI breaking changes
None.
# Expected complexity level and risk
2
# Testing
"I" added some unit tests to cover the new cases
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
# Description of Changes
Fixes#3492.
# 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! -->
- [ ] <!-- 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
This PR fixes the bug where WASM procedures could commit a transaction
without refreshing affected materialized views, which caused view-backed
subscriptions to miss updates from procedure writes.
The equivalent changes for V8 will be made in a separate patch.
# API and ABI breaking changes
None
# Expected complexity level and risk
3
This was not a simple translation of the reducer code path, because
reducers are run in a single transaction whereas procedures can have
multiple transactions via `with_tx` and views must be refreshed with
each transaction instead of once at the end of the procedure. This
required refresh to be inserted into the syscall itself which required
some extra plumbing. Mainly that we had to attach the validated
`ModuleDef` to the `WasmInstanceEnv`. This should not affect hotswapping
because we instantiate an entirely new `WasmInstanceEnv` in that case.
# Testing
- [x] Added a regression test in the form of a smoketest that subscribes
to a view and calls a procedure
# Description of Changes
In the typescript quickstart example, this includes the server and
module name in the local storage variable name that we use for the auth
token.
This fixes an otherwise annoying issue people run into if they start
running the quickstart locally, then try to run it on maincloud. If they
have already run the app with a local server, their browser will store
the locally signed token, which will get rejected by maincloud.
# Expected complexity level and risk
1.
# Testing
I was able to connect to my local quickstart, then change the variables
to point to a module on maincloud, and I didn't get any errors.
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
## 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>
# 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>
# Description of Changes
Case conversion addtion to `RawModuleDefV10`.
Chunk has been taken from -
https://github.com/clockworklabs/SpacetimeDB/pull/4264 to unblock
csharp, and ts modules.
# API and ABI breaking changes
NA
Documents the automated agents operating on this repo. Starting with
Clawd (clockwork-labs-bot), the CI watchdog.
This is a living document — new bots/gremlins get documented here.
# API and ABI breaking changes
None — documentation only.
# Expected complexity level and risk
0 — documentation only.
# Testing
N/A — documentation only.
---------
Co-authored-by: clockwork-labs-bot <bot@clockworklabs.com>
# Description of Changes
`Cargo.lock` was getting stale in our smoketests modules, because we
don't check it anywhere. I added a check.
# API and ABI breaking changes
CI only.
# Expected complexity level and risk
1
# Testing
- [x] new CI step fails without the `Cargo.lock` changes
(<https://github.com/clockworklabs/SpacetimeDB/actions/runs/21960035403/job/63435284426?pr=4282>)
- [x] new CI step passes with the `Cargo.lock` changes
---------
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
# Description of Changes
Gitignore a file that's an intermediate artifact of updating the
external client SDKs when the WS protocol gets extended.
# API and ABI breaking changes
N/a
# Expected complexity level and risk
0
# Testing
N/a
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
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>
# 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>
# Description of Changes
Fixes a problem with renaming the project from client_unreal to
blackholio which causes the C++ header code to be incorrect
# API and ABI breaking changes
N/A
# Expected complexity level and risk
1 - Updates a small portion of the Unreal Tutorial documentation
# Testing
Testing the current docs is what found the issue.
- [x] Rebuilt the Unreal Blackholio from the tutorial
---------
Signed-off-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Changes the commitlog (and durability) write API, such that the caller
decides how many transactions are in a single commit, and has to supply
the transaction offsets.
This simplifies commitlog-side buffering logic to essentially a
`BufWriter` (which, of course, we must not forget to flush). This will
help throughput, but offers less opportunity to retry failed writes.
This is probably a good thing, as disks can fail in erratic ways, and we
should rather crash and re-verify the commitlog (suffix) than continue
writing.
To that end, this patch liberally raises panics when there is a chance
that internal state could be "poisoned" by partial writes, which may be
debatable.
# Motivation
The main motivation is to avoid maintaining the transaction offset in
two places in such a way that they could diverge. As ordering commits is
the responsibility of the datastore, we make it authoritative on this
matter -- the commitlog will still check that offsets are contiguous,
and refuse to commit if that's not the case.
A secondary, related motivation is the following:
A "commit" is an atomic unit of storage, meaning that a torn (partial)
write of a commit will render the entire commit corrupt. There hasn't
been a compelling case where we would want this, and have always
configured the server to write exactly one transaction per commit.
The code to handle buffering of transactions is, however, rather
complex, as it tries hard to allow the caller to retry writes at commit
boundaries. An unfortunate consequence of this is that we'd flush to the
OS very often, leaving throughput performance on the table.
So, if there is a compelling case for batching multiple transactions in
a commit, it should be the datastore's responsibility.
# API and ABI breaking changes
Breaks internal APIs only.
# Expected complexity level and risk
5 - Mostly for the risk
# Testing
Existing tests.
# Description of Changes
Implements the rest of the casing proposal.
# Expected complexity level and risk
<!--
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! -->
- [ ] <!-- 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
This is the implementation of #4255
This is a rebuild of #4262 after a rebase throughly messed up that PR's
changelog, this time under `master` branch.
* Refactored `Module` so all V10 builder state and registration helpers
now live on `partial class RawModuleDefV10`. The static `Module` class
simply registers components against that builder and serializes via
`moduleDef.BuildModuleDefinition()`
* Removed the deprecated `__describe_module__` export. Only
`__describe_module_v10__` is emitted now across the runtime, native
shim, generated bindings, and snapshots
* Mirrored the Rust TODO that future V10 sections will cover Event
tables and Case-conversion policy so we don't lose track of those items
Event Tables will be added once they are finished being implemented.
# API and ABI breaking changes
Modules built with these bindings now expose only
`__describe_module_v10__`
The legacy `__describe_module__` symbol is gone from both managed and
native layers. Hosts expecting the old export must switch to the V10
entry point (which is already the canonical ABI for 2.0).
# Expected complexity level and risk
2 - Low. The refactor keeps the previous builder logic but relocates it,
and the export removal matches the already-supported V10 host path.
# Testing
- [X] Successfully built CLI and DLLs without errors.
- [X] Ran `dotnet build crates/bindings-csharp/Runtime/Runtime.csproj`
without errors.
- [X] Ran `dotnet test
crates/bindings-csharp/Codegen.Tests/Codegen.Tests.csproj` without
errors.
- [X] Ran `bash run-regression-tests.sh` without errors.
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# 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
# Description of Changes
Cherry-picks the core event table implementation (`fa83d6d40`,
`07d57a552`) and adds:
1. **Bootstrap fix**: Register `st_event_table` in
`bootstrap_system_tables()` — it was missing from the cherry-picked
commit, causing event table creation to fail at runtime when inserting
into `ST_EVENT_TABLE_ID`.
2. **4 datastore unit tests** covering event table behaviors:
- Insert+delete in the same tx cancels out (no TxData entry, no
committed state)
- Update yields only the final row in TxData (old row replaced, not
accumulated)
- Bare insert records in TxData but not in committed state
- `replay_insert` is a no-op for event tables (commitlog replay doesn't
rebuild state)
3. **Migration validation**: `ChangeTableEventFlag` error in
`auto_migrate.rs` prevents changing a table's event flag
(event→non-event or vice versa) via auto-migration. Includes tests for
both directions and a positive test that identical flags are accepted.
4. **Test fixture updates**: Bootstrap test expectations updated for the
new `st_event_table` system table (table row, column, index ID 23,
constraint ID 19). Enabled `spacetimedb-schema/test` feature in
datastore dev-deps to fix pre-existing test compilation issue with
`for_test` methods.
# API and ABI breaking changes
None. The `ChangeTableEventFlag` error variant is added to the internal
`AutoMigrateError` enum but this is not a public API.
# Expected complexity level and risk
1 — Straightforward additions. The bootstrap fix is a one-liner that was
simply missing from the cherry-pick. The tests exercise existing
behavior without changing it. The migration guard follows the exact same
pattern as the existing `ChangeTableType` check.
# Testing
- [x] `cargo test -p spacetimedb-datastore` — 77 tests pass (73 existing
+ 4 new)
- [x] `cargo test -p spacetimedb-schema --features test --lib` — 98
tests pass (96 existing + 2 new)
- [x] `cargo check --workspace --exclude view-client` — compiles clean
(`view-client` has a pre-existing issue with `CanBeLookupTable` from the
cherry-pick)
- [ ] Reviewer: confirm that the 4 event table test names/assertions
match the behaviors described in review feedback
---------
Signed-off-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: Mazdak Farrokhzad <twingoow@gmail.com>
# Description of Changes
Spiritual successor to #4162.
# 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! -->
- [ ] <!-- 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
Uses the
[`object-inspect`](https://www.npmjs.com/package/object-inspect) package
to stringify objects passed to console methods, so that you can actually
get useful information without having to `JSON.stringify`. Should've
happened a long time ago.
# 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! -->
- [ ] <!-- 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
Update the Rust client SDK to use the new V2 WebSocket format, and
present the V2 user-facing API.
## Reducer events
### Remove on-reducer callbacks
It's no longer possible to observe reducers called by other clients by
registering callbacks with `ctx.reducers.on_{my_reducer}`. We no longer
code-generate those methods, or the associated
`ctx.reducers.remove_on_{my_reducer}`. Internal plumbing for storing and
invoking those callbacks is also removed.
### Add specific reducer invocation callbacks
In addition to the previous way to invoke reducers,
`ctx.reducers.{my_reducer}(args...)`, we add a method that registers a
callback to run after the reducer is finished. This method has the
suffix `_then`, as in `ctx.reducers.{my_reducer}_then(args...,
callback)`.
The callback will accept two arguments:
- `ctx: &ReducerEventContext`, the same context as was previously passed
to on-reducer callbacks.
- `status: Result<Result<(), String>, InternalError>`, denoting the
outcome of the reducer.
- `Ok(Ok(())` means the reducer committed. This corresponds to
`ReducerOutcome::Ok` or `ReducerOutcome::Okmpty` in the new WS format.
- `Ok(Err(message))` means the reducer returned an "expected" or "user"
error. This corresponds to `ReducerOutcome::Err` in the new WS format.
- `Err(internal_error)` means something went wrong with host execution.
This corresponds to `ReducerOutcome::InternalError` in the new WS
format.
Internally, the SDK stores the callbacks in its `ReducerCallbacks` map.
This is keyed on `request_id: u32`, a number that is generated for each
reducer call (from an `AtomicU32` that we increment each time), and
included in the `ClientMessage::CallReducer` request. The
`ServerMessage::ReducerResult` includes the same `request_id`, so the
SDK pops out of the `ReducerCallbacks` and invokes the appropriate
callback when processing that message.
These new callbacks are very similar to the existing procedure
callbacks.
### The `Event` exposed to row callbacks
Row callbacks caused by a reducer invoked by this client will see
`Event::Reducer`, the same as they would prior to this PR. These
callbacks will be the result of a `ServerMessage::ReducerResult` with
`ReducerOutcome::Ok`. In order to expose the reducer name and arguments
to this event, the client stores them in its `ReducerCallbacks` map,
alongside the callback for when the reducer is complete.
Row callbacks caused by any other reducer, or any non-reducer
transaction, are now indistinguishable to the client. These will see
`Event::Transaction`, which is renamed from the old
`Event::UnknownTransaction`.
### Less metadata in `ReducerEvent`
Some metadata is removed from `ReducerEvent`, as the V2 WebSocket format
no longer publishes it, even to the caller.
## `CallReducerFlags` are removed
All machinery for setting, storing and applying call reducer flags is
removed from the SDK, as the new WS format does not have any non-default
flags.
## Requesting rows in unsubscribe
When sending a `ClientMessage::Unsubscribe`, we always request that the
server include the matching rows in its response
`ServerMessage::UnsubscribeApplied`. This saves us having to update the
SDK to store query sets separately, at least for now. (We'll do that
later.)
## Handling rows
The new SDK does some additional parsing to wrangle rows in the new
WebSocket format into the same internal data structures as before,
rather than re-writing the client cache. (We'll do that later.)
Specifically, parsing of `DbUpdate` is changed so that:
- We parse raw `TransactionUpdate` into the generated `DbUpdate` type,
which requires an additional loop compared to the previous version, to
cope with the new WS format's dividing updates by query set. We define a
function `transaction_update_iter_table_updates` which encapsulates this
nested loop in an iterator.
- We have two new functions for parsing raw `QueryRows` into the
generated `DbUpdate` type, one for when they come from a
`SubscribeApplied`, and the other when they come from an
`UnsubscribeApplied`. `QueryRows` from `SubscribeApplied` translate to a
`DbUpdate` of all inserts, while one from `UnsubscribeApplied` will be
all deletes.
## Legacy subscriptions
"Legacy subscriptions" are removed. These were only used for
`subscribe_to_all_tables`, which as of now is stubbed. I will follow up
with a change to re-implement `subscribe_to_all_tables` by
code-generating a list of all known tables, and having it subscribe to
`select * from {table}` for every table in that list.
## `subscribe_to_all_tables` via a list
Previously, `subscribe_to_all_tables` worked by sending a legacy
subscription with the query `SELECT * FROM *`, which the host had
special handling to expand to subscribing to all tables. As legacy
subscriptions are no longer usable in V2 clients, this can't work.
Instead, we code-generate `SpacetimeModule::ALL_TABLE_NAMES`, a list of
all the known table names. `subscribe_to_all_tables` then maps across
this list to construct a list of queries in the form `SELECT * FROM
{table_name}`, and subscribes to all of those queries. This has the
upside that defining a new table in the module without regenerating
client bindings will no longer result in the client seeing rows of
tables it does not know about and cannot parse.
## Light mode removed
Light mode is no longer meaningful in the V2 WS format, so all code
related to it is removed.
## Internal changes
### Renamed WS messages
The SDK's internal code is updated to account for various renames:
- `QueryId` -> `QuerySetId`, `query_id` -> `query_set_id`.
- `SubscribeMulti` -> `Subscribe`, `UnsubscribeMulti` -> `Unsubscribe`.
## Incidental changes in this PR, not necessary for other client SDKs
### Don't filter out empty ranges in `RowSizeHint`
The Rust implementation of `RowSizeHint` in `BsatnRowList` got regressed
in the base branch to not work with zero-sized rows. This change fixes
that.
# API and ABI breaking changes
Boy howdy is it!
# Expected complexity level and risk
3? Changes ended up being less complicated than I feared, but we do have
some fiddly code here, and we have internal dependencies on the SDK.
# 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] Updated automated test suite.
- Known failures:
- [ ] `subscribe_all_select_star`, which is currently broken because
it's trying to subscribe to rows from private tables. #4241 will fix
this.
---------
Co-authored-by: Jeffrey Dallatezza <jeffreydallatezza@gmail.com>
Co-authored-by: = <cloutiertyler@gmail.com>
## Summary
- Restricts `update()` across all three server-side SDKs (Rust, C#,
TypeScript) to only work on primary key columns, not all unique columns
- Calling `update()` on a non-PK unique column is semantically a
delete+insert — clients won't see it as a row update unless the primary
key stays the same
- Fresh re-implementation of #1862, extended to cover C# and TypeScript
bindings
### Design principle
Primary key is a constraint on columns, not a property of indexes. An
index is unique or not unique — whether `update()` is available is
derived from the column's attributes at the point of use, not stored on
the index.
This differs from #1862 which introduced a `Uniqueness` enum (`No |
Unique | PrimaryKey`) on the index itself. Instead, we keep `is_unique:
bool` and check the column metadata where needed.
### Rust changes
- Add `PrimaryKey` marker trait and `where Col: PrimaryKey` bound on
`UniqueColumn::update()`
- `marker_type()` receives `primary_key_column` and checks the column
directly — no `is_pk` field on the index
- `sdk-test` unique tables use `update_non_pk_by` (delete+insert)
instead of `update_by`
- Benchmarks that used `update()` on `#[unique]` columns changed to
either `#[primary_key]` or delete+insert
### C# changes
- Only emit `Update()` on `UniqueIndex` when the column has `PrimaryKey`
attrs
- Update `unique_*` test reducers in `sdk-test-cs` to use
`Delete()`+`Insert()` instead
### TypeScript changes
- `UniqueIndex` now has only `find` + `delete` (no `update`)
- `AllColumnsPrimaryKey` type-level helper checks column metadata from
the `TableDef`
- `Index` routing conditionally intersects `{ update() }` when columns
are PK
- Runtime only attaches `update` method for PK unique indexes
- `sdk-test-ts` unique tables use delete+insert instead of update
- Type-level test in `schema.test-d.ts` verifies `id.update()` compiles
(PK) and `name2.update` errors (non-PK unique)
## Test plan
- [x] C# codegen tests pass (`dotnet test
crates/bindings-csharp/Codegen.Tests`)
- [x] Rust SDK test module compiles
- [x] Benchmarks compile
- [x] TypeScript type checks pass (`npx tsc --noEmit`)
- [ ] CI passes
Closes#1862
# Description of Changes
This update the typescript sdk to use the v2 protocol.
The main user-facing API change is removing the existing reducer
callbacks, and instead having reducers return a `Promise`.
# API and ABI breaking changes
The reducer functions `conn.reducers.onX` and `conn.reducers.removeOnX`
no longer exist, and reducers now return `Promise<void>`.
# Expected complexity level and risk
2.5.
# Testing
This has mostly been tested manually. I'm still updating some of the
unit tests (I commented out the ones that used reducer callbacks).
---------
Co-authored-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: = <cloutiertyler@gmail.com>
# Description of Changes
Hasn't been needed in months (since #3800), it'd be nice to get it in to
2.0 if possible.
# Expected complexity level and risk
1
# Testing
- [x] Builds successfully
- [ ] <!-- maybe a test you want a reviewer to do, so they can check it
off when they're satisfied. -->
# Description of Changes
This adds the v2 websocket protocol and adds support on the server side.
For context on many of the changes/decisions, you can look at the
discussion on https://github.com/clockworklabs/SpacetimeDB/pull/4023.
To restate some of the key changes:
- The reducer event information is no longer sent with transaction
updates (because we don't want to broadcast reducer call information
anymore).
- If a client calls a reducer, they are sent a `ReducerResult` which
includes the outcome of the reducer call and and related row updates for
queries that the client is subscribed to.
- We no longer dedupe queries that appear in multiple query sets for the
same client. This is because we are moving toward per-query storage.
- Related to that, Unsubscribe requests have an option to send the
related rows. We need this for now, since clients don't have per-query
storage implemented yet.
- We don't have the json format in v2.
Notes for reviewers:
- This moves around the messages in
`crates/client-api-messages/src/websocket` (into `common`, `v1`, and
`v2`), and this renaming of existing messages adds a lot of noise to the
PR.
- In many places, I chose to duplicate a lot of code to have a v1
version and a v2 version. I went with this to make it easier to remove
the v1 version in the future (hopefully we can just fully delete most of
the v1 functions).
- `module_subscription_manager.rs` has probably has the biggest changes,
since we now track queries by query_set_id, and we get to remove some
complexity of v1's FormatSwitch.
<!-- Please describe your change, mention any related tickets, and so on
here. -->
# API and ABI breaking changes
The v1 protocol still works, though we won't send the reducer event info
for v10 modules.
# Expected complexity level and risk
4. This touches a lot of places.
# Testing
Unit testing is pretty minimal for the new code paths. I've done some
manual e2e testing with the typescript quickstart, and this has been
tested with a different branch implementing the v2 rust client.
---------
Co-authored-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: Jeffrey Dallatezza <jeffreydallatezza@gmail.com>
# Description of Changes
The output of `spacetime version list` is sorted in alphabetical order,
which is not the correct semver order.
This fixes the order printed, by sorting correctly.
Example before:
```
1.11.0
1.9.0
1.3.0
1.3.1
1.1.2
1.12.0 (current)
1.0.0
```
After:
```
1.12.0 (current)
1.11.0
1.9.0
1.3.1
1.3.0
1.1.2
1.0.0
```
# API and ABI breaking changes
Not an API or ABI breaking change
# Expected complexity level and risk
1
# Testing
Ran `spacetime version list` and `spacetime version list --all` with the
new code and confirmed that the result was correctly sorted.
I additionally tested that if the latest available version was not
installed that it would show with the upgrade hint command.
# Description of Changes
Title.
# API and ABI breaking changes
N/a
# Expected complexity level and risk
1
# Testing
- [ ] Get @coolreader18 to confirm what I've written here is correct.
# Description of Changes
The smoketests try to infer whether to use the built `debug` or
`release` binaries.. but the common invocation via `cargo ci smoketests`
always pre-builds the release binaries. This was causing people to test
the wrong binary locally.
# API and ABI breaking changes
None.
# Expected complexity level and risk
1.
# Testing
- [x] CI passes
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
# Description of Changes
Adjusts the websocket format to use `RawIdentifier` instead of
`Box<str>`, avoiding some allocations in the process.
This seems to be a net gain of 1.5k TPS on phoenix nap.
Based on https://github.com/clockworklabs/SpacetimeDB/pull/4177.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
Covered by existing tests.
# 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>
# Description of Changes
- Quickstart template `tanstack-ts` and client for TanStack Start
- Add Vue Quickstart Docs
<!-- Please describe your change, mention any related tickets, and so on
here. -->
# Screenshots
- `tanstack-ts` template
<img width="1461" height="898" alt="image"
src="https://github.com/user-attachments/assets/6b7e5473-33c4-4f76-92a7-18607c74422c"
/>
- TanStack Start Quickstart Docs
<img width="1459" height="896" alt="image"
src="https://github.com/user-attachments/assets/b7557498-ff5a-4ce5-9c85-68db943e1b9a"
/>
# 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
<!--
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] Tested the templates locally (e.g. able to add people), works well
for me
# Description of Changes
Rolldown likely [won't release 1.0 until after vite
8.0](https://voidzero.dev/posts/announcing-rolldown-rc), but I figure we
should keep up to date somewhat and switch from the beta to the rc.
# Expected complexity level and risk
1
# Testing
- [x] `spacetime build` with typescript modules still works.
---------
Signed-off-by: Noa <coolreader18@gmail.com>
# Description of Changes
This lets us avoid the try/catch around every syscall in javascript.
# 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
<!--
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! -->
- [ ] <!-- 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
Document the client query builder api for rust, csharp, and typescript.
Also add/fix some documentation for the module-side query builder.
# API and ABI breaking changes
N/A
# Expected complexity level and risk
0
# Testing
N/A. Just documentation.
---------
Signed-off-by: joshua-spacetime <josh@clockworklabs.io>
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
# Description of Changes
<!-- Please describe your change, mention any related tickets, and so on
here. -->
Since Github has been going down *a lot* recently, we would like to add
support for downloading from our mirror instead. This PR updates:
- The install script for both windows and linux to try the mirror if
Github is down
- The `spacetime version install ...` to install a specific version
- The `spacetime upgrade` which grabs the latest version from Github.
# 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
3 - This is touching both the windows and linux/macos install scripts
which are quite sensitive. Proper manual testing is needed on this (see
Testing below)
<!--
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! -->
For these tests I executed the respective install script locally. To
simulate github being down I set the github download to http instead of
https and then I spun up a local server which returns 500. I also added
a `127.0.0.1 github.com` entry to my hosts file (this works on both
Windows, linux and macOS).
Linux
- [x] Tested that the Github download works normally
- [x] Tested that if Github returns a 500 the digital ocean download
works normally
The download failed here and then it correctly retried with the mirror -
I wasn't able to capture the retry part because it's part of the
progress spinner so it just updates dynamically but this was the final
output:
```
boppy@geralt:~/clockwork/SpacetimeDB$ spacetime-install
The SpacetimeDB command line tool will now be installed:
CLI configuration directory: /home/boppy/.config/spacetime/
`spacetime` binary: /home/boppy/.local/bin/spacetime
directory for installed SpacetimeDB versions: /home/boppy/.local/share/spacetime/bin
database directory: /home/boppy/.local/share/spacetime/data
Would you like to continue? yes
Downloading latest version...
Installing v1.12.0: done! The `spacetime` command has been installed as /home/boppy/.local/bin/spacetime
The install process is complete; check out our quickstart guide to get started!
<https://spacetimedb.com/docs/getting-started>
```
Windows
- [x] Tested that the Github download works normally
- [x] Tested that if Github returns a 500 the digital ocean download
works normally
This worked as well:
```
PS C:\Users\boppy\clockwork\SpacetimeDB\crates\update> .\spacetime-install.ps1
vcruntime140.dll is already installed at C:\WINDOWS\System32\vcruntime140.dll
Downloading installer...
Download failed, trying mirror...
We have added spacetimedb to your Path. You may have to logout and log back in to reload your environment.
```
macOS
- [x] Tested that the Github download works normally
- [x] Tested that if Github returns a 500 the digital ocean download
works normally
```
boppy@Johns-Laptop update % bash ./spacetime-install.sh
Downloading installer...
curl: (22) The requested URL returned error: 500
Download failed, trying mirror...
The SpacetimeDB command line tool will now be installed:
CLI configuration directory: /Users/boppy/.config/spacetime/
`spacetime` binary: /Users/boppy/.local/bin/spacetime
directory for installed SpacetimeDB versions: /Users/boppy/.local/share/spacetime/bin
database directory: /Users/boppy/.local/share/spacetime/data
Would you like to continue? yes
Downloading latest version...
Installing v1.12.0: done!
The `spacetime` command has been installed as /Users/boppy/.local/bin/spacetime
The install process is complete; check out our quickstart guide to get started!
<https://spacetimedb.com/docs/getting-started>
```
# 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
# Description of Changes
Adds a comprehensive benchmarking suite for comparing SpacetimeDB
performance against other databases and backends.
**Key features:**
- Load testing framework that runs repeatable benchmarks across multiple
connectors
- Supports SpacetimeDB, PostgreSQL, CockroachDB, SQLite, Supabase,
Convex, and Bun
- Configurable test parameters: duration, concurrency, Zipf distribution
(α) for hot/cold account skew
- Outputs JSON reports with TPS and latency statistics to `./runs/`
- Docker Compose support for containerized benchmarking
- Includes a test SpacetimeDB Rust module (`modules/test-1/server`)
**Connectors included:**
- Direct SQL connectors (Postgres, CockroachDB, SQLite)
- Drizzle ORM wrappers
- RPC-based connectors for network-isolated benchmarking
- SpacetimeDB WebSocket connector
- Supabase and Convex cloud connectors
# API and ABI breaking changes
None. This is a new standalone template with no changes to existing
code.
# Expected complexity level and risk
**1** - This is an additive change that introduces a new isolated
template folder. It has no interactions with existing SpacetimeDB crates
or modules.
# Testing
- [ ] Run `pnpm install` in `templates/keynote-2/`
- [ ] Verify SpacetimeDB module compiles: `cd
templates/keynote-2/modules/test-1/server && cargo build`
- [ ] Run a basic benchmark against SpacetimeDB (requires local
SpacetimeDB instance)
---------
Signed-off-by: bradleyshep <148254416+bradleyshep@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: = <cloutiertyler@gmail.com>
# Description of Changes
This allows `.index('hash')`.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
Verified that it works using the keynote 2 benchmark.
# Description of Changes
Haven't changed `schema()` to accept an object yet, maybe that's for a
followup?
Now everything exported from the module must be exported from the
typescript module.
# Expected complexity level and risk
<!--
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! -->
- [ ] <!-- 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
Adds a Deno quickstart template and documentation.
**Template (`templates/deno-ts/`):**
- `deno.json` with tasks and import map for spacetimedb
- `src/main.ts` using Deno-native APIs (`Deno.stdin`,
`Deno.readTextFile`, `Deno.writeTextFile`, `Deno.env`)
- `spacetimedb/` server module (TypeScript)
- Pre-generated `module_bindings/`
**Documentation
(`docs/docs/00100-intro/00200-quickstarts/00275-deno.md`):**
- Step-by-step quickstart following existing pattern
- Covers project structure, tables/reducers, running the client, CLI
usage
- Documents Deno-specific features: permissions, built-in TypeScript,
import maps, no node_modules
- Explains `--unstable-sloppy-imports` flag (required because generated
bindings use extensionless imports)
# API and ABI breaking changes
None. This is a new template and documentation addition.
# Expected complexity level and risk
**1** - Trivial addition. New template files and documentation only, no
changes to existing code or generator.
# Testing
- [x] Server module publishes successfully
- [x] Bindings generate correctly
- [x] Run `deno task start` and verify connection to SpacetimeDB
- [x] Test interactive CLI commands: add names, `list`, `hello`
# Description of Changes
The PR implements the following updates:
- Create `nuxt-ts` template
- Add Nuxt Quickstart Docs
<!-- Please describe your change, mention any related tickets, and so on
here. -->
# Screenshots
- `nuxt-ts` template
<img width="1446" height="894" alt="image"
src="https://github.com/user-attachments/assets/743a946a-3570-4c0b-823a-c919be722d0a"
/>
- Nuxt Quickstart Docs
<img width="1460" height="898" alt="image"
src="https://github.com/user-attachments/assets/a7014d04-6dc1-4e1d-ac39-051c9ef7c09e"
/>
# 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
<!--
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! -->
- [ ] <!-- 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: = <cloutiertyler@gmail.com>