Provider
The Provider is the client-side API that manages Y.js document synchronization, awareness, offline persistence, and RPC operations. It wraps a Connection and handles the higher-level document synchronization protocol.
Overview
Section titled “Overview”The provider system is built on two main abstractions:
Connection: Manages the low-level network connection (WebSocket, HTTP, or fallback), handles reconnection logic, message buffering, and connection state.Provider: Manages Yjs document synchronization, awareness, offline persistence, and RPC operations. It uses aConnectionfor network communication.
Basic Usage
Section titled “Basic Usage”import { Provider } from "teleportal/providers";
// Create a provider with automatic connectionconst provider = await Provider.create({ url: "wss://example.com", document: "my-document-id",});
// Wait for document to be syncedawait provider.synced;
// Access the Yjs documentconst ymap = provider.doc.getMap("data");ymap.set("key", "value");
// Listen to connection stateprovider.on("update", (state) => { console.log("Connection state:", state.type);});Connection Types
Section titled “Connection Types”Fallback Connection (Default)
Section titled “Fallback Connection (Default)”Will attempt to connect over one connection type, then fallback to another if it fails (while still attempting to re-dial in the background if possible to upgrade to the preferred connection type):
// Provider.create() automatically uses FallbackConnectionconst provider = await Provider.create({ url: "wss://example.com", // Tries WebSocket first, then falls back to HTTP if it fails document: "my-document",});WebSocket Connection
Section titled “WebSocket Connection”The default connection type, sends & receives all messages over the websocket protocol:
import { WebSocketConnection } from "teleportal/providers/websocket";
const connection = new WebSocketConnection({ url: "wss://example.com",});
const provider = new Provider({ client: connection, document: "my-document",});HTTP Connection
Section titled “HTTP Connection”A fallback for when websockets don’t work (some corporate networks), utilizes HTTP POSTs for writes and a long-running HTTP SSE connection for reads:
import { HttpConnection } from "teleportal/providers/http";
const connection = new HttpConnection({ url: "https://example.com",});
const provider = new Provider({ client: connection, document: "my-document",});Document Operations
Section titled “Document Operations”Accessing the Document
Section titled “Accessing the Document”// Access the Y.js documentconst ydoc = provider.doc;
// Create Y.js typesconst ytext = ydoc.getText("content");const ymap = ydoc.getMap("data");const yarray = ydoc.getArray("items");
// Make changesytext.insert(0, "Hello, world!");ymap.set("key", "value");yarray.push([1, 2, 3]);Listening to Updates
Section titled “Listening to Updates”// Listen to document updatesydoc.on("update", (update, origin) => { console.log("Document updated"); // Changes are automatically synced to other clients});Awareness
Section titled “Awareness”The provider includes an Awareness instance for user presence and cursor information:
// Access awarenessconst awareness = provider.awareness;
// Set local stateawareness.setLocalStateField("user", { name: "John Doe", color: "#ff0000",});
// Listen to awareness updatesawareness.on("update", ({ added, updated, removed }) => { console.log("Users changed:", { added, updated, removed });});Subdocuments
Section titled “Subdocuments”The provider supports Y.js sub-documents and properly lets the ydoc know that it is synced:
// Listen to subdocument eventsprovider.on("load-subdoc", ({ subdoc, provider: subdocProvider }) => { console.log("Subdocument loaded:", subdoc.guid); // subdocProvider is a Provider instance for the subdocument});
// Access subdocumentsconst subdocProvider = provider.subdocs.get("subdoc-guid");if (subdocProvider) { await subdocProvider.synced;}Document Switching
Section titled “Document Switching”Efficiently switch between documents while maintaining the same connection:
// Switch to a new document (reuses connection)const newProvider = provider.switchDocument({ document: "new-document-id",});
// Old provider is destroyed, new provider is readyawait newProvider.synced;Offline Persistence
Section titled “Offline Persistence”The provider automatically enables offline persistence by default using IndexedDB:
const provider = await Provider.create({ url: "wss://example.com", document: "my-document-id", enableOfflinePersistence: true, // default indexedDBPrefix: "my-app-", // custom prefix});
// Document will be loaded from IndexedDB if availableawait provider.loaded; // Resolves when local data is loadedawait provider.synced; // Resolves when synced with serverConnection State
Section titled “Connection State”Monitor connection state:
// Get current connection stateconst connection = provider.state;
if (connection.type === "connected") { console.log("Connected!");} else if (connection.type === "errored") { console.error("Connection error:", connection.error);}
// Wait for connectiontry { await provider.synced; console.log("Fully synced!");} catch (error) { console.error("Sync failed:", error);}Connection Sharing
Section titled “Connection Sharing”Multiple providers can share the same connection:
// Create a connectionconst connection = new WebSocketConnection({ url: "wss://example.com",});
// Create multiple providers with the same connectionconst provider1 = new Provider({ client: connection, document: "doc-1",});
const provider2 = new Provider({ client: connection, document: "doc-2",});Lifecycle Management
Section titled “Lifecycle Management”The provider supports explicit resource management:
// Using explicit resource managementusing provider = await Provider.create({ url: "wss://example.com", document: "my-document",});
// Provider automatically disposes when exiting scope
// Or manually destroyprovider.destroy({ destroyConnection: true, // default: true destroyDoc: true, // default: true});Events
Section titled “Events”The provider extends Observable and emits events:
// Subdocument eventsprovider.on("load-subdoc", ({ subdoc, provider }) => { console.log("Subdocument loaded");});
provider.on("unload-subdoc", ({ subdoc, provider }) => { console.log("Subdocument unloaded");});
// Connection state events (delegated from connection)provider.on("update", (state) => { console.log("Connection state changed:", state.type);});Next Steps
Section titled “Next Steps”- Server - Learn how the server handles provider connections
- Transport - Understand the transport layer
- Milestones - Learn about document versioning