Commit Graph

11 Commits

Author SHA1 Message Date
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
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
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
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
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