Skip to content

Releases: clockworklabs/SpacetimeDB

Release v1.11.1 - Bug Fixes + Performance Improvements

18 Dec 21:23

Choose a tag to compare

Hello again everyone! This is likely going to be our last release before the holidays. We will potentially have one more release before the end of the year but for now we hope you are all happy with these improvements 🙂

Typescript

This release includes several bug fixes and performance improvements related to Typescript:

  • SpacetimeDB now processes sourcemaps included in Typescript modules, so stacktraces in both new and existing modules now show the filenames and line numbers from your source code, not from the bundled JS file.
  • The UTF-8 processing of the TextEncoder and TextDecoder classes is now implemented in native code, meaning string de/serialization will now have less overhead.
  • useTable in a React client now works when specifying columns with camelcase names.
  • Generated client code is now compatible with the noImplicitOverride Typescript configuration option.

What's Changed

Full Changelog: v1.11.0...v1.11.1

⛄ 🎄 🎁 Happy Holidays everyone! 🎁 🎄 ⛄

Release v1.11.0 - Typed Query Builder

09 Dec 13:35

Choose a tag to compare

Today we've released query builders for Rust and TypeScript modules. The purpose of the query builder API is so that you can write views that will take advantage of the unique performance guarantees of SpacetimeDB's query engine, particularly for realtime subscription updates.

The query builder also now allows you to iterate or scan a table in a view, something that previously wasn't possible using only the index accessors exposed by ViewContext and AnonymousViewContext.

The query builder exposes the following query operators:

  • .where()
    Used for filtering. Equivalent to a WHERE condition in SQL.
  • .leftSemijoin()
    Equivalent to an inner join in sql where a row is return from the lhs only if it matches with a row on the rhs.
  • .rightSemijoin()
    Equivalent to an inner join in sql where a row is return from the rhs only if it matches with a row on the lhs.

Examples (Rust)

use spacetimedb::{Identity, Query, Table, ViewContext, AnonymousViewContext};

#[spacetimedb::table(name = player_state)]
pub struct PlayerState {
    #[unique]
    player_id: u64,
    online: bool,
}

#[spacetimedb::table(name = player_internal)]
pub struct Player {
    #[auto_inc]
    #[primary_key]
    id: u64,
    #[unique]
    identity: Identity,
    name: String,
    #[index(btree)]
    age: u8,
}

#[spacetimedb::table(name = moderator_internal)]
pub struct Moderator {
    #[unique]
    player_id: u64,
}

/// Returns all players.
/// Equivalent to `SELECT * FROM player_internal`.
#[spacetimedb::view(name = player, public)]
fn player(ctx: &AnonymousViewContext) -> Query<Player> {
    ctx.from.player_internal().build()
}

/// Returns the caller's player.
/// Equivalent to `SELECT * FROM player_internal WHERE "identity" = :sender`.
#[spacetimedb::view(name = my_player, public)]
fn my_player(ctx: &ViewContext) -> Query<Player> {
    ctx.from.player_internal().r#where(|p| p.identity.eq(ctx.sender)).build()
}

/// Returns only online players.
/// Equivalent to:
/// ```sql
/// SELECT q.*
/// FROM player_state p JOIN player_internal q ON p.player_id = q.id
/// WHERE p.online
/// ```
#[spacetimedb::view(name = online_player, public)]
fn online_player(ctx: &AnonymousViewContext) -> Query<Player> {
    ctx.from
        .player_state()
        .r#where(|p| p.online.eq(true))
        .right_semijoin(ctx.from.player_internal(), |(p, q)| p.player_id.eq(q.id))
        .build()
}

/// Returns only the caller's player if online.
/// Equivalent to:
/// ```sql
/// SELECT q.*
/// FROM player_state p JOIN player_internal q ON p.player_id = q.id
/// WHERE p.online AND q.identity = :sender
/// ```
#[spacetimedb::view(name = my_online_player, public)]
fn my_online_player(ctx: &ViewContext) -> Query<Player> {
    ctx.from
        .player_state()
        .r#where(|p| p.online.eq(true))
        .right_semijoin(ctx.from.player_internal(), |(p, q)| p.player_id.eq(q.id))
        .r#where(|p| p.identity.eq(ctx.sender))
        .build()
}

/// Returns the moderators.
/// Equivalent to:
/// ```sql
/// SELECT p.* FROM player_internal p JOIN moderator_internal m ON p.id = m.player_id
/// ```
#[spacetimedb::view(name = moderator, public)]
fn moderator(ctx: &AnonymousViewContext) -> Query<Player> {
    ctx.from
        .player_internal()
        .left_semijoin(ctx.from.moderator_internal(), |(p, m)| p.id.eq(m.player_id))
        .build()
}

Examples (TypeScript)

import { schema, table, t, type RowObj } from 'spacetimedb/server';

const playerState = table('playerState', {
  playerId: t.u64().unique(),
  online: t.bool(),
});

const playerInternal = table('playerInternal', {
  id: t.u64().primaryKey().autoInc(),
  identity: t.identity().unique(),
  name: t.string(),
  age: t.u8().index('btree'),
});

const spacetimedb = schema(playerState, playerInternal);

spacetimedb.view(
  { name: 'my_online_player', public: true },
  t.array(playerInternal.row()),
  ctx => {
    return ctx.from.playerState
      .where(p => p.online.eq(true))
      .rightSemijoin(ctx.from.playerInternal, (p, q) => p.playerId.eq(q.id))
      .where(p => p.identity.eq(ctx.sender))
      .build();
  }
);

Bug Fixes

  • Fixes an issue with the --delete-data=on-conflict flag of spacetimedb publish
  • Fixes an issue where databases were returning 400/500 errors after publishing with -c
  • Fixes an issue where on_insert and on_delete were not firing correctly for per-client (ViewContext) views

What's Changed

New Contributors

Full Changelog: v1.10.0...v1.11.0

Release v1.10.0 - Procedures and HTTP Requests

27 Nov 04:42

Choose a tag to compare

Today we have an absolute game changer for SpacetimeDB. SpacetimeDB 1.10 introduces the ability for databases to perform HTTP requests to external services right from within your module! This is one of our most-requested features, and we're very excited to share it with you all.

SpacetimeDB Reducers are extremely powerful. They are atomic, transactional, pure, retryable, and replayable. The challenge was: in order to maintain these properties and guarantees, they need to be isolated from the outside world and can't be allowed to cause any observable side effects.

However, HTTP requests are inherently side-effecting, and are too useful not to have. It turns out the solution is pretty simple: keep reducers side effect free, and introduce a new kind of database function with weaker guarantees and more powers. Enter a new type of SpacetimeDB function: Procedures.

Examples

Just like a reducer, a procedure is a function defined in your module which runs inside the database. Unlike a reducer, procedures don't correspond 1-to-1 with transactions. Instead, you explicitly manage transactions inside the body of your procedure:

#[spacetimedb::procedure]
fn find_highest_level_player(ctx: &mut ProcedureContext) {
    let highest_level_player = ctx.with_tx(|ctx| {
        ctx.db.player().iter().max_by_key(|player| player.level)
    });
    match highest_level_player {
        Some(player) => log::info!("Congratulations to {}", player.id),
        None => log::warn!("No players..."),
    }
}

Being able to run code in the database without a transaction opens a lot of possibilities for new APIs we could expose. The first of these, releasing today, is HTTP requests:

#[spacetimedb::procedure]
fn get_request(ctx: &mut ProcedureContext) {
    match ctx.http.get("https://example.invalid") {
        Ok(response) => {
            let (response, body) = response.into_parts();
            log::info!(
                "Got response with status {} and body {}",
                response.status,
                body.into_string_lossy(),
            )
        },
        Err(error) => log::error!("Request failed: {error:?}"),
    }
}

Take a look at the documentation on the new procedure APIs for more details,
and join us on Discord to let us know what other side effects you want APIs for!

As of this release, only Rust and TypeScript modules can define procedures. We're hard at work adding support to C# modules, and will be releasing them soon. We'll also be cleaning up the new APIs in response to your feedback, so for now procedures are unstable and subject to breaking changes.

TypeScript fixes

In this release, we've also fixed quite a few issues which were reported in the new TypeScript SDK.

  • This issue by exporting the SubscriptionHandle type with the REMOTE_MODULE type applied.
  • This issue by converting to camelCase for column names in code generation.
  • Fixes an issue where onMyReducer callbacks were passing arguments as variadic params, while the types indicated they would be passed as an object. onMyReducer((ctx, argA, argB, argC) => {}) vs onMyReducer((ctx, { argA, argB, argC}) => {})`
  • Fixes an issue where the table type name was used instead of the table name in code generation for constructing tables.
  • Fixes issue with ScheduleAt being used in non-table types.
  • Fixes issue where template projects do not use the correct lifecycle reducer setup
  • Fixes an issue where .insert() returns incorrect objects
  • Fixes an issue where .update() causes error with .autoInc() field

We intend for TypeScript modules and clients to rapidly approach stability. The most invasive breaking changes have already been made.

What's Changed

New Contributors

Full Changelog: v1.9.0...v1.10.0

Release v1.9.0 - Project Collaborators

21 Nov 19:29

Choose a tag to compare

Today we have a long overdue feature we're releasing, project collaborators! 👯

Project Collaborators

Now you can invite other members of your team to join your projects that you deploy to Maincloud.

image

In order to add collaborators, navigate to your project on the website and go to Settings > Collaborators, and then press Add People to add a new collaborator to your project.

Depending on the role you assign the user, they will be able to perform actions that were previously only possible for the database owner to run, including updating the module, viewing logs, and editing tables.

TypeScript (Beta) - API Update

We also have the first major update to our TypeScript API. This change dramatically improves usability in a few key areas and fixes some critical bugs in the TypeScript and React SDKs.

Important

This update also comes with a few breaking changes to the TypeScript API, which are detailed below. In general, we will try to minimize the number of changes to the existing API, but while TypeScript is in Beta we will be making a few important changes until we stabilize the API completely.

TypeScript Modules

TypeScript modules only get a modest change from the previous API:

  • Table accessor names and index accessor names are converted to camelCase on the ctx, so if your table name is foo_bar, the accessor changes from ctx.db.foo_bar to ctx.db.fooBar. This allows you to use whatever table name you want for your tables without running afoul of TypeScript linters.
  • Infer<> now also does InferTypeOfRow<> if applicable which means you can forget about InferTypeOfRow and just use Infer in all cases to get the type of a type builder.

TypeScript SDK

The TypeScript SDK has now been unified with the API of server modules. Code generation now uses the same types and functions that you use on the server. The eventual goals is to allow you to use your actual server types in your TypeScript client without needing to do any code generation. This leads to the following changes:

  • All types exported by generated files are now TypeBuilders, meaning that if you were previously using a type from a generated file, you will now have to do const x: Infer<typeof MyType> instead of const x: MyType. This may seem like an inconvenience, but it vastly improves a lot of the other APIs and is very flexible to extend and is inspired by the very powerful Zod library.
  • We no longer generate and export MyTypeVariants for sum types (these are now accessed by Infer<typeof MyType.variants.myVariant>)
  • Your module_bindings now export a tables object with references to all the TableDefs
  • Your module_bindings now export a reducers object with references to all the ReducerDefs
  • On the client my_table.iter() now returns IterableIterator instead of an Array
  • MyType.getTypeScriptAlgebraicType() has been replaced with MyType.algebraicType
  • Reducers are now called with the same format on the server and clients. e.g. ctx.reducers.createPlayer(argA, argB) -> ctx.reducers.createPlayer({ argA, argB })
  • Reducer callbacks now also take arguments the same way: ctx.reducers.onCreatePlayer(ctx, argA, argB) -> ctx.reducers.onCreatePlayer(ctx, { argA, argB }) & ctx.reducers.removeOnCreatePlayer(ctx, argA, argB) -> ctx.reducers.removeOnCreatePlayer(ctx, { argA, argB })
  • count() now returns a bigint instead of a number to match the server API e.g. myTable.count(): number -> myTable.count(): bigint. This may be changed in the future as it is unlikely that you will have a table with more than 2^53 rows.

Notable things that did not change:

  • MyType.serialize(writer: BinaryWriter, value: Infer<typeof MyType>) and MyType.deserialize(reader: BinaryReader): Infer<typeof MyType> are still supported exactly as before.
  • The MyType.MyVariant(...) constructor function on sum types is still present, but implemented with the private MyType.create('MyVariant', ...). We could choose to move away from this API later if we didn't like the variants polluting the namespace

Warning

You will need to regenerate your module bindings for your TypeScript clients with the latest version of the spacetime CLI tool.

React SDK

The React SDK gets a major improvement in both usability and correctness.

  • useSpacetimeDB() no longer takes type parameters
  • useSpacetimeDB() now returns a ConnectionState. All fields on the ConnectionState are not React state and will cause a rerender any time they change
  • useTable() now takes a TableDef parameter and type params are inferred
  • useTable() now just returns a tuple with the first element being an Array instead of a object with { rows }
  • Added a useReducer() React hook

So now you can write this in your React client:

  import { reducers, tables } from "./module_bindings";

  const { identity, isActive: connected } = useSpacetimeDB();
  const setName = useReducer(reducers.setName);
  const sendMessage = useReducer(reducers.sendMessage);
  const [onlineUsers] = useTable(tables.user, where(eq('online', true)));

The API for using a view is the same as using a table:

  const [myViewRows] = useTable(tables.myView);

What's Changed

Read more

Release v1.8.0 - Module Defined Views

12 Nov 15:46

Choose a tag to compare

Module Defined Views

The shipping continues! This time we have Module Defined Views or just "views". Views are a simple, but incredibly expressive way to define custom and intricate read permissioning for your tables.

Views, which are inspired by a similar concept from SQL, are virtual tables that are defined by new "view functions" in your module and derived from other tables or parameters.

Views are defined by read-only procedural, functions in the language of your module. This function returns data derived from your database tables. You can then query and subscribe to this view as you would any normal database table and it will be updated automatically in realtime.

Here's a look at the syntax for defining a view in the various module languages:

Rust

Declare with #[view]. First argument is a view context (&ViewContext or &AnonymousViewContext). Return Option<T> (0–1 row) or Vec<T> (many rows).

#[view(name = my_player, public)]
fn my_player(ctx: &ViewContext) -> Option<Player> {
    ctx.db.player().identity().find(ctx.sender)
}

#[view(name = players_for_level, public)]
fn players_for_level(ctx: &AnonymousViewContext) -> Vec<Player> {
    ctx.db
        .player_level()
        .level()
        .filter(2u64) // players for level 2
        .map(|player| {
            ctx.db
                .player()
                .id()
                .find(player.player_id)
        })
        .collect()
}

Notes

  • A name is required.
  • Only the context parameter is allowed; no extra args (yet).
  • The context provides a read-only view of the database
  • Mutations are not allowed
  • Full table scans are not allowed

C#

Use [SpacetimeDB.View] with ViewContext or AnonymousViewContext. Return a single row as T? or many rows as List<T> / T[].

[SpacetimeDB.View(Name = "my_player", Public = true)]
public static Player? MyPlayer(ViewContext ctx) =>
    ctx.Db.Player.Identity.Find(ctx.Sender) as Player;

[SpacetimeDB.View(Name = "players_for_level", Public = true)]
public static List<Player> PlayerLocations(AnonymousViewContext ctx) {
    var rows = new List<Player>();
    foreach (var player in ctx.Db.PlayerLevel.Level.Filter(2))
    {
        if (ctx.Db.Player.Id.Find(player.PlayerId) is Player p)
        {
            rows.Add(p);
        }
    }
    return rows;
}

TypeScript

Register with schema.view(...) or schema.anonymousView(...). Use t.option(row) for 0–1 row or t.array(row) for many rows.

spacetimedb.view(
  { name: 'my_player', public: true },
  t.option(players.row()),
  (ctx) => {
  return ctx.db.players.identity.find(ctx.sender) ?? null;
  }
);

spacetimedb.anonymousView(
  { name: 'players_for_level', public: true },
  t.option(players.row()),
  (ctx) => {
    const out = [];
    for (const pl of ctx.db.playerLevels.level.find(2)) {
      const p = ctx.db.players.id.find(pl.player_id);
      if (p) out.push(p);
    }
    return out;
  }
);

Row-level security rules

Currently procedurally defined view functions are limited to index probing tables so that we can efficiently compute the real-time delta for procedural functions. However, we also plan to shortly add the ability to return typed queries from view functions which will allow you to define performant, incrementally evaluated queries which execute full tables scans.

This functionality will make views strictly more expressive and powerful than the existing unstable RLS (row-level security) rules API that we introduced earlier this year. As such we will be deprecating the RLS API in favor of the view API. Here is an idea (not final API) of what that might look like in TypeScript

spacetimedb.view(
  { name: 'high_level_players', public: true },
  t.query(players.row()),
  (ctx) => {
  return ctx.from(ctx.db.player).where(player => gt(player.level, 50))
  }
);

What's Changed

Full Changelog: v1.7.0...v1.8.0

Release v1.7.0 - `spacetime dev`

03 Nov 21:29

Choose a tag to compare

New CLI Command - spacetime dev

We are continuing the month of shipping with a new CLI command for you all, spacetime dev.

spacetime dev automates your development loop to make developing with SpacetimeDB much faster and easier. It does the following:

  1. Generates types for your client (spacetime generate)
  2. Builds your application (spacetime build)
  3. Publishes your module (spacetime publish)
  4. Subscribes to your module logs (spacetime logs)
  5. Watches your module files for changes and repeats the process

spacetime dev is 5 commands in one and it's a real game changer once you try it!

With the introduction of spacetime dev we're also introducing a canonical default project structure:

my-spacetimedb-project/
├── package.json
├── tsconfig.json
├── src/                     # regular client app code
│   ├── main.ts
│   ├── App.tsx
│   └── components/
│
└── spacetimedb/             # SpacetimeDB module lives here
    ├── package.json         # its own TypeScript package
    ├── tsconfig.json
    └── src/
        ├── index.ts         # entrypoint for the module
        └── schema.ts         # schema / logic

With this structure, you can just include a spacetimedb folder inside your client project and have spacetime dev automatically publish your modules for you while you're developing. This makes it super easy to develop apps with a single server and client.

Although convenient, this default project structure is not mandatory and can be customized and configured for more complex multi-client applications or in situations where you want to separate your client and server into different repositories.

Usage

If you run spacetime dev in a directory without a spacetimedb directory (and do not specify a module-project-path), spacetime dev will take you through the process of setting up a new project.

$ spacetime dev
No SpacetimeDB project found in current directory.
Would you like to initialize a new project? yes
WARNING: This command is UNSTABLE and subject to breaking changes.

✔ Project name · my-spacetime-app
✔ Project path · ./my-spacetime-app
? Select a client type for your project (you can add other clients later) ›
❯ React - React web app with TypeScript server
  Use Template - Choose from a list of built-in template projects or clone an existing SpacetimeDB project from GitHub
  None

If you run spacetime dev in a directory with an existing spacetimedb directory (or specify a module-project-path), spacetime dev will ask you to publish a new module or connect to an existing one.

$ spacetime dev
Found existing SpacetimeDB project.
Now we need to select a database to publish to.

Selected database: grumpy-lunchroom-2109
Tip: Use `--database grumpy-lunchroom-2109` to skip this question next time

Starting development mode...
Database: grumpy-lunchroom-2109
Watching for changes in: /Users/tylercloutier/Developer/SpacetimeDB/my-spacetime-app/spacetimedb
Press Ctrl+C to stop

Updating .env.local with database name grumpy-lunchroom-2109...
Building...
Build complete!
Generating module bindings...
Generate finished successfully.
Publishing...
Build finished successfully.
Uploading to local => http://127.0.0.1:3000
Checking for breaking changes...
Publishing module...
JavaScript / TypeScript support is currently in BETA.
There may be bugs. Please file issues if you encounter any.
<https://github.com/clockworklabs/SpacetimeDB/issues/new>
Created new database with name: grumpy-lunchroom-2109, identity: c20008053ab940eb968e981c506037220be5dba2a948f8f7e7a131ba156bf28f
Published successfully!
---
Watching for file changes...
2025-10-30T23:19:12.862606Z  INFO: Creating table `person`
2025-10-30T23:19:12.863539Z  INFO: Database initialized

In either case, spacetime dev will watch for changes in your module files, update your client generated code, build your module, and publish it automatically!

Updated spacetime init

The spacetime init subcommand has been completely reworked. There are a few major changes here:

  1. You now specify a project name when creating a project
  2. There is a new interactive mode for selecting project templates (see below)

SpacetimeDB Project Templates

A Template is a pre-made project configuration that you can quickly deploy via spacetime init. Now when you run spacetime init you'll see all of the built-in options ready to deploy immediately:

You are logged in to SpacetimeDB.
✔ Project name · my-spacetime-app
✔ Project path · ./my-spacetime-app
✔ Select a client type for your project (you can add other clients later) · Use Template - Choose from a list of built-in template projects or clone an existing SpacetimeDB project from GitHub

Available built-in templates:
  basic-typescript - A basic TypeScript client and server template with only stubs for code
  basic-c-sharp - A basic C# client and server template with only stubs for code
  basic-rust - A basic Rust client and server template with only stubs for code
  basic-react - React web app with TypeScript server
  quickstart-chat-rust - Rust server/client implementing quickstart chat
  quickstart-chat-c-sharp - C# server/client implementing quickstart chat
  quickstart-chat-typescript - TypeScript server/client implementing quickstart chat

? Template ID or GitHub repository (owner/repo) or git URL ›

As you can see you can also specify a Github URL here to deploy a custom template. This allows the community to build and share their own templates to be used by others.

Auth claims in modules

Client credentials are now exposed to your module code, so you can have more control over your authorization logic. For some examples of how to use it to secure your app, check out the docs.

Other changes

Docusaurus Migration

We recently migrated all of our documentation to docusaurus! You can view the newly updated documentation here: https://spacetimedb.com/docs .

Postgres Wire Protocol on Maincloud

The big update here is that we have re-enabled postgres wire protocol on Maincloud! You can see the full release notes for our Postgres Wire Protocol release here: https://github.com/clockworklabs/SpacetimeDB/releases/tag/v1.5.0 .

Default Server

The default server for newly installed CLI tools has been changed from local to maincloud. This only affects new users as existing users will already have a default server set in their spacetime CLI config.toml.

What's Changed

Read more

Release v1.6.0 - TypeScript Modules (Beta)

16 Oct 22:39

Choose a tag to compare

0_cy5S4LnOIInTBXed

TypeScript Modules (Beta)

TypeScript/JavaScript modules are finally here! We're extremely excited to announce v1.6. For the first time in several years we've added a new server module language, and it required a whole new runtime! SpacetimeDB now ships with v8.

In order to get started with TypeScript modules, follow our quickstart guide or read the module API reference. Publishing a TypeScript module is almost exactly the same as publishing a Rust or C# module. In order to get started simply run:

spacetime init --lang typescript # in the appropriate directory
spacetime publish <your-module-name> # in the directory with your package.json

The spacetime CLI tool will look for src/index.ts and automatically bundle your application and upload it to SpacetimeDB.

⚠️ BETA NOTICE: TypeScript modules are currently in beta. As a result performance is not representative of the final product. If you encounter bugs or other issues, please file a new issue here with the typescript-modules label.

Other Features

In v1.6 we are now also adding additional schema migration support, including adding columns to tables! In order to add a column, just add a column to the end of your table definition, specify a default value, and push the new module. The CLI will warn you if your new schema is compatible with existing clients, and will disconnect the appropriate clients if required by the migration. This is one more step in our journey to provide a world class schema migration experience for your apps and games.

Other improvements

  • Added a Default attribute to fields in C# modules
  • Database snapshot improvements:
    • The database snapshots at a more intelligent interval
    • Improve snapshot compression + metrics (#3296)
  • Unreal Engine
    • allow access to inherited properties from all contexts in Blueprint
    • Fixed some Unreal code generation bugs when using optional types.
    • Adding wss:// support for the Unreal SDK (#3328)
  • TypeScript SDK
    • Fixed an issue where we use table_name_camelcase instead of table_name for useTable in TypeScript
    • Fix bug where TypeScript SDK crashes when I32 is the primary key
  • Misc bugfixes:
    • Fixed an issue where Rust dependencies would automatically be rolled forward beyond the specified version
    • Fix some errors when using indexes on floating-point types
    • Reduced some spammy logs on the server side
  • Other miscellaneous performance improvements

What's Changed

New Contributors

Full Changelog: v1.5.0...v1.6.0

Release v1.5.0

01 Oct 16:58

Choose a tag to compare

We've got some releases coming at you fast this month, and there's more to come! We've got some very exciting new features in SpacetimeDB v1.5.0.

Postgres Wire Format (Beta)

The initial version of the Postgres Wire Protocol is now implemented in SpacetimeDB. This means you can connect normal Postgres clients like psql or tokio-postgres to SpacetimeDB on port 5432.

Please note that this is the first step on a (very) long journey to make SpacetimeDB as Postgres compatible as the architecture allows and it comes with a set of caveats, but as of today you can officially connect to SpacetimeDB with a Postgres client! You can find the full documentation on what is supported in the docs.

image

SpacetimeAuth (Beta)

We are also releasing another major feature today as well, SpacetimeAuth! SpacetimeAuth is a new authentication and user management service operated by Clockwork Labs. The goal is deep integration with SpacetimeDB so you get user management for all your projects and databases with the click of a button.

No more having to spin up an auth service just to deploy an app on SpacetimeDB. Now you can just navigate to SpacetimeAuth in your profile menu dropdown or go to https://spacetimedb.com/spacetimeauth and create a new project for your application.

Your users can then log in to your SpacetimeDB application by using a new customizable webpage.

SpacetimeAuth

What's Changed

  • Removed @clockworklabs/typescript-sdk in favor of spacetimedb by @cloutiertyler in #3262
  • Bump remaining versions to 1.4.0 by @bfops in #3267
  • datastore: add clear_table and fix drop_table by @Centril in #3214
  • datastore: add support for truncation by @Centril in #3215
  • Add reducer name to database log records by @gefjon in #3274
  • Update C# DLLs to 1.4.0 by @bfops in #3270
  • datastore: add columns support by @Shubham8287 in #3230
  • Finish making PG tests use a dynamic server address by @bfops in #3277
  • Remove incorrect broken links by @JasonAtClockwork in #3280
  • Wrap some tests in a mod so that I can --skip them by @gefjon in #3284
  • Loosen spacetimedb dep on spacetime init --lang rust by @bfops in #3286
  • TypeScript: Add confirmed reads config by @kim in #3247
  • Rust SDK: Make confirmed parameter optional by @kim in #3283
  • Add metrics tracking time to restore a database from disk by @gefjon in #3285
  • Expand scope of DurabilityProvider to include snapshotting by @kim in #3281
  • Revert "Expand scope of DurabilityProvider to include snapshotting (#3281)" by @kim in #3293
  • SATS: impl ser/de for tuples by @Centril in #3292
  • Support BytesSources other than the one for reducer args by @gefjon in #3294
  • Make optional to listen to pg wire protocol and param for the port by @mamcx in #3309
  • Fix CI breakage by PR #3309 by @mamcx in #3314
  • Make the .NET global.json file global by @kim in #3297
  • Bump versions to 1.5.0, update DLLs, and regenerate files by @bfops in #3310
  • Integrate tools/upgrade-version into cargo and expand by @bfops in #3308
  • CI - Move Unity testsuite to a different runner by @bfops in #3318
  • CI - apt install invocations correctly pass -y by @bfops in #3324
  • C# tests - update snapshots by @bfops in #3321
  • Improve message error if the port is taken by @mamcx in #3320

Full Changelog: v1.4.0...v1.5.0

Release v1.4.0

23 Sep 01:55

Choose a tag to compare

We have an exciting announcement for you today 🎉🎉🎉 We've been cooking on Unreal Engine and React Hooks for a while now and we're finally ready to release both of them.

Unreal Engine

We know this is one highly requested feature so today we're happy to announce that SpacetimeDB now fully supports Unreal Engine. You can use our Unreal Engine SDK with either C# or Rust SpacetimeDB modules. We have even extended the Blackholio demo to work with the existing modules. So this means we've added Unreal Engine as a client alongside our Unity implementation. You can even connect both a Unity and Unreal Engine Blackholio client to the same module. We know this has been a highly requested feature that the community has been asking for so we're excited to see what everyone builds with it!

If you don't want to do the tutorial and you just want to play around want to try out our Blackholio demo you can find the latest version here: https://github.com/clockworklabs/SpacetimeDB/tree/master/demo/Blackholio

Shoutout to Arvikasoft who we collaborated with for the development of this SDK!

React Hooks 🪝 (Beta)

React hooks for SpacetimeDB are now here! Using SpacetimeDB with React is now much much easier. Just add a SpacetimeDBProvider to your component hierarchy and use the useTable React hook!

// main.tsx
const connectionBuilder = DbConnection.builder()
  .withUri('wss://maincloud.spacetimedb.com')
  .withModuleName('MODULE_NAME');

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <SpacetimeDBProvider connectionBuilder={connectionBuilder}>
      <App />
    </SpacetimeDBProvider>
  </React.StrictMode>
);

// App.tsx
function App() {
  const conn = useSpacetimeDB<DbConnection>();
  const { rows: messages } = useTable<DbConnection, Message>('message');

  ...
}

SpacetimeDB will magically synchronize your table state with your React client and re-render your UI as it changes. About as simple as it gets!

For added power, add a typed where clause to your useTable hook to filter the rows you want to subscribe to:

const { rows: users } = useTable<DbConnection, User>('user', where(eq('online', true)));

Upgrade Instructions

In order to receive this update you'll first need CLI version 1.4.0. In order to upgrade to the new CLI version you can just run spacetime version upgrade which will automatically upgrade you to the newest version. If you don't have SpacetimeDB installed you'll need to go to https://spacetimedb.com/install .

You can verify that you have the newest version installed by running spacetime version list in your terminal application:

> spacetime version list
1.4.0 (current)

Then you'll need to update your SpacetimeDB SDK version in your package.json file. Before this update you would have had something like this:

  "dependencies": {
    "@clockworklabs/spacetimedb-sdk": "^1.3.0",
    ...
  },

Now our new package looks like this:

  "dependencies": {
    "spacetimedb": "^1.4.0",
    ...
  },

If you are at all confused you can just look at our Typescript quickstart which has instructions on installing the CLI + using the correct package in package.json: https://staging.spacetimedb.com/docs/sdks/typescript/quickstart

Confirmed Reads

"Confirmed reads" is a feature which allows you to specify during the connection setup that you only want to hear back about transactions which have already been persisted. This means these transactions will not be lost if the server you are connected to experiences a hardware failure of some sort.

Here is an example of how to enable confirmed reads:

const connectionBuilder = DbConnection.builder()
  .withUri('ws://localhost:3000')
  .withModuleName('quickstart-chat')
  .withConfirmedReads(true)
  .withToken(localStorage.getItem('auth_token') || undefined)
  .onConnect(onConnect)
  .onDisconnect(onDisconnect)
  .onConnectError(onConnectError);

Improvements/Fixes

  • The version number for codegen is now only written to a single file instead of every single generated file. This helps cut down on conflicts when changing SpacetimeDB CLI versions. (#3216)
  • Improve error reporting for invalid column-type-changing automigrations (#3202)
  • Sort columns in st_column_changed before automigrating. (#3203)
  • Fixed not being able to have columns named "read", "write", etc. (#2525)
  • Typescript SDK: Fix to actually use the passed onclose function (#3152)
  • Removed // @ts-ignore directive from generated files and fixes associated errors (#3228)
  • TimeSpan-Style TimeDuration Constructors in C# Bindings (#2778)

What's Changed

Read more

Release v1.3.2

04 Sep 17:46

Choose a tag to compare

Just a small bugfix release to re-enable and fix functionality for adding new enum variants!

Full Changelog: v1.3.1...v1.3.2