Client Connection
Stdb.project(Module) produces a client-safe projection. It contains no
server runtime; it is only the callable, route, table, and subscription shape
needed by clients.
HTTP Client
Section titled “HTTP Client”import * as Effect from "effect/Effect"import * as Stdb from "effect-spacetimedb"
declare const Module: Stdb.AnyStdbModuledeclare const uri: stringdeclare const databaseName: stringdeclare const token: string
const Example = Stdb.project(Module)const HttpLive = Example.client.http.layer({ 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))Typed HTTP handlers are called with just their payload. Raw handlers take the payload and request options.
Effect HttpApi Projection
Section titled “Effect HttpApi Projection”Typed post, put, and patch routes can be projected into a stock Effect
HttpApi:
const api = Stdb.toHttpApi(Module)This is useful when callers already use HttpApiClient.make(...) and want
status-based declared-error decoding.
WebSocket Client
Section titled “WebSocket Client”WebSocket sessions use generated native bindings through
effect-spacetimedb/client.
import * as StdbClient from "effect-spacetimedb/client"import * as Stdb from "effect-spacetimedb"
declare const Module: Stdb.AnyStdbModuledeclare const DbConnection: StdbClient.GeneratedWsConnectionFactory< typeof Module.spec, unknown>declare const uri: stringdeclare const databaseName: stringdeclare const token: string
const Example = Stdb.project(Module)
const WsLive = Example.client.ws.layerGenerated({ DbConnection, uri, databaseName, token,})layerGenerated and scopedGenerated are the generated-client paths. The
standalone generated config helper is reserved for the package testing
entrypoint.
Named tags let one process hold multiple sessions for the same module.
import * as StdbClient from "effect-spacetimedb/client"import * as Stdb from "effect-spacetimedb"
declare const Module: Stdb.AnyStdbModuledeclare const DbConnection: StdbClient.GeneratedWsConnectionFactory< typeof Module.spec, unknown>declare const uri: stringdeclare const databaseName: stringdeclare const token: string
const Example = Stdb.project(Module)const MainSession = Example.client.ws.tag("main")const MainLive = Example.client.ws.layerGenerated( { DbConnection, uri, databaseName, token }, { name: "main" },)The native generated client still owns the actual WebSocket connection. effect-spacetimedb layers typed Effect services, scoped sessions, and projected HTTP clients over the module contract.
Connection Failures
Section titled “Connection Failures”The handshake is the dividing line. A failure before the connection is
established fails the scoped acquisition with WsConnectError; a failure after
it is a connection loss, which invalidates the session and fails in-flight and
subsequent calls with ConnectionLostError.
| What happened | During acquisition | On an established session |
|---|---|---|
| Socket error before the handshake | WsConnectError with the socket error as cause | — |
| Socket error after the handshake | WsConnectError with the socket error as cause | ConnectionLostError whose raw is that error’s message |
| Close with no reported error | WsConnectError with cause: undefined | ConnectionLostError with raw: "WebSocket connection disconnected" |
| Connect timeout | WsConnectError whose cause is WsConnectTimeoutError | — |
| Generated client missing contract relations | GeneratedArtifactShapeError, naming the missing keys | — |
A socket error raised after the handshake never arrives as a connect error.
The SDK records it, closes the socket, and reports it on the disconnect path, so
cause is what distinguishes a connection that died with a reason from one that
simply closed. The causeless case covers both a clean close and the close the
SDK performs when an inbound frame fails to decompress.
In a browser, onerror hands the SDK an ErrorEvent rather than an Error.
The SDK normalizes that to an Error carrying the event’s message, with the
original event on .cause, so WsConnectError.cause is an Error on every
runtime.
ConnectionLostError means the client never observed a terminal response for a
call. The reducer or procedure may already have committed on the server. Treat
the outcome as unknown, prefer idempotent mutations, and reconcile from the
replacement session’s subscribed state before retrying anything that is not.
A bare scoped session surfaces terminal invalidation and stops there. Long-lived clients can opt into the package supervisor for bounded acquisition, jittered reconnect backoff, scoped per-session setup, and resubscription; a reconnect after a causeless close behaves exactly like one after a reported socket error.
Not affiliated with SpacetimeDB (Clockwork Laboratories) or Effect (Effectful Technologies).