Repository navigation
Async IDC: Typescript. - #6327
Merged
Merged
Conversation
Shubham8287
changed the base branch from
shub/idc-ux
to
shub/idc-rust-outbox-macro
October 17, 2026 08:30
Shubham8287
force-pushed
the
shub/idc-typescript
branch
from
October 17, 2026 09:20
8e5f8f3 to
65e7c7e
Compare
Shubham8287
force-pushed
the
shub/idc-rust-outbox-macro
branch
2 times, most recently
from
October 22, 2026 07:22
138855d to
b393c47
Compare
Shubham8287
force-pushed
the
shub/idc-typescript
branch
from
October 22, 2026 09:01
65e7c7e to
7f2c784
Compare
Shubham8287
force-pushed
the
shub/idc-rust-outbox-macro
branch
from
October 22, 2026 09:06
b393c47 to
8942ea8
Compare
Shubham8287
force-pushed
the
shub/idc-typescript
branch
2 times, most recently
from
October 26, 2026 11:47
7f996d0 to
ff91af0
Compare
Shubham8287
changed the base branch from
shub/idc-rust-outbox-macro
to
shub/idc-rust-outbox-macro-split
October 26, 2026 12:14
Shubham8287
force-pushed
the
shub/idc-rust-outbox-macro-split
branch
from
October 27, 2026 14:55
e657762 to
9d87560
Compare
Shubham8287
force-pushed
the
shub/idc-typescript
branch
2 times, most recently
from
October 28, 2026 11:26
bb4c0b4 to
90b2a05
Compare
5 of 7 tasks
# Description of Changes This PR tidies the TypeScript side of async IDC after the review of #6327: it drops the `declare const` brand on `ReceiverIdentity` and the `boolean &` cast on `isOutbox`, takes `onResult` at the top level of the reducer options, lets index lookups and query comparisons take a plain `Identity`, and names the conflict when `onResult` is combined with `onSchedule` or a lifecycle reducer. Previously the brand duplicated the `unique symbol` that every `remoteModule` caller already passes ([thread](#6327 (comment))), the cast only existed because `table()` intersected `TableSchema`'s `isOutbox?: boolean` with its literal type ([thread](#6327 (comment))), `reactive: { onResult }` didn't match the shipped `onSchedule` option from #5435 or Rust's `#[reducer(on_result(t))]` ([thread](#6327 (comment))), a reducer or view couldn't check `ctx.sender` against a `gw.identity()` column without casting to a type users can't name, and both conflicts were reported as a parameter mismatch. Now `ReceiverIdentity` is keyed by the module symbol, `TableSchema` takes an `IsOutbox extends boolean = boolean` parameter that `table()` sets directly, index keys and comparison literals accept any `Identity` while rows keep the receiver's type, each conflict has its own error, and proposals 0036 and 0037 match in SpacetimeDBPrivate#2862 and SpacetimeDBPrivate#4056. # API and ABI breaking changes None for users, because everything here except the lookup and comparison changes is new in #6327 and hasn't shipped, and those two only loosen types, so code that compiled before still compiles. Code written against #6327's `reactive: { onResult }` stops compiling, but only the SDK tests, the `idc-sender-ts` smoketest, `module-test-ts` and the SDK README used it, and they're updated here. `TableSchema`'s `isOutbox` is now required, which only matters to code that builds a `TableSchema` by hand instead of through `table()`, and the new parameter defaults to `boolean`, so two-argument annotations like `TableSchema<Row, []>` keep the full table API. # Rollback safety impact n/a # Expected complexity level and risk 1 # Testing - [x] `tsc -p tsconfig.json --noEmit` reports no new errors, and the cases in `src/server/idc.test-d.ts` and `src/server/table-compatibility.test-d.ts` pass, including the `@ts-expect-error` ones that reject another module's identity, a raw `Identity` and an unchecked `ctx.sender` as outbox targets - [x] The new check-then-reply and view cases in `idc.test-d.ts` fail without the `indexes.ts` and `query.ts` changes and pass with them - [x] `vitest run tests/idc.test.ts` (18 passing), including the new conflict errors - [x] The full SDK unit suite passes apart from four files that need a full workspace install (built wasm datastore, `react-dom`, and the `spacetimedb` workspace link) - [x] ESLint and Prettier on the changed SDK files and README - [ ] The `idc-sender-ts` and `module-test-ts` modules build in CI - [ ] CI
LookupValue was named after index lookups, but query comparisons use it too, and the name didn't say what it does: it removes a receiver identity's module brand and passes other types through.
TableSchema carried both isOutbox and outbox, and they always agreed. The outbox field is now typed from the table options, so its presence is the type-level marker for DbView and onResult. The internal table definition keeps an isOutbox flag, now derived from outbox.
The comments said scope segments of type names stay unchanged, but the validator converts them to PascalCase too, which the test's own assertion (MyLib::Utils::MetaInfo) and describe.rs's scoped_ref test both check.
cloutiertyler
approved these changes
Oct 29, 2026
Contributor
There was a problem hiding this comment.
I'm okay to have this merge. The one thing I have concerns with is:
export const PingDetails = __t.object("game_world.PingDetails", { // ← sender's name baked in
labels: __t.array(__t.string()),
owner: __t.identity(),
});game_world I don't think should belong here. I think rather it should belong here:
export const PingDetails = __t.object("PingDetails", { // ← same as the source
labels: __t.array(__t.string()),
owner: __t.identity(),
});
export type PingDetails = __Infer<typeof PingDetails>;
const __receiverModule: unique symbol = globalThis.Symbol() as typeof __receiverModule;
// The scope is given once, where the dependency is attached. remoteModule records
// the named types reachable from these params, and the sender registers them
// as game_world.PingDetails.
export default __remoteModule("game_world", {
"receivePing": { /* unchanged */ },
}, __receiverModule);
I'm having Claude prototype this in a PR into this PR, but I don't think that should necessarily block this from merging (it is not hard to fix later, because we can just change codegen). See #6414 for what I'm talking about.
5 of 7 tasks
cloutiertyler
enabled auto-merge
October 29, 2026 04:25
cloutiertyler
disabled auto-merge
October 29, 2026 04:25
cloutiertyler
enabled auto-merge
October 29, 2026 04:28
Receiver bindings formatted the receiver's type name with ScopedTypeName's Display, which joins scope segments with `::`. Rust splits sats names on `::` and `.`, but the TypeScript SDK's splitName splits only on `.`, so a receiver type like module-test's Namespace.TestC registered in a TypeScript sender as the invalid identifier `Namespace::TestC`, and the sender failed to publish.
cloutiertyler
enabled auto-merge
October 29, 2026 04:32
This was referenced Oct 30, 2026
Merged
Penguinjanator
pushed a commit
to Penguinjanator/SpacetimeDB
that referenced
this pull request
Oct 31, 2026
# Description of Changes This PR teaches the agent skills about asynchronous inter-database communication (IDC). Async IDC shipped in clockworklabs#6150 through clockworklabs#6327, but the skills only mentioned receiver bindings in the CLI skill, so an agent writing a module wouldn't know how to declare an outbox table or handle `on_result`, or that a receiving database's `client_connected` must not require a JWT. Following the docs page in clockworklabs#6424, this adds IDC sections to the Rust server, TypeScript server, and concepts skills, switches the CLI skill to the docs' "sending database" wording, and resyncs the Codex plugin copy, without touching code or the plugin version. # API and ABI breaking changes This PR doesn't break anything because it only changes agent skill text. # Rollback safety impact n/a # Expected complexity level and risk 1 # Testing - [x] Compiled the Rust skill snippet against generated receiver bindings with `cargo check --target wasm32-unknown-unknown`. - [x] Typechecked the TypeScript skill snippet against generated receiver bindings with `tsc --noEmit`. - [x] `node codex-plugin/scripts/check-skills-sync.ts` reports the Codex copy in sync. - [ ] CI
Penguinjanator
pushed a commit
to Penguinjanator/SpacetimeDB
that referenced
this pull request
Oct 31, 2026
# Description of Changes This PR adds a Core Concepts page that documents asynchronous inter-database communication (IDC). The feature landed in clockworklabs#6150, clockworklabs#6156, clockworklabs#6313, clockworklabs#6364, clockworklabs#6375, clockworklabs#6376, and clockworklabs#6327, but the only docs so far covered receiver-dependency configuration (clockworklabs#6362), so database developers had nothing explaining what an outbox is, what delivery guarantees they get, or how to send a call and handle its result. Following SpacetimeDBPrivate#2863, the new page explains the concept and motivation, leads with a lobby-to-game-world example in TypeScript and Rust, and then covers outbox tables, receiving calls, `on_result`, receiver changes, and current limitations, with links from the Databases, `spacetime dev`, `spacetime.json`, and auth usage pages, which now say "sending database" instead of "calling database", and a new `parent` row in the `spacetime.json` reference, with no code changes. # API and ABI breaking changes This PR doesn't break anything because it only adds and links documentation. # Rollback safety impact n/a # Expected complexity level and risk 1 # Testing - [x] Ran the lobby and game world example end to end in both Rust and TypeScript against a local standalone server built from master, and confirmed the SQL and log output shown on the page. - [x] Compiled or typechecked every smaller snippet, and checked formatting with the repo's rustfmt and Prettier settings. - [x] Reproduced the signature-mismatch error, the compile error after regenerating bindings, and the `client_connected` retry behavior that the page quotes. - [x] `pnpm build` in `docs` passes with broken links and anchors set to throw. - [x] Published the example with `"parent": "lobby"` on a local server, published again, and confirmed calls still deliver. - [ ] Confirm IDC works between two databases on Maincloud, which the "same server" limitation assumes. - [ ] Remove the Rust index-lookup limitation if it is fixed before release. - [ ] CI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description of Changes
Based on #6376.
Adds TypeScript receiver bindings and outbox declarations for intermodule reducer calls.
It can be reviewed through commits:
onResultcallbacks..param({ name })and make outboxes insert-only while preserving existing table APIs.Proposal drfits:
{ name }, rather than{ accessor, name }. The key passed toschema({...})defines the accessor, matching regular TypeScript tables.name, the sugar uses the outbox table's accessor name (case converted) as the canonical name rather than defaulting to<reducer>Outbox.API and ABI breaking changes
NA
Rollback safety impact
n/a
Expected complexity level and risk
Testing
unit tests and smoketests.