clockworklabs / clockworklabs/SpacetimeDB

TypeScript codegen: server-defined views not exposed as typed client accessors (`useTable` cannot subscribe)

Open
#4,936 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
25.2k
Forks
1.1k
Avg merge
2d 7h
Merged PRs (30d)
46

Description

Summary

When a table is public: false and a server-defined spacetimedb.view(...) filters its rows by ctx.sender, the TypeScript client codegen produces no accessor for the view — neither a tables.<view_name> entry nor a <view_name>_table.ts file. The view runs on the server and a raw SELECT * FROM <view> SQL subscription works, but useTable() (the React reactive primitive most apps use) has no surface to bind to. This forces apps that want per-user-filtered subscriptions to abandon useTable and write a custom row-tracking layer for every screen, which defeats most of the ergonomic value of the SDK.

Tested against spacetimedb 2.1.0 and 2.2.0 (TypeScript SDK + CLI codegen); behaviour is identical in both.

Repro

Schema:

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

const user_settings = table(
  { name: 'user_settings', public: false },
  { identity: t.identity().primaryKey(), pref: t.string() }
);

const spacetimedb = schema({ user_settings });
export default spacetimedb;

spacetimedb.view(
  { name: 'my_user_settings', public: true },
  t.array(user_settings.rowType),
  ctx => {
    const own = ctx.db.user_settings.identity.find(ctx.sender);
    return own ? [own] : [];
  }
);

spacetime publish succeeds. spacetime generate --lang typescript output:

Skipping private tables during codegen: user_settings.
The following files were not generated by this command and will be deleted:
  src/module_bindings/user_settings_table.ts

The resulting module_bindings/index.ts has no entry for user_settings and no entry for my_user_settings. There is no my_user_settings_table.ts file. Client side, tables.user_settings is gone (TS error at every callsite) and tables.my_user_settings doesn't exist either.

Expected

One of the following, ideally option 1:

  1. tables.<view_name> accessor, generated with the same row-type as the view's declared return type, usable directly with useTable(tables.my_user_settings). The SDK would auto-issue SELECT * FROM my_user_settings on subscription and route incoming rows into a typed cache keyed by the view name.
  2. Subscription-routed rows — keep the underlying tables.<table_name> accessor in bindings even when public: false, and have the SDK route rows from the view's SQL subscription into that cache (rows are already row-type-compatible since the view returns t.array(table.rowType)).
  3. At minimum, document the supported pattern explicitly. If raw SQL subscribe('SELECT * FROM my_view') plus manual db.connection.db.<view_name>.iter() is the intended client API, the docs and the codegen output should reflect that — currently the codegen warning (Skipping private tables) reads as a problem to fix, and there's no obvious path from there to a working client.

Use case

Pretty much every multi-tenant SaaS pattern on top of SpacetimeDB. We're building an anonymous social platform — DMs, per-user settings, moderation reports, etc. — where most tables need per-user-filtered subscriptions. Without this, the only choices are:

  • Keep tables public: true and accept the privacy leak (every authenticated client subscribes to every row).
  • Move all reads into reducers/procedures with HTTP responses, losing the live-update story SpacetimeDB exists for.
  • Manually wire subscriptionBuilder().subscribe(...) SQL queries into Zustand/Jotai stores per screen, replacing useTable everywhere.

The spacetimedb.view(...) API + CLAUDE.md's "Private table + view pattern" guidance suggest this is the intended path, but the typed client wiring isn't there yet.

Environment

  • spacetime CLI: 2.2.0 (also tested 2.1.0)
  • spacetimedb npm package: 2.2.0 (also tested 2.1.0)
  • TypeScript: 5.9.3
  • Backend module: TypeScript on Maincloud
  • Client: Next.js 16 + React 18, using useTable from spacetimedb/react

Happy to provide a minimal repro repo or test against a pre-release branch if useful.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the TypeScript schema with a private table and server-defined view, then run spacetime generate --lang typescript. Inspect the private-table filtering and generated module_bindings/index.ts; compare the missing view accessor with useTable and raw SQL subscription behavior. Done means the supported path is typed and documented, or the intended raw-SQL workflow is explicitly documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
sql, typescript
Domain
database, developer-experience
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.