y-socket.io
Version:
Socket IO Connector for Yjs (Inspired by y-websocket)
121 lines (119 loc) • 4.89 kB
JavaScript
// src/server/document.ts
import * as d from "yjs";
import * as l from "y-protocols/awareness";
var w = process.env.GC !== "false" && process.env.GC !== "0", c = class extends d.Doc {
constructor(t, e, s) {
super({ gc: w });
this.onUpdateDoc = (t) => {
var e;
if (((e = this.callbacks) == null ? void 0 : e.onUpdate) != null)
try {
this.callbacks.onUpdate(this, t);
} catch (s) {
console.warn(s);
}
this.namespace.emit("sync-update", t);
};
this.onUpdateAwareness = ({ added: t, updated: e, removed: s }, n) => {
var r;
let o = t.concat(e, s), a = l.encodeAwarenessUpdate(this.awareness, o);
if (((r = this.callbacks) == null ? void 0 : r.onChangeAwareness) != null)
try {
this.callbacks.onChangeAwareness(this, a);
} catch (y) {
console.warn(y);
}
this.namespace.emit("awareness-update", a);
};
this.name = t, this.namespace = e, this.awareness = new l.Awareness(this), this.awareness.setLocalState(null), this.callbacks = s, this.awareness.on("update", this.onUpdateAwareness), this.on("update", this.onUpdateDoc);
}
async destroy() {
var t;
if (((t = this.callbacks) == null ? void 0 : t.onDestroy) != null)
try {
await this.callbacks.onDestroy(this);
} catch (e) {
console.warn(e);
}
this.awareness.off("update", this.onUpdateAwareness), this.off("update", this.onUpdateDoc), this.namespace.disconnectSockets(), super.destroy();
}
};
// src/server/y-socket-io.ts
import * as i from "yjs";
import * as p from "y-protocols/awareness";
import { LeveldbPersistence as v } from "y-leveldb";
import { Observable as A } from "lib0/observable";
var u = class extends A {
constructor(t, e) {
var s;
super();
this._documents = /* @__PURE__ */ new Map();
this._levelPersistenceDir = null;
this.persistence = null;
this.nsp = null;
this.initSyncListeners = (t, e) => {
t.on("sync-step-1", (s, n) => {
n(i.encodeStateAsUpdate(e, new Uint8Array(s)));
}), t.on("sync-update", (s) => {
i.applyUpdate(e, s, null);
});
};
this.initAwarenessListeners = (t, e) => {
t.on("awareness-update", (s) => {
p.applyAwarenessUpdate(e.awareness, new Uint8Array(s), t);
});
};
this.initSocketListeners = (t, e) => {
t.on("disconnect", async () => {
(await t.nsp.allSockets()).size === 0 && (this.emit("all-document-connections-closed", [e]), this.persistence != null && (await this.persistence.writeState(e.name, e), await e.destroy()));
});
};
this.startSynchronization = (t, e) => {
t.emit("sync-step-1", i.encodeStateVector(e), (s) => {
i.applyUpdate(e, new Uint8Array(s), this);
}), t.emit("awareness-update", p.encodeAwarenessUpdate(e.awareness, Array.from(e.awareness.getStates().keys())));
};
this.io = t, this._levelPersistenceDir = (s = e == null ? void 0 : e.levelPersistenceDir) != null ? s : process.env.YPERSISTENCE, this._levelPersistenceDir != null && this.initLevelDB(this._levelPersistenceDir), this.configuration = e;
}
initialize() {
this.nsp = this.io.of(/^\/yjs\|.*$/), this.nsp.use(async (t, e) => {
var s;
return ((s = this.configuration) == null ? void 0 : s.authenticate) == null || await this.configuration.authenticate(t.handshake) ? e() : e(new Error("Unauthorized"));
}), this.nsp.on("connection", async (t) => {
var n;
let e = t.nsp.name.replace(/\/yjs\|/, ""), s = await this.initDocument(e, t.nsp, (n = this.configuration) == null ? void 0 : n.gcEnabled);
this.initSyncListeners(t, s), this.initAwarenessListeners(t, s), this.initSocketListeners(t, s), this.startSynchronization(t, s);
});
}
get documents() {
return this._documents;
}
async initDocument(t, e, s = !0) {
var o;
let n = (o = this._documents.get(t)) != null ? o : new c(t, e, {
onUpdate: (a, r) => this.emit("document-update", [a, r]),
onChangeAwareness: (a, r) => this.emit("awareness-update", [a, r]),
onDestroy: async (a) => {
this._documents.delete(a.name), this.emit("document-destroy", [a]);
}
});
return n.gc = s, this._documents.has(t) || (this.persistence != null && await this.persistence.bindState(t, n), this._documents.set(t, n), this.emit("document-loaded", [n])), n;
}
initLevelDB(t) {
let e = new v(t);
this.persistence = {
provider: e,
bindState: async (s, n) => {
let o = await e.getYDoc(s), a = i.encodeStateAsUpdate(n);
await e.storeUpdate(s, a), i.applyUpdate(n, i.encodeStateAsUpdate(o)), n.on("update", async (r) => await e.storeUpdate(s, r));
},
writeState: async (s, n) => {
}
};
}
};
export {
c as a,
u as b
};
//# sourceMappingURL=chunk-6P3PWBA3.mjs.map