Skip to content

SDK API

SpacetimeDB: SDK API ↗

Stdb.project(Module.spec) is the Effect-native SDK companion for a module.

import * as Effect from "effect/Effect"
import * as Stdb from "effect-spacetimedb"
declare const uri: string
declare const databaseName: string
declare const token: string
const Users = Stdb.StdbGroup.make("Users").add(
Stdb.StdbFn.reducer("user_upsert", {
params: Stdb.struct({ userId: Stdb.string(), name: Stdb.string() }),
}),
)
const Module = Stdb.StdbModule.make("app").add(Users)
const Example = Stdb.project(Module.spec)
const HttpLive = Example.client.http.layerFetch({ uri, databaseName, token })
const program = Effect.gen(function* () {
const client = yield* Example.client.http.Tag
yield* client.reducers.user_upsert({ userId: "u1", name: "Ada" })
}).pipe(Effect.provide(HttpLive))

The projection contains:

  • client.http: typed Effect service, direct make, and layer constructors.
  • client.ws: scoped/layered WebSocket sessions over generated native bindings.
  • targets: public persistent-table, event-table, and all-public-table targets.
  • module, tables, reducers, procedures, httpHandlers, and lifecycle metadata for tooling.
  • Stdb.toHttpApi(Module.spec): an Effect HttpApi projection for typed HTTP routes.

effect-spacetimedb’s client surface uses Effect services and typed errors. It does not replace the native generated WebSocket cache; it wraps it with scoped resources, projected callables, and subscription helpers.

Reducer and procedure functions expose a typed call and a .raw variant. The typed call decodes declared domain errors into the error channel directly. The raw variant preserves a DomainCallError wrapper so callers can distinguish a remote declared error from transport, rejection, or decode failures.

import * as Effect from "effect/Effect"
import * as Stdb from "effect-spacetimedb"
import * as StdbClient from "effect-spacetimedb/client"
const AppErrors = Stdb.errors.namespace("App")({
UserMissing: Stdb.error({ userId: Stdb.string() }, { status: 404 }),
})
const Users = Stdb.StdbGroup.make("Users").add(
Stdb.StdbFn.procedure("user_get", {
params: Stdb.struct({ userId: Stdb.string() }),
returns: Stdb.option(Stdb.struct({ userId: Stdb.string(), name: Stdb.string() })),
errors: AppErrors,
}),
)
const Module = Stdb.StdbModule.make("app").add(Users)
const Example = Stdb.project(Module.spec)
const program = Effect.gen(function* () {
const client = yield* Example.client.http.Tag
return yield* client.procedures.user_get.raw({ userId: "u1" })
}).pipe(
Effect.catchTag("DomainCallError", (failure: StdbClient.DomainCallError<unknown>) =>
Effect.fail(failure.error),
),
)

The exported failure model is:

TypeMeaning
CallFailure<E>Typed call error union: declared errors, RemoteRejectedError, TransportError, or StdbDecodeError.
RawCallFailure<E>Raw call error union: DomainCallError<E>, RemoteRejectedError, TransportError, or StdbDecodeError.
DomainCallError<E>Declared error preserved as a wrapper by .raw.
RemoteRejectedErrorThe remote side rejected the call without a decodable declared error.
TransportErrorThe HTTP or WebSocket transport failed before a typed response arrived.
StdbDecodeErrorA response, row, event, or payload could not be decoded with the module contract.

The lower-level catchRawTags helper is exported from effect-spacetimedb/testing for fixture and protocol-level assertions. Public application clients should usually handle the exported failure classes directly or use the typed call form.

Use Stdb.httpApiBaseUrl with Stdb.toHttpApi(Module.spec) when you want a stock Effect HttpApiClient over typed post, put, or patch routes.

import * as Effect from "effect/Effect"
import * as HttpClient from "effect/unstable/http/HttpClient"
import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest"
import * as HttpApiClient from "effect/unstable/httpapi/HttpApiClient"
import * as Stdb from "effect-spacetimedb"
declare const Module: Stdb.AnyStdbModule
declare const uri: string
declare const databaseName: string
declare const token: string
const api = Stdb.toHttpApi(Module.spec)
const program = Effect.gen(function* () {
const client = yield* HttpApiClient.make(api, {
baseUrl: Stdb.httpApiBaseUrl({ uri, databaseName }),
transformClient: HttpClient.mapRequest(
HttpClientRequest.bearerToken(token),
),
})
return client
})