UNPKG

y-socket.io

Version:

Socket IO Connector for Yjs (Inspired by y-websocket)

138 lines 6.83 kB
// src/client/provider.ts import * as s from "yjs"; import * as a from "lib0/broadcastchannel"; import * as n from "y-protocols/awareness"; import { Observable as u } from "lib0/observable"; import { io as b } from "socket.io-client"; var h = class extends u { constructor(e, t, o = new s.Doc(), { autoConnect: c = !0, awareness: i = new n.Awareness(o), resyncInterval: l = -1, disableBc: p = !1, auth: y = {} }, d = void 0) { super(); this.bcconnected = !1; this._synced = !1; this.resyncInterval = null; this.initSyncListeners = () => { this.socket.on("sync-step-1", (e, t) => { t(s.encodeStateAsUpdate(this.doc, new Uint8Array(e))), this.synced = !0; }), this.socket.on("sync-update", this.onSocketSyncUpdate); }; this.initAwarenessListeners = () => { this.socket.on("awareness-update", (e) => { n.applyAwarenessUpdate(this.awareness, new Uint8Array(e), this); }); }; this.initSystemListeners = () => { typeof window != "undefined" ? window.addEventListener("beforeunload", this.beforeUnloadHandler) : typeof process != "undefined" && process.on("exit", this.beforeUnloadHandler); }; this.onSocketConnection = (e = -1) => { this.emit("status", [{ status: "connected" }]), this.socket.emit("sync-step-1", s.encodeStateVector(this.doc), (t) => { s.applyUpdate(this.doc, new Uint8Array(t), this); }), this.awareness.getLocalState() !== null && this.socket.emit("awareness-update", n.encodeAwarenessUpdate(this.awareness, [this.doc.clientID])), e > 0 && (this.resyncInterval = setInterval(() => { this.socket.disconnected || this.socket.emit("sync-step-1", s.encodeStateVector(this.doc), (t) => { s.applyUpdate(this.doc, new Uint8Array(t), this); }); }, e)); }; this.onSocketDisconnection = (e) => { this.emit("connection-close", [e, this]), this.synced = !1, n.removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter((t) => t !== this.doc.clientID), this), this.emit("status", [{ status: "disconnected" }]); }; this.onSocketConnectionError = (e) => { this.emit("connection-error", [e, this]); }; this.onUpdateDoc = (e, t) => { t !== this && (this.socket.emit("sync-update", e), this.bcconnected && a.publish(this._broadcastChannel, { type: "sync-update", data: e }, this)); }; this.onSocketSyncUpdate = (e) => { s.applyUpdate(this.doc, new Uint8Array(e), this); }; this.awarenessUpdate = ({ added: e, updated: t, removed: o }, c) => { let i = e.concat(t).concat(o); this.socket.emit("awareness-update", n.encodeAwarenessUpdate(this.awareness, i)), this.bcconnected && a.publish(this._broadcastChannel, { type: "awareness-update", data: n.encodeAwarenessUpdate(this.awareness, i) }, this); }; this.beforeUnloadHandler = () => { n.removeAwarenessStates(this.awareness, [this.doc.clientID], "window unload"); }; this.connectBc = () => { this.bcconnected || (a.subscribe(this._broadcastChannel, this.onBroadcastChannelMessage), this.bcconnected = !0), a.publish(this._broadcastChannel, { type: "sync-step-1", data: s.encodeStateVector(this.doc) }, this), a.publish(this._broadcastChannel, { type: "sync-step-2", data: s.encodeStateAsUpdate(this.doc) }, this), a.publish(this._broadcastChannel, { type: "query-awareness", data: null }, this), a.publish(this._broadcastChannel, { type: "awareness-update", data: n.encodeAwarenessUpdate(this.awareness, [this.doc.clientID]) }, this); }; this.disconnectBc = () => { a.publish(this._broadcastChannel, { type: "awareness-update", data: n.encodeAwarenessUpdate(this.awareness, [this.doc.clientID], /* @__PURE__ */ new Map()) }, this), this.bcconnected && (a.unsubscribe(this._broadcastChannel, this.onBroadcastChannelMessage), this.bcconnected = !1); }; this.onBroadcastChannelMessage = (e, t) => { if (t !== this && e.type.length > 0) switch (e.type) { case "sync-step-1": a.publish(this._broadcastChannel, { type: "sync-step-2", data: s.encodeStateAsUpdate(this.doc, e.data) }, this); break; case "sync-step-2": s.applyUpdate(this.doc, new Uint8Array(e.data), this); break; case "sync-update": s.applyUpdate(this.doc, new Uint8Array(e.data), this); break; case "query-awareness": a.publish(this._broadcastChannel, { type: "awareness-update", data: n.encodeAwarenessUpdate(this.awareness, Array.from(this.awareness.getStates().keys())) }, this); break; case "awareness-update": n.applyAwarenessUpdate(this.awareness, new Uint8Array(e.data), this); break; default: break; } }; for (; e[e.length - 1] === "/"; ) e = e.slice(0, e.length - 1); this._url = e, this.roomName = t, this.doc = o, this.awareness = i, this._broadcastChannel = `${e}/${t}`, this.disableBc = p, this._socketIoOptions = d, this.socket = b(`${this.url}/yjs|${t}`, { autoConnect: !1, transports: ["websocket"], forceNew: !0, auth: y, ...d }), this.doc.on("update", this.onUpdateDoc), this.socket.on("connect", () => this.onSocketConnection(l)), this.socket.on("disconnect", (r) => this.onSocketDisconnection(r)), this.socket.on("connect_error", (r) => this.onSocketConnectionError(r)), this.initSyncListeners(), this.initAwarenessListeners(), this.initSystemListeners(), i.on("update", this.awarenessUpdate), c && this.connect(); } get broadcastChannel() { return this._broadcastChannel; } get url() { return this._url; } get synced() { return this._synced; } set synced(e) { this._synced !== e && (this._synced = e, this.emit("synced", [e]), this.emit("sync", [e])); } connect() { this.socket.connected || (this.emit("status", [{ status: "connecting" }]), this.socket.connect(), this.disableBc || this.connectBc(), this.synced = !1); } disconnect() { this.socket.connected && (this.disconnectBc(), this.socket.disconnect()); } destroy() { this.resyncInterval != null && clearInterval(this.resyncInterval), this.disconnect(), typeof window != "undefined" ? window.removeEventListener("beforeunload", this.beforeUnloadHandler) : typeof process != "undefined" && process.off("exit", this.beforeUnloadHandler), this.awareness.off("update", this.awarenessUpdate), this.awareness.destroy(), this.doc.off("update", this.onUpdateDoc), super.destroy(); } }; export { h as SocketIOProvider }; //# sourceMappingURL=index.mjs.map