clockworklabs / clockworklabs/SpacetimeDB
TypeScript codegen: server-defined views not exposed as typed client accessors (`useTable` cannot subscribe)
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:
tables.<view_name>accessor, generated with the same row-type as the view's declared return type, usable directly withuseTable(tables.my_user_settings). The SDK would auto-issueSELECT * FROM my_user_settingson subscription and route incoming rows into a typed cache keyed by the view name.- Subscription-routed rows — keep the underlying
tables.<table_name>accessor in bindings even whenpublic: 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 returnst.array(table.rowType)). - At minimum, document the supported pattern explicitly. If raw SQL
subscribe('SELECT * FROM my_view')plus manualdb.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: trueand 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, replacinguseTableeverywhere.
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
spacetimeCLI: 2.2.0 (also tested 2.1.0)spacetimedbnpm 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
useTablefromspacetimedb/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
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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