Skip to content

js-bao-wss-client


js-bao-wss-client / JsBaoClientOptions

Interface: JsBaoClientOptions ​

Configuration for constructing a JsBaoClient (or calling initializeClient). Only apiUrl, wsUrl, and appId are required; everything else tunes authentication, offline persistence, sync behavior, networking, and analytics.

Properties ​

analyticsAutoEvents? ​

optional analyticsAutoEvents?: AnalyticsAutoEventsOptions


apiUrl ​

apiUrl: string


appId ​

appId: string


auth? ​

optional auth?: object

persistJwtInStorage? ​

optional persistJwtInStorage?: boolean

refreshProxy? ​

optional refreshProxy?: object

refreshProxy.baseUrl ​

baseUrl: string

refreshProxy.cookieMaxAgeSeconds? ​

optional cookieMaxAgeSeconds?: number

refreshProxy.enabled? ​

optional enabled?: boolean

storageKeyPrefix? ​

optional storageKeyPrefix?: string


autoNetwork? ​

optional autoNetwork?: boolean


autoOAuth? ​

optional autoOAuth?: boolean


autoUnlockOfflineOnInit? ​

optional autoUnlockOfflineOnInit?: boolean


blobUploadConcurrency? ​

optional blobUploadConcurrency?: number


commitRetryBackoff? ​

optional commitRetryBackoff?: object

baseMs? ​

optional baseMs?: number

factor? ​

optional factor?: number

jitter? ​

optional jitter?: boolean

maxMs? ​

optional maxMs?: number


databaseConfig? ​

optional databaseConfig?: DatabaseConfig

The local query engine. Default { type: "sqljs" }, in memory. A web app that opens large documents passes { type: "opfs", options: { workerURL?, brokerURL?, locateFile? } }: format-1 documents keep the SQL.js mirror and each large document gets a worker-hosted store that survives a reload. brokerURL points at a small SharedWorker (js-bao/format2-broker) that lets several tabs of the same app share one document's store — one tab hosts the engine, the others reach it through a port the broker hands over; without it, a second tab opening the same large document is refused. Needs js-bao 0.7.0 or newer (0.8.0 for brokerURL); with an older js-bao the client throws OPFS_ENGINE_UNAVAILABLE.


globalAdminAppId? ​

optional globalAdminAppId?: string


largeDocumentStorage? ​

optional largeDocumentStorage?: object

What this device may keep of a large document.

Loading a large document materializes its records into local storage. On a platform whose quota will not take the whole document, models names the ones worth the space — the rest are left unloaded, and the models named are queryable as usual. With none configured, a device short of space is refused with a typed error rather than loaded arbitrarily, and a platform with no durable storage at all is always refused.

capability overrides the platform probe, for a host that owns its own store and knows what it can hold.

capability? ​

optional capability?: object

capability.persistent ​

persistent: boolean

capability.quotaBytes ​

quotaBytes: number | null

capability.usedBytes? ​

optional usedBytes?: number

models? ​

optional models?: string[]


logLevel? ​

optional logLevel?: LogLevel


maxReconnectDelay? ​

optional maxReconnectDelay?: number


models? ​

optional models?: TypedModelConstructor<any>[]


oauthRedirectUri? ​

optional oauthRedirectUri?: string


offline? ​

optional offline?: boolean


schemaToml? ​

optional schemaToml?: string

TOML schema string for client-side model validation. Parsed via loadSchemaFromTomlString from js-bao. Precedence: models > schemaToml > auto-discover from YDoc.


serviceWorkerBridge? ​

optional serviceWorkerBridge?: object

enabled? ​

optional enabled?: boolean


storageConfig? ​

optional storageConfig?: StorageConfig


suppressAutoLoginMs? ​

optional suppressAutoLoginMs?: number


sync? ​

optional sync?: object

handshakeTimeoutMs? ​

optional handshakeTimeoutMs?: number

How long a handshake may take before the client gives up on it and lets the reconnect logic retry, in milliseconds. Defaults to 10000, and is also settable through CLIENT_SYNC_HANDSHAKE_TIMEOUT_MS.

The budget covers both halves: opening the WebSocket (an endpoint that accepts the connection but never answers the upgrade is abandoned here, rather than holding the connect open forever) and the sync handshake that follows it.

outboundDebounceMs? ​

optional outboundDebounceMs?: number


token? ​

optional token?: string


wsHeaders? ​

optional wsHeaders?: Record<string, string>


wsUrl ​

wsUrl: string


yjsPersistence? ​

optional yjsPersistence?: YjsPersistenceFactory

Custom Yjs persistence factory for document storage.

If not provided:

  • Browser: uses y-indexeddb (built-in)
  • Node.js: no Yjs persistence (documents only synced via server)

The factory's first argument is the STORE NAME to persist this Yjs state under, not necessarily the document id. For an ordinary document, and for a large document (documentFormat: 2) that has not rotated yet, the two are the same. A large document's Yjs state is an epoch OVERLAY, so once it rotates each epoch gets its own name ({documentId}@{epoch}): a rotation attaches a provider for the fresh epoch and then clears the sealed one, so a factory that put both epochs under one name would lose the writes made since the rotation to that clear. Keying storage on the first argument, as the example below does, is therefore correct for both kinds of document; context.documentId is the plain document id when you want to group a document's stores.

For Node.js persistence, use y-sqlite3:

Example ​

typescript
import { SqlitePersistence } from 'y-sqlite3';

const client = new JsBaoClient({
  // ...
  yjsPersistence: (storeName, ydoc, { appId, userId }) => {
    return new SqlitePersistence(storeName, ydoc, {
      dbPath: `~/.my-app/${appId}/${userId}/yjs.sqlite`
    });
  }
});
Documentation validated against js-bao-wss-client 3.4.0 · js-bao 0.11.0 · primitive-admin 1.0.62 · primitive-app 3.1.0 — 2026-09-30