@roomservice/browser
Advanced tools
Comparing version 2.1.4 to 2.1.5-0
@@ -1066,7 +1066,14 @@ 'use strict'; | ||
var WEBSOCKET_TIMEOUT = 1000 * 2; | ||
var MAP_CMDS = ['mcreate', 'mput', 'mputref', 'mdel']; | ||
var LIST_CMDS = ['lcreate', 'lins', 'linsref', 'lput', 'lputref', 'ldel']; | ||
var RoomClient = /*#__PURE__*/function () { | ||
function RoomClient(params) { | ||
var _this = this; | ||
this.listClients = {}; | ||
this.mapClients = {}; | ||
this.expires = {}; | ||
this.mapCallbacksByObjID = {}; | ||
this.listCallbacksByObjID = {}; | ||
this.presenceCallbacksByKey = {}; | ||
this.ws = new SuperlumeWebSocket(params.conn); | ||
@@ -1078,4 +1085,51 @@ this.token = params.token; | ||
this.checkpoint = params.checkpoint; | ||
this.vs = this.checkpoint.vs; | ||
this.InnerPresenceClient = undefined; | ||
this.ws.bind('doc:fwd', function (body) { | ||
if (body.room !== _this.roomID) return; | ||
if (!body.args || body.args.length < 3) { | ||
// Potentially a network failure, we don't want to crash, | ||
// but do want to warn people | ||
console.error('Unexpected command: ', body.args); | ||
return; | ||
} // Ignore version stamps older than checkpoint | ||
if (isOlderVS(body.vs, _this.checkpoint.vs)) return; // Ignore validated commands | ||
if (body.from === _this.actor) return; | ||
var _ref = [body.args[0], body.args[1], body.args[2]], | ||
cmd = _ref[0], | ||
docID = _ref[1], | ||
objID = _ref[2]; | ||
if (docID !== _this.docID) return; | ||
if (MAP_CMDS.includes(cmd)) { | ||
_this.dispatchMapCmd(objID, body); | ||
} else if (LIST_CMDS.includes(cmd)) { | ||
_this.dispatchListCmd(objID, body); | ||
} else { | ||
console.warn("Unhandled Room Service doc:fwd command: " + cmd + ". Consider updating the Room Service client."); | ||
} | ||
}); | ||
this.ws.bind('presence:fwd', function (body) { | ||
_this.dispatchPresenceCmd(body); | ||
}); | ||
this.ws.bind('room:rm_guest', function (body) { | ||
if (body.room !== _this.roomID) return; | ||
var client = _this.presence(); | ||
var newClient = client.dangerouslyUpdateClientDirectly('room:rm_guest', body); | ||
for (var _i = 0, _Object$entries = Object.entries(_this.presenceCallbacksByKey); _i < _Object$entries.length; _i++) { | ||
var _Object$entries$_i = _Object$entries[_i], | ||
cbs = _Object$entries$_i[1]; | ||
for (var _iterator = _createForOfIteratorHelperLoose(cbs), _step; !(_step = _iterator()).done;) { | ||
var cb = _step.value; | ||
cb(newClient, body.guest); | ||
} | ||
} | ||
}); | ||
} | ||
@@ -1085,5 +1139,83 @@ | ||
_proto.dispatchMapCmd = function dispatchMapCmd(objID, body) { | ||
if (!this.mapClients[objID]) { | ||
var m = new InnerMapClient(this.checkpoint.maps[objID] || {}, this.roomID, this.docID, objID, this.ws); | ||
this.mapClients[objID] = m; | ||
} | ||
var client = this.mapClients[objID]; | ||
var updatedClient = client.dangerouslyUpdateClientDirectly(body.args); | ||
for (var _iterator2 = _createForOfIteratorHelperLoose(this.mapCallbacksByObjID[objID] || []), _step2; !(_step2 = _iterator2()).done;) { | ||
var cb = _step2.value; | ||
cb(updatedClient, body.from); | ||
} | ||
}; | ||
_proto.dispatchListCmd = function dispatchListCmd(objID, body) { | ||
if (!this.listClients[objID]) { | ||
var l = new InnerListClient(this.checkpoint, this.roomID, this.docID, objID, this.ws, this.actor); | ||
this.listClients[objID] = l; | ||
} | ||
var client = this.listClients[objID]; | ||
var updatedClient = client.dangerouslyUpdateClientDirectly(body.args); | ||
for (var _iterator3 = _createForOfIteratorHelperLoose(this.listCallbacksByObjID[objID] || []), _step3; !(_step3 = _iterator3()).done;) { | ||
var cb = _step3.value; | ||
cb(updatedClient, body.from); | ||
} | ||
}; | ||
_proto.dispatchPresenceCmd = function dispatchPresenceCmd(body) { | ||
var _this2 = this; | ||
if (body.room !== this.roomID) return; | ||
if (body.from === this.actor) return; | ||
var client = this.presence(); | ||
var key = body.key; | ||
var now = new Date().getTime() / 1000; | ||
var secondsTillTimeout = body.expAt - now; | ||
if (secondsTillTimeout < 0) { | ||
// don't show expired stuff | ||
return; | ||
} // Expire stuff if it's within a reasonable range (12h) | ||
if (secondsTillTimeout < 60 * 60 * 12) { | ||
if (this.expires[key]) { | ||
clearTimeout(this.expires[key]); | ||
} | ||
var timeout = setTimeout(function () { | ||
var newClient = client.dangerouslyUpdateClientDirectly('presence:expire', { | ||
key: body.key | ||
}); | ||
if (!newClient) return; | ||
for (var _iterator4 = _createForOfIteratorHelperLoose((_this2$presenceCallba = _this2.presenceCallbacksByKey[key]) !== null && _this2$presenceCallba !== void 0 ? _this2$presenceCallba : []), _step4; !(_step4 = _iterator4()).done;) { | ||
var _this2$presenceCallba; | ||
var cb = _step4.value; | ||
cb(newClient, body.from); | ||
} | ||
}, secondsTillTimeout * 1000); | ||
this.expires[key] = timeout; | ||
} | ||
var newClient = client.dangerouslyUpdateClientDirectly('presence:fwd', body); | ||
if (!newClient) return; | ||
for (var _iterator5 = _createForOfIteratorHelperLoose((_this$presenceCallbac = this.presenceCallbacksByKey[key]) !== null && _this$presenceCallbac !== void 0 ? _this$presenceCallbac : []), _step5; !(_step5 = _iterator5()).done;) { | ||
var _this$presenceCallbac; | ||
var cb = _step5.value; | ||
cb(newClient, body.from); | ||
} | ||
}; | ||
_proto.once = function once(msg) { | ||
try { | ||
var _this2 = this; | ||
var _this4 = this; | ||
@@ -1096,7 +1228,7 @@ var off; | ||
}), new Promise(function (resolve) { | ||
off = _this2.ws.bind(msg, function (body) { | ||
off = _this4.ws.bind(msg, function (body) { | ||
resolve(body); | ||
}); | ||
})]).then(function () { | ||
if (off) _this2.ws.unbind(msg, off); | ||
if (off) _this4.ws.unbind(msg, off); | ||
}); | ||
@@ -1114,6 +1246,6 @@ } catch (e) { | ||
try { | ||
var _this4 = this; | ||
var _this6 = this; | ||
if (!_this4.errorListener) { | ||
_this4.errorListener = _this4.ws.bind('error', function (err) { | ||
if (!_this6.errorListener) { | ||
_this6.errorListener = _this6.ws.bind('error', function (err) { | ||
console.error('Room Service encountered a server-side error. If you see this, please let us know; this could be a bug.', err); | ||
@@ -1123,10 +1255,10 @@ }); | ||
var authenticated = _this4.once('guest:authenticated'); | ||
var authenticated = _this6.once('guest:authenticated'); | ||
_this4.ws.send('guest:authenticate', _this4.token); | ||
_this6.ws.send('guest:authenticate', _this6.token); | ||
return Promise.resolve(authenticated).then(function () { | ||
var joined = _this4.once('room:joined'); | ||
var joined = _this6.once('room:joined'); | ||
_this4.ws.send('room:join', _this4.roomID); | ||
_this6.ws.send('room:join', _this6.roomID); | ||
@@ -1199,36 +1331,31 @@ return Promise.resolve(joined).then(function () {}); | ||
_proto.subscribe = function subscribe(obj, onChangeFnOrString, onChangeFn) { | ||
var _this5 = this; | ||
// Presence handler | ||
if (typeof onChangeFnOrString === 'string') { | ||
return this.subscribePresence(obj, onChangeFnOrString, onChangeFn); | ||
} // Map and list handler | ||
} // create new closure so fns can be subscribed/unsubscribed multiple times | ||
var bound = this.ws.bind('doc:fwd', function (body) { | ||
if (body.room !== _this5.roomID) return; | ||
var cb = function cb(obj, from) { | ||
onChangeFnOrString(obj, from); | ||
}; | ||
if (!body.args || body.args.length < 3) { | ||
// Potentially a network failure, we don't want to crash, | ||
// but do want to warn people | ||
console.error('Unexpected command: ', body.args); | ||
return; | ||
} // Ignore out of order version stamps | ||
var objID; | ||
if (obj instanceof InnerMapClient) { | ||
var client = obj; | ||
objID = client.id; | ||
this.mapCallbacksByObjID[objID] = this.mapCallbacksByObjID[objID] || []; | ||
this.mapCallbacksByObjID[objID].push(cb); | ||
} | ||
if (isOlderVS(body.vs, _this5.vs)) return; // Ignore validated commands | ||
if (obj instanceof InnerListClient) { | ||
var _client = obj; | ||
objID = _client.id; | ||
this.listCallbacksByObjID[objID] = this.listCallbacksByObjID[objID] || []; | ||
this.listCallbacksByObjID[objID].push(cb); | ||
} | ||
if (body.from === _this5.actor) return; | ||
var _ref = [body.args[1], body.args[2]], | ||
docID = _ref[0], | ||
objID = _ref[1]; | ||
if (docID !== _this5.docID) return; | ||
if (objID !== obj.id) return; | ||
_this5.vs = body.vs; | ||
var newObj = obj.dangerouslyUpdateClientDirectly(body.args); | ||
onChangeFnOrString(newObj, body.from); | ||
}); | ||
return [{ | ||
event: 'doc:fwd', | ||
fn: bound | ||
objID: objID, | ||
fn: cb | ||
}]; | ||
@@ -1238,52 +1365,15 @@ }; | ||
_proto.subscribePresence = function subscribePresence(obj, key, onChangeFn) { | ||
var _this6 = this; | ||
!obj ? invariant(false, 'subscribe() expects the first argument to not be undefined.') : void 0; // create new closure so fns can be subscribed/unsubscribed multiple times | ||
!obj ? invariant(false, 'subscribe() expects the first argument to not be undefined.') : void 0; | ||
var fwdListener = this.ws.bind('presence:fwd', function (body) { | ||
if (body.room !== _this6.roomID) return; | ||
if (body.key !== key) return; | ||
if (body.from === _this6.actor) return; | ||
var now = new Date().getTime() / 1000; | ||
var secondsTillTimeout = body.expAt - now; | ||
if (secondsTillTimeout < 0) { | ||
// don't show expired stuff | ||
return; | ||
} // Expire stuff if it's within a reasonable range (12h) | ||
if (secondsTillTimeout < 60 * 60 * 12) { | ||
if (_this6.expires[key]) { | ||
clearTimeout(_this6.expires[key]); | ||
} | ||
var timeout = setTimeout(function () { | ||
var newObj = obj.dangerouslyUpdateClientDirectly('presence:expire', { | ||
key: body.key | ||
}); | ||
if (!newObj) return; | ||
!onChangeFn ? invariant(false) : void 0; | ||
onChangeFn(newObj, body.from); | ||
}, secondsTillTimeout * 1000); | ||
_this6.expires[key] = timeout; | ||
var cb = function cb(obj, from) { | ||
if (onChangeFn) { | ||
onChangeFn(obj, from); | ||
} | ||
}; | ||
var newObj = obj.dangerouslyUpdateClientDirectly('presence:fwd', body); | ||
if (!newObj) return; | ||
!onChangeFn ? invariant(false) : void 0; | ||
onChangeFn(newObj, body.from); | ||
}); | ||
var leaveListener = this.ws.bind('room:rm_guest', function (body) { | ||
if (body.room !== _this6.roomID) return; | ||
var newObj = obj.dangerouslyUpdateClientDirectly('room:rm_guest', body); | ||
if (!newObj) return; | ||
!onChangeFn ? invariant(false) : void 0; | ||
onChangeFn(newObj, body.guest); | ||
}); | ||
this.presenceCallbacksByKey[key] = this.presenceCallbacksByKey[key] || []; | ||
this.presenceCallbacksByKey[key].push(cb); | ||
return [{ | ||
event: 'presence:fwd', | ||
fn: fwdListener | ||
}, { | ||
event: 'room:rm_guest', | ||
fn: leaveListener | ||
objID: key, | ||
fn: cb | ||
}]; | ||
@@ -1293,5 +1383,14 @@ }; | ||
_proto.unsubscribe = function unsubscribe(listeners) { | ||
for (var _iterator = _createForOfIteratorHelperLoose(listeners), _step; !(_step = _iterator()).done;) { | ||
var l = _step.value; | ||
this.ws.unbind(l.event, l.fn); | ||
for (var _iterator6 = _createForOfIteratorHelperLoose(listeners), _step6; !(_step6 = _iterator6()).done;) { | ||
var l = _step6.value; | ||
if (l.objID) { | ||
this.mapCallbacksByObjID[l.objID] = removeCallback(this.mapCallbacksByObjID[l.objID], l.fn); | ||
this.listCallbacksByObjID[l.objID] = removeCallback(this.listCallbacksByObjID[l.objID], l.fn); | ||
this.presenceCallbacksByKey[l.objID] = removeCallback(this.presenceCallbacksByKey[l.objID], l.fn); | ||
} | ||
if (l.event) { | ||
this.ws.unbind(l.event, l.fn); | ||
} | ||
} | ||
@@ -1310,2 +1409,12 @@ }; | ||
function removeCallback(cbs, rmCb) { | ||
if (!cbs) { | ||
return []; | ||
} | ||
return cbs.filter(function (existingCb) { | ||
return existingCb !== rmCb; | ||
}); | ||
} | ||
var RoomService = /*#__PURE__*/function () { | ||
@@ -1312,0 +1421,0 @@ function RoomService(params) { |
@@ -1,2 +0,2 @@ | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t=(e=require("tiny-invariant"))&&"object"==typeof e&&"default"in e?e.default:e;function r(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function n(e,t,n){return t&&r(e.prototype,t),n&&r(e,n),e}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function o(e,t){var r;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(r=function(e,t){if(e){if("string"==typeof e)return i(e,void 0);var r=Object.prototype.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?i(e,void 0):void 0}}(e))||t&&e&&"number"==typeof e.length){r&&(e=r);var n=0;return function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(r=e[Symbol.iterator]()).next.bind(r)}var s=function(){function e(e){var t=this;this.callbacks={},this.lastTime=0,this.msgsThisMilisecond=0,this.conn=e,this.conn.onmessage=function(e){var r=JSON.parse(e.data);t.dispatch(r.type,r.body)}}var t=e.prototype;return t.timestamp=function(){var e=Date.now();return e===this.lastTime?this.msgsThisMilisecond++:(this.lastTime=e,this.msgsThisMilisecond=0),e+":"+this.msgsThisMilisecond},t.send=function(e,t){var r=this,n=this.timestamp();this.conn.readyState!==this.conn.CONNECTING?this.conn.send(JSON.stringify({type:e,ts:n,ver:0,body:t})):setTimeout((function(){r.send(e,t)}),100+100*Math.random())},t.bind=function(e,t){return this.callbacks[e]=this.callbacks[e]||[],this.callbacks[e].push(t),t},t.unbind=function(e,t){this.callbacks[e]=this.callbacks[e].filter((function(e){return e!==t}))},t.dispatch=function(e,t){var r=this.callbacks[e];if(r)for(var n=0;n<r.length;n++)r[n](t)},e}();function c(e,t){if("root"===t)return"root";var r=t.split(":");return r[0]+":"+e.actors[parseInt(r[1])]}var u=function(){function e(e){this.count=0,this.actor=e,this.nodes={},this.log=[]}var r=e.prototype;return r.import=function(e,r){e||t(!1);for(var n=e.lists[r],i=n.afters||[],o=n.ids||[],s=n.values||[],u=0;u<i.length;u++){var h={after:c(e,i[u]),id:c(e,o[u]),value:s[u]};this.nodes[h.id]=h,this.log.push(h)}this.count=this.log.length},r.get=function(e){if(this.nodes[e])return this.nodes[e].value},r.insert=function(e,r,n){this.log||t(!1);var i=n;i||(i=this.count+":"+this.actor),this.count++;var o={after:e,value:r,id:i};return this.nodes[i]=o,this.log.push(o),i},r.put=function(e,t){this.nodes[e]&&(this.nodes[e].value=t)},r.has=function(e){return!!this.nodes[e]},r.delete=function(e){this.nodes[e]&&(this.nodes[e].value={t:""})},r.toTree=function(){for(var e,t={children:[],id:"root",value:""},r={root:t},n=o(this.log);!(e=n()).done;){var i=e.value,s={children:[],id:i.id,value:i.value};if(r[i.id]=s,"root"===i.after)t.children.push(s);else{if(!r[i.after])continue;r[i.after].children.push(s)}}return t},r.sortLog=function(){this.log.sort((function(e,t){var r=e.id.split(":"),n=r[0],i=r[1],o=t.id.split(":"),s=o[0];return n===s?i.localeCompare(o[1]):parseInt(n)-parseInt(s)}))},r.lastID=function(){return 0===this.log.length?"root":(this.sortLog(),function e(t){return t.children&&0!==t.children.length?e(t.children[t.children.length-1]):t}(this.toTree()).id)},r.postOrderTraverse=function(){return this.sortLog(),function e(t){if(!t.children||0===t.children.length)return[];for(var r,n=[],i=o(t.children);!(r=i()).done;){var s=r.value;if("string"!=typeof s.value){if(""===s.value.t){n=n.concat([].concat(e(s)));continue}throw new Error("Unimplemented")}n=n.concat([s].concat(e(s)))}return n}(this.toTree())},r.toArray=function(){return this.postOrderTraverse().map((function(e){return e.value}))},n(e,[{key:"length",get:function(){return Object.keys(this.nodes).length}}]),e}();function h(e){return JSON.stringify(e)}function a(e){try{return JSON.parse(e)}catch(t){return e}}var d=function(){function e(e,r,n,i,o,s){this.itemIDs=[],this.roomID=r,this.docID=n,this.id=i,this.ws=o,this.rt=new u(s),e.lists[i]||t(!1),this.rt.import(e,i);for(var h=e.lists[i].ids||[],a=0;a<h.length;a++){var d=e.lists[i].values[a];"object"==typeof d&&""===d.t||this.itemIDs.push(c(e,h[a]))}}var r=e.prototype;return r.sendCmd=function(e){this.ws.send("doc:cmd",{room:this.roomID,args:e})},r.clone=function(){return Object.assign(Object.create(Object.getPrototypeOf(this)),this)},r.dangerouslyUpdateClientDirectly=function(e){if(e.length<3)throw new Error("Unexpected command: "+e);var t=e[0];if(e[1]!==this.docID||e[2]!==this.id)throw new Error("Command unexpectedly routed to the wrong client");switch(t){case"lins":var r=e[3],n=e[4],i=e[5];this.itemIDs.splice(this.itemIDs.findIndex((function(e){return e===r}))+1,0,n),this.rt.insert(r,i,n);break;case"lput":this.rt.put(e[3],e[4]);break;case"ldel":var o=e[3];this.rt.delete(o),this.itemIDs.splice(this.itemIDs.findIndex((function(e){return e===o})),1);break;default:throw new Error("Unexpected command keyword: "+t)}return this.clone()},r.get=function(e){var t=this.itemIDs[e];if(t){var r=this.rt.get(t);if(r){if("object"==typeof r){if(""===r.t)return;throw new Error("Unimplemented references")}return a(r)}}},r.set=function(e,t){var r=this.itemIDs[e];if(!r)throw new Error("Index '"+e+"' doesn't already exist. Try .push() or .insertAfter() instead.");var n=h(t);return this.rt.put(r,n),this.sendCmd(["lput",this.docID,this.id,r,n]),this.clone()},r.delete=function(e){if(0===this.itemIDs.length)return this.clone();var t=this.itemIDs[e];return t?(this.rt.delete(t),this.itemIDs.splice(e,1),this.sendCmd(["ldel",this.docID,this.id,t]),this.clone()):(console.warn("Unknown index: ",e,this.itemIDs),this.clone())},r.insertAfter=function(e,t){var r=this.itemIDs[e];if(!r)throw new RangeError("List '"+this.id+"' has no index: '"+e+"'");var n=h(t),i=this.rt.insert(r,n);return this.itemIDs.splice(e,0,i),this.sendCmd(["lins",this.docID,this.id,r,i,n]),this.clone()},r.pushOne=function(e){var t=this.rt.lastID(),r=h(e),n=this.rt.insert(t,r);return this.itemIDs.push(n),this.sendCmd(["lins",this.docID,this.id,t,n,r]),this.clone()},r.push=function(){for(var e,t=arguments.length,r=new Array(t),n=0;n<t;n++)r[n]=arguments[n];for(var i=0,o=r;i<o.length;i++){var s=o[i];e=this.pushOne(s)}return e},r.map=function(e){return this.rt.postOrderTraverse().map((function(t,r){return e(a(t.value),r,t.id)}))},r.toArray=function(){return this.rt.toArray().map((function(e){return a(e)}))},e}(),f=function(){function e(e,t,r,n,i){for(var o in this.roomID=t,this.docID=r,this.id=n,this.ws=i,this.store={},e){var s=e[o];"string"==typeof s&&(this.store[o]=a(s))}}var t=e.prototype;return t.sendCmd=function(e){this.ws.send("doc:cmd",{room:this.roomID,args:e})},t.clone=function(){return Object.assign(Object.create(Object.getPrototypeOf(this)),this)},t.dangerouslyUpdateClientDirectly=function(e){if(e.length<3)throw new Error("Unexpected command: "+e);var t=e[0];if(e[1]!==this.docID||e[2]!==this.id)throw new Error("Command unexpectedly routed to the wrong client");switch(t){case"mput":if(5!==e.length){console.error("Malformed command ",e);break}this.store[e[3]]=a(e[4]);break;case"mdel":if(4!==e.length){console.error("Malformed command ",e);break}delete this.store[e[3]];break;default:throw new Error("Unexpected command keyword: "+t)}return this.clone()},t.get=function(e){return this.store[e]},t.set=function(e,t){var r=h(t);return this.store[e]=t,this.sendCmd(["mput",this.docID,this.id,e,r]),this.clone()},t.toObject=function(){for(var e,t={},r=o(this.keys);!(e=r()).done;){var n=e.value;t[n]=this.get(n)}return t},t.delete=function(e){return delete this.store[e],this.sendCmd(["mdel",this.docID,this.id,e]),this.clone()},n(e,[{key:"keys",get:function(){return Object.keys(this.store)}}]),e}(),l=function(){function e(e,t,r,n){var i=this;this.roomID=e,this.ws=t,this.actor=r,this.token=n,this.cache={},this.sendPres=function(e,t,r){void 0===r&&(r=!1);var n={},i=!0;return function(){var t=arguments,o=this,s=r&&i,c=function(){e.apply(o,t),n[t[0]]=null};s&&(i=!1,c()),n[arguments[0]]||(n[arguments[0]]=setTimeout(c,40))}}((function(e,t){i.ws.send("presence:cmd",t)}))}var t=e.prototype;return t.getAll=function(e){try{var t=this;return Promise.resolve(function(e,t,r,n){try{return Promise.resolve(fetch("https://super.roomservice.dev/presence/"+r+"/"+encodeURIComponent(n),{headers:{Authorization:"Bearer: "+t}})).then((function(e){return Promise.resolve(e.json()).then((function(e){for(var t in e)if("string"==typeof e[t].value){var r=void 0;try{r=JSON.parse(e[t].value)}catch(e){}r&&(e[t].value=r)}return e}))}))}catch(e){return Promise.reject(e)}}(0,t.token,t.roomID,e)).then((function(r){return t.cache[e]=r,t.withoutExpiredAndSelf(e)}))}catch(e){return Promise.reject(e)}},t.withoutExpiredAndSelf=function(e){var t={};for(var r in this.cache[e]){var n=this.cache[e][r];r===this.actor&&delete this.cache[e][r],new Date>n.expAt?delete this.cache[e][r]:t[r]=n.value}return t},t.withoutActorOrExpired=function(e){var t={};for(var r in this.cache)for(var n in this.cache[r]){var i=this.cache[r][n];i&&(n===e&&this.cache[r][n]||new Date>i.expAt?delete this.cache[r][n]:t[n]=i.value)}return t},t.set=function(e,t,r){var n=r||60,i=Math.round((new Date).getTime()/1e3)+n;return this.sendPres(e,{room:this.roomID,key:e,value:JSON.stringify(t),expAt:i}),this.cache[e]||(this.cache[e]={}),this.cache[e][this.actor]={value:t,expAt:new Date(1e3*i)},this.withoutExpiredAndSelf(e)},t.dangerouslyUpdateClientDirectly=function(e,t){if("room:rm_guest"===e)return this.withoutActorOrExpired(t.guest);if("presence:expire"===e)return this.withoutExpiredAndSelf(t.key);if(t.room!==this.roomID)return!1;if(t.from===this.actor)return!1;var r={expAt:new Date(1e3*t.expAt),value:JSON.parse(t.value)};return this.cache[t.key]||(this.cache[t.key]={}),this.cache[t.key][t.from]=r,this.withoutExpiredAndSelf(t.key)},n(e,[{key:"me",get:function(){return console.warn("presence.me() is deprecated and will be removed in a future version!"),this.actor}}]),e}();function m(e){for(var t=window.atob(e),r=t.length,n=new Uint8Array(r),i=0;i<r;i++)n[i]=t.charCodeAt(i);return n.buffer}var v=function(){function e(e){this.listClients={},this.mapClients={},this.expires={},this.ws=new s(e.conn),this.token=e.token,this.roomID=e.roomID,this.docID=e.checkpoint.id,this.actor=e.actor,this.checkpoint=e.checkpoint,this.vs=this.checkpoint.vs,this.InnerPresenceClient=void 0}var r=e.prototype;return r.once=function(e){try{var t,r=this;return Promise.race([new Promise((function(e,t){return setTimeout((function(){return t("timeout")}),2e3)})),new Promise((function(n){t=r.ws.bind(e,(function(e){n(e)}))}))]).then((function(){t&&r.ws.unbind(e,t)}))}catch(e){return Promise.reject(e)}},r.reconnect=function(){try{var e=this;e.errorListener||(e.errorListener=e.ws.bind("error",(function(e){console.error("Room Service encountered a server-side error. If you see this, please let us know; this could be a bug.",e)})));var t=e.once("guest:authenticated");return e.ws.send("guest:authenticate",e.token),Promise.resolve(t).then((function(){var t=e.once("room:joined");return e.ws.send("room:join",e.roomID),Promise.resolve(t).then((function(){}))}))}catch(e){return Promise.reject(e)}},r.list=function(e){if(this.listClients[e])return this.listClients[e];this.checkpoint.lists[e]||(this.ws.send("doc:cmd",{args:["lcreate",this.docID,e],room:this.roomID}),this.checkpoint.lists[e]={afters:[],ids:[],values:[]});var t=new d(this.checkpoint,this.roomID,this.docID,e,this.ws,this.actor);return this.listClients[e]=t,t},r.map=function(e){if(this.mapClients[e])return this.mapClients[e];this.checkpoint.maps[e]||this.ws.send("doc:cmd",{args:["mcreate",this.docID,e],room:this.roomID});var t=new f(this.checkpoint.maps[e]||{},this.roomID,this.docID,e,this.ws);return this.mapClients[e]=t,t},r.presence=function(){if(this.InnerPresenceClient)return this.InnerPresenceClient;var e=new l(this.roomID,this.ws,this.actor,this.token);try{this.InnerPresenceClient=e}catch(e){throw new Error("Don't Freeze State. See more: https://err.sh/getroomservice/browser/dont-freeze")}return this.InnerPresenceClient},r.subscribe=function(e,t,r){var n=this;return"string"==typeof t?this.subscribePresence(e,t,r):[{event:"doc:fwd",fn:this.ws.bind("doc:fwd",(function(r){if(r.room===n.roomID)if(!r.args||r.args.length<3)console.error("Unexpected command: ",r.args);else if(!function(e,t){if(!e)return!0;if(!t)return!1;for(var r=new Uint8Array(m(e).slice(0,9)),n=new Uint8Array(m(t).slice(0,9)),i=0;i<r.byteLength;i++){if(n[i]>r[i])return!0;if(n[i]<r[i])return!1}return!1}(r.vs,n.vs)&&r.from!==n.actor){var i=[r.args[1],r.args[2]];if(i[0]===n.docID&&i[1]===e.id){n.vs=r.vs;var o=e.dangerouslyUpdateClientDirectly(r.args);t(o,r.from)}}}))}]},r.subscribePresence=function(e,r,n){var i=this;return e||t(!1),[{event:"presence:fwd",fn:this.ws.bind("presence:fwd",(function(o){if(o.room===i.roomID&&o.key===r&&o.from!==i.actor){var s=(new Date).getTime()/1e3,c=o.expAt-s;if(!(c<0)){if(c<43200){i.expires[r]&&clearTimeout(i.expires[r]);var u=setTimeout((function(){var r=e.dangerouslyUpdateClientDirectly("presence:expire",{key:o.key});r&&(n||t(!1),n(r,o.from))}),1e3*c);i.expires[r]=u}var h=e.dangerouslyUpdateClientDirectly("presence:fwd",o);h&&(n||t(!1),n(h,o.from))}}}))},{event:"room:rm_guest",fn:this.ws.bind("room:rm_guest",(function(r){if(r.room===i.roomID){var o=e.dangerouslyUpdateClientDirectly("room:rm_guest",r);o&&(n||t(!1),n(o,r.guest))}}))}]},r.unsubscribe=function(e){for(var t,r=o(e);!(t=r()).done;){var n=t.value;this.ws.unbind(n.event,n.fn)}},n(e,[{key:"me",get:function(){return this.actor}}]),e}(),p=function(){function e(e){this.roomClients={},this.auth=e.auth}return e.prototype.room=function(e){try{var t=this;if(t.roomClients[e])return Promise.resolve(t.roomClients[e]);var r=new WebSocket("wss://super.roomservice.dev/ws");return Promise.resolve(function(e,t,r,n,i){try{return Promise.resolve(function(e,t,r){try{var n=function(r){return i?r:Promise.resolve(fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({resources:[{object:"document",reference:"default",permission:"read_write",room:t},{object:"room",reference:t,permission:"join"}]})})).then((function(e){if(401===e.status)throw new Error("The Auth Webhook returned unauthorized.");if(200!==e.status)throw new Error("The Auth Webhook returned a status code other than 200.");return Promise.resolve(e.json()).then((function(e){var t=e.resources,r=e.token,n=e.user;if(!t||!r||!n){if("Unauthorized"===e.body)throw new Error("The Auth Webhook unexpectedly return unauthorized. You may be using an invalid API key.");throw new Error("The Auth Webhook has an incorrectly formatted JSON response.")}return{token:r,guestReference:n,docID:t.find((function(e){return"document"===e.object})).id,roomID:t.find((function(e){return"room"===e.object})).id}}))}))},i=!1,o=function(){if("function"==typeof e)return Promise.resolve(e(t)).then((function(e){if(!e.user)throw new Error("The auth function must return a 'user' key.");var t=e.resources.find((function(e){return"document"===e.object})).id,r=e.resources.find((function(e){return"room"===e.object})).id;return i=!0,{token:e.token,guestReference:e.user,docID:t,roomID:r}}))}();return Promise.resolve(o&&o.then?o.then(n):n(o))}catch(e){return Promise.reject(e)}}(r,n)).then((function(t){return Promise.resolve(function(e,t,r){try{return Promise.resolve(fetch("https://super.roomservice.dev/docs/"+r,{headers:{Authorization:"Bearer: "+t}})).then((function(e){return Promise.resolve(e.json())}))}catch(e){return Promise.reject(e)}}(0,t.token,t.docID)).then((function(r){var n=new v({conn:e,actor:t.guestReference,checkpoint:r.body,token:t.token,roomID:t.roomID});return Promise.resolve(n.reconnect()).then((function(){return n}))}))}))}catch(e){return Promise.reject(e)}}(r,0,t.auth,e)).then((function(r){return t.roomClients[e]=r,r}))}catch(e){return Promise.reject(e)}},e}();exports.RoomClient=v,exports.RoomService=p,exports.default=p; | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t=(e=require("tiny-invariant"))&&"object"==typeof e&&"default"in e?e.default:e;function r(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function n(e,t,n){return t&&r(e.prototype,t),n&&r(e,n),e}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function s(e,t){var r;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(r=function(e,t){if(e){if("string"==typeof e)return i(e,void 0);var r=Object.prototype.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?i(e,void 0):void 0}}(e))||t&&e&&"number"==typeof e.length){r&&(e=r);var n=0;return function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(r=e[Symbol.iterator]()).next.bind(r)}var o=function(){function e(e){var t=this;this.callbacks={},this.lastTime=0,this.msgsThisMilisecond=0,this.conn=e,this.conn.onmessage=function(e){var r=JSON.parse(e.data);t.dispatch(r.type,r.body)}}var t=e.prototype;return t.timestamp=function(){var e=Date.now();return e===this.lastTime?this.msgsThisMilisecond++:(this.lastTime=e,this.msgsThisMilisecond=0),e+":"+this.msgsThisMilisecond},t.send=function(e,t){var r=this,n=this.timestamp();this.conn.readyState!==this.conn.CONNECTING?this.conn.send(JSON.stringify({type:e,ts:n,ver:0,body:t})):setTimeout((function(){r.send(e,t)}),100+100*Math.random())},t.bind=function(e,t){return this.callbacks[e]=this.callbacks[e]||[],this.callbacks[e].push(t),t},t.unbind=function(e,t){this.callbacks[e]=this.callbacks[e].filter((function(e){return e!==t}))},t.dispatch=function(e,t){var r=this.callbacks[e];if(r)for(var n=0;n<r.length;n++)r[n](t)},e}();function c(e,t){if("root"===t)return"root";var r=t.split(":");return r[0]+":"+e.actors[parseInt(r[1])]}var a=function(){function e(e){this.count=0,this.actor=e,this.nodes={},this.log=[]}var r=e.prototype;return r.import=function(e,r){e||t(!1);for(var n=e.lists[r],i=n.afters||[],s=n.ids||[],o=n.values||[],a=0;a<i.length;a++){var h={after:c(e,i[a]),id:c(e,s[a]),value:o[a]};this.nodes[h.id]=h,this.log.push(h)}this.count=this.log.length},r.get=function(e){if(this.nodes[e])return this.nodes[e].value},r.insert=function(e,r,n){this.log||t(!1);var i=n;i||(i=this.count+":"+this.actor),this.count++;var s={after:e,value:r,id:i};return this.nodes[i]=s,this.log.push(s),i},r.put=function(e,t){this.nodes[e]&&(this.nodes[e].value=t)},r.has=function(e){return!!this.nodes[e]},r.delete=function(e){this.nodes[e]&&(this.nodes[e].value={t:""})},r.toTree=function(){for(var e,t={children:[],id:"root",value:""},r={root:t},n=s(this.log);!(e=n()).done;){var i=e.value,o={children:[],id:i.id,value:i.value};if(r[i.id]=o,"root"===i.after)t.children.push(o);else{if(!r[i.after])continue;r[i.after].children.push(o)}}return t},r.sortLog=function(){this.log.sort((function(e,t){var r=e.id.split(":"),n=r[0],i=r[1],s=t.id.split(":"),o=s[0];return n===o?i.localeCompare(s[1]):parseInt(n)-parseInt(o)}))},r.lastID=function(){return 0===this.log.length?"root":(this.sortLog(),function e(t){return t.children&&0!==t.children.length?e(t.children[t.children.length-1]):t}(this.toTree()).id)},r.postOrderTraverse=function(){return this.sortLog(),function e(t){if(!t.children||0===t.children.length)return[];for(var r,n=[],i=s(t.children);!(r=i()).done;){var o=r.value;if("string"!=typeof o.value){if(""===o.value.t){n=n.concat([].concat(e(o)));continue}throw new Error("Unimplemented")}n=n.concat([o].concat(e(o)))}return n}(this.toTree())},r.toArray=function(){return this.postOrderTraverse().map((function(e){return e.value}))},n(e,[{key:"length",get:function(){return Object.keys(this.nodes).length}}]),e}();function h(e){return JSON.stringify(e)}function u(e){try{return JSON.parse(e)}catch(t){return e}}var l=function(){function e(e,r,n,i,s,o){this.itemIDs=[],this.roomID=r,this.docID=n,this.id=i,this.ws=s,this.rt=new a(o),e.lists[i]||t(!1),this.rt.import(e,i);for(var h=e.lists[i].ids||[],u=0;u<h.length;u++){var l=e.lists[i].values[u];"object"==typeof l&&""===l.t||this.itemIDs.push(c(e,h[u]))}}var r=e.prototype;return r.sendCmd=function(e){this.ws.send("doc:cmd",{room:this.roomID,args:e})},r.clone=function(){return Object.assign(Object.create(Object.getPrototypeOf(this)),this)},r.dangerouslyUpdateClientDirectly=function(e){if(e.length<3)throw new Error("Unexpected command: "+e);var t=e[0];if(e[1]!==this.docID||e[2]!==this.id)throw new Error("Command unexpectedly routed to the wrong client");switch(t){case"lins":var r=e[3],n=e[4],i=e[5];this.itemIDs.splice(this.itemIDs.findIndex((function(e){return e===r}))+1,0,n),this.rt.insert(r,i,n);break;case"lput":this.rt.put(e[3],e[4]);break;case"ldel":var s=e[3];this.rt.delete(s),this.itemIDs.splice(this.itemIDs.findIndex((function(e){return e===s})),1);break;default:throw new Error("Unexpected command keyword: "+t)}return this.clone()},r.get=function(e){var t=this.itemIDs[e];if(t){var r=this.rt.get(t);if(r){if("object"==typeof r){if(""===r.t)return;throw new Error("Unimplemented references")}return u(r)}}},r.set=function(e,t){var r=this.itemIDs[e];if(!r)throw new Error("Index '"+e+"' doesn't already exist. Try .push() or .insertAfter() instead.");var n=h(t);return this.rt.put(r,n),this.sendCmd(["lput",this.docID,this.id,r,n]),this.clone()},r.delete=function(e){if(0===this.itemIDs.length)return this.clone();var t=this.itemIDs[e];return t?(this.rt.delete(t),this.itemIDs.splice(e,1),this.sendCmd(["ldel",this.docID,this.id,t]),this.clone()):(console.warn("Unknown index: ",e,this.itemIDs),this.clone())},r.insertAfter=function(e,t){var r=this.itemIDs[e];if(!r)throw new RangeError("List '"+this.id+"' has no index: '"+e+"'");var n=h(t),i=this.rt.insert(r,n);return this.itemIDs.splice(e,0,i),this.sendCmd(["lins",this.docID,this.id,r,i,n]),this.clone()},r.pushOne=function(e){var t=this.rt.lastID(),r=h(e),n=this.rt.insert(t,r);return this.itemIDs.push(n),this.sendCmd(["lins",this.docID,this.id,t,n,r]),this.clone()},r.push=function(){for(var e,t=arguments.length,r=new Array(t),n=0;n<t;n++)r[n]=arguments[n];for(var i=0,s=r;i<s.length;i++){var o=s[i];e=this.pushOne(o)}return e},r.map=function(e){return this.rt.postOrderTraverse().map((function(t,r){return e(u(t.value),r,t.id)}))},r.toArray=function(){return this.rt.toArray().map((function(e){return u(e)}))},e}(),d=function(){function e(e,t,r,n,i){for(var s in this.roomID=t,this.docID=r,this.id=n,this.ws=i,this.store={},e){var o=e[s];"string"==typeof o&&(this.store[s]=u(o))}}var t=e.prototype;return t.sendCmd=function(e){this.ws.send("doc:cmd",{room:this.roomID,args:e})},t.clone=function(){return Object.assign(Object.create(Object.getPrototypeOf(this)),this)},t.dangerouslyUpdateClientDirectly=function(e){if(e.length<3)throw new Error("Unexpected command: "+e);var t=e[0];if(e[1]!==this.docID||e[2]!==this.id)throw new Error("Command unexpectedly routed to the wrong client");switch(t){case"mput":if(5!==e.length){console.error("Malformed command ",e);break}this.store[e[3]]=u(e[4]);break;case"mdel":if(4!==e.length){console.error("Malformed command ",e);break}delete this.store[e[3]];break;default:throw new Error("Unexpected command keyword: "+t)}return this.clone()},t.get=function(e){return this.store[e]},t.set=function(e,t){var r=h(t);return this.store[e]=t,this.sendCmd(["mput",this.docID,this.id,e,r]),this.clone()},t.toObject=function(){for(var e,t={},r=s(this.keys);!(e=r()).done;){var n=e.value;t[n]=this.get(n)}return t},t.delete=function(e){return delete this.store[e],this.sendCmd(["mdel",this.docID,this.id,e]),this.clone()},n(e,[{key:"keys",get:function(){return Object.keys(this.store)}}]),e}(),f=function(){function e(e,t,r,n){var i=this;this.roomID=e,this.ws=t,this.actor=r,this.token=n,this.cache={},this.sendPres=function(e,t,r){void 0===r&&(r=!1);var n={},i=!0;return function(){var t=arguments,s=this,o=r&&i,c=function(){e.apply(s,t),n[t[0]]=null};o&&(i=!1,c()),n[arguments[0]]||(n[arguments[0]]=setTimeout(c,40))}}((function(e,t){i.ws.send("presence:cmd",t)}))}var t=e.prototype;return t.getAll=function(e){try{var t=this;return Promise.resolve(function(e,t,r,n){try{return Promise.resolve(fetch("https://super.roomservice.dev/presence/"+r+"/"+encodeURIComponent(n),{headers:{Authorization:"Bearer: "+t}})).then((function(e){return Promise.resolve(e.json()).then((function(e){for(var t in e)if("string"==typeof e[t].value){var r=void 0;try{r=JSON.parse(e[t].value)}catch(e){}r&&(e[t].value=r)}return e}))}))}catch(e){return Promise.reject(e)}}(0,t.token,t.roomID,e)).then((function(r){return t.cache[e]=r,t.withoutExpiredAndSelf(e)}))}catch(e){return Promise.reject(e)}},t.withoutExpiredAndSelf=function(e){var t={};for(var r in this.cache[e]){var n=this.cache[e][r];r===this.actor&&delete this.cache[e][r],new Date>n.expAt?delete this.cache[e][r]:t[r]=n.value}return t},t.withoutActorOrExpired=function(e){var t={};for(var r in this.cache)for(var n in this.cache[r]){var i=this.cache[r][n];i&&(n===e&&this.cache[r][n]||new Date>i.expAt?delete this.cache[r][n]:t[n]=i.value)}return t},t.set=function(e,t,r){var n=r||60,i=Math.round((new Date).getTime()/1e3)+n;return this.sendPres(e,{room:this.roomID,key:e,value:JSON.stringify(t),expAt:i}),this.cache[e]||(this.cache[e]={}),this.cache[e][this.actor]={value:t,expAt:new Date(1e3*i)},this.withoutExpiredAndSelf(e)},t.dangerouslyUpdateClientDirectly=function(e,t){if("room:rm_guest"===e)return this.withoutActorOrExpired(t.guest);if("presence:expire"===e)return this.withoutExpiredAndSelf(t.key);if(t.room!==this.roomID)return!1;if(t.from===this.actor)return!1;var r={expAt:new Date(1e3*t.expAt),value:JSON.parse(t.value)};return this.cache[t.key]||(this.cache[t.key]={}),this.cache[t.key][t.from]=r,this.withoutExpiredAndSelf(t.key)},n(e,[{key:"me",get:function(){return console.warn("presence.me() is deprecated and will be removed in a future version!"),this.actor}}]),e}();function m(e){for(var t=window.atob(e),r=t.length,n=new Uint8Array(r),i=0;i<r;i++)n[i]=t.charCodeAt(i);return n.buffer}var p=["mcreate","mput","mputref","mdel"],v=["lcreate","lins","linsref","lput","lputref","ldel"],y=function(){function e(e){var t=this;this.listClients={},this.mapClients={},this.expires={},this.mapCallbacksByObjID={},this.listCallbacksByObjID={},this.presenceCallbacksByKey={},this.ws=new o(e.conn),this.token=e.token,this.roomID=e.roomID,this.docID=e.checkpoint.id,this.actor=e.actor,this.checkpoint=e.checkpoint,this.InnerPresenceClient=void 0,this.ws.bind("doc:fwd",(function(e){if(e.room===t.roomID)if(!e.args||e.args.length<3)console.error("Unexpected command: ",e.args);else if(!function(e,t){if(!e)return!0;if(!t)return!1;for(var r=new Uint8Array(m(e).slice(0,9)),n=new Uint8Array(m(t).slice(0,9)),i=0;i<r.byteLength;i++){if(n[i]>r[i])return!0;if(n[i]<r[i])return!1}return!1}(e.vs,t.checkpoint.vs)&&e.from!==t.actor){var r=[e.args[0],e.args[1],e.args[2]],n=r[0],i=r[2];r[1]===t.docID&&(p.includes(n)?t.dispatchMapCmd(i,e):v.includes(n)?t.dispatchListCmd(i,e):console.warn("Unhandled Room Service doc:fwd command: "+n+". Consider updating the Room Service client."))}})),this.ws.bind("presence:fwd",(function(e){t.dispatchPresenceCmd(e)})),this.ws.bind("room:rm_guest",(function(e){if(e.room===t.roomID)for(var r=t.presence().dangerouslyUpdateClientDirectly("room:rm_guest",e),n=0,i=Object.entries(t.presenceCallbacksByKey);n<i.length;n++)for(var o,c=s(i[n][1]);!(o=c()).done;)(0,o.value)(r,e.guest)}))}var r=e.prototype;return r.dispatchMapCmd=function(e,t){if(!this.mapClients[e]){var r=new d(this.checkpoint.maps[e]||{},this.roomID,this.docID,e,this.ws);this.mapClients[e]=r}for(var n,i=this.mapClients[e].dangerouslyUpdateClientDirectly(t.args),o=s(this.mapCallbacksByObjID[e]||[]);!(n=o()).done;)(0,n.value)(i,t.from)},r.dispatchListCmd=function(e,t){if(!this.listClients[e]){var r=new l(this.checkpoint,this.roomID,this.docID,e,this.ws,this.actor);this.listClients[e]=r}for(var n,i=this.listClients[e].dangerouslyUpdateClientDirectly(t.args),o=s(this.listCallbacksByObjID[e]||[]);!(n=o()).done;)(0,n.value)(i,t.from)},r.dispatchPresenceCmd=function(e){var t=this;if(e.room===this.roomID&&e.from!==this.actor){var r=this.presence(),n=e.key,i=(new Date).getTime()/1e3,o=e.expAt-i;if(!(o<0)){if(o<43200){this.expires[n]&&clearTimeout(this.expires[n]);var c=setTimeout((function(){var i=r.dangerouslyUpdateClientDirectly("presence:expire",{key:e.key});if(i)for(var o,c=s(null!==(a=t.presenceCallbacksByKey[n])&&void 0!==a?a:[]);!(o=c()).done;){var a;(0,o.value)(i,e.from)}}),1e3*o);this.expires[n]=c}var a=r.dangerouslyUpdateClientDirectly("presence:fwd",e);if(a)for(var h,u=s(null!==(l=this.presenceCallbacksByKey[n])&&void 0!==l?l:[]);!(h=u()).done;){var l;(0,h.value)(a,e.from)}}}},r.once=function(e){try{var t,r=this;return Promise.race([new Promise((function(e,t){return setTimeout((function(){return t("timeout")}),2e3)})),new Promise((function(n){t=r.ws.bind(e,(function(e){n(e)}))}))]).then((function(){t&&r.ws.unbind(e,t)}))}catch(e){return Promise.reject(e)}},r.reconnect=function(){try{var e=this;e.errorListener||(e.errorListener=e.ws.bind("error",(function(e){console.error("Room Service encountered a server-side error. If you see this, please let us know; this could be a bug.",e)})));var t=e.once("guest:authenticated");return e.ws.send("guest:authenticate",e.token),Promise.resolve(t).then((function(){var t=e.once("room:joined");return e.ws.send("room:join",e.roomID),Promise.resolve(t).then((function(){}))}))}catch(e){return Promise.reject(e)}},r.list=function(e){if(this.listClients[e])return this.listClients[e];this.checkpoint.lists[e]||(this.ws.send("doc:cmd",{args:["lcreate",this.docID,e],room:this.roomID}),this.checkpoint.lists[e]={afters:[],ids:[],values:[]});var t=new l(this.checkpoint,this.roomID,this.docID,e,this.ws,this.actor);return this.listClients[e]=t,t},r.map=function(e){if(this.mapClients[e])return this.mapClients[e];this.checkpoint.maps[e]||this.ws.send("doc:cmd",{args:["mcreate",this.docID,e],room:this.roomID});var t=new d(this.checkpoint.maps[e]||{},this.roomID,this.docID,e,this.ws);return this.mapClients[e]=t,t},r.presence=function(){if(this.InnerPresenceClient)return this.InnerPresenceClient;var e=new f(this.roomID,this.ws,this.actor,this.token);try{this.InnerPresenceClient=e}catch(e){throw new Error("Don't Freeze State. See more: https://err.sh/getroomservice/browser/dont-freeze")}return this.InnerPresenceClient},r.subscribe=function(e,t,r){if("string"==typeof t)return this.subscribePresence(e,t,r);var n,i=function(e,r){t(e,r)};return e instanceof d&&(this.mapCallbacksByObjID[n=e.id]=this.mapCallbacksByObjID[n]||[],this.mapCallbacksByObjID[n].push(i)),e instanceof l&&(this.listCallbacksByObjID[n=e.id]=this.listCallbacksByObjID[n]||[],this.listCallbacksByObjID[n].push(i)),[{objID:n,fn:i}]},r.subscribePresence=function(e,r,n){e||t(!1);var i=function(e,t){n&&n(e,t)};return this.presenceCallbacksByKey[r]=this.presenceCallbacksByKey[r]||[],this.presenceCallbacksByKey[r].push(i),[{objID:r,fn:i}]},r.unsubscribe=function(e){for(var t,r=s(e);!(t=r()).done;){var n=t.value;n.objID&&(this.mapCallbacksByObjID[n.objID]=b(this.mapCallbacksByObjID[n.objID],n.fn),this.listCallbacksByObjID[n.objID]=b(this.listCallbacksByObjID[n.objID],n.fn),this.presenceCallbacksByKey[n.objID]=b(this.presenceCallbacksByKey[n.objID],n.fn)),n.event&&this.ws.unbind(n.event,n.fn)}},n(e,[{key:"me",get:function(){return this.actor}}]),e}();function b(e,t){return e?e.filter((function(e){return e!==t})):[]}var w=function(){function e(e){this.roomClients={},this.auth=e.auth}return e.prototype.room=function(e){try{var t=this;if(t.roomClients[e])return Promise.resolve(t.roomClients[e]);var r=new WebSocket("wss://super.roomservice.dev/ws");return Promise.resolve(function(e,t,r,n,i){try{return Promise.resolve(function(e,t,r){try{var n=function(r){return i?r:Promise.resolve(fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({resources:[{object:"document",reference:"default",permission:"read_write",room:t},{object:"room",reference:t,permission:"join"}]})})).then((function(e){if(401===e.status)throw new Error("The Auth Webhook returned unauthorized.");if(200!==e.status)throw new Error("The Auth Webhook returned a status code other than 200.");return Promise.resolve(e.json()).then((function(e){var t=e.resources,r=e.token,n=e.user;if(!t||!r||!n){if("Unauthorized"===e.body)throw new Error("The Auth Webhook unexpectedly return unauthorized. You may be using an invalid API key.");throw new Error("The Auth Webhook has an incorrectly formatted JSON response.")}return{token:r,guestReference:n,docID:t.find((function(e){return"document"===e.object})).id,roomID:t.find((function(e){return"room"===e.object})).id}}))}))},i=!1,s=function(){if("function"==typeof e)return Promise.resolve(e(t)).then((function(e){if(!e.user)throw new Error("The auth function must return a 'user' key.");var t=e.resources.find((function(e){return"document"===e.object})).id,r=e.resources.find((function(e){return"room"===e.object})).id;return i=!0,{token:e.token,guestReference:e.user,docID:t,roomID:r}}))}();return Promise.resolve(s&&s.then?s.then(n):n(s))}catch(e){return Promise.reject(e)}}(r,n)).then((function(t){return Promise.resolve(function(e,t,r){try{return Promise.resolve(fetch("https://super.roomservice.dev/docs/"+r,{headers:{Authorization:"Bearer: "+t}})).then((function(e){return Promise.resolve(e.json())}))}catch(e){return Promise.reject(e)}}(0,t.token,t.docID)).then((function(r){var n=new y({conn:e,actor:t.guestReference,checkpoint:r.body,token:t.token,roomID:t.roomID});return Promise.resolve(n.reconnect()).then((function(){return n}))}))}))}catch(e){return Promise.reject(e)}}(r,0,t.auth,e)).then((function(r){return t.roomClients[e]=r,r}))}catch(e){return Promise.reject(e)}},e}();exports.RoomClient=y,exports.RoomService=w,exports.default=w; | ||
//# sourceMappingURL=browser.cjs.production.min.js.map |
@@ -1060,7 +1060,14 @@ import invariant from 'tiny-invariant'; | ||
var WEBSOCKET_TIMEOUT = 1000 * 2; | ||
var MAP_CMDS = ['mcreate', 'mput', 'mputref', 'mdel']; | ||
var LIST_CMDS = ['lcreate', 'lins', 'linsref', 'lput', 'lputref', 'ldel']; | ||
var RoomClient = /*#__PURE__*/function () { | ||
function RoomClient(params) { | ||
var _this = this; | ||
this.listClients = {}; | ||
this.mapClients = {}; | ||
this.expires = {}; | ||
this.mapCallbacksByObjID = {}; | ||
this.listCallbacksByObjID = {}; | ||
this.presenceCallbacksByKey = {}; | ||
this.ws = new SuperlumeWebSocket(params.conn); | ||
@@ -1072,4 +1079,51 @@ this.token = params.token; | ||
this.checkpoint = params.checkpoint; | ||
this.vs = this.checkpoint.vs; | ||
this.InnerPresenceClient = undefined; | ||
this.ws.bind('doc:fwd', function (body) { | ||
if (body.room !== _this.roomID) return; | ||
if (!body.args || body.args.length < 3) { | ||
// Potentially a network failure, we don't want to crash, | ||
// but do want to warn people | ||
console.error('Unexpected command: ', body.args); | ||
return; | ||
} // Ignore version stamps older than checkpoint | ||
if (isOlderVS(body.vs, _this.checkpoint.vs)) return; // Ignore validated commands | ||
if (body.from === _this.actor) return; | ||
var _ref = [body.args[0], body.args[1], body.args[2]], | ||
cmd = _ref[0], | ||
docID = _ref[1], | ||
objID = _ref[2]; | ||
if (docID !== _this.docID) return; | ||
if (MAP_CMDS.includes(cmd)) { | ||
_this.dispatchMapCmd(objID, body); | ||
} else if (LIST_CMDS.includes(cmd)) { | ||
_this.dispatchListCmd(objID, body); | ||
} else { | ||
console.warn("Unhandled Room Service doc:fwd command: " + cmd + ". Consider updating the Room Service client."); | ||
} | ||
}); | ||
this.ws.bind('presence:fwd', function (body) { | ||
_this.dispatchPresenceCmd(body); | ||
}); | ||
this.ws.bind('room:rm_guest', function (body) { | ||
if (body.room !== _this.roomID) return; | ||
var client = _this.presence(); | ||
var newClient = client.dangerouslyUpdateClientDirectly('room:rm_guest', body); | ||
for (var _i = 0, _Object$entries = Object.entries(_this.presenceCallbacksByKey); _i < _Object$entries.length; _i++) { | ||
var _Object$entries$_i = _Object$entries[_i], | ||
cbs = _Object$entries$_i[1]; | ||
for (var _iterator = _createForOfIteratorHelperLoose(cbs), _step; !(_step = _iterator()).done;) { | ||
var cb = _step.value; | ||
cb(newClient, body.guest); | ||
} | ||
} | ||
}); | ||
} | ||
@@ -1079,5 +1133,83 @@ | ||
_proto.dispatchMapCmd = function dispatchMapCmd(objID, body) { | ||
if (!this.mapClients[objID]) { | ||
var m = new InnerMapClient(this.checkpoint.maps[objID] || {}, this.roomID, this.docID, objID, this.ws); | ||
this.mapClients[objID] = m; | ||
} | ||
var client = this.mapClients[objID]; | ||
var updatedClient = client.dangerouslyUpdateClientDirectly(body.args); | ||
for (var _iterator2 = _createForOfIteratorHelperLoose(this.mapCallbacksByObjID[objID] || []), _step2; !(_step2 = _iterator2()).done;) { | ||
var cb = _step2.value; | ||
cb(updatedClient, body.from); | ||
} | ||
}; | ||
_proto.dispatchListCmd = function dispatchListCmd(objID, body) { | ||
if (!this.listClients[objID]) { | ||
var l = new InnerListClient(this.checkpoint, this.roomID, this.docID, objID, this.ws, this.actor); | ||
this.listClients[objID] = l; | ||
} | ||
var client = this.listClients[objID]; | ||
var updatedClient = client.dangerouslyUpdateClientDirectly(body.args); | ||
for (var _iterator3 = _createForOfIteratorHelperLoose(this.listCallbacksByObjID[objID] || []), _step3; !(_step3 = _iterator3()).done;) { | ||
var cb = _step3.value; | ||
cb(updatedClient, body.from); | ||
} | ||
}; | ||
_proto.dispatchPresenceCmd = function dispatchPresenceCmd(body) { | ||
var _this2 = this; | ||
if (body.room !== this.roomID) return; | ||
if (body.from === this.actor) return; | ||
var client = this.presence(); | ||
var key = body.key; | ||
var now = new Date().getTime() / 1000; | ||
var secondsTillTimeout = body.expAt - now; | ||
if (secondsTillTimeout < 0) { | ||
// don't show expired stuff | ||
return; | ||
} // Expire stuff if it's within a reasonable range (12h) | ||
if (secondsTillTimeout < 60 * 60 * 12) { | ||
if (this.expires[key]) { | ||
clearTimeout(this.expires[key]); | ||
} | ||
var timeout = setTimeout(function () { | ||
var newClient = client.dangerouslyUpdateClientDirectly('presence:expire', { | ||
key: body.key | ||
}); | ||
if (!newClient) return; | ||
for (var _iterator4 = _createForOfIteratorHelperLoose((_this2$presenceCallba = _this2.presenceCallbacksByKey[key]) !== null && _this2$presenceCallba !== void 0 ? _this2$presenceCallba : []), _step4; !(_step4 = _iterator4()).done;) { | ||
var _this2$presenceCallba; | ||
var cb = _step4.value; | ||
cb(newClient, body.from); | ||
} | ||
}, secondsTillTimeout * 1000); | ||
this.expires[key] = timeout; | ||
} | ||
var newClient = client.dangerouslyUpdateClientDirectly('presence:fwd', body); | ||
if (!newClient) return; | ||
for (var _iterator5 = _createForOfIteratorHelperLoose((_this$presenceCallbac = this.presenceCallbacksByKey[key]) !== null && _this$presenceCallbac !== void 0 ? _this$presenceCallbac : []), _step5; !(_step5 = _iterator5()).done;) { | ||
var _this$presenceCallbac; | ||
var cb = _step5.value; | ||
cb(newClient, body.from); | ||
} | ||
}; | ||
_proto.once = function once(msg) { | ||
try { | ||
var _this2 = this; | ||
var _this4 = this; | ||
@@ -1090,7 +1222,7 @@ var off; | ||
}), new Promise(function (resolve) { | ||
off = _this2.ws.bind(msg, function (body) { | ||
off = _this4.ws.bind(msg, function (body) { | ||
resolve(body); | ||
}); | ||
})]).then(function () { | ||
if (off) _this2.ws.unbind(msg, off); | ||
if (off) _this4.ws.unbind(msg, off); | ||
}); | ||
@@ -1108,6 +1240,6 @@ } catch (e) { | ||
try { | ||
var _this4 = this; | ||
var _this6 = this; | ||
if (!_this4.errorListener) { | ||
_this4.errorListener = _this4.ws.bind('error', function (err) { | ||
if (!_this6.errorListener) { | ||
_this6.errorListener = _this6.ws.bind('error', function (err) { | ||
console.error('Room Service encountered a server-side error. If you see this, please let us know; this could be a bug.', err); | ||
@@ -1117,10 +1249,10 @@ }); | ||
var authenticated = _this4.once('guest:authenticated'); | ||
var authenticated = _this6.once('guest:authenticated'); | ||
_this4.ws.send('guest:authenticate', _this4.token); | ||
_this6.ws.send('guest:authenticate', _this6.token); | ||
return Promise.resolve(authenticated).then(function () { | ||
var joined = _this4.once('room:joined'); | ||
var joined = _this6.once('room:joined'); | ||
_this4.ws.send('room:join', _this4.roomID); | ||
_this6.ws.send('room:join', _this6.roomID); | ||
@@ -1193,36 +1325,31 @@ return Promise.resolve(joined).then(function () {}); | ||
_proto.subscribe = function subscribe(obj, onChangeFnOrString, onChangeFn) { | ||
var _this5 = this; | ||
// Presence handler | ||
if (typeof onChangeFnOrString === 'string') { | ||
return this.subscribePresence(obj, onChangeFnOrString, onChangeFn); | ||
} // Map and list handler | ||
} // create new closure so fns can be subscribed/unsubscribed multiple times | ||
var bound = this.ws.bind('doc:fwd', function (body) { | ||
if (body.room !== _this5.roomID) return; | ||
var cb = function cb(obj, from) { | ||
onChangeFnOrString(obj, from); | ||
}; | ||
if (!body.args || body.args.length < 3) { | ||
// Potentially a network failure, we don't want to crash, | ||
// but do want to warn people | ||
console.error('Unexpected command: ', body.args); | ||
return; | ||
} // Ignore out of order version stamps | ||
var objID; | ||
if (obj instanceof InnerMapClient) { | ||
var client = obj; | ||
objID = client.id; | ||
this.mapCallbacksByObjID[objID] = this.mapCallbacksByObjID[objID] || []; | ||
this.mapCallbacksByObjID[objID].push(cb); | ||
} | ||
if (isOlderVS(body.vs, _this5.vs)) return; // Ignore validated commands | ||
if (obj instanceof InnerListClient) { | ||
var _client = obj; | ||
objID = _client.id; | ||
this.listCallbacksByObjID[objID] = this.listCallbacksByObjID[objID] || []; | ||
this.listCallbacksByObjID[objID].push(cb); | ||
} | ||
if (body.from === _this5.actor) return; | ||
var _ref = [body.args[1], body.args[2]], | ||
docID = _ref[0], | ||
objID = _ref[1]; | ||
if (docID !== _this5.docID) return; | ||
if (objID !== obj.id) return; | ||
_this5.vs = body.vs; | ||
var newObj = obj.dangerouslyUpdateClientDirectly(body.args); | ||
onChangeFnOrString(newObj, body.from); | ||
}); | ||
return [{ | ||
event: 'doc:fwd', | ||
fn: bound | ||
objID: objID, | ||
fn: cb | ||
}]; | ||
@@ -1232,52 +1359,15 @@ }; | ||
_proto.subscribePresence = function subscribePresence(obj, key, onChangeFn) { | ||
var _this6 = this; | ||
!obj ? process.env.NODE_ENV !== "production" ? invariant(false, 'subscribe() expects the first argument to not be undefined.') : invariant(false) : void 0; // create new closure so fns can be subscribed/unsubscribed multiple times | ||
!obj ? process.env.NODE_ENV !== "production" ? invariant(false, 'subscribe() expects the first argument to not be undefined.') : invariant(false) : void 0; | ||
var fwdListener = this.ws.bind('presence:fwd', function (body) { | ||
if (body.room !== _this6.roomID) return; | ||
if (body.key !== key) return; | ||
if (body.from === _this6.actor) return; | ||
var now = new Date().getTime() / 1000; | ||
var secondsTillTimeout = body.expAt - now; | ||
if (secondsTillTimeout < 0) { | ||
// don't show expired stuff | ||
return; | ||
} // Expire stuff if it's within a reasonable range (12h) | ||
if (secondsTillTimeout < 60 * 60 * 12) { | ||
if (_this6.expires[key]) { | ||
clearTimeout(_this6.expires[key]); | ||
} | ||
var timeout = setTimeout(function () { | ||
var newObj = obj.dangerouslyUpdateClientDirectly('presence:expire', { | ||
key: body.key | ||
}); | ||
if (!newObj) return; | ||
!onChangeFn ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0; | ||
onChangeFn(newObj, body.from); | ||
}, secondsTillTimeout * 1000); | ||
_this6.expires[key] = timeout; | ||
var cb = function cb(obj, from) { | ||
if (onChangeFn) { | ||
onChangeFn(obj, from); | ||
} | ||
}; | ||
var newObj = obj.dangerouslyUpdateClientDirectly('presence:fwd', body); | ||
if (!newObj) return; | ||
!onChangeFn ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0; | ||
onChangeFn(newObj, body.from); | ||
}); | ||
var leaveListener = this.ws.bind('room:rm_guest', function (body) { | ||
if (body.room !== _this6.roomID) return; | ||
var newObj = obj.dangerouslyUpdateClientDirectly('room:rm_guest', body); | ||
if (!newObj) return; | ||
!onChangeFn ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0; | ||
onChangeFn(newObj, body.guest); | ||
}); | ||
this.presenceCallbacksByKey[key] = this.presenceCallbacksByKey[key] || []; | ||
this.presenceCallbacksByKey[key].push(cb); | ||
return [{ | ||
event: 'presence:fwd', | ||
fn: fwdListener | ||
}, { | ||
event: 'room:rm_guest', | ||
fn: leaveListener | ||
objID: key, | ||
fn: cb | ||
}]; | ||
@@ -1287,5 +1377,14 @@ }; | ||
_proto.unsubscribe = function unsubscribe(listeners) { | ||
for (var _iterator = _createForOfIteratorHelperLoose(listeners), _step; !(_step = _iterator()).done;) { | ||
var l = _step.value; | ||
this.ws.unbind(l.event, l.fn); | ||
for (var _iterator6 = _createForOfIteratorHelperLoose(listeners), _step6; !(_step6 = _iterator6()).done;) { | ||
var l = _step6.value; | ||
if (l.objID) { | ||
this.mapCallbacksByObjID[l.objID] = removeCallback(this.mapCallbacksByObjID[l.objID], l.fn); | ||
this.listCallbacksByObjID[l.objID] = removeCallback(this.listCallbacksByObjID[l.objID], l.fn); | ||
this.presenceCallbacksByKey[l.objID] = removeCallback(this.presenceCallbacksByKey[l.objID], l.fn); | ||
} | ||
if (l.event) { | ||
this.ws.unbind(l.event, l.fn); | ||
} | ||
} | ||
@@ -1304,2 +1403,12 @@ }; | ||
function removeCallback(cbs, rmCb) { | ||
if (!cbs) { | ||
return []; | ||
} | ||
return cbs.filter(function (existingCb) { | ||
return existingCb !== rmCb; | ||
}); | ||
} | ||
var RoomService = /*#__PURE__*/function () { | ||
@@ -1306,0 +1415,0 @@ function RoomService(params) { |
@@ -7,3 +7,4 @@ import { WebSocketLikeConnection, DocumentCheckpoint, AuthStrategy, Prop } from './types'; | ||
declare type Listener = { | ||
event: Prop<WebSocketServerMessage, 'type'>; | ||
event?: Prop<WebSocketServerMessage, 'type'>; | ||
objID?: string; | ||
fn: (args: any) => void; | ||
@@ -18,3 +19,2 @@ }; | ||
private ws; | ||
private vs; | ||
private token; | ||
@@ -37,2 +37,5 @@ private roomID; | ||
}); | ||
private dispatchMapCmd; | ||
private dispatchListCmd; | ||
private dispatchPresenceCmd; | ||
private once; | ||
@@ -47,2 +50,5 @@ /** | ||
presence(): PresenceClient; | ||
private mapCallbacksByObjID; | ||
private listCallbacksByObjID; | ||
private presenceCallbacksByKey; | ||
subscribe<T>(list: ListClient<T>, onChangeFn: (list: ListClient<T>) => any): ListenerBundle; | ||
@@ -49,0 +55,0 @@ subscribe<T>(list: ListClient<T>, onChangeFn: (list: ListClient<T>, from: string) => any): ListenerBundle; |
{ | ||
"version": "2.1.4", | ||
"version": "2.1.5-0", | ||
"license": "MIT", | ||
@@ -4,0 +4,0 @@ "main": "dist/index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
325423
2841
6
3
10