# Description of Changes
Thanks to @lisandroct for calling this miss out, with the update to 2.0
for Unreal I missed cleaning up the Blackholio tutorial from the pinned
1.12 version, this clears that up to work from the latest.
# API and ABI breaking changes
N/A
# Expected complexity level and risk
1 - docs only
# Testing
Double checked all the updated links
# Description of Changes
- Fix TypeScript connection examples to call `DbConnection.builder()`
without `new` and include `.build()`.
- Document reducer context random APIs across TypeScript, C#, Rust, and
C++.
- Align reducer skill determinism guidance with the documented
context-provided RNG API.
- Consolidates the work from #5403 and #5306 into the single daily docs
audit branch `bot/docs-audit`.
# API and ABI breaking changes
None. Documentation and agent skill guidance only.
# Expected complexity level and risk
1. This is a low-risk docs-only change plus one agent skill wording
update.
# Testing
- [x] `pnpm --dir docs build` passed. Docusaurus emitted the existing
`docusaurus-plugin-llms-txt` warning for `/docs/ask-ai/ask-ai`, then
generated static files successfully.
- [ ] Reviewer can check that the TypeScript connection snippets match
the SDK builder API.
- [ ] Reviewer can check that the reducer context RNG examples match the
supported APIs for each SDK.
---------
Co-authored-by: rain <rain@rain.local>
# Description of Changes
- Added a client-side query builder for the Unreal SDK
- Added typed query-builder subscriptions for Unreal C++ via
SubscriptionBuilder.AddQuery(...).Subscribe()
- Added generated Blueprint query-builder support with source query
nodes, column nodes, predicates, Where, AddQuery, and Subscribe
- Added Blueprint autocasts at the AddQuery boundary so source-specific
Blueprint queries can connect cleanly into the generic subscription
builder for better devex in Blueprint
- Synced the Unreal query-builder core with the C++ module
implementation
- Updated the copied Unreal core query-builder headers to match the
shared C++
- Moved Unreal-specific literal/type adapters out of the shared core
copy and into Unreal-specific expansion code
- Added Unreal SDK test coverage and documentation for the new
query-builder surface
- Added new test harnesses to start to match the View/ViewPk tests
- Added documentation for the Unreal query builder
- Refactor generation for modules with more than 255 reducers, required
to get the TestClient back in working order
# API and ABI breaking changes
- No intended API or ABI breaking changes to released Unreal SDK
behavior
- Adds a new public client-side query-builder API to the Unreal SDK for
C++ and Blueprint
- Raw SQL subscriptions remain available
# Expected complexity level and risk
3 - Adds new query-builder surface with large changes to the code-gen,
the risk here is keeping the C++ module core mirrored to the SDK in the
future
# Testing
What I've done so far:
- [x] Updated and ran the following tests:
- [x] TestClientEditor
- [x] TestViewClientEditor
- [x] TestViewPkClientEditor
- [x] Ran the Unreal harness suites covering the query-builder client
paths
- [x] Verified the generated Unreal query-builder surface in both C++
and Blueprint testing supported fields with a small sample project
Should be done at least once by a reviewer:
- [ ] Re-run the full `sdk-unreal-test-harness` as it's disabled in CI
- [ ] Play with the C++ and Blueprint versions in a small Unreal project
---------
Signed-off-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
# Description of Changes
Adds primary keys to procedural views in C++. This mirrors the work from
#5111, #5246, and #5327 adding the feature and the docs changes.
# API and ABI breaking changes
None
# Expected complexity level and risk
3
# Testing
- [x] Equivalent tests as were added in #5111 and #5246 for rust,
typescript, and C#
# API and ABI breaking changes
None. Docs-only change.
# Expected complexity level and risk
1 - trivial documentation fix, no code or behaviour change.
# Testing
- [x] Confirmed accessor names against the SDK source:
`database_identity()` (Rust/C++), `databaseIdentity` (TS),
`DatabaseIdentity` (C#); the old forms are marked deprecated/obsolete in
bindings.
# Description of Changes
<!-- Please describe your change, mention any related tickets, and so on
here. -->
The reducer-context cheat-sheet and the "Context Properties Reference"
tables still listed `ctx.identity` / `ctx.identity()` as the accessor
for the module's own identity. That accessor was deprecated in favour of
`databaseIdentity` / `database_identity()` / `DatabaseIdentity`, and the
troubleshooting guide added in c70d00246 (#5142) documented the
deprecation but missed updating these other references — these stray
updates should have landed there. This brings all four language tabs in
line with the non-deprecated accessor.
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
# Description of Changes
All of rust, C#, and typescript are included.
# API and ABI breaking changes
N/A
# Expected complexity level and risk
1
# Testing
N/A - docs only change
## Summary
- Fix TypeScript view examples to use `ctx.sender` as a property,
matching the server SDK `ViewCtx` API.
- Update the architecture overview TypeScript view snippet to use
`players.rowType` and `undefined` for optional view returns.
- Clarify shared `ViewContext` prose so it does not imply every language
uses a callable `ctx.sender()` API.
- Improve docs agent-readiness metadata:
- publish `/docs/robots.txt` with a docs sitemap directive and
Content-Signal policy
- add Markdown alternate links for the existing `/docs/llms.txt` and
`/docs/llms-full.txt` outputs
- generate `/.well-known/agent-skills`-style discovery metadata under
`/docs/.well-known/agent-skills/` from the repo's existing `skills/`
source files during docs builds
## Validation
- `pnpm --dir docs build`
- `pnpm --dir docs typecheck`
- Verified the docs build emits `robots.txt` and
`.well-known/agent-skills/index.json`.
- Verified generated Agent Skills SHA-256 digests match the emitted
`SKILL.md` artifacts.
## Notes
The Cloudflare agent-readiness scan for `spacetimedb.com` still depends
on the root/marketing host exposing root-level files such as
`/robots.txt`, `/sitemap.xml`, and
`/.well-known/agent-skills/index.json`. This PR makes the docs origin
produce the corresponding docs-scoped artifacts at `/docs/...`; the root
host can route or mirror these if we want the exact `spacetimedb.com`
scan to pick them up.
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: rain <rain@rain.local>
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
# Description of Changes
- Added a query builder for C++ module bindings
- Added query-builder table/filter/join types
- Added semijoin support with compile-time checks for lookup-table and
indexed-field usage
- Added support for returning query-builder queries from C++ views
- Hooked query-builder metadata into the C++ table/view macros and V10
module-def path
- Added test coverage for the new C++ query-builder behavior
- Compile tests for pass/fail cases
- SQL tests for generated query output
- Added a C++ test module for view primary key coverage
- **Update:** Switched the core to pass the columns and index-columns
metadata with the table source for better client-side codegen to have
some shared code between server + client.
# API and ABI breaking changes
- No intended API or ABI breaking changes
- Adds a new public query-builder API to the C++ bindings
- C++ views can now return query-builder query types in addition to
materialized row results
# Expected complexity level and risk
3 - Mostly contained to C++ bindings, but it touches macros, view
registration/serialization, and module-def generation, so there are a
few places where the pieces need to stay in sync.
# Testing
I've done end to end testing of I think every type as well as built some
tests to confirm the SQL output.
- [x] Run the C++ query-builder SQL tests
[crates/bindings-cpp/tests/query-builder-compile/run_query_builder_compile_tests.sh]
- [x] Smoke test a generated C++ module using query-builder views
---------
Signed-off-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
# Description of Changes
Fix TypeScript SDK React provider recovery when the underlying WebSocket
closes or reports an error while a `SpacetimeDBProvider` is still
mounted.
- Mark `DbConnection` inactive before emitting `disconnect` /
`connectError`, so lifecycle callbacks observe the closed state.
- Teach the React `ConnectionManager` to clear closed retained provider
connections and rebuild them after a short delay.
- Cancel pending reconnects during provider release so React StrictMode
cleanup does not create replacement connections.
- Detach manager callbacks from the old connection before reconnecting,
preventing stale closed connections from updating provider state.
- Use the latest same-key retained builder when a replacement connection
is needed.
- Add focused lifecycle/reconnect regression tests and document that
this recovery is provider-level only; direct `DbConnection` users still
own reconnection.
# API and ABI breaking changes
None. This does not remove or change public APIs. It changes React
provider lifecycle behavior so retained provider connections recover
after close/error.
# Expected complexity level and risk
3/5.
The change is localized to the TypeScript SDK, but it touches async
connection lifecycle behavior, timer cancellation, React provider
reference counting, and callback-visible connection state. Main risks
are duplicate reconnects, stale connection callbacks updating state,
using an outdated retained builder for replacement connections, or
StrictMode release/remount regressions. The implementation guards
against stale callbacks, detaches manager callbacks from closed
connections, and cancels reconnect timers during release.
# Testing
- [x] `pnpm --dir crates/bindings-typescript exec vitest run
tests/db_connection.test.ts tests/connection_manager.test.ts
tests/connection_manager_reconnect.test.ts`
- [x] `pnpm --dir crates/bindings-typescript lint`
- [x] `pnpm --dir crates/bindings-typescript build`
- [x] `pnpm --dir crates/bindings-typescript test`
# Description of Changes
Previously, if the server closed the connection, it was not considered
an error. The reason for this was because `-n` did not always mean the
connection should receive **exactly** `n` updates. Sometimes it meant
that the connection should receive **at most** `n` updates. This was the
case for client disconnecting auto-migration tests.
However, as a consequence, if the server were to close the connection
for some other reason - let's say it crashed before broadcasting all `n`
updates - the cli would not report this as an error. If this happened
during a smoketest, it would fail on some later assertion, but it
wouldn't be immediately obvious why.
`spacetime subscribe -n N` now fails if the websocket closes before it
receives `N` transaction updates. `subscribe_background(..., n)` also
fails if the CLI exits successfully but produced fewer or more than `n`
JSON update lines, where previously it did not.
This change, makes it very clear when this happens that the connection
to the server was closed before the test received its expected number of
updates.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
The purpose of this change is to provide more diagnostic info for
smoketest failures.
---------
Signed-off-by: joshua-spacetime <josh@clockworklabs.io>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
## Summary
- document schedule row lifecycle differences for scheduled reducers,
scheduled procedures, and interval schedules
- clarify that scheduled functions should read row data from the
argument they receive
- document the scheduler's in-memory queue behavior when a schedule row
is deleted before its queued entry fires
Fixes#5252
## Testing
- `pnpm build` from `docs/`
Note: docs build completed successfully. It emitted the existing
`docusaurus-plugin-llms-txt` warning for `/docs/ask-ai/ask-ai` being
skipped during HTML-to-Markdown conversion.
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
Fix a broken link
# API and ABI breaking changes
None
# Expected complexity level and risk
Between 0.001 and 0.01
# Testing
- [x] Rendered locally
# Description of Changes
Graduate **procedures** (and the outgoing HTTP client used from
procedures) out of the `unstable` feature gate /
`SPACETIMEDB_UNSTABLE_FEATURES` across all module libraries. The
`procedure` macro, `ProcedureContext`, `with_tx`/`try_with_tx`,
scheduled procedures, and `ctx.http` are now available without opting
into `unstable`.
**Still gated** (unchanged): HTTP handlers/webhooks, views, RLS /
`client_visibility_filter`, and immediate-scheduling
(`volatile_nonatomic_schedule_immediate`).
Per library:
- **`bindings-sys`**: ungate the `procedure` host-call module + raw ABI
imports (`procedure_start/commit/abort_mut_tx`,
`procedure_http_request`) and `call_no_ret`. Scheduling ABI stays gated.
- **`bindings` (Rust)**: ungate the `procedure` macro,
`ProcedureContext`, `TxContext`/`with_tx`/`try_with_tx`,
`db_read_only`/`get_read_only`, the procedure traits,
`register_procedure`, `__call_procedure__`, and procedure RNG. The
`http` module (previously gated as a unit) now has fine-grained gating
so the outgoing `HttpClient` is exposed while
`HandlerContext`/`Router`/handler macros stay gated.
- **`bindings-csharp`**: drop `[Experimental("STDB_UNSTABLE")]` from
`ProcedureContext.WithTx/TryWithTx` (runtime + codegen) and the
generated `ProcedureTxContext`; FFI snapshots regenerated. Handler
context members + RLS attribute stay gated.
- **`bindings-cpp`**: ungate the procedure ABI (`abi.h`/`FFI.h`),
`tx_execution.h`, the outgoing HTTP client (`http.h`/`http_convert.h`),
and `procedure_context.h`.
`handler_context.h`/`router.h`/`http_handler_macros.h` still `#error`
without `SPACETIMEDB_UNSTABLE_FEATURES`.
- **docs**: remove the procedures beta notices (HTTP handlers stay
marked beta for a later release); regenerate `static/llms.md`.
- **`sdk-test-procedure`**: no longer needs `features = ["unstable"]`.
# API and ABI breaking changes
Not breaking. This is purely additive to the stable surface: procedures
become available **without** the `unstable` feature, while modules that
already opt into `unstable` are unaffected. The wasm host-ABI imports
were already implemented host-side and merely gated module-side, so
there is no ABI version change. (No breaking-change label needed.)
# Expected complexity level and risk
**3/5.** The diff itself is mostly removing
`#[cfg]`/`#ifdef`/`[Experimental]` guards, but the gate bundled
procedures + outgoing HTTP + handlers + the ABI crate together, so the
work was in *separating* procedures from the features that stay gated.
Areas reviewers may want to scrutinize:
- The Rust `http` module went from "gated as a whole" to fine-grained
per-item gating; the outgoing `HttpClient` is exposed while handler
types/macros stay behind `unstable`.
- The `unstable` cut reaches the ABI crate (`bindings-sys`), which is
the only way procedures can compile without the feature.
- C++ separation of the outgoing HTTP client from HTTP handlers across
several headers.
# Testing
- [x] Rust: `cargo check -p spacetimedb` passes in default, `--features
unstable`, and `--no-default-features --features unstable`.
- [x] Rust end-to-end: `sdk-test-procedure` (uses procedures,
`with_tx`/`try_with_tx`, `ctx.http.get`, `new_uuid_v7`, scheduled
procedures) builds **without** `unstable`.
- [x] C#: Codegen + Runtime build; `Codegen.Tests` pass (6/6) after FFI
snapshot regen.
- [x] C++: host syntax-check confirms procedures + `ctx.http.send()`
compile **without** the flag, full headers compile **with** it, and
`handler_context.h` still `#error`s without it. (Not built for the real
wasm/emscripten target locally — relying on CI.)
- [x] `cargo ci lint` components reproduced locally: rustfmt, clippy
(`-D warnings`, default + `unstable`), csharpier, and `cargo doc --deny
warnings`.
- [ ] Reviewer: confirm the wasm bindings + C#/C++ test suites pass in
CI (especially the C++ wasm build, which couldn't run locally).
---------
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
# Description of Changes
This PR adds support for Solid.
Related issue: https://github.com/clockworklabs/SpacetimeDB/issues/4820
The initial implementation was with an LLM, since Solid and React are
very similar. Then I improved on it.
The docs though are completely written by the LLM, I just read through
them once to make sure there aren't any problems.
# API and ABI breaking changes
There are no API or ABI changes. Just added support for Solid.
# Expected complexity level and risk
I'd say around 1 or 2. I haven't tested it too much except for the
example that I added.
# Testing
I'll be testing it more with the test app I'm planing to build.
- [ ] I've added the test solid router similar to test react router, and
it was working, but it'll be nice if someone else can verify as well.
- [ ] I'll be testing it more with the test app I'm planing to build
---------
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
- Add BetterAuth tutorial
- Improved using #5009
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
I followed the tutorial
Closes#4229
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
# Description of Changes
- Completes the Blackholio demo with username selection, leader board,
split mechanic, improved visuals...
- Add Godot tests
# API and ABI breaking changes
- Nothing
# Expected complexity level and risk
1. It just updates the Blackholio demo project
# Testing
- [X] Play the updated demo
- [X] Run the tests locally
# Description of Changes
Adds a basic troubleshooting guide for some common issues we've seen
users encounter.
# API and ABI breaking changes
N/a: it's docs.
# Expected complexity level and risk
1: it's docs.
# Testing
N/a.
# Description of Changes
Adds support to Rust modules and the SpacetimeDB host for defining HTTP
handlers and registering them to routes.
## User-facing API
In a Rust module, users can annotate functions with the new macro
`#[spacetimedb::http::handler]`. A function annotated this way must
accept exactly two arguments, of types `&mut
spacetimedb::http::HandlerContext` and `spacetimedb::http::Request`
(which is a type alias for `http::Request<spacetimedb::http::Body>`. It
must also return `spacetimedb::http::Response` (which is a type alias
for `http::Response<spacetimedb::http::Body>`).
Once the user has defined an HTTP handler, they can register it to a
route by annotating a function with `#[spacetimedb::http::router]`. Such
a function must take no arguments and return a
`spacetimedb::http::Router`. (The original design put this annotation on
a `static` variable rather than a function, but that turned out to be
undesirable because it required that constructing a `Router` be
`const`.) `Router` exposes various methods for registering handlers to
routes.
All of a database's user-defined routes are exposed under
`/v1/database/:name_or_identity/route/{*path}`.
## Example
See [the new
smoketest](https://github.com/clockworklabs/SpacetimeDB/blob/phoebe/http-handlers-webhooks/crates/smoketests/tests/smoketests/http_routes.rs)
for a more exhaustive example.
A simpler example, which stores arbitrary byte data in a table via a
`POST` request, returns an ID, and then retrieves that same data via a
`GET` request with a query parameter:
```rust
#[spacetimedb::table(accessor = data)]
struct Data {
#[primary_key]
#[auto_inc]
id: u64,
body: Vec<u8>,
}
#[spacetimedb::http::handler]
fn insert(ctx: &mut HandlerContext, request: Request) -> Response {
let body: Vec<u8> = request.into_body().into_bytes().into();
let id = ctx.with_tx(|tx| tx.db.data().insert(Data { id: 0, body: body.clone() }).id);
Response::new(Body::from_bytes(format!("{id}")))
}
#[spacetimedb::http::handler]
fn retrieve(ctx: &mut HandlerContext, request: Request) -> Response {
let id = request
.uri()
.query()
.and_then(|query| query.strip_prefix("id="))
.and_then(|id| u64::from_str(id).ok())
.unwrap();
let body = ctx.with_tx(|tx| tx.db.data().id().find(id).map(|data| data.body));
if let Some(body) = body {
Response::new(Body::from_bytes(body))
} else {
Response::builder().status(404).body(Body::empty()).unwrap()
}
}
#[spacetimedb::http::router]
fn router() -> Router {
Router::new().post("/insert", insert).get("/retrieve", retrieve)
}
```
## Design and implementation notes
- As mentioned above, the router is registered via a function, not a
`static` or `const` item. This is because `static` or `const`
initializers must be `const`, and it turns out to be a pain to make all
of the `Router` constructors be `const fn`s.
- The `#[handler]` macro clobbers the original function name with a
`const` variable of type `HttpHandler`. This is unfortunate, but AFAICT
necessary, 'cause we need to pass the string identifier for the handler
to the `Router`, not the function pointer, and Rust allows no (stable
and reliable) way to get a unique string identifier out of a function
item/value, nor to attach data or implement traits for function
items/values. The alternative(s) would involve changing the signature of
the `Router` methods to have uglier and more complex callsites, e.g.
like `.get("/retrieve", retrieve::handler())`, `.get("/retrieve",
handler!(retrieve))` or `.get::<retrieve>("/retrieve")`. I believe that
registering handlers will be much more common than calling their
functions, so I've chosen to make it so that registering them gets the
convenient syntax, even though the inability to call them directly will
be somewhat surprising.
- I haven't wired up energy handling or timing metrics for handler
execution to anywhere. Procedures are still in the same boat.
- HTTP requests to user-defined routes bypass the usual SpacetimeDB auth
middleware, meaning that the host does not validate (or inspect in any
way) `Authorization` headers in requests before invoking the
user-defined handler. This is required to allow arbitrary
user-programmable handling of `Authorization` headers, including those
in formations which SpacetimeDB would reject. As a result of this,
`HandlerContext` doesn't expose a `sender` or `sender_connection_id`.
- HTTP route paths may consist only of a very restrictive set of
characters. I've chosen this set to keep our options open in the future
to add additional syntax to routes, like for registering wildcard
segments and path parameters:
- ASCII digits.
- ASCII letters.
- `-_~/`.
- The internal data structure that represents a `Router` is currently a
`Vec<Route>`, meaning that resolving a request to a route is
`O(num_routes)`. Registering a route checks against each previous route
for uniqueness, meaning that constructing a router is `O(num_routes ^
2)`. There are TODO comments to use a trie, but I think this can wait,
as I expect most databases to register few routes.
- Commit 999a7c317 contains a fix to a mostly-unrelated bug where a few
bindings introduced by the SATS derive macros were unhygienic and not in
a reserved namespace, leading to name conflicts. I discovered this
'cause I tried writing an HTTP handler named `index` to serve the
index/root of a website and it broke.
## Still TODO
- [x] Resolve various TODO comments in the diff.
- [x] Documentation.
- [x] C# bindings support.
- [x] C++ bindings support.
- [x] V8 host support.
- [x] TypeScript bindings support.
# API and ABI breaking changes
New APIs, currently flagged as `unstable`, which will eventually need
stability guarantees. No (intentional) breaking changes, or changes to
existing APIs at all.
# Expected complexity level and risk
3? Changes to our HTTP routing to support the user-defined routes.
# 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] New smoketest of the behavior!
- [x] I dunno, maybe try hosting a simple webpage and see how it works?
- [x] Build a test app with Stripe integration.
- @aasoni did this.
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
## Summary
Adds `docs/DEEP_DATABASE_STYLE.md`, a style guide for the **deep core**
of the SpacetimeDB database (datastore, commitlog, snapshotting,
replication).
[**Read the rendered
document**](https://github.com/clockworklabs/SpacetimeDB/blob/tyler/programming-standards/docs/DEEP_DATABASE_STYLE.md)
The document is organized around seven principles:
1. Work towards zero dependencies
2. Work towards deterministic simulation testing
3. Work towards thread-per-core
4. Work towards `no_std`
5. Think in terms of persistent data structures
6. Think in terms of pipelining
7. Think in terms of unreliable processes
A short style section follows the principles, covering assertions,
bounded loops and queues, error handling, control flow, naming, and
formatting. Inspired by [TIGER
STYLE](https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md),
narrowed and adapted for Rust and our principles.
This is a seed document. It will grow as we make the principles
operational in code and as the practices that serve them become clearer
with use.
## Test plan
- [ ] Read the document and review the principles
- [ ] Discuss any principle the team disagrees with before merging
---------
Co-authored-by: Alessandro Asoni <alessandro@clockworklabs.io>
# Description of Changes
Very small additions to the C# SDK specific for Godot.
I wrote the Godot Blackholio tutorial and updated the Unity one.
I added the image assets necessary for the tutorial.
I added the files for the Godot demo.
# API and ABI breaking changes
No breaking changes.
# Expected complexity level and risk
1. There's really no risk for current systems or projects, it's all new
additions to support nicely(-ish) Godot, new Blackholio demo for Godot
and updates to the tutorials.
# Testing
- [X] Follow the tutorial and verify everything works.
- [X] Build for Windows and verify it works.
- [x] Build for Linux and verify it works.
- [x] Build SDK
- [x] Publish to Nuget
---------
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
# Description of Changes
- Fix style issue with double logos when docs loading
<!-- Please describe your change, mention any related tickets, and so on
here. -->
# Demo
- Before
https://github.com/user-attachments/assets/283a2c2e-8b64-4f10-a3b7-4a96be81ecda
- After
https://github.com/user-attachments/assets/299aa69e-691e-4330-9979-84c6f7d6fb76
# 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
- Add documentation for Steam Session Ticket authentication with
SpacetimeAuth
# API and ABI breaking changes
None.
# Expected complexity level and risk
1
# Testing
Ran the steps manually
# Description of Changes
Adds the commitlog knobs `max_segment_size`, `write_buffer_size`, and
`preallocate_segments` to the server's `config.toml`. There are other
seemingly more advanced knobs that I did not add at this time.
This patch also increases the `DEFAULT_WRITE_BUFFER_SIZE` from `8KiB` to
`128KiB` to optimize high throughput workloads like the keynote-2
benchmark.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
Manual
# Description of Changes
Due to the relatively frequent supply chain attacks on especially npm
packages, we're instituting a minimum package age in the whole repo.
- Globally set a minimum npm package age in CI
- Best-effort set npm package age using `.npmrc` beside any
`package.json`
- Add CI checks that pnpm version and minimum package age values are the
same everywhere
# API and ABI breaking changes
None
# Expected complexity level and risk
2
# 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] CI passes
- [x] if I remove a `.npmrc` then `cargo ci lint` fails
- [x] if I change a value in `.npmrc` then `cargo ci lint` fails
---------
Signed-off-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
# Description of Changes
LLM benchmark infrastructure improvements and new benchmark tasks.
**Runner & scoring:**
- Add retry logic with backoff for LLM API calls (rate limits,
502/503/504, timeouts)
- Fix `generation_duration_ms` to only time the successful attempt, not
retries+sleep delays
- Add `--dry-run` flag to run benchmarks without saving results
- Add OpenRouter client as unified fallback when direct vendor keys
aren't set
- Add web search mode via OpenRouter `:online` suffix
- Extract shared OpenAI-compatible response types into `oa_compat.rs`
- Add `ReducerCallBothScorer` for calling reducers on both golden and
LLM databases
- Set `max_tokens` on OpenRouter and Meta clients to prevent silent
truncation
**Model routing:**
- Add `ModelRoute` with display name, vendor, API model, and OpenRouter
model ID
- Support ad-hoc model IDs via `--models vendor:model` without static
registration
- Add model name normalization (OpenRouter IDs, case variants →
canonical display names)
**Context modes:**
- Add `guidelines`, `cursor_rules`, `search`, `no_context` modes with
`is_empty_context_mode()` helper
- Add mode-specific prompt preambles
- Consolidate mode alias normalization (`none`/`no_guidelines` →
`no_context`)
**CI workflows:**
- Add `llm-benchmark-periodic.yml` for scheduled nightly runs with
per-language failure tracking
- **Note**: The periodic workflow requires `OPENROUTER_API_KEY`,
`LLM_BENCHMARK_UPLOAD_URL`, and `LLM_BENCHMARK_API_KEY` as GitHub
secrets.
- Add `llm-benchmark-validate-goldens.yml` for validating golden answers
still compile
**Results & summary:**
- Add `cmd_status` to show incomplete benchmark combinations with rerun
commands
- Add `cmd_analyze` for LLM-powered failure analysis
- Split `normalize_details_file` from `write_summary_from_details_file`
- Derive task categories from filesystem for summary generation
- Add timestamp tracking (`started_at`/`finished_at`) and token usage
**New benchmark tasks:**
- 30 new tasks across auth, data_modeling, queries, basics, and schema
categories
- Updated/fixed existing task prompts and golden answers
# API and ABI breaking changes
None. Internal tooling only.
# Expected complexity level and risk
2 — Changes are scoped to the LLM benchmark CLI tool
(`xtask-llm-benchmark`) and CI workflows. No impact on SpacetimeDB core.
# Testing
- [x] `cargo check -p xtask-llm-benchmark` — zero errors, zero warnings
- [x] Dry run: `llm_benchmark run --lang typescript --modes no_context
--tasks t_001 --models openai:gpt-5-mini --dry-run` — ran end-to-end,
confirmed no results saved to disk
- [ ] Verify periodic workflow runs successfully on next scheduled
trigger
---------
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
# Description of Changes
- Update docs to new designs
<!-- Please describe your change, mention any related tickets, and so on
here. -->
# Screenshots
<img width="1505" height="853" alt="Demo1"
src="https://github.com/user-attachments/assets/227e07d9-8e3b-464f-ad0b-eb39f3f34c63"
/>
<img width="1505" height="854" alt="Demo2"
src="https://github.com/user-attachments/assets/8fdc9418-e41b-477f-a9a2-bc0e075f80ea"
/>
<img width="1508" height="860" alt="Demo3"
src="https://github.com/user-attachments/assets/ad2eed7b-a592-4822-b5d0-165d3d61f30e"
/>
<img width="1501" height="854" alt="Demo4"
src="https://github.com/user-attachments/assets/2ab770d6-005e-44db-ace0-ad09fcced383"
/>
# 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
2
<!--
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 docs with updated designs
- [ ] <!-- 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
This change addresses reviewer feedback on #4576.
As requested by `@cloutiertyler`, here are the changes:
- moved the persistent default listen address for `spacetime start` from
project `spacetime.json` to CLI `cli.toml`
- threaded the already-loaded CLI `Config` into `spacetime start`
instead of introducing a separate project-config lookup in that
subcommand
- preserved precedence so explicit `--listen-addr` / `-l` still wins
over config, and config still wins over the built-in standalone default
- documented the setting in the `spacetime start` CLI reference instead
of the standalone runtime-config page
Behavior precedence is now:
1. Explicit CLI flag, such as `spacetime start --listen-addr
127.0.0.1:5000`
2. `listen_addr` from `cli.toml`
3. Built-in standalone default `0.0.0.0:3000`
Example:
```toml
listen_addr = "0.0.0.0:4000"
```
With that config in place, `spacetime start` will bind to `0.0.0.0:4000`
unless the user passes `--listen-addr` explicitly.
Implementation details:
- added a top-level `listen_addr` field to the existing CLI config
parser and persistence path
- updated `spacetime start` to use the loaded CLI config rather than
reading project config directly
- added/kept focused tests for `--listen-addr` and `-l` detection so
config is only injected when the user did not provide an explicit listen
address
- updated the checked-in CLI reference text for `spacetime start`
Related:
- Follow-up to #4576
# API and ABI breaking changes
None.
This change does not modify any public API or ABI. It only changes where
the CLI reads an optional default value for an existing `spacetime
start` flag.
# Expected complexity level and risk
Complexity: 2/5
This is a small, localized CLI behavior change.
The main interaction point is precedence between forwarded CLI args and
persisted CLI config. Risk is low because this change:
- preserves the existing standalone default when `listen_addr` is absent
- preserves explicit CLI `--listen-addr` and `-l` precedence
- reuses the existing `cli.toml` loading path instead of adding another
config system
# Testing
Completed:
- [x] `cargo fmt --all --check`
- [x] `cargo check -p spacetimedb-cli`
- [x] `cargo clippy -p spacetimedb-cli --all-targets`
- [x] `cargo test -p spacetimedb-cli config::tests --lib`
- [x] `cargo test -p spacetimedb-cli subcommands::start::tests --lib`
Reviewer checks:
- [ ] Run `spacetime start` without `listen_addr` in `cli.toml` and
confirm it still binds to `0.0.0.0:3000`
- [ ] Add `listen_addr = "0.0.0.0:4000"` to `cli.toml`, run `spacetime
start`, and confirm it binds to `0.0.0.0:4000`
- [ ] Run `spacetime start --listen-addr 127.0.0.1:5000` with config
present and confirm the CLI flag still wins
---------
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
# Description of Changes
A user in the public Discord was confused about the intended way(s) to
interact with SpacetimeDB, and was attempting to (mis)use the HTTP API's
SQL endpoint in production rather than or in addition to the WebSocket
API.
After some discussion, we determined these additions to the
documentation would be helpful.
# API and ABI breaking changes
N/a
# Expected complexity level and risk
1
# Testing
N/a
# Description of Changes
This pull request improves the handling of connection lifecycle events
in the Rust client SDK for SpacetimeDB, particularly distinguishing
between connection failures and disconnections. It introduces a new
`ConnectionLifecycle` state machine to track connection progress,
ensures that the correct callback (`on_connect_error` or
`on_disconnect`) is invoked based on the connection state.
**Changes**
* `ConnectionLifecycle` enum to track the connection state
(`Connecting`, `Connected`, `Ended`)
* Refactored error handling so that if a connection fails before
establishment, the `on_connect_error` callback is invoked; if the
connection fails after establishment, the `on_disconnect` callback is
invoked. See `end_connection`.
* Updated where disconnections are handled
(`advance_one_message_blocking`, `advance_one_message_async`, and
message processing) to use `finish_connection`
* Improved handling of user-initiated disconnects during the connection
process to avoid reporting them as connection errors and to ensure
proper cleanup.
# API and ABI breaking changes
I guess maybe if people relied on the `on_connect_error` to actually
fire the `on_disconnect` then this changes that behavior.
# Expected complexity level and risk
Maybe a 2? Seems pretty low risk but I'm still new to the codebase,
please double check.
This doesn't fix the websocket issues, that'll be for another day. I
noticed websocket.rs has some places it just drops and the error isn't
handled properly. We could technically surface that information and run
our callbacks with more specific error messages.
# Testing
I had an agent build and run loads of tests for this but didn't commit
those since it would have made the PR massive. I was planning on testing
locally though to see if I could trigger a connection failure at some
point, maybe via an invalid access token.
# Description of Changes
Add documentation for how to deploy on Railway under "Hosting" in the
docs
https://github.com/user-attachments/assets/b36a7f53-e0db-4fa3-8b0e-65930c71b3a8
# 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 - just a docs change
# Testing
Ran the docs locally and verified the page looked good and that the
content is correct. See video above.
# 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
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
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>
Resolves#3652
# Description of Changes
Update docs nginx configuration to better support `spacetime logs
--follow` when self hosting configured to use ssl.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
I have added this location to my own nginx configuration and confirmed I
am able to `spacetime logs -s some-https-server <my-module> --follow`
and see logs immediately and continue following even if no log is
produced after 1 minute.
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
# 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>
## 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>
## 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>
## Summary
- add a new `templates/astro-ts` template based on the existing Astro +
SpacetimeDB integration work
- include Astro SSR, a React client island for realtime updates, and a
small `server:defer` example
- add Astro quickstart documentation under
`docs/docs/00100-intro/00200-quickstarts/00152-astro.md`
## Validation
- `pnpm install`
- `pnpm -F spacetimedb build`
- `pnpm -F ./templates/astro-ts build`
## Notes
- I did not add `astro-ts` to the built-in template listing in
`spacetime dev` docs, to match the current `nextjs-ts` pattern.
---------
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. -->
moves the docs file for spacetime.json into the right folder so that the
website shows it.
# API and ABI breaking changes
<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->
no
# 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. -->
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! -->
no testing needed
Per Tyler's request. Consolidates the three commitlog proposals from
SpacetimeDBPrivate into a single public reference document:
- **Proposal 0003** (commitlog format): Segment structure, commit
format, transaction records, mutations, integrity model, wire format,
versioning
- **Proposal 0016** (offset index): Index files, entry format,
read/write behavior, configuration
- **Proposal 0027** (commitlog epoch): Epoch field for replication,
format version 1
The document is written in textbook style with no emdashes or
contractions, following the docs style guide. All proposal-specific
language (motivation sections, alternatives considered, implementation
stages, etc.) has been removed in favor of a direct reference format.
Placed at
`docs/docs/00200-core-concepts/00100-databases/00400-commitlog.md`
alongside the existing database concept docs.
No private repo details are referenced.
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
Fixed a CLI call in docs Unity tutorial that generated client module
code in an incorrect directory.
# API and ABI breaking changes
None.
# Expected complexity level and risk
1
# Testing
Built a project by following the tutorial with the wrong call vs the
fixed call. Compared against different parts of the tutorial to confirm
the intent.
---------
Signed-off-by: T-Podgorski <147391857+T-Podgorski@users.noreply.github.com>
Signed-off-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Fixes#4592
Adds a "Supported Column Types" section to the Index documentation page
listing:
- **Supported types**: integers (all widths), bool, String, Identity,
ConnectionId, Uuid, Hash, and no-payload enums with
`#[derive(SpacetimeType)]`
- **Unsupported types**: floats (no total ordering),
ScheduleAt/TimeDuration/Timestamp (not yet supported, links #2650),
Vec/arrays, enums with payloads, nested structs
- **Workaround tip**: scaled integers for floating-point coordinates
- **Direct index restrictions**: only u8/u16/u32/u64 and no-payload
enums
The list is derived from the `FilterableValue` trait implementations in
`crates/lib/src/filterable_value.rs` and the direct index validation in
`crates/schema/src/def/validate/v9.rs`.
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>