31 Commits

Author SHA1 Message Date
John Detter eb11e2f5c4 Version bump 2.2.0 (#4916)
# Description of Changes

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

- Bumps version to 2.2.0

# API and ABI breaking changes

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

None

# Expected complexity level and risk

- 1 - this is just a version bump

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

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

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

# Testing

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

- [x] Version number is correct (`2.2.0`)
- [x] BSL license file has been updated with the new date and version
number

---------

Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-04-30 19:24:41 +00:00
DexterKoelson 59ac77970f Add useProcedure React hook and export procedures from codegen (#4752)
Closes #4751

# Description of Changes
- Add `useProcedure` React hook that mirrors `useReducer` which returns
a stable, typed callback that queues calls until the connection is ready
- Add `ProcedureParamsType` and `ProcedureReturnType` utility types to
`type_utils.ts`
- Update TypeScript codegen to emit `export const procedures =
__convertToAccessorMap(proceduresSchema.procedures)` in generated module
bindings, matching the existing pattern for reducers

```ts
import { procedures } from './module_bindings';
import { useProcedure } from 'spacetimedb/react';

const doSomeThing = useProcedure(procedures.doSomeThing);
const result = await doSomeThing({ foo: "..." });
```

# API and ABI breaking changes
None. Additive only — new hook export and new codegen line.

# Expected complexity level and risk
Low. The hook is a near-copy of `useReducer` adapted for procedure
signatures. The codegen change adds one line following the identical
pattern used for reducers.

# Testing
- [x] TypeScript SDK compiles with no new errors (`tsc --noEmit`)
- [x] All 170 existing tests pass (17 test files)
- [x] Tested end-to-end in a React app calling a procedure

---------

Co-authored-by: Jason Larabie <jason@clockworklabs.io>
2026-04-21 21:06:06 +00:00
clockwork-labs-bot cd65a0785d Add .gitignore files to quickstart templates (#4609)
Fixes #4582

Templates created via `spacetime init` were missing `.gitignore` files,
causing build artifacts like `node_modules`, `target/`, `bin/`, `obj/`,
`dist/`, `.next/`, etc. to show up in git diffs when users initialize a
project inside a git repository.

Adds `.gitignore` files to the 15 templates that were missing one:

| Template | Ignores |
|----------|---------|
| Node/TS (`basic-ts`, `browser-ts`, `bun-ts`, `chat-react-ts`,
`deno-ts`, `nodejs-ts`, `react-ts`, `vue-ts`) | `node_modules`, `dist`,
`*.log` |
| Next.js (`nextjs-ts`) | `node_modules`, `.next`, `out`, `dist`,
`*.log` |
| Svelte (`svelte-ts`) | `node_modules`, `dist`, `.svelte-kit`, `*.log`
|
| Rust (`basic-rs`, `chat-console-rs`) | `target` |
| C# (`basic-cs`, `chat-console-cs`) | `bin`, `obj` |
| C++ (`basic-cpp`) | `target`, `build` |

All files also include `spacetime.local.json` and `.DS_Store`.

The 5 templates that already had `.gitignore` files (`angular-ts`,
`keynote-2`, `nuxt-ts`, `remix-ts`, `tanstack-ts`) are left unchanged.

Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
2026-03-30 21:02:56 +00:00
Zeke Foppa 480fd5841a Bump versions to 2.1.0 (#4681)
# Description of Changes

Bump versions to 2.1.0

# API and ABI breaking changes

None

# Expected complexity level and risk

1

# Testing
CI

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-03-20 21:53:51 +00:00
bradleyshep 7454329a08 Template README + template.json generation tool (#4570)
# Description of Changes

Adds `tools/templates/` scripts to derive template metadata from
manifests and generate READMEs from quickstart docs. Replaces slug-based
`builtWith` with manifest-derived data and hardcoded quickstart mappings
with discovery from docs.

**Manifest-based `builtWith`** (`update-template-jsons.ts`)

- Reads `package.json`, `Cargo.toml`, and `.csproj` to populate
`builtWith` in `.template.json`.
- Scoped npm packages normalize to scope (`@angular/core` → `angular`).
Excludes `@types/*`. Adds `nodejs` only for nodejs-ts when `@types/node`
is present.
- Root manifests processed before subdirs; primary framework first (e.g.
`react` before `spacetimedb` in react-ts). Dependencies reordered in
package.json where needed.

**Dynamic quickstart discovery** (`generate-template-readmes.ts`)

- Discovers template → quickstart by parsing `--template X` from files
in `docs/docs/00100-intro/00200-quickstarts/`.
- Optional `quickstart` override in `.template.json`; must resolve under
quickstarts dir.
- chat-react-ts has no quickstart; uses manual README.

**New:** `tools/templates/` (update-template-jsons.ts,
generate-template-readmes.ts, README, package.json, pnpm-lock).
**Modified:** all `templates/*/.template.json` (added `builtWith`),
new/generated `templates/*/README.md`.

# API and ABI breaking changes

None.

# Expected complexity level and risk

**1** – Dev tooling only. No runtime or API changes. Scripts are
isolated; failures only affect generated metadata and READMEs.

# Testing

- [ ] `cd tools/templates && pnpm run generate` completes without errors
- [ ] Spot-check `builtWith` and generated READMEs for a few templates
2026-03-20 13:01:58 +00:00
John Detter cf06f8ad3c Version bump to 2.0.5 (#4623)
# Description of Changes

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

- Bumps version to 2.0.5

# API and ABI breaking changes

None - this is just a version bump

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

# Expected complexity level and risk

1 - 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 properly updated, including the date change
- [x] CI is passing other than the internal check
2026-03-12 21:03:37 +00:00
John Detter 354dd45499 Version bump 2.0.4 (#4600)
# Description of Changes

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

- Bumps version to 2.0.4

# API and ABI breaking changes

None - this is just a version bump

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

# Expected complexity level and risk

1 - this is just a version bump

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

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

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

# Testing

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

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

---------

Signed-off-by: John Detter <4099508+jdetter@users.noreply.github.com>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
2026-03-10 18:37:47 +00:00
joshua-spacetime 33f3ea18e2 Make accessor required for table-level index defs in typescript (#4525)
# Description of Changes

This patch contains two main changes:

1. It makes `accessor` a required argument for table-level index defs in
typescript to align with rust.

2. It removes unsound index typing in the TypeScript bindings by
splitting index data into two explicit representations:

- `indexes`: declarative user config (`IndexOpts`) used for type
inference
- `resolvedIndexes`: normalized runtime metadata (`UntypedIndex`)
derived from `RawTableDefV10`

`TableCacheImpl` now builds index accessors from `resolvedIndexes`
instead of re-casting `indexes` at runtime.

    This addressed the following comment:
    ```
// TODO: horrible horrible horrible. we smuggle this
`Array<UntypedIndex>`
// by casting it to an `Array<IndexOpts>` as `TableToSchema` expects.
// This is then used in `TableCacheImpl.constructor` and who knows where
else.
    // We should stop lying about our types.
    ```

    > Why?

    We were conflating two different concepts under `tableDef.indexes`:

      1. declared table-level index options authored by users
2. resolved runtime index definitions (including field-level inferred
indexes)

This required unsafe casts (`T['idxs']` / `UntypedIndex`) and made the
type model unsound.

Note, (2) was largely ai assisted.

# API and ABI breaking changes

Technically breaks the module api, although I believe this is the
behavior that is outlined in the spec, and so the current behavior
should really be considered a bug.

# Expected complexity level and risk

2

# Testing

Added unit tests covering the following:
1. Table-level explicit index without accessor throws.
2. Table-level duplicate accessor throws.
3. Table-level explicit accessor is accepted and used.
4. Field-level `.index(...)` derives accessor from the field name
(`displayName`).
2026-03-03 15:09:05 +00:00
John Detter c29a44c50b Version upgrade 2.0.3 (#4489)
# Description of Changes

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

- Version upgrade 2.0.3

# API and ABI breaking changes

- None, this is a version bump

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

# Expected complexity level and risk

- 1 - this is a version bump

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

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

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

# Testing

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

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

Bumping all versions to 2.0.2 for the release.

# API and ABI breaking changes

None.

# Expected complexity level and risk

1

# Testing

CI

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-02-26 01:54:35 +00:00
Noa bb08c8b571 [TS] Add typescript dependency to typescript templates (#4409)
# Description of Changes

`spacetime build` now attempts to run tsc for typescript modules, and
will emit a warning if it's not present. This PR makes it so our CLI
stops emitting a warning for our templates.

# Expected complexity level and risk

1

# Testing

- [x] Verified that typescript gets properly installed.
2026-02-23 22:40:41 +00:00
Zeke Foppa 88407f0958 Bump versions to 2.0.1 (#4403)
# Description of Changes

Just bumping versions to 2.0.1.

# API and ABI breaking changes

None

# Expected complexity level and risk

1

# Testing
- [ ] CI passes

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-02-23 21:54:10 +00:00
Shubham Mishra e2f8a60759 Case conversion (#4263)
# Description of Changes

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

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

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

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

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


 
 
 
 
 
 -  -  -

---------

Signed-off-by: Shubham Mishra <shivam828787@gmail.com>
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <bot@clockworklabs.com>
Co-authored-by: joshua-spacetime <josh@clockworklabs.io>
Co-authored-by: Noa <coolreader18@gmail.com>
Co-authored-by: = <cloutiertyler@gmail.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@clockworklabs.io>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: Phoebe Goldman <phoebe@clockworklabs.io>
2026-02-20 10:44:29 +00:00
Jeffrey Dallatezza 9cf4af4ff2 Add more debug logging to the typescript client (#4356)
# Description of Changes

This adds some logging utilities, that will probably be helpful for
debugging issues. `stdbLogger` can now accept lazy messages. If you call
`setGlobalLogLevel`, that will set a log level globally. It is set to
`info` by default, but when troubleshooting, we can ask people to run
`setGlobalLogLevel('trace')` and share more detailed logs.

In this PR, it adds a new new logs at the `trace` level:
 - All outgoing messages to the server
 - All incoming messages from the server
- After handling a server message, we log the number of triggered row
callbacks

There are also some formatting niceties to truncate large arrays and
redact fields that look like credentials.

We are also using `safe-stable-stringify` to handle some cases that
would be errors in `JSON.stringify`.

# API and ABI breaking changes

This adds the `setGlobalLogLevel` function, which is useful for
debugging.

# Expected complexity level and risk

1.5 - the only real risk here is that 

# Testing

This has some tests of formatting in `logger.test.ts`.
2026-02-20 00:36:18 +00:00
Noa 098afaf1a5 [TS] Improve autogen autocompletion and typing (#4309)
# Description of Changes

All types are now defined and exported in `module_bindings/types.ts`,
meanings there's only one module you need to import from to access
types.

# Expected complexity level and risk

2

# Testing

n/a, no change in behavior.
2026-02-19 06:17:02 +00:00
Jeffrey Dallatezza 45bc0451ac Add more tests for typescript client and fix some bugs (#4307)
# Description of Changes

This fixes a couple issues:
 - We are now using the `SendDroppedRows` flag for unsubscribe messages.
 - We parse reducer errors as strings now when throwing errors.
- `useTable` was not doing client-side filtering correctly for object
types (Timestamp, ConnectionId, Identity)
- `useTable` was not always recomputing snapshots when it needed to,
because it couldn't distinguish between two events if they were caused
by reducers called by other connections (or two subscription applied
events). All events how have a client-generated id attached, so we can
tell if there was actually a new event processed.

Once we have per-query storage, we can purge the client-side filtering
code.

This also adds some tests to cover these cases, and includes a bit of
refactoring.

Another change added here is to use `SenderError` in the typescript SDK
for errors that were returned by reducers (which throw `SenderError` in
typescript modules).


# Expected complexity level and risk

1

# Testing

This has some new tests added.

Much of the `useTable` logic was tested manually.
2026-02-19 03:00:16 +00:00
Jeffrey Dallatezza 08ff1e1c11 TS Quickstart: Store different auth tokens for different servers/modules (#3252)
# 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>
2026-02-16 16:34:46 +00:00
Shubham Mishra e4098f98d9 Rust: macro change name -> accessor (#4264)
## Description of Changes

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

### Core changes

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

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

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


## Breaking changes (API/ABI)

1. **Rust modules**

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

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

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


**Complexity:** 3

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

---------

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

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

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

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

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

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

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

In a similar fashion, running:

```
spacetime publish region-1
```

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

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

# API and ABI breaking changes

None

# Expected complexity level and risk

3

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

# Testing

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

---------

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

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

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

## What's included

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

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

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

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

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

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

## API and ABI breaking changes

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

## Expected complexity level and risk

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

## Testing

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

---------

Signed-off-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: joshua-spacetime <josh@clockworklabs.io>
2026-02-15 22:56:20 +00:00
Noa c044d96a7a [TS] schema() takes an object (#4273)
# 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. -->
2026-02-13 07:53:42 +00:00
Tyler Cloutier 2ec07a3f70 Standardize query builder syntax across Rust, TypeScript, and C# (Server/Client) (#4261)
# Description of Changes

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

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

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

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

# API and ABI breaking changes

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

# Expected complexity level and risk

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

# Testing

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

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

- Version upgrade to 2.0.

# API and ABI breaking changes

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

# Expected complexity level and risk

1 - this is just a version bump

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

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

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

# Testing

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

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

---------

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

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

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

# API and ABI breaking changes

Yep!

# Expected complexity level and risk

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

# Testing

N/a
2026-02-12 02:11:33 +00:00
Noa 7677b5478f [TS] Export reducers, etc from a module (#4220)
# 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. -->
2026-02-11 22:45:36 +00:00
joshua-spacetime a78b056fcc Reorganize types generated for typescript clients (#4258)
NOTE: Cherry-picking
https://github.com/clockworklabs/SpacetimeDB/pull/4127 from the
`2.0-breaking-changes` branch.

## Original PR Description

This changes generated types in ts client bindings. We currently
generate a few different types of types: reducer args, procedure args,
rows, and user defined types. To avoid potential conflicts between these
types (for example, if a user defined a type called `FooRow`, and also
had a tabled named `foo`, we would end up with two types named
`FooRow`), this puts each set of types in a different file and
namespace. We also stopped exporting the `xxxRow` types, because there
is always another type generated for those. We now have a `types`
directory, which has an `index.ts` with user defined types, along with
`reducers.ts` and `procedures.ts` for the types generated for
reducer/procedure parameters.

```
import type * as Types from './module_bindings/types';

var currentMessages: Types.Message[] = [];
```

or

```
import { type Message } from './module_bindings/types';

var currentMessages: Message[] = [];
```

This has a couple other changes:
- For procedure and reducer types, this adds a suffix of `Args`, since
we may want types for the return values in the future.
- For all of the types, instead of exposing the schema object, we are
now giving the typescript type (e.g. `export type Message =
__Infer<typeof MessageRow>;`). I couldn't think of a reason for users to
want the schema object, so this should save users from needing to do all
of the `Infer` boilerplate.

This is a breaking change for v2.

2. This only changes typescript, and it should generally make thing
easier to use.

---------

Co-authored-by: Jeffrey Dallatezza <jeffreydallatezza@gmail.com>
2026-02-11 15:51:16 +00:00
Zeke Foppa 56d7cc8fa8 Bump version to v1.12.0 attempt #2 (#4164)
# Description of Changes

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

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

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

Version upgrade to `v1.12.0`.

# API and ABI breaking changes

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

None

# Expected complexity level and risk

1 - this is just a version upgrade

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

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

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

# Testing

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

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

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

---------

Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-02-02 23:22:29 +00:00
Zeke Foppa cd71963efd Revert "Upgrade version to 1.12.0 (#4084)" (#4147)
# Description of Changes

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

# API and ABI breaking changes

None

# Expected complexity level and risk

1

# Testing

- [ ] CI passes

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
2026-01-28 17:47:24 +00:00
John Detter 2044a536b0 Upgrade version to 1.12.0 (#4084)
# Description of Changes

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

Version upgrade to `v1.12.0`.

# API and ABI breaking changes

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

None

# Expected complexity level and risk

1 - this is just a version upgrade

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

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

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

# Testing

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

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

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

---------

Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
2026-01-27 18:15:36 +00:00
Piotr Sarnacki cd1ec90d16 Templates naming standarization (#4042)
# Description of Changes

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

# Expected complexity level and risk

1

# Testing

I've tested generating templates manually

---------

Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
2026-01-23 16:08:23 +00:00