UNPKG

@eweser/db

Version:
1,473 lines (1,472 loc) 110 kB
(function(global, factory) { typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("yjs")) : typeof define === "function" && define.amd ? define(["exports", "yjs"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["eweser-db"] = {}, global.Y)); })(this, function(exports2, Y) { "use strict";var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); function _interopNamespaceDefault(e) { const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } }); if (e) { for (const k in e) { if (k !== "default") { const d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: () => e[k] }); } } } n.default = e; return Object.freeze(n); } const Y__namespace = /* @__PURE__ */ _interopNamespaceDefault(Y); var events = { exports: {} }; var hasRequiredEvents; function requireEvents() { if (hasRequiredEvents) return events.exports; hasRequiredEvents = 1; var R = typeof Reflect === "object" ? Reflect : null; var ReflectApply = R && typeof R.apply === "function" ? R.apply : function ReflectApply2(target, receiver, args) { return Function.prototype.apply.call(target, receiver, args); }; var ReflectOwnKeys; if (R && typeof R.ownKeys === "function") { ReflectOwnKeys = R.ownKeys; } else if (Object.getOwnPropertySymbols) { ReflectOwnKeys = function ReflectOwnKeys2(target) { return Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)); }; } else { ReflectOwnKeys = function ReflectOwnKeys2(target) { return Object.getOwnPropertyNames(target); }; } function ProcessEmitWarning(warning) { if (console && console.warn) console.warn(warning); } var NumberIsNaN = Number.isNaN || function NumberIsNaN2(value) { return value !== value; }; function EventEmitter() { EventEmitter.init.call(this); } events.exports = EventEmitter; events.exports.once = once; EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype._events = void 0; EventEmitter.prototype._eventsCount = 0; EventEmitter.prototype._maxListeners = void 0; var defaultMaxListeners = 10; function checkListener(listener) { if (typeof listener !== "function") { throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); } } Object.defineProperty(EventEmitter, "defaultMaxListeners", { enumerable: true, get: function() { return defaultMaxListeners; }, set: function(arg) { if (typeof arg !== "number" || arg < 0 || NumberIsNaN(arg)) { throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + "."); } defaultMaxListeners = arg; } }); EventEmitter.init = function() { if (this._events === void 0 || this._events === Object.getPrototypeOf(this)._events) { this._events = /* @__PURE__ */ Object.create(null); this._eventsCount = 0; } this._maxListeners = this._maxListeners || void 0; }; EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { if (typeof n !== "number" || n < 0 || NumberIsNaN(n)) { throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + "."); } this._maxListeners = n; return this; }; function _getMaxListeners(that) { if (that._maxListeners === void 0) return EventEmitter.defaultMaxListeners; return that._maxListeners; } EventEmitter.prototype.getMaxListeners = function getMaxListeners() { return _getMaxListeners(this); }; EventEmitter.prototype.emit = function emit(type) { var args = []; for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); var doError = type === "error"; var events2 = this._events; if (events2 !== void 0) doError = doError && events2.error === void 0; else if (!doError) return false; if (doError) { var er; if (args.length > 0) er = args[0]; if (er instanceof Error) { throw er; } var err = new Error("Unhandled error." + (er ? " (" + er.message + ")" : "")); err.context = er; throw err; } var handler = events2[type]; if (handler === void 0) return false; if (typeof handler === "function") { ReflectApply(handler, this, args); } else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args); } return true; }; function _addListener(target, type, listener, prepend) { var m; var events2; var existing; checkListener(listener); events2 = target._events; if (events2 === void 0) { events2 = target._events = /* @__PURE__ */ Object.create(null); target._eventsCount = 0; } else { if (events2.newListener !== void 0) { target.emit( "newListener", type, listener.listener ? listener.listener : listener ); events2 = target._events; } existing = events2[type]; } if (existing === void 0) { existing = events2[type] = listener; ++target._eventsCount; } else { if (typeof existing === "function") { existing = events2[type] = prepend ? [listener, existing] : [existing, listener]; } else if (prepend) { existing.unshift(listener); } else { existing.push(listener); } m = _getMaxListeners(target); if (m > 0 && existing.length > m && !existing.warned) { existing.warned = true; var w = new Error("Possible EventEmitter memory leak detected. " + existing.length + " " + String(type) + " listeners added. Use emitter.setMaxListeners() to increase limit"); w.name = "MaxListenersExceededWarning"; w.emitter = target; w.type = type; w.count = existing.length; ProcessEmitWarning(w); } } return target; } EventEmitter.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.prependListener = function prependListener(type, listener) { return _addListener(this, type, listener, true); }; function onceWrapper() { if (!this.fired) { this.target.removeListener(this.type, this.wrapFn); this.fired = true; if (arguments.length === 0) return this.listener.call(this.target); return this.listener.apply(this.target, arguments); } } function _onceWrap(target, type, listener) { var state = { fired: false, wrapFn: void 0, target, type, listener }; var wrapped = onceWrapper.bind(state); wrapped.listener = listener; state.wrapFn = wrapped; return wrapped; } EventEmitter.prototype.once = function once2(type, listener) { checkListener(listener); this.on(type, _onceWrap(this, type, listener)); return this; }; EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) { checkListener(listener); this.prependListener(type, _onceWrap(this, type, listener)); return this; }; EventEmitter.prototype.removeListener = function removeListener(type, listener) { var list, events2, position, i, originalListener; checkListener(listener); events2 = this._events; if (events2 === void 0) return this; list = events2[type]; if (list === void 0) return this; if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) this._events = /* @__PURE__ */ Object.create(null); else { delete events2[type]; if (events2.removeListener) this.emit("removeListener", type, list.listener || listener); } } else if (typeof list !== "function") { position = -1; for (i = list.length - 1; i >= 0; i--) { if (list[i] === listener || list[i].listener === listener) { originalListener = list[i].listener; position = i; break; } } if (position < 0) return this; if (position === 0) list.shift(); else { spliceOne(list, position); } if (list.length === 1) events2[type] = list[0]; if (events2.removeListener !== void 0) this.emit("removeListener", type, originalListener || listener); } return this; }; EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { var listeners, events2, i; events2 = this._events; if (events2 === void 0) return this; if (events2.removeListener === void 0) { if (arguments.length === 0) { this._events = /* @__PURE__ */ Object.create(null); this._eventsCount = 0; } else if (events2[type] !== void 0) { if (--this._eventsCount === 0) this._events = /* @__PURE__ */ Object.create(null); else delete events2[type]; } return this; } if (arguments.length === 0) { var keys2 = Object.keys(events2); var key; for (i = 0; i < keys2.length; ++i) { key = keys2[i]; if (key === "removeListener") continue; this.removeAllListeners(key); } this.removeAllListeners("removeListener"); this._events = /* @__PURE__ */ Object.create(null); this._eventsCount = 0; return this; } listeners = events2[type]; if (typeof listeners === "function") { this.removeListener(type, listeners); } else if (listeners !== void 0) { for (i = listeners.length - 1; i >= 0; i--) { this.removeListener(type, listeners[i]); } } return this; }; function _listeners(target, type, unwrap) { var events2 = target._events; if (events2 === void 0) return []; var evlistener = events2[type]; if (evlistener === void 0) return []; if (typeof evlistener === "function") return unwrap ? [evlistener.listener || evlistener] : [evlistener]; return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); } EventEmitter.prototype.listeners = function listeners(type) { return _listeners(this, type, true); }; EventEmitter.prototype.rawListeners = function rawListeners(type) { return _listeners(this, type, false); }; EventEmitter.listenerCount = function(emitter, type) { if (typeof emitter.listenerCount === "function") { return emitter.listenerCount(type); } else { return listenerCount.call(emitter, type); } }; EventEmitter.prototype.listenerCount = listenerCount; function listenerCount(type) { var events2 = this._events; if (events2 !== void 0) { var evlistener = events2[type]; if (typeof evlistener === "function") { return 1; } else if (evlistener !== void 0) { return evlistener.length; } } return 0; } EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; }; function arrayClone(arr, n) { var copy = new Array(n); for (var i = 0; i < n; ++i) copy[i] = arr[i]; return copy; } function spliceOne(list, index) { for (; index + 1 < list.length; index++) list[index] = list[index + 1]; list.pop(); } function unwrapListeners(arr) { var ret = new Array(arr.length); for (var i = 0; i < ret.length; ++i) { ret[i] = arr[i].listener || arr[i]; } return ret; } function once(emitter, name) { return new Promise(function(resolve, reject) { function errorListener(err) { emitter.removeListener(name, resolver); reject(err); } function resolver() { if (typeof emitter.removeListener === "function") { emitter.removeListener("error", errorListener); } resolve([].slice.call(arguments)); } eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); if (name !== "error") { addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); } }); } function addErrorHandlerIfEventEmitter(emitter, handler, flags) { if (typeof emitter.on === "function") { eventTargetAgnosticAddListener(emitter, "error", handler, flags); } } function eventTargetAgnosticAddListener(emitter, name, listener, flags) { if (typeof emitter.on === "function") { if (flags.once) { emitter.once(name, listener); } else { emitter.on(name, listener); } } else if (typeof emitter.addEventListener === "function") { emitter.addEventListener(name, function wrapListener(arg) { if (flags.once) { emitter.removeEventListener(name, wrapListener); } listener(arg); }); } else { throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); } } return events.exports; } var eventsExports = requireEvents(); class TypedEventEmitter extends eventsExports.EventEmitter { on(event, listener) { return super.on(event, listener); } emit(event, ...args) { return super.emit(event, ...args); } } const setupLogger = (db) => { db.on("log", (level, ...message) => { switch (level) { case 0: return console.info(...message); case 1: return console.log(...message); case 2: return console.warn(...message); case 3: return console.error(...message); } }); }; const newDocument = (_id, _ref, doc) => { const now = (/* @__PURE__ */ new Date()).getTime(); const base = { _created: now, _id, _ref, _updated: now, _deleted: false, _ttl: void 0 }; return { ...base, ...doc }; }; const buildRef = (params) => { Object.entries(params).forEach(([key, param]) => { if (!param) throw new Error(`${key} is required`); if (typeof param !== "string") throw new Error(`${key} must be a string`); if (param.includes("|")) throw new Error(`${key} cannot include |`); }); const { collectionKey, roomId, documentId, authServer } = params; return `${authServer}|${collectionKey}|${roomId}|${documentId}`; }; const wait$1 = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const randomString = (length2) => Math.random().toString(36).substring(2, length2 + 2); function getRoomDocuments(room) { if (!room.ydoc) throw new Error("room.ydoc not found"); const registryMap = room.ydoc.getMap("documents"); return registryMap; } const getRoom = (_db) => ({ collectionKey, roomId }) => { const room = _db.collections[collectionKey][roomId]; if (!room) return null; return room; }; const getDocuments = (_db) => (room) => { var _a; if (!room) throw new Error("no room"); const documents = (_a = room.ydoc) == null ? void 0 : _a.getMap("documents"); if (!documents) throw new Error("no documents"); return { documents, get: (id) => { return documents.get(id); }, set: (doc) => { doc._updated = Date.now(); return documents.set(doc._id, doc); }, new: (doc, id) => { if (id && documents.get(id)) { throw new Error("document already exists"); } let documentId = id || randomString(24); if (documents.get(documentId)) { documentId = randomString(24); if (documents.get(documentId)) { throw new Error("document already exists"); } } const ref = buildRef({ authServer: _db.authServer, collectionKey: room.collectionKey, roomId: room.id, documentId }); const newDoc = newDocument(documentId, ref, doc); documents.set(documentId, newDoc); return newDoc; }, delete: (id, timeToLiveMs) => { const doc = documents.get(id); if (!doc) throw new Error("document does not exist"); const oneMonth = 1e3 * 60 * 60 * 24 * 30; doc._deleted = true; doc._ttl = timeToLiveMs ?? (/* @__PURE__ */ new Date()).getTime() + oneMonth; return documents.set(id, doc); }, getAll: () => { return documents.toJSON(); }, getAllToArray: () => { return Object.values(documents.toJSON()); }, getUndeleted: () => { const undeleted = {}; documents.forEach((doc) => { if (doc && !doc._deleted) { undeleted[doc._id] = doc; } }); return undeleted; }, getUndeletedToArray: () => { const undeleted = []; documents.forEach((doc) => { if (doc && !doc._deleted) { undeleted.push(doc); } }); return undeleted; }, toArray: (docs) => { return Object.values(docs); }, onChange: (callback) => { documents.observe(callback); }, sortByRecent: (docs) => { const sortedArray = Object.entries(docs).sort( (a, b) => b[1]._updated - a[1]._updated ); return Object.fromEntries(sortedArray); } }; }; const floor$1 = Math.floor; const min$1 = (a, b) => a < b ? a : b; const max$1 = (a, b) => a > b ? a : b; const getUnixTime = Date.now; const create$4 = (f) => ( /** @type {Promise<T>} */ new Promise(f) ); Promise.all.bind(Promise); const create$3 = (s) => new Error(s); const rtop = (request) => create$4((resolve, reject) => { request.onerror = (event) => reject(new Error(event.target.error)); request.onsuccess = (event) => resolve(event.target.result); }); const openDB = (name, initDB) => create$4((resolve, reject) => { const request = indexedDB.open(name); request.onupgradeneeded = (event) => initDB(event.target.result); request.onerror = (event) => reject(create$3(event.target.error)); request.onsuccess = (event) => { const db = event.target.result; db.onversionchange = () => { db.close(); }; resolve(db); }; }); const deleteDB = (name) => rtop(indexedDB.deleteDatabase(name)); const createStores = (db, definitions) => definitions.forEach( (d) => ( // @ts-ignore db.createObjectStore.apply(db, d) ) ); const transact = (db, stores, access = "readwrite") => { const transaction = db.transaction(stores, access); return stores.map((store) => getStore(transaction, store)); }; const count = (store, range) => rtop(store.count(range)); const get = (store, key) => rtop(store.get(key)); const del = (store, key) => rtop(store.delete(key)); const put = (store, item, key) => rtop(store.put(item, key)); const addAutoKey = (store, item) => rtop(store.add(item)); const getAll = (store, range, limit) => rtop(store.getAll(range, limit)); const queryFirst = (store, query, direction) => { let first = null; return iterateKeys(store, query, (key) => { first = key; return false; }, direction).then(() => first); }; const getLastKey = (store, range = null) => queryFirst(store, range, "prev"); const iterateOnRequest = (request, f) => create$4((resolve, reject) => { request.onerror = reject; request.onsuccess = async (event) => { const cursor = event.target.result; if (cursor === null || await f(cursor) === false) { return resolve(); } cursor.continue(); }; }); const iterateKeys = (store, keyrange, f, direction = "next") => iterateOnRequest(store.openKeyCursor(keyrange, direction), (cursor) => f(cursor.key)); const getStore = (t, store) => t.objectStore(store); const createIDBKeyRangeUpperBound = (upper, upperOpen) => IDBKeyRange.upperBound(upper, upperOpen); const createIDBKeyRangeLowerBound = (lower, lowerOpen) => IDBKeyRange.lowerBound(lower, lowerOpen); const create$2 = () => /* @__PURE__ */ new Map(); const setIfUndefined = (map, key, createT) => { let set = map.get(key); if (set === void 0) { map.set(key, set = createT()); } return set; }; const create$1 = () => /* @__PURE__ */ new Set(); const from = Array.from; class Observable { constructor() { this._observers = create$2(); } /** * @param {N} name * @param {function} f */ on(name, f) { setIfUndefined(this._observers, name, create$1).add(f); } /** * @param {N} name * @param {function} f */ once(name, f) { const _f = (...args) => { this.off(name, _f); f(...args); }; this.on(name, _f); } /** * @param {N} name * @param {function} f */ off(name, f) { const observers = this._observers.get(name); if (observers !== void 0) { observers.delete(f); if (observers.size === 0) { this._observers.delete(name); } } } /** * Emit a named event. All registered event listeners that listen to the * specified name will receive the event. * * @todo This should catch exceptions * * @param {N} name The event name. * @param {Array<any>} args The arguments that are applied to the event listener. */ emit(name, args) { return from((this._observers.get(name) || create$2()).values()).forEach((f) => f(...args)); } destroy() { this._observers = create$2(); } } const customStoreName = "custom"; const updatesStoreName = "updates"; const PREFERRED_TRIM_SIZE = 500; const fetchUpdates = (idbPersistence, beforeApplyUpdatesCallback = () => { }, afterApplyUpdatesCallback = () => { }) => { const [updatesStore] = transact( /** @type {IDBDatabase} */ idbPersistence.db, [updatesStoreName] ); return getAll(updatesStore, createIDBKeyRangeLowerBound(idbPersistence._dbref, false)).then((updates) => { if (!idbPersistence._destroyed) { beforeApplyUpdatesCallback(updatesStore); Y__namespace.transact(idbPersistence.doc, () => { updates.forEach((val) => Y__namespace.applyUpdate(idbPersistence.doc, val)); }, idbPersistence, false); afterApplyUpdatesCallback(updatesStore); } }).then(() => getLastKey(updatesStore).then((lastKey) => { idbPersistence._dbref = lastKey + 1; })).then(() => count(updatesStore).then((cnt) => { idbPersistence._dbsize = cnt; })).then(() => updatesStore); }; const storeState = (idbPersistence, forceStore = true) => fetchUpdates(idbPersistence).then((updatesStore) => { if (forceStore || idbPersistence._dbsize >= PREFERRED_TRIM_SIZE) { addAutoKey(updatesStore, Y__namespace.encodeStateAsUpdate(idbPersistence.doc)).then(() => del(updatesStore, createIDBKeyRangeUpperBound(idbPersistence._dbref, true))).then(() => count(updatesStore).then((cnt) => { idbPersistence._dbsize = cnt; })); } }); class IndexeddbPersistence extends Observable { /** * @param {string} name * @param {Y.Doc} doc */ constructor(name, doc) { super(); this.doc = doc; this.name = name; this._dbref = 0; this._dbsize = 0; this._destroyed = false; this.db = null; this.synced = false; this._db = openDB( name, (db) => createStores(db, [ ["updates", { autoIncrement: true }], ["custom"] ]) ); this.whenSynced = create$4((resolve) => this.on("synced", () => resolve(this))); this._db.then((db) => { this.db = db; const beforeApplyUpdatesCallback = (updatesStore) => addAutoKey(updatesStore, Y__namespace.encodeStateAsUpdate(doc)); const afterApplyUpdatesCallback = () => { if (this._destroyed) return this; this.synced = true; this.emit("synced", [this]); }; fetchUpdates(this, beforeApplyUpdatesCallback, afterApplyUpdatesCallback); }); this._storeTimeout = 1e3; this._storeTimeoutId = null; this._storeUpdate = (update, origin) => { if (this.db && origin !== this) { const [updatesStore] = transact( /** @type {IDBDatabase} */ this.db, [updatesStoreName] ); addAutoKey(updatesStore, update); if (++this._dbsize >= PREFERRED_TRIM_SIZE) { if (this._storeTimeoutId !== null) { clearTimeout(this._storeTimeoutId); } this._storeTimeoutId = setTimeout(() => { storeState(this, false); this._storeTimeoutId = null; }, this._storeTimeout); } } }; doc.on("update", this._storeUpdate); this.destroy = this.destroy.bind(this); doc.on("destroy", this.destroy); } destroy() { if (this._storeTimeoutId) { clearTimeout(this._storeTimeoutId); } this.doc.off("update", this._storeUpdate); this.doc.off("destroy", this.destroy); this._destroyed = true; return this._db.then((db) => { db.close(); }); } /** * Destroys this instance and removes all data from indexeddb. * * @return {Promise<void>} */ clearData() { return this.destroy().then(() => { deleteDB(this.name); }); } /** * @param {String | number | ArrayBuffer | Date} key * @return {Promise<String | number | ArrayBuffer | Date | any>} */ get(key) { return this._db.then((db) => { const [custom] = transact(db, [customStoreName], "readonly"); return get(custom, key); }); } /** * @param {String | number | ArrayBuffer | Date} key * @param {String | number | ArrayBuffer | Date} value * @return {Promise<String | number | ArrayBuffer | Date>} */ set(key, value) { return this._db.then((db) => { const [custom] = transact(db, [customStoreName]); return put(custom, value, key); }); } /** * @param {String | number | ArrayBuffer | Date} key * @return {Promise<undefined>} */ del(key) { return this._db.then((db) => { const [custom] = transact(db, [customStoreName]); return del(custom, key); }); } } const Doc = Y.Doc; const initializeDocAndLocalProvider = async (roomId, existingDoc, provider) => { const yDoc = existingDoc || new Doc(); if (!yDoc) throw new Error("could not create doc"); const localProvider = provider ? provider(roomId, yDoc) : new IndexeddbPersistence(roomId, yDoc); if (localProvider.synced) return { yDoc, localProvider }; const synced = await localProvider.whenSynced; if (synced.synced) return { yDoc, localProvider }; else throw new Error("could not sync doc"); }; function stringToBase64(input) { if (typeof window !== "undefined" && window.btoa) { return window.btoa(input); } else if (typeof Buffer !== "undefined") { return Buffer.from(input).toString("base64"); } else { throw new Error("Unable to encode to Base64"); } } function encodeClientToken(token) { const jsonString = JSON.stringify(token); let base64 = stringToBase64(jsonString); base64 = base64.replace("+", "-").replace("/", "_").replace(/=+$/, ""); return base64; } const BIT8$1 = 128; const BITS7$1 = 127; const MAX_SAFE_INTEGER$1 = Number.MAX_SAFE_INTEGER; const _encodeUtf8Polyfill$1 = (str) => { const encodedString = unescape(encodeURIComponent(str)); const len = encodedString.length; const buf = new Uint8Array(len); for (let i = 0; i < len; i++) { buf[i] = /** @type {number} */ encodedString.codePointAt(i); } return buf; }; const utf8TextEncoder$1 = ( /** @type {TextEncoder} */ typeof TextEncoder !== "undefined" ? new TextEncoder() : null ); const _encodeUtf8Native$1 = (str) => utf8TextEncoder$1.encode(str); const encodeUtf8$1 = utf8TextEncoder$1 ? _encodeUtf8Native$1 : _encodeUtf8Polyfill$1; let utf8TextDecoder$1 = typeof TextDecoder === "undefined" ? null : new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }); if (utf8TextDecoder$1 && utf8TextDecoder$1.decode(new Uint8Array()).length === 1) { utf8TextDecoder$1 = null; } let Encoder$1 = class Encoder { constructor() { this.cpos = 0; this.cbuf = new Uint8Array(100); this.bufs = []; } }; const createEncoder$1 = () => new Encoder$1(); const length$2 = (encoder) => { let len = encoder.cpos; for (let i = 0; i < encoder.bufs.length; i++) { len += encoder.bufs[i].length; } return len; }; const toUint8Array$1 = (encoder) => { const uint8arr = new Uint8Array(length$2(encoder)); let curPos = 0; for (let i = 0; i < encoder.bufs.length; i++) { const d = encoder.bufs[i]; uint8arr.set(d, curPos); curPos += d.length; } uint8arr.set(new Uint8Array(encoder.cbuf.buffer, 0, encoder.cpos), curPos); return uint8arr; }; const write$1 = (encoder, num) => { const bufferLen = encoder.cbuf.length; if (encoder.cpos === bufferLen) { encoder.bufs.push(encoder.cbuf); encoder.cbuf = new Uint8Array(bufferLen * 2); encoder.cpos = 0; } encoder.cbuf[encoder.cpos++] = num; }; const writeVarUint$1 = (encoder, num) => { while (num > BITS7$1) { write$1(encoder, BIT8$1 | BITS7$1 & num); num = floor$1(num / 128); } write$1(encoder, BITS7$1 & num); }; const _strBuffer$1 = new Uint8Array(3e4); const _maxStrBSize$1 = _strBuffer$1.length / 3; const _writeVarStringNative$1 = (encoder, str) => { if (str.length < _maxStrBSize$1) { const written = utf8TextEncoder$1.encodeInto(str, _strBuffer$1).written || 0; writeVarUint$1(encoder, written); for (let i = 0; i < written; i++) { write$1(encoder, _strBuffer$1[i]); } } else { writeVarUint8Array$1(encoder, encodeUtf8$1(str)); } }; const _writeVarStringPolyfill$1 = (encoder, str) => { const encodedString = unescape(encodeURIComponent(str)); const len = encodedString.length; writeVarUint$1(encoder, len); for (let i = 0; i < len; i++) { write$1( encoder, /** @type {number} */ encodedString.codePointAt(i) ); } }; const writeVarString = utf8TextEncoder$1 && /** @type {any} */ utf8TextEncoder$1.encodeInto ? _writeVarStringNative$1 : _writeVarStringPolyfill$1; const writeUint8Array$1 = (encoder, uint8Array) => { const bufferLen = encoder.cbuf.length; const cpos = encoder.cpos; const leftCopyLen = min$1(bufferLen - cpos, uint8Array.length); const rightCopyLen = uint8Array.length - leftCopyLen; encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos); encoder.cpos += leftCopyLen; if (rightCopyLen > 0) { encoder.bufs.push(encoder.cbuf); encoder.cbuf = new Uint8Array(max$1(bufferLen * 2, rightCopyLen)); encoder.cbuf.set(uint8Array.subarray(leftCopyLen)); encoder.cpos = rightCopyLen; } }; const writeVarUint8Array$1 = (encoder, uint8Array) => { writeVarUint$1(encoder, uint8Array.byteLength); writeUint8Array$1(encoder, uint8Array); }; const errorUnexpectedEndOfArray$1 = create$3("Unexpected end of array"); const errorIntegerOutOfRange$1 = create$3("Integer out of Range"); let Decoder$1 = class Decoder { /** * @param {Uint8Array} uint8Array Binary data to decode */ constructor(uint8Array) { this.arr = uint8Array; this.pos = 0; } }; const createDecoder$1 = (uint8Array) => new Decoder$1(uint8Array); const readUint8Array$1 = (decoder, len) => { const view = new Uint8Array(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len); decoder.pos += len; return view; }; const readVarUint8Array$1 = (decoder) => readUint8Array$1(decoder, readVarUint$1(decoder)); const readUint8 = (decoder) => decoder.arr[decoder.pos++]; const readVarUint$1 = (decoder) => { let num = 0; let mult = 1; const len = decoder.arr.length; while (decoder.pos < len) { const r = decoder.arr[decoder.pos++]; num = num + (r & BITS7$1) * mult; mult *= 128; if (r < BIT8$1) { return num; } if (num > MAX_SAFE_INTEGER$1) { throw errorIntegerOutOfRange$1; } } throw errorUnexpectedEndOfArray$1; }; const _readVarStringPolyfill = (decoder) => { let remainingLen = readVarUint$1(decoder); if (remainingLen === 0) { return ""; } else { let encodedString = String.fromCodePoint(readUint8(decoder)); if (--remainingLen < 100) { while (remainingLen--) { encodedString += String.fromCodePoint(readUint8(decoder)); } } else { while (remainingLen > 0) { const nextLen = remainingLen < 1e4 ? remainingLen : 1e4; const bytes = decoder.arr.subarray(decoder.pos, decoder.pos + nextLen); decoder.pos += nextLen; encodedString += String.fromCodePoint.apply( null, /** @type {any} */ bytes ); remainingLen -= nextLen; } } return decodeURIComponent(escape(encodedString)); } }; const _readVarStringNative = (decoder) => ( /** @type any */ utf8TextDecoder$1.decode(readVarUint8Array$1(decoder)) ); const readVarString = utf8TextDecoder$1 ? _readVarStringNative : _readVarStringPolyfill; const keys = Object.keys; const length$1 = (obj) => keys(obj).length; const hasProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key); const equalityStrict = (a, b) => a === b; const equalityDeep = (a, b) => { if (a == null || b == null) { return equalityStrict(a, b); } if (a.constructor !== b.constructor) { return false; } if (a === b) { return true; } switch (a.constructor) { case ArrayBuffer: a = new Uint8Array(a); b = new Uint8Array(b); // eslint-disable-next-line no-fallthrough case Uint8Array: { if (a.byteLength !== b.byteLength) { return false; } for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) { return false; } } break; } case Set: { if (a.size !== b.size) { return false; } for (const value of a) { if (!b.has(value)) { return false; } } break; } case Map: { if (a.size !== b.size) { return false; } for (const key of a.keys()) { if (!b.has(key) || !equalityDeep(a.get(key), b.get(key))) { return false; } } break; } case Object: if (length$1(a) !== length$1(b)) { return false; } for (const key in a) { if (!hasProperty(a, key) || !equalityDeep(a[key], b[key])) { return false; } } break; case Array: if (a.length !== b.length) { return false; } for (let i = 0; i < a.length; i++) { if (!equalityDeep(a[i], b[i])) { return false; } } break; default: return false; } return true; }; const outdatedTimeout = 3e4; class Awareness extends Observable { /** * @param {Y.Doc} doc */ constructor(doc) { super(); this.doc = doc; this.clientID = doc.clientID; this.states = /* @__PURE__ */ new Map(); this.meta = /* @__PURE__ */ new Map(); this._checkInterval = /** @type {any} */ setInterval(() => { const now = getUnixTime(); if (this.getLocalState() !== null && outdatedTimeout / 2 <= now - /** @type {{lastUpdated:number}} */ this.meta.get(this.clientID).lastUpdated) { this.setLocalState(this.getLocalState()); } const remove = []; this.meta.forEach((meta, clientid) => { if (clientid !== this.clientID && outdatedTimeout <= now - meta.lastUpdated && this.states.has(clientid)) { remove.push(clientid); } }); if (remove.length > 0) { removeAwarenessStates(this, remove, "timeout"); } }, floor$1(outdatedTimeout / 10)); doc.on("destroy", () => { this.destroy(); }); this.setLocalState({}); } destroy() { this.emit("destroy", [this]); this.setLocalState(null); super.destroy(); clearInterval(this._checkInterval); } /** * @return {Object<string,any>|null} */ getLocalState() { return this.states.get(this.clientID) || null; } /** * @param {Object<string,any>|null} state */ setLocalState(state) { const clientID = this.clientID; const currLocalMeta = this.meta.get(clientID); const clock = currLocalMeta === void 0 ? 0 : currLocalMeta.clock + 1; const prevState = this.states.get(clientID); if (state === null) { this.states.delete(clientID); } else { this.states.set(clientID, state); } this.meta.set(clientID, { clock, lastUpdated: getUnixTime() }); const added = []; const updated = []; const filteredUpdated = []; const removed = []; if (state === null) { removed.push(clientID); } else if (prevState == null) { if (state != null) { added.push(clientID); } } else { updated.push(clientID); if (!equalityDeep(prevState, state)) { filteredUpdated.push(clientID); } } if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) { this.emit("change", [{ added, updated: filteredUpdated, removed }, "local"]); } this.emit("update", [{ added, updated, removed }, "local"]); } /** * @param {string} field * @param {any} value */ setLocalStateField(field, value) { const state = this.getLocalState(); if (state !== null) { this.setLocalState({ ...state, [field]: value }); } } /** * @return {Map<number,Object<string,any>>} */ getStates() { return this.states; } } const removeAwarenessStates = (awareness, clients, origin) => { const removed = []; for (let i = 0; i < clients.length; i++) { const clientID = clients[i]; if (awareness.states.has(clientID)) { awareness.states.delete(clientID); if (clientID === awareness.clientID) { const curMeta = ( /** @type {MetaClientState} */ awareness.meta.get(clientID) ); awareness.meta.set(clientID, { clock: curMeta.clock + 1, lastUpdated: getUnixTime() }); } removed.push(clientID); } } if (removed.length > 0) { awareness.emit("change", [{ added: [], updated: [], removed }, origin]); awareness.emit("update", [{ added: [], updated: [], removed }, origin]); } }; const encodeAwarenessUpdate = (awareness, clients, states = awareness.states) => { const len = clients.length; const encoder = createEncoder$1(); writeVarUint$1(encoder, len); for (let i = 0; i < len; i++) { const clientID = clients[i]; const state = states.get(clientID) || null; const clock = ( /** @type {MetaClientState} */ awareness.meta.get(clientID).clock ); writeVarUint$1(encoder, clientID); writeVarUint$1(encoder, clock); writeVarString(encoder, JSON.stringify(state)); } return toUint8Array$1(encoder); }; const applyAwarenessUpdate = (awareness, update, origin) => { const decoder = createDecoder$1(update); const timestamp = getUnixTime(); const added = []; const updated = []; const filteredUpdated = []; const removed = []; const len = readVarUint$1(decoder); for (let i = 0; i < len; i++) { const clientID = readVarUint$1(decoder); let clock = readVarUint$1(decoder); const state = JSON.parse(readVarString(decoder)); const clientMeta = awareness.meta.get(clientID); const prevState = awareness.states.get(clientID); const currClock = clientMeta === void 0 ? 0 : clientMeta.clock; if (currClock < clock || currClock === clock && state === null && awareness.states.has(clientID)) { if (state === null) { if (clientID === awareness.clientID && awareness.getLocalState() != null) { clock++; } else { awareness.states.delete(clientID); } } else { awareness.states.set(clientID, state); } awareness.meta.set(clientID, { clock, lastUpdated: timestamp }); if (clientMeta === void 0 && state !== null) { added.push(clientID); } else if (clientMeta !== void 0 && state === null) { removed.push(clientID); } else if (state !== null) { if (!equalityDeep(state, prevState)) { filteredUpdated.push(clientID); } updated.push(clientID); } } } if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) { awareness.emit("change", [{ added, updated: filteredUpdated, removed }, origin]); } if (added.length > 0 || updated.length > 0 || removed.length > 0) { awareness.emit("update", [{ added, updated, removed }, origin]); } }; const messageYjsSyncStep1 = 0; const messageYjsSyncStep2 = 1; const messageYjsUpdate = 2; const writeSyncStep1 = (encoder, doc) => { writeVarUint$1(encoder, messageYjsSyncStep1); const sv = Y__namespace.encodeStateVector(doc); writeVarUint8Array$1(encoder, sv); }; const writeSyncStep2 = (encoder, doc, encodedStateVector) => { writeVarUint$1(encoder, messageYjsSyncStep2); writeVarUint8Array$1(encoder, Y__namespace.encodeStateAsUpdate(doc, encodedStateVector)); }; const readSyncStep1 = (decoder, encoder, doc) => writeSyncStep2(encoder, doc, readVarUint8Array$1(decoder)); const readSyncStep2 = (decoder, doc, transactionOrigin) => { try { Y__namespace.applyUpdate(doc, readVarUint8Array$1(decoder), transactionOrigin); } catch (error) { console.error("Caught error while handling a Yjs update", error); } }; const writeUpdate = (encoder, update) => { writeVarUint$1(encoder, messageYjsUpdate); writeVarUint8Array$1(encoder, update); }; const readUpdate = readSyncStep2; const readSyncMessage = (decoder, encoder, doc, transactionOrigin) => { const messageType = readVarUint$1(decoder); switch (messageType) { case messageYjsSyncStep1: readSyncStep1(decoder, encoder, doc); break; case messageYjsSyncStep2: readSyncStep2(decoder, doc, transactionOrigin); break; case messageYjsUpdate: readUpdate(decoder, doc, transactionOrigin); break; default: throw new Error("Unknown message type"); } return messageType; }; var BIT8 = 128; var BITS7 = 127; var floor = Math.floor; var min = (a, b) => a < b ? a : b; var max = (a, b) => a > b ? a : b; var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; var _encodeUtf8Polyfill = (str) => { const encodedString = unescape(encodeURIComponent(str)); const len = encodedString.length; const buf = new Uint8Array(len); for (let i = 0; i < len; i++) { buf[i] = /** @type {number} */ encodedString.codePointAt(i); } return buf; }; var utf8TextEncoder = ( /** @type {TextEncoder} */ typeof TextEncoder !== "undefined" ? new TextEncoder() : null ); var _encodeUtf8Native = (str) => utf8TextEncoder.encode(str); var encodeUtf8 = utf8TextEncoder ? _encodeUtf8Native : _encodeUtf8Polyfill; var utf8TextDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }); if (utf8TextDecoder && utf8TextDecoder.decode(new Uint8Array()).length === 1) { utf8TextDecoder = null; } var create = (s) => new Error(s); var Encoder = class { constructor() { this.cpos = 0; this.cbuf = new Uint8Array(100); this.bufs = []; } }; var createEncoder = () => new Encoder(); var length = (encoder) => { let len = encoder.cpos; for (let i = 0; i < encoder.bufs.length; i++) { len += encoder.bufs[i].length; } return len; }; var toUint8Array = (encoder) => { const uint8arr = new Uint8Array(length(encoder)); let curPos = 0; for (let i = 0; i < encoder.bufs.length; i++) { const d = encoder.bufs[i]; uint8arr.set(d, curPos); curPos += d.length; } uint8arr.set(new Uint8Array(encoder.cbuf.buffer, 0, encoder.cpos), curPos); return uint8arr; }; var write = (encoder, num) => { const bufferLen = encoder.cbuf.length; if (encoder.cpos === bufferLen) { encoder.bufs.push(encoder.cbuf); encoder.cbuf = new Uint8Array(bufferLen * 2); encoder.cpos = 0; } encoder.cbuf[encoder.cpos++] = num; }; var writeVarUint = (encoder, num) => { while (num > BITS7) { write(encoder, BIT8 | BITS7 & num); num = floor(num / 128); } write(encoder, BITS7 & num); }; var _strBuffer = new Uint8Array(3e4); var _maxStrBSize = _strBuffer.length / 3; var _writeVarStringNative = (encoder, str) => { if (str.length < _maxStrBSize) { const written = utf8TextEncoder.encodeInto(str, _strBuffer).written || 0; writeVarUint(encoder, written); for (let i = 0; i < written; i++) { write(encoder, _strBuffer[i]); } } else { writeVarUint8Array(encoder, encodeUtf8(str)); } }; var _writeVarStringPolyfill = (encoder, str) => { const encodedString = unescape(encodeURIComponent(str)); const len = encodedString.length; writeVarUint(encoder, len); for (let i = 0; i < len; i++) { write( encoder, /** @type {number} */ encodedString.codePointAt(i) ); } }; utf8TextEncoder && /** @type {any} */ utf8TextEncoder.encodeInto ? _writeVarStringNative : _writeVarStringPolyfill; var writeUint8Array = (encoder, uint8Array) => { const bufferLen = encoder.cbuf.length; const cpos = encoder.cpos; const leftCopyLen = min(bufferLen - cpos, uint8Array.length); const rightCopyLen = uint8Array.length - leftCopyLen; encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos); encoder.cpos += leftCopyLen; if (rightCopyLen > 0) { encoder.bufs.push(encoder.cbuf); encoder.cbuf = new Uint8Array(max(bufferLen * 2, rightCopyLen)); encoder.cbuf.set(uint8Array.subarray(leftCopyLen)); encoder.cpos = rightCopyLen; } }; var writeVarUint8Array = (encoder, uint8Array) => { writeVarUint(encoder, uint8Array.byteLength); writeUint8Array(encoder, uint8Array); }; var errorUnexpectedEndOfArray = create("Unexpected end of array"); var errorIntegerOutOfRange = create("Integer out of Range"); var Decoder = class { /** * @param {Uint8Array} uint8Array Binary data to decode */ constructor(uint8Array) { this.arr = uint8Array; this.pos = 0; } }; var createDecoder = (uint8Array) => new Decoder(uint8Array); var readUint8Array = (decoder, len) => { const view = new Uint8Array(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len); decoder.pos += len; return view; }; var readVarUint8Array = (decoder) => readUint8Array(decoder, readVarUint(decoder)); var readVarUint = (decoder) => { let num = 0; let mult = 1; const len = decoder.arr.length; while (decoder.pos < len) { const r = decoder.arr[decoder.pos++]; num = num + (r & BITS7) * mult; mult *= 128; if (r < BIT8) { return num; } if (num > MAX_SAFE_INTEGER) { throw errorIntegerOutOfRange; } } throw errorUnexpectedEndOfArray; }; var Sleeper = class { constructor(timeout) { this.promise = new Promise((resolve,