1/******/ (() => { // webpackBootstrap 2/******/ var __webpack_modules__ = ({ 3 4/***/ 2167: 5/***/ ((module) => { 6 7"use strict"; 8 9 10function _typeof(obj) { 11 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { 12 _typeof = function (obj) { 13 return typeof obj; 14 }; 15 } else { 16 _typeof = function (obj) { 17 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 18 }; 19 } 20 21 return _typeof(obj); 22} 23 24function _classCallCheck(instance, Constructor) { 25 if (!(instance instanceof Constructor)) { 26 throw new TypeError("Cannot call a class as a function"); 27 } 28} 29 30function _defineProperties(target, props) { 31 for (var i = 0; i < props.length; i++) { 32 var descriptor = props[i]; 33 descriptor.enumerable = descriptor.enumerable || false; 34 descriptor.configurable = true; 35 if ("value" in descriptor) descriptor.writable = true; 36 Object.defineProperty(target, descriptor.key, descriptor); 37 } 38} 39 40function _createClass(Constructor, protoProps, staticProps) { 41 if (protoProps) _defineProperties(Constructor.prototype, protoProps); 42 if (staticProps) _defineProperties(Constructor, staticProps); 43 return Constructor; 44} 45 46/** 47 * Given an instance of EquivalentKeyMap, returns its internal value pair tuple 48 * for a key, if one exists. The tuple members consist of the last reference 49 * value for the key (used in efficient subsequent lookups) and the value 50 * assigned for the key at the leaf node. 51 * 52 * @param {EquivalentKeyMap} instance EquivalentKeyMap instance. 53 * @param {*} key The key for which to return value pair. 54 * 55 * @return {?Array} Value pair, if exists. 56 */ 57function getValuePair(instance, key) { 58 var _map = instance._map, 59 _arrayTreeMap = instance._arrayTreeMap, 60 _objectTreeMap = instance._objectTreeMap; // Map keeps a reference to the last object-like key used to set the 61 // value, which can be used to shortcut immediately to the value. 62 63 if (_map.has(key)) { 64 return _map.get(key); 65 } // Sort keys to ensure stable retrieval from tree. 66 67 68 var properties = Object.keys(key).sort(); // Tree by type to avoid conflicts on numeric object keys, empty value. 69 70 var map = Array.isArray(key) ? _arrayTreeMap : _objectTreeMap; 71 72 for (var i = 0; i < properties.length; i++) { 73 var property = properties[i]; 74 map = map.get(property); 75 76 if (map === undefined) { 77 return; 78 } 79 80 var propertyValue = key[property]; 81 map = map.get(propertyValue); 82 83 if (map === undefined) { 84 return; 85 } 86 } 87 88 var valuePair = map.get('_ekm_value'); 89 90 if (!valuePair) { 91 return; 92 } // If reached, it implies that an object-like key was set with another 93 // reference, so delete the reference and replace with the current. 94 95 96 _map.delete(valuePair[0]); 97 98 valuePair[0] = key; 99 map.set('_ekm_value', valuePair); 100 101 _map.set(key, valuePair); 102 103 return valuePair; 104} 105/** 106 * Variant of a Map object which enables lookup by equivalent (deeply equal) 107 * object and array keys. 108 */ 109 110 111var EquivalentKeyMap = 112/*#__PURE__*/ 113function () { 114 /** 115 * Constructs a new instance of EquivalentKeyMap. 116 * 117 * @param {Iterable.<*>} iterable Initial pair of key, value for map. 118 */ 119 function EquivalentKeyMap(iterable) { 120 _classCallCheck(this, EquivalentKeyMap); 121 122 this.clear(); 123 124 if (iterable instanceof EquivalentKeyMap) { 125 // Map#forEach is only means of iterating with support for IE11. 126 var iterablePairs = []; 127 iterable.forEach(function (value, key) { 128 iterablePairs.push([key, value]); 129 }); 130 iterable = iterablePairs; 131 } 132 133 if (iterable != null) { 134 for (var i = 0; i < iterable.length; i++) { 135 this.set(iterable[i][0], iterable[i][1]); 136 } 137 } 138 } 139 /** 140 * Accessor property returning the number of elements. 141 * 142 * @return {number} Number of elements. 143 */ 144 145 146 _createClass(EquivalentKeyMap, [{ 147 key: "set", 148 149 /** 150 * Add or update an element with a specified key and value. 151 * 152 * @param {*} key The key of the element to add. 153 * @param {*} value The value of the element to add. 154 * 155 * @return {EquivalentKeyMap} Map instance. 156 */ 157 value: function set(key, value) { 158 // Shortcut non-object-like to set on internal Map.
159 if (key === null || _typeof(key) !== 'object') { 160 this._map.set(key, value); 161 162 return this; 163 } // Sort keys to ensure stable assignment into tree. 164 165 166 var properties = Object.keys(key).sort(); 167 var valuePair = [key, value]; // Tree by type to avoid conflicts on numeric object keys, empty value. 168 169 var map = Array.isArray(key) ? this._arrayTreeMap : this._objectTreeMap; 170 171 for (var i = 0; i < properties.length; i++) { 172 var property = properties[i]; 173 174 if (!map.has(property)) { 175 map.set(property, new EquivalentKeyMap()); 176 } 177 178 map = map.get(property); 179 var propertyValue = key[property]; 180 181 if (!map.has(propertyValue)) { 182 map.set(propertyValue, new EquivalentKeyMap()); 183 } 184 185 map = map.get(propertyValue); 186 } // If an _ekm_value exists, there was already an equivalent key. Before 187 // overriding, ensure that the old key reference is removed from map to 188 // avoid memory leak of accumulating equivalent keys. This is, in a 189 // sense, a poor man's WeakMap, while still enabling iterability. 190 191 192 var previousValuePair = map.get('_ekm_value'); 193 194 if (previousValuePair) { 195 this._map.delete(previousValuePair[0]); 196 } 197 198 map.set('_ekm_value', valuePair); 199 200 this._map.set(key, valuePair); 201 202 return this; 203 } 204 /** 205 * Returns a specified element. 206 * 207 * @param {*} key The key of the element to return. 208 * 209 * @return {?*} The element associated with the specified key or undefined 210 * if the key can't be found. 211 */ 212 213 }, { 214 key: "get", 215 value: function get(key) { 216 // Shortcut non-object-like to get from internal Map. 217 if (key === null || _typeof(key) !== 'object') { 218 return this._map.get(key); 219 } 220 221 var valuePair = getValuePair(this, key); 222 223 if (valuePair) { 224 return valuePair[1]; 225 } 226 } 227 /** 228 * Returns a boolean indicating whether an element with the specified key 229 * exists or not. 230 * 231 * @param {*} key The key of the element to test for presence. 232 * 233 * @return {boolean} Whether an element with the specified key exists. 234 */ 235 236 }, { 237 key: "has", 238 value: function has(key) { 239 if (key === null || _typeof(key) !== 'object') { 240 return this._map.has(key); 241 } // Test on the _presence_ of the pair, not its value, as even undefined 242 // can be a valid member value for a key. 243 244 245 return getValuePair(this, key) !== undefined; 246 } 247 /** 248 * Removes the specified element. 249 * 250 * @param {*} key The key of the element to remove. 251 * 252 * @return {boolean} Returns true if an element existed and has been 253 * removed, or false if the element does not exist. 254 */ 255 256 }, { 257 key: "delete", 258 value: function _delete(key) { 259 if (!this.has(key)) { 260 return false; 261 } // This naive implementation will leave orphaned child trees. A better 262 // implementation should traverse and remove orphans. 263 264 265 this.set(key, undefined); 266 return true; 267 } 268 /** 269 * Executes a provided function once per each key/value pair, in insertion 270 * order. 271 * 272 * @param {Function} callback Function to execute for each element. 273 * @param {*} thisArg Value to use as `this` when executing 274 * `callback`. 275 */ 276 277 }, { 278 key: "forEach", 279 value: function forEach(callback) { 280 var _this = this; 281 282 var thisArg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this; 283 284 this._map.forEach(function (value, key) { 285 // Unwrap value from object-like value pair. 286 if (key !== null && _typeof(key) === 'object') { 287 value = value[1]; 288 } 289 290 callback.call(thisArg, value, key, _this); 291 }); 292 } 293 /** 294 * Removes all elements. 295 */ 296 297 }, { 298 key: "clear", 299 value: function clear() { 300 this._map = new Map(); 301 this._arrayTreeMap = new Map(); 302 this._objectTreeMap = new Map(); 303 } 304 }, { 305 key: "size", 306 get: function get() { 307 return this._map.size; 308 } 309 }]); 310 311 return EquivalentKeyMap; 312}(); 313 314module.exports = EquivalentKeyMap; 315 316 317/***/ }), 318 319/***/ 5619: 320/***/ ((module) => { 321 322"use strict"; 323 324 325// do not edit .js files directly - edit src/index.jst 326 327 328 var envHasBigInt64Array = typeof BigInt64Array !== 'undefined'; 329 330 331module.exports = function equal(a, b) { 332 if (a === b) return true; 333 334 if (a && b && typeof a == 'object' && typeof b == 'object') { 335 if (a.constructor !== b.constructor) return false;
336 337 var length, i, keys; 338 if (Array.isArray(a)) { 339 length = a.length; 340 if (length != b.length) return false; 341 for (i = length; i-- !== 0;) 342 if (!equal(a[i], b[i])) return false; 343 return true; 344 } 345 346 347 if ((a instanceof Map) && (b instanceof Map)) { 348 if (a.size !== b.size) return false; 349 for (i of a.entries()) 350 if (!b.has(i[0])) return false; 351 for (i of a.entries()) 352 if (!equal(i[1], b.get(i[0]))) return false; 353 return true; 354 } 355 356 if ((a instanceof Set) && (b instanceof Set)) { 357 if (a.size !== b.size) return false; 358 for (i of a.entries()) 359 if (!b.has(i[0])) return false; 360 return true; 361 } 362 363 if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) { 364 length = a.length; 365 if (length != b.length) return false; 366 for (i = length; i-- !== 0;) 367 if (a[i] !== b[i]) return false; 368 return true; 369 } 370 371 372 if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags; 373 if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf(); 374 if (a.toString !== Object.prototype.toString) return a.toString() === b.toString(); 375 376 keys = Object.keys(a); 377 length = keys.length; 378 if (length !== Object.keys(b).length) return false; 379 380 for (i = length; i-- !== 0;) 381 if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false; 382 383 for (i = length; i-- !== 0;) { 384 var key = keys[i]; 385 386 if (!equal(a[key], b[key])) return false; 387 } 388 389 return true; 390 } 391 392 // true if both NaN, false otherwise 393 return a!==a && b!==b; 394}; 395 396 397/***/ }), 398 399/***/ 2248: 400/***/ ((module, __unused_webpack_exports, __webpack_require__) => { 401 402(function(e){if(true)module.exports=e();else { var t; }})(function(){var t=Math.floor,n=Math.abs,r=Math.pow;return function(){function d(s,e,n){function t(o,i){if(!e[o]){if(!s[o]){var l=undefined;if(!i&&l)return require(o,!0);if(r)return r(o,!0);var c=new Error("Cannot find module '"+o+"'");throw c.code="MODULE_NOT_FOUND",c}var a=e[o]={exports:{}};s[o][0].call(a.exports,function(e){var r=s[o][1][e];return t(r||e)},a,a.exports,d,s,e,n)}return e[o].exports}for(var r=undefined,a=0;a<n.length;a++)t(n[a]);return t}return d}()({1:[function(e,t,n){'use strict';function r(e){var t=e.length;if(0<t%4)throw new Error("Invalid string. Length must be a multiple of 4");var n=e.indexOf("=");-1===n&&(n=t);var r=n===t?0:4-n%4;return[n,r]}function a(e,t,n){return 3*(t+n)/4-n}function o(e){var t,n,o=r(e),d=o[0],s=o[1],l=new p(a(e,d,s)),c=0,f=0<s?d-4:d;for(n=0;n<f;n+=4)t=u[e.charCodeAt(n)]<<18|u[e.charCodeAt(n+1)]<<12|u[e.charCodeAt(n+2)]<<6|u[e.charCodeAt(n+3)],l[c++]=255&t>>16,l[c++]=255&t>>8,l[c++]=255&t;return 2===s&&(t=u[e.charCodeAt(n)]<<2|u[e.charCodeAt(n+1)]>>4,l[c++]=255&t),1===s&&(t=u[e.charCodeAt(n)]<<10|u[e.charCodeAt(n+1)]<<4|u[e.charCodeAt(n+2)]>>2,l[c++]=255&t>>8,l[c++]=255&t),l}function d(e){return c[63&e>>18]+c[63&e>>12]+c[63&e>>6]+c[63&e]}function s(e,t,n){for(var r,a=[],o=t;o<n;o+=3)r=(16711680&e[o]<<16)+(65280&e[o+1]<<8)+(255&e[o+2]),a.push(d(r));return a.join("")}function l(e){for(var t,n=e.length,r=n%3,a=[],o=16383,d=0,l=n-r;d<l;d+=o)a.push(s(e,d,d+o>l?l:d+o));return 1===r?(t=e[n-1],a.push(c[t>>2]+c[63&t<<4]+"==")):2===r&&(t=(e[n-2]<<8)+e[n-1],a.push(c[t>>10]+c[63&t>>4]+c[63&t<<2]+"=")),a.join("")}n.byteLength=function(e){var t=r(e),n=t[0],a=t[1];return 3*(n+a)/4-a},n.toByteArray=o,n.fromByteArray=l;for(var c=[],u=[],p="undefined"==typeof Uint8Array?Array:Uint8Array,f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",g=0,_=f.length;g<_;++g)c[g]=f[g],u[f.charCodeAt(g)]=g;u[45]=62,u[95]=63},{}],2:[function(){},{}],3:[function(e,t,n){(function(){(function(){/*! 403 * The buffer module from node.js, for the browser. 404 * 405 * @author Feross Aboukhadijeh <https://feross.org> 406 * @license MIT 407 */'use strict';var t=String.fromCharCode,o=Math.min;function d(e){if(2147483647<e)throw new RangeError("The value \""+e+"\" is invalid for option \"size\"");var t=new Uint8Array(e);return t.__proto__=s.prototype,t}function s(e,t,n){if("number"==typeof e){if("string"==typeof t)throw new TypeError("The \"string\" argument must be of type string. Received type number");return p(e)}return l(e,t,n)}function l(e,t,n){if("string"==typeof e)return f(e,t);if(ArrayBuffer.isView(e))return g(e);if(null==e)throw TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e);if(K(e,ArrayBuffer)||e&&K(e.buffer,ArrayBuffer))return _(e,t,n);if("number"==typeof e)throw new TypeError("The \"value\" argument must not be of type number. Received type number");var r=e.valueOf&&e.valueOf();if(null!=r&&r!==e)return s.from(r,t,n);var a=h(e);if(a)return a;
407if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof e[Symbol.toPrimitive])return s.from(e[Symbol.toPrimitive]("string"),t,n);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e)}function c(e){if("number"!=typeof e)throw new TypeError("\"size\" argument must be of type number");else if(0>e)throw new RangeError("The value \""+e+"\" is invalid for option \"size\"")}function u(e,t,n){return c(e),0>=e?d(e):void 0===t?d(e):"string"==typeof n?d(e).fill(t,n):d(e).fill(t)}function p(e){return c(e),d(0>e?0:0|m(e))}function f(e,t){if(("string"!=typeof t||""===t)&&(t="utf8"),!s.isEncoding(t))throw new TypeError("Unknown encoding: "+t);var n=0|b(e,t),r=d(n),a=r.write(e,t);return a!==n&&(r=r.slice(0,a)),r}function g(e){for(var t=0>e.length?0:0|m(e.length),n=d(t),r=0;r<t;r+=1)n[r]=255&e[r];return n}function _(e,t,n){if(0>t||e.byteLength<t)throw new RangeError("\"offset\" is outside of buffer bounds");if(e.byteLength<t+(n||0))throw new RangeError("\"length\" is outside of buffer bounds");var r;return r=void 0===t&&void 0===n?new Uint8Array(e):void 0===n?new Uint8Array(e,t):new Uint8Array(e,t,n),r.__proto__=s.prototype,r}function h(e){if(s.isBuffer(e)){var t=0|m(e.length),n=d(t);return 0===n.length?n:(e.copy(n,0,0,t),n)}return void 0===e.length?"Buffer"===e.type&&Array.isArray(e.data)?g(e.data):void 0:"number"!=typeof e.length||X(e.length)?d(0):g(e)}function m(e){if(e>=2147483647)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+2147483647 .toString(16)+" bytes");return 0|e}function b(e,t){if(s.isBuffer(e))return e.length;if(ArrayBuffer.isView(e)||K(e,ArrayBuffer))return e.byteLength;if("string"!=typeof e)throw new TypeError("The \"string\" argument must be one of type string, Buffer, or ArrayBuffer. Received type "+typeof e);var n=e.length,r=2<arguments.length&&!0===arguments[2];if(!r&&0===n)return 0;for(var a=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":return H(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return z(e).length;default:if(a)return r?-1:H(e).length;t=(""+t).toLowerCase(),a=!0;}}function y(e,t,n){var r=!1;if((void 0===t||0>t)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),0>=n)return"";if(n>>>=0,t>>>=0,n<=t)return"";for(e||(e="utf8");;)switch(e){case"hex":return P(this,t,n);case"utf8":case"utf-8":return x(this,t,n);case"ascii":return D(this,t,n);case"latin1":case"binary":return I(this,t,n);case"base64":return A(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return M(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0;}}function C(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function R(e,t,n,r,a){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):2147483647<n?n=2147483647:-2147483648>n&&(n=-2147483648),n=+n,X(n)&&(n=a?0:e.length-1),0>n&&(n=e.length+n),n>=e.length){if(a)return-1;n=e.length-1}else if(0>n)if(a)n=0;else return-1;if("string"==typeof t&&(t=s.from(t,r)),s.isBuffer(t))return 0===t.length?-1:E(e,t,n,r,a);if("number"==typeof t)return t&=255,"function"==typeof Uint8Array.prototype.indexOf?a?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):E(e,[t],n,r,a);throw new TypeError("val must be string, number or Buffer")}function E(e,t,n,r,a){function o(e,t){return 1===d?e[t]:e.readUInt16BE(t*d)}var d=1,s=e.length,l=t.length;if(void 0!==r&&(r=(r+"").toLowerCase(),"ucs2"===r||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(2>e.length||2>t.length)return-1;d=2,s/=2,l/=2,n/=2}var c;if(a){var u=-1;for(c=n;c<s;c++)if(o(e,c)!==o(t,-1===u?0:c-u))-1!==u&&(c-=c-u),u=-1;else if(-1===u&&(u=c),c-u+1===l)return u*d}else for(n+l>s&&(n=s-l),c=n;0<=c;c--){for(var p=!0,f=0;f<l;f++)if(o(e,c+f)!==o(t,f)){p=!1;break}if(p)return c}return-1}function w(e,t,n,r){n=+n||0;var a=e.length-n;r?(r=+r,r>a&&(r=a)):r=a;var o=t.length;r>o/2&&(r=o/2);for(var d,s=0;s<r;++s){if(d=parseInt(t.substr(2*s,2),16),X(d))return s;e[n+s]=d}return s}function S(e,t,n,r){return G(H(t,e.length-n),e,n,r)}
407function T(e,t,n,r){return G(Y(t),e,n,r)}function v(e,t,n,r){return T(e,t,n,r)}function k(e,t,n,r){return G(z(t),e,n,r)}function L(e,t,n,r){return G(V(t,e.length-n),e,n,r)}function A(e,t,n){return 0===t&&n===e.length?$.fromByteArray(e):$.fromByteArray(e.slice(t,n))}function x(e,t,n){n=o(e.length,n);for(var r=[],a=t;a<n;){var d=e[a],s=null,l=239<d?4:223<d?3:191<d?2:1;if(a+l<=n){var c,u,p,f;1===l?128>d&&(s=d):2===l?(c=e[a+1],128==(192&c)&&(f=(31&d)<<6|63&c,127<f&&(s=f))):3===l?(c=e[a+1],u=e[a+2],128==(192&c)&&128==(192&u)&&(f=(15&d)<<12|(63&c)<<6|63&u,2047<f&&(55296>f||57343<f)&&(s=f))):4===l?(c=e[a+1],u=e[a+2],p=e[a+3],128==(192&c)&&128==(192&u)&&128==(192&p)&&(f=(15&d)<<18|(63&c)<<12|(63&u)<<6|63&p,65535<f&&1114112>f&&(s=f))):void 0}null===s?(s=65533,l=1):65535<s&&(s-=65536,r.push(55296|1023&s>>>10),s=56320|1023&s),r.push(s),a+=l}return N(r)}function N(e){var n=e.length;if(n<=4096)return t.apply(String,e);for(var r="",a=0;a<n;)r+=t.apply(String,e.slice(a,a+=4096));return r}function D(e,n,r){var a="";r=o(e.length,r);for(var d=n;d<r;++d)a+=t(127&e[d]);return a}function I(e,n,r){var a="";r=o(e.length,r);for(var d=n;d<r;++d)a+=t(e[d]);return a}function P(e,t,n){var r=e.length;(!t||0>t)&&(t=0),(!n||0>n||n>r)&&(n=r);for(var a="",o=t;o<n;++o)a+=W(e[o]);return a}function M(e,n,r){for(var a=e.slice(n,r),o="",d=0;d<a.length;d+=2)o+=t(a[d]+256*a[d+1]);return o}function O(e,t,n){if(0!=e%1||0>e)throw new RangeError("offset is not uint");if(e+t>n)throw new RangeError("Trying to access beyond buffer length")}function F(e,t,n,r,a,o){if(!s.isBuffer(e))throw new TypeError("\"buffer\" argument must be a Buffer instance");if(t>a||t<o)throw new RangeError("\"value\" argument is out of bounds");if(n+r>e.length)throw new RangeError("Index out of range")}function B(e,t,n,r){if(n+r>e.length)throw new RangeError("Index out of range");if(0>n)throw new RangeError("Index out of range")}function U(e,t,n,r,a){return t=+t,n>>>=0,a||B(e,t,n,4,34028234663852886e22,-34028234663852886e22),J.write(e,t,n,r,23,4),n+4}function j(e,t,n,r,a){return t=+t,n>>>=0,a||B(e,t,n,8,17976931348623157e292,-17976931348623157e292),J.write(e,t,n,r,52,8),n+8}function q(e){if(e=e.split("=")[0],e=e.trim().replace(Q,""),2>e.length)return"";for(;0!=e.length%4;)e+="=";return e}function W(e){return 16>e?"0"+e.toString(16):e.toString(16)}function H(e,t){t=t||1/0;for(var n,r=e.length,a=null,o=[],d=0;d<r;++d){if(n=e.charCodeAt(d),55295<n&&57344>n){if(!a){if(56319<n){-1<(t-=3)&&o.push(239,191,189);continue}else if(d+1===r){-1<(t-=3)&&o.push(239,191,189);continue}a=n;continue}if(56320>n){-1<(t-=3)&&o.push(239,191,189),a=n;continue}n=(a-55296<<10|n-56320)+65536}else a&&-1<(t-=3)&&o.push(239,191,189);if(a=null,128>n){if(0>(t-=1))break;o.push(n)}else if(2048>n){if(0>(t-=2))break;o.push(192|n>>6,128|63&n)}else if(65536>n){if(0>(t-=3))break;o.push(224|n>>12,128|63&n>>6,128|63&n)}else if(1114112>n){if(0>(t-=4))break;o.push(240|n>>18,128|63&n>>12,128|63&n>>6,128|63&n)}else throw new Error("Invalid code point")}return o}function Y(e){for(var t=[],n=0;n<e.length;++n)t.push(255&e.charCodeAt(n));return t}function V(e,t){for(var n,r,a,o=[],d=0;d<e.length&&!(0>(t-=2));++d)n=e.charCodeAt(d),r=n>>8,a=n%256,o.push(a),o.push(r);return o}function z(e){return $.toByteArray(q(e))}function G(e,t,n,r){for(var a=0;a<r&&!(a+n>=t.length||a>=e.length);++a)t[a+n]=e[a];return a}function K(e,t){return e instanceof t||null!=e&&null!=e.constructor&&null!=e.constructor.name&&e.constructor.name===t.name}function X(e){return e!==e}var $=e("base64-js"),J=e("ieee754");n.Buffer=s,n.SlowBuffer=function(e){return+e!=e&&(e=0),s.alloc(+e)},n.INSPECT_MAX_BYTES=50;n.kMaxLength=2147483647,s.TYPED_ARRAY_SUPPORT=function(){try{var e=new Uint8Array(1);return e.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42}},42===e.foo()}catch(t){return!1}}(),s.TYPED_ARRAY_SUPPORT||"undefined"==typeof console||"function"!=typeof console.error||console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support."),Object.defineProperty(s.prototype,"parent",{enumerable:!0,get:function(){return s.isBuffer(this)?this.buffer:void 0}}),Object.defineProperty(s.prototype,"offset",{enumerable:!0,get:function(){return s.isBuffer(this)?this.byteOffset:void 0}}),"undefined"!=typeof Symbol&&null!=Symbol.species&&s[Symbol.species]===s&&Object.defineProperty(s,Symbol.species,{value:null,configurable:!0,enumerable:!1,writable:!1}),s.poolSize=8192,s.from=function(e,t,n){return l(e,t,n)},s.prototype.__proto__=Uint8Array.prototype,s.__proto__=Uint8Array,s.alloc=function(e,t,n){return u(e,t,n)},s.allocUnsafe=function(e){return p(e)},s.allocUnsafeSlow=function(e){return p(e)},s.isBuffer=function(e){return null!=e&&!0===e._isBuffer&&e!==s.prototype},s.compare=function(e,t){if(K(e,Uint8Array)&&(e=s.from(e,e.offset,e.byteLength)),K(t,Uint8Array)&&(t=s.from(t,t.offset,t.byteLength)),!s.isBuffer(e)||!s.isBuffer(t))throw new TypeError("The \"buf1\", \"buf2\" arguments must be one of type Buffer or Uint8Array");if(e===t)return 0;for(var n=e.length,r=t.length,d=0,l=o(n,r);d<l;++d)if(e[d]!==t[d]){n=e[d],r=t[d];break}return n<r?-1:r<n?1:0},s.isEncoding=function(e){switch((e+"").toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"latin1":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return!0;default:return!1;}},s.concat=function(e,t){if(!Array.isArray(e))throw new TypeError("\"list\" argument must be an Array of Buffers");if(0===e.length)return s.alloc(0);var n;if(t===void 0)for(t=0,n=0;n<e.length;++n)t+=e[n].length;var r=s.allocUnsafe(t),a=0;for(n=0;n<e.length;++n){var o=e[n];if(K(o,Uint8Array)&&(o=s.from(o)),!s.isBuffer(o))throw new TypeError("\"list\" argument must be an Array of Buffers");o.copy(r,a),a+=o.length}return r},s.byteLength=b,s.prototype._isBuffer=!0,s.prototype.swap16=function(){var e=this.length;if(0!=e%2)throw new RangeError("Buffer size must be a multiple of 16-bits");for(var t=0;t<e;t+=2)C(this,t,t+1);return this},s.prototype.swap32=function(){var e=this.length;if(0!=e%4)throw new RangeError("Buffer size must be a multiple of 32-bits");for(var t=0;t<e;t+=4)C(this,t,t+3),C(this,t+1,t+2);return this},s.prototype.swap64=function(){var e=this.length;if(0!=e%8)throw new RangeError("Buffer size must be a multiple of 64-bits");for(var t=0;t<e;t+=8)C(this,t,t+7),C(this,t+1,t+6),C(this,t+2,t+5),C(this,t+3,t+4);return this},s.prototype.toString=function(){var e=this.length;return 0===e?"":0===arguments.length?x(this,0,e):y.apply(this,arguments)}
vendor: 8,406 bytes, line 407
407,s.prototype.toLocaleString=s.prototype.toString,s.prototype.equals=function(e){if(!s.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e||0===s.compare(this,e)},s.prototype.inspect=function(){var e="",t=n.INSPECT_MAX_BYTES;return e=this.toString("hex",0,t).replace(/(.{2})/g,"$1 ").trim(),this.length>t&&(e+=" ... "),"<Buffer "+e+">"},s.prototype.compare=function(e,t,n,r,a){if(K(e,Uint8Array)&&(e=s.from(e,e.offset,e.byteLength)),!s.isBuffer(e))throw new TypeError("The \"target\" argument must be one of type Buffer or Uint8Array. Received type "+typeof e);if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===a&&(a=this.length),0>t||n>e.length||0>r||a>this.length)throw new RangeError("out of range index");if(r>=a&&t>=n)return 0;if(r>=a)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,a>>>=0,this===e)return 0;for(var d=a-r,l=n-t,c=o(d,l),u=this.slice(r,a),p=e.slice(t,n),f=0;f<c;++f)if(u[f]!==p[f]){d=u[f],l=p[f];break}return d<l?-1:l<d?1:0},s.prototype.includes=function(e,t,n){return-1!==this.indexOf(e,t,n)},s.prototype.indexOf=function(e,t,n){return R(this,e,t,n,!0)},s.prototype.lastIndexOf=function(e,t,n){return R(this,e,t,n,!1)},s.prototype.write=function(e,t,n,r){if(void 0===t)r="utf8",n=this.length,t=0;else if(void 0===n&&"string"==typeof t)r=t,n=this.length,t=0;else if(isFinite(t))t>>>=0,isFinite(n)?(n>>>=0,void 0===r&&(r="utf8")):(r=n,n=void 0);else throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");var a=this.length-t;if((void 0===n||n>a)&&(n=a),0<e.length&&(0>n||0>t)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var o=!1;;)switch(r){case"hex":return w(this,e,t,n);case"utf8":case"utf-8":return S(this,e,t,n);case"ascii":return T(this,e,t,n);case"latin1":case"binary":return v(this,e,t,n);case"base64":return k(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return L(this,e,t,n);default:if(o)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),o=!0;}},s.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};s.prototype.slice=function(e,t){var n=this.length;e=~~e,t=t===void 0?n:~~t,0>e?(e+=n,0>e&&(e=0)):e>n&&(e=n),0>t?(t+=n,0>t&&(t=0)):t>n&&(t=n),t<e&&(t=e);var r=this.subarray(e,t);return r.__proto__=s.prototype,r},s.prototype.readUIntLE=function(e,t,n){e>>>=0,t>>>=0,n||O(e,t,this.length);for(var r=this[e],a=1,o=0;++o<t&&(a*=256);)r+=this[e+o]*a;return r},s.prototype.readUIntBE=function(e,t,n){e>>>=0,t>>>=0,n||O(e,t,this.length);for(var r=this[e+--t],a=1;0<t&&(a*=256);)r+=this[e+--t]*a;return r},s.prototype.readUInt8=function(e,t){return e>>>=0,t||O(e,1,this.length),this[e]},s.prototype.readUInt16LE=function(e,t){return e>>>=0,t||O(e,2,this.length),this[e]|this[e+1]<<8},s.prototype.readUInt16BE=function(e,t){return e>>>=0,t||O(e,2,this.length),this[e]<<8|this[e+1]},s.prototype.readUInt32LE=function(e,t){return e>>>=0,t||O(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},s.prototype.readUInt32BE=function(e,t){return e>>>=0,t||O(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},s.prototype.readIntLE=function(e,t,n){e>>>=0,t>>>=0,n||O(e,t,this.length);for(var a=this[e],o=1,d=0;++d<t&&(o*=256);)a+=this[e+d]*o;return o*=128,a>=o&&(a-=r(2,8*t)),a},s.prototype.readIntBE=function(e,t,n){e>>>=0,t>>>=0,n||O(e,t,this.length);for(var a=t,o=1,d=this[e+--a];0<a&&(o*=256);)d+=this[e+--a]*o;return o*=128,d>=o&&(d-=r(2,8*t)),d},s.prototype.readInt8=function(e,t){return e>>>=0,t||O(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},s.prototype.readInt16LE=function(e,t){e>>>=0,t||O(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},s.prototype.readInt16BE=function(e,t){e>>>=0,t||O(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},s.prototype.readInt32LE=function(e,t){return e>>>=0,t||O(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},s.prototype.readInt32BE=function(e,t){return e>>>=0,t||O(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},s.prototype.readFloatLE=function(e,t){return e>>>=0,t||O(e,4,this.length),J.read(this,e,!0,23,4)},s.prototype.readFloatBE=function(e,t){return e>>>=0,t||O(e,4,this.length),J.read(this,e,!1,23,4)},s.prototype.readDoubleLE=function(e,t){return e>>>=0,t||O(e,8,this.length),J.read(this,e,!0,52,8)},s.prototype.readDoubleBE=function(e,t){return e>>>=0,t||O(e,8,this.length),J.read(this,e,!1,52,8)},s.prototype.writeUIntLE=function(e,t,n,a){if(e=+e,t>>>=0,n>>>=0,!a){var o=r(2,8*n)-1;F(this,e,t,n,o,0)}var d=1,s=0;for(this[t]=255&e;++s<n&&(d*=256);)this[t+s]=255&e/d;return t+n},s.prototype.writeUIntBE=function(e,t,n,a){if(e=+e,t>>>=0,n>>>=0,!a){var o=r(2,8*n)-1;F(this,e,t,n,o,0)}var d=n-1,s=1;for(this[t+d]=255&e;0<=--d&&(s*=256);)this[t+d]=255&e/s;return t+n},s.prototype.writeUInt8=function(e,t,n){return e=+e,t>>>=0,n||F(this,e,t,1,255,0),this[t]=255&e,t+1},s.prototype.writeUInt16LE=function(e,t,n){return e=+e,t>>>=0,n||F(this,e,t,2,65535,0),this[t]=255&e,this[t+1]=e>>>8,t+2},s.prototype.writeUInt16BE=function(e,t,n){return e=+e,t>>>=0,n||F(this,e,t,2,65535,0),this[t]=e>>>8,this[t+1]=255&e,t+2},s.prototype.writeUInt32LE=function(e,t,n){return e=+e,t>>>=0,n||F(this,e,t,4,4294967295,0),this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e,t+4},s.prototype.writeUInt32BE=function(e,t,n){return e=+e,t>>>=0,n||F(this,e,t,4,4294967295,0),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},s.prototype.writeIntLE=function(e,t,n,a){if(e=+e,t>>>=0,!a){var o=r(2,8*n-1);F(this,e,t,n,o-1,-o)}var d=0,s=1,l=0;for(this[t]=255&e;++d<n&&(s*=256);)0>e&&0===l&&0!==this[t+d-1]&&(l=1),this[t+d]=255&(e/s>>0)-l;return t+n},s.prototype.writeIntBE=function(e,t,n,a){if(e=+e,t>>>=0,!a){var o=r(2,8*n-1);F(this,e,t,n,o-1,-o)}var d=n-1,s=1,l=0;for(this[t+d]=255&e;0<=--d&&(s*=256);)0>e&&0===l&&0!==this[t+d+1]&&(l=1),this[t+d]=255&(e/s>>0)-l;return t+n},s.prototype.writeInt8=function(e,t,n){return e=+e,t>>>=0,n||F(this,e,t,1,127,-128),0>e&&(e=255+e+1),this[t]=255&e,t+1},s.prototype.writeInt16LE=function(e,t,n){return e=+e,t>>>=0,n||F(this,e,t,2,32767,-32768),this[t]=255&e,this[t+1]=e>>>8,t+2},s.prototype.writeInt16BE=function(e,t,n){return e=+e,t>>>=0,n||F(this,e,t,2,32767,-32768),this[t]=e>>>8,this[t+1]=255&e,t+2},s.prototype.writeInt32LE=function(e,t,n){return e=+e,t>>>=0,n||F(this,e,t,4,2147483647,-2147483648),this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24,t+4},s.prototype.writeInt32BE=function(e,t,n){return e=+e,t>>>=0,n||F(this,e,t,4,2147483647,-2147483648),0>e&&(e=4294967295+e+1),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},s.prototype.writeFloatLE=function(e,t,n){return U(this,e,t,!0,n)},s.prototype.writeFloatBE=function(e,t,n){return U(this,e,t,!1,n)},s.prototype.writeDoubleLE=function(e,t,n){return j(this,e,t,!0,n)},s.prototype.writeDoubleBE=function(e,t,n){return j(this,e,t,!1,n)},s.prototype.copy=function(e,t,n,r){if(!s.isBuffer(e))throw new TypeError("argument should be a Buffer");if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),0<r&&r<n&&(r=n),r===n)return 0;if(0===e.length||0===this.length)return 0;if(0>t)throw new RangeError("targetStart out of bounds");if(0>n||n>=this.length)throw new RangeError("Index out of range");if(0>r)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t<r-n&&(r=e.length-t+n);var a=r-n;if(this===e&&"function"==typeof Uint8Array.prototype.copyWithin)this.copyWithin(t,n,r);else if(this===e&&n<t&&t<r)for(var o=a-1;0<=o;--o)e[o+t]=this[o+n];else Uint8Array.prototype.set.call(e,this.subarray(n,r),t);return a},s.prototype.fill=function(e,t,n,r){if("string"==typeof e){if("string"==typeof t?(r=t,t=0,n=this.length):"string"==typeof n&&(r=n,n=this.length),void 0!==r&&"string"!=typeof r)throw new TypeError("encoding must be a string");if("string"==typeof r&&!s.isEncoding(r))throw new TypeError("Unknown encoding: "+r);if(1===e.length){var a=e.charCodeAt(0);("utf8"===r&&128>a||"latin1"===r)&&(e=a)}}else"number"==typeof e&&(e&=255);if(0>t||this.length<t||this.length<n)throw new RangeError("Out of range index");if(n<=t)return this;t>>>=0,n=n===void 0?this.length:n>>>0,e||(e=0);var o;if("number"==typeof e)for(o=t;o<n;++o)this[o]=e;else{var d=s.isBuffer(e)?e:s.from(e,r),l=d.length;
407if(0===l)throw new TypeError("The value \""+e+"\" is invalid for argument \"value\"");for(o=0;o<n-t;++o)this[o+t]=d[o%l]}return this};var Q=/[^+/0-9A-Za-z-_]/g}).call(this)}).call(this,e("buffer").Buffer)},{"base64-js":1,buffer:3,ieee754:9}],4:[function(e,t,n){(function(a){(function(){function r(){let e;try{e=n.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof a&&"env"in a&&(e=a.env.DEBUG),e}n.formatArgs=function(e){if(e[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+e[0]+(this.useColors?"%c ":" ")+"+"+t.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;e.splice(1,0,n,"color: inherit");let r=0,a=0;e[0].replace(/%[a-zA-Z%]/g,e=>{"%%"===e||(r++,"%c"===e&&(a=r))}),e.splice(a,0,n)},n.save=function(e){try{e?n.storage.setItem("debug",e):n.storage.removeItem("debug")}catch(e){}},n.load=r,n.useColors=function(){return!!("undefined"!=typeof window&&window.process&&("renderer"===window.process.type||window.process.__nwjs))||!("undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&31<=parseInt(RegExp.$1,10)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},n.storage=function(){try{return localStorage}catch(e){}}(),n.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),n.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],n.log=console.debug||console.log||(()=>{}),t.exports=e("./common")(n);const{formatters:o}=t.exports;o.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}}).call(this)}).call(this,e("_process"))},{"./common":5,_process:12}],5:[function(e,t){t.exports=function(t){function r(e){function t(...e){if(!t.enabled)return;const a=t,o=+new Date,i=o-(n||o);a.diff=i,a.prev=n,a.curr=o,n=o,e[0]=r.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let d=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,(t,n)=>{if("%%"===t)return"%";d++;const o=r.formatters[n];if("function"==typeof o){const n=e[d];t=o.call(a,n),e.splice(d,1),d--}return t}),r.formatArgs.call(a,e);const s=a.log||r.log;s.apply(a,e)}let n,o=null;return t.namespace=e,t.useColors=r.useColors(),t.color=r.selectColor(e),t.extend=a,t.destroy=r.destroy,Object.defineProperty(t,"enabled",{enumerable:!0,configurable:!1,get:()=>null===o?r.enabled(e):o,set:e=>{o=e}}),"function"==typeof r.init&&r.init(t),t}function a(e,t){const n=r(this.namespace+("undefined"==typeof t?":":t)+e);return n.log=this.log,n}function o(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return r.debug=r,r.default=r,r.coerce=function(e){return e instanceof Error?e.stack||e.message:e},r.disable=function(){const e=[...r.names.map(o),...r.skips.map(o).map(e=>"-"+e)].join(",");return r.enable(""),e},r.enable=function(e){r.save(e),r.names=[],r.skips=[];let t;const n=("string"==typeof e?e:"").split(/[\s,]+/),a=n.length;for(t=0;t<a;t++)n[t]&&(e=n[t].replace(/\*/g,".*?"),"-"===e[0]?r.skips.push(new RegExp("^"+e.substr(1)+"$")):r.names.push(new RegExp("^"+e+"$")))},r.enabled=function(e){if("*"===e[e.length-1])return!0;let t,n;for(t=0,n=r.skips.length;t<n;t++)if(r.skips[t].test(e))return!1;for(t=0,n=r.names.length;t<n;t++)if(r.names[t].test(e))return!0;return!1},r.humanize=e("ms"),r.destroy=function(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}
407,Object.keys(t).forEach(e=>{r[e]=t[e]}),r.names=[],r.skips=[],r.formatters={},r.selectColor=function(e){let t=0;for(let n=0;n<e.length;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return r.colors[n(t)%r.colors.length]},r.enable(r.load()),r}},{ms:11}],6:[function(e,t){'use strict';function n(e,t){for(const n in t)Object.defineProperty(e,n,{value:t[n],enumerable:!0,configurable:!0});return e}t.exports=function(e,t,r){if(!e||"string"==typeof e)throw new TypeError("Please pass an Error to err-code");r||(r={}),"object"==typeof t&&(r=t,t=""),t&&(r.code=t);try{return n(e,r)}catch(t){r.message=e.message,r.stack=e.stack;const a=function(){};a.prototype=Object.create(Object.getPrototypeOf(e));const o=n(new a,r);return o}}},{}],7:[function(e,t){'use strict';function n(e){console&&console.warn&&console.warn(e)}function r(){r.init.call(this)}function a(e){if("function"!=typeof e)throw new TypeError("The \"listener\" argument must be of type Function. Received type "+typeof e)}function o(e){return void 0===e._maxListeners?r.defaultMaxListeners:e._maxListeners}function i(e,t,r,i){var d,s,l;if(a(r),s=e._events,void 0===s?(s=e._events=Object.create(null),e._eventsCount=0):(void 0!==s.newListener&&(e.emit("newListener",t,r.listener?r.listener:r),s=e._events),l=s[t]),void 0===l)l=s[t]=r,++e._eventsCount;else if("function"==typeof l?l=s[t]=i?[r,l]:[l,r]:i?l.unshift(r):l.push(r),d=o(e),0<d&&l.length>d&&!l.warned){l.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+l.length+" "+(t+" listeners added. Use emitter.setMaxListeners() to increase limit"));c.name="MaxListenersExceededWarning",c.emitter=e,c.type=t,c.count=l.length,n(c)}return e}function d(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function s(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},a=d.bind(r);return a.listener=n,r.wrapFn=a,a}function l(e,t,n){var r=e._events;if(r===void 0)return[];var a=r[t];return void 0===a?[]:"function"==typeof a?n?[a.listener||a]:[a]:n?f(a):u(a,a.length)}function c(e){var t=this._events;if(t!==void 0){var n=t[e];if("function"==typeof n)return 1;if(void 0!==n)return n.length}return 0}function u(e,t){for(var n=Array(t),r=0;r<t;++r)n[r]=e[r];return n}function p(e,t){for(;t+1<e.length;t++)e[t]=e[t+1];e.pop()}function f(e){for(var t=Array(e.length),n=0;n<t.length;++n)t[n]=e[n].listener||e[n];return t}function g(e,t,n){"function"==typeof e.on&&_(e,"error",t,n)}function _(e,t,n,r){if("function"==typeof e.on)r.once?e.once(t,n):e.on(t,n);else if("function"==typeof e.addEventListener)e.addEventListener(t,function a(o){r.once&&e.removeEventListener(t,a),n(o)});else throw new TypeError("The \"emitter\" argument must be of type EventEmitter. Received type "+typeof e)}var h,m="object"==typeof Reflect?Reflect:null,b=m&&"function"==typeof m.apply?m.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)};h=m&&"function"==typeof m.ownKeys?m.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var y=Number.isNaN||function(e){return e!==e};t.exports=r,t.exports.once=function(e,t){return new Promise(function(n,r){function a(n){e.removeListener(t,o),r(n)}function o(){"function"==typeof e.removeListener&&e.removeListener("error",a),n([].slice.call(arguments))}_(e,t,o,{once:!0}),"error"!==t&&g(e,a,{once:!0})})},r.EventEmitter=r,r.prototype._events=void 0,r.prototype._eventsCount=0,r.prototype._maxListeners=void 0;var C=10;Object.defineProperty(r,"defaultMaxListeners",{enumerable:!0,get:function(){return C},set:function(e){if("number"!=typeof e||0>e||y(e))throw new RangeError("The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received "+e+".");C=e}}),r.init=function(){(this._events===void 0||this._events===Object.getPrototypeOf(this)._events)&&(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},r.prototype.setMaxListeners=function(e){if("number"!=typeof e||0>e||y(e))throw new RangeError("The value of \"n\" is out of range. It must be a non-negative number. Received "+e+".");return this._maxListeners=e,this},r.prototype.getMaxListeners=function(){return o(this)},r.prototype.emit=function(e){for(var t=[],n=1;n<arguments.length;n++)t.push(arguments[n]);var r="error"===e,a=this._events;if(a!==void 0)r=r&&a.error===void 0;else if(!r)return!1;if(r){var o;if(0<t.length&&(o=t[0]),o instanceof Error)throw o;var d=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw d.context=o,d}var s=a[e];if(s===void 0)return!1;if("function"==typeof s)b(s,this,t);else for(var l=s.length,c=u(s,l),n=0;n<l;++n)b(c[n],this,t);return!0},r.prototype.addListener=function(e,t){return i(this,e,t,!1)},r.prototype.on=r.prototype.addListener,r.prototype.prependListener=function(e,t){return i(this,e,t,!0)},r.prototype.once=function(e,t){return a(t),this.on(e,s(this,e,t)),this},r.prototype.prependOnceListener=function(e,t){return a(t),this.prependListener(e,s(this,e,t)),this},r.prototype.removeListener=function(e,t){var n,r,o,d,s;if(a(t),r=this._events,void 0===r)return this;if(n=r[e],void 0===n)return this;if(n===t||n.listener===t)0==--this._eventsCount?this._events=Object.create(null):(delete r[e],r.removeListener&&this.emit
407("removeListener",e,n.listener||t));else if("function"!=typeof n){for(o=-1,d=n.length-1;0<=d;d--)if(n[d]===t||n[d].listener===t){s=n[d].listener,o=d;break}if(0>o)return this;0===o?n.shift():p(n,o),1===n.length&&(r[e]=n[0]),void 0!==r.removeListener&&this.emit("removeListener",e,s||t)}return this},r.prototype.off=r.prototype.removeListener,r.prototype.removeAllListeners=function(e){var t,n,r;if(n=this._events,void 0===n)return this;if(void 0===n.removeListener)return 0===arguments.length?(this._events=Object.create(null),this._eventsCount=0):void 0!==n[e]&&(0==--this._eventsCount?this._events=Object.create(null):delete n[e]),this;if(0===arguments.length){var a,o=Object.keys(n);for(r=0;r<o.length;++r)a=o[r],"removeListener"!==a&&this.removeAllListeners(a);return this.removeAllListeners("removeListener"),this._events=Object.create(null),this._eventsCount=0,this}if(t=n[e],"function"==typeof t)this.removeListener(e,t);else if(void 0!==t)for(r=t.length-1;0<=r;r--)this.removeListener(e,t[r]);return this},r.prototype.listeners=function(e){return l(this,e,!0)},r.prototype.rawListeners=function(e){return l(this,e,!1)},r.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):c.call(e,t)},r.prototype.listenerCount=c,r.prototype.eventNames=function(){return 0<this._eventsCount?h(this._events):[]}},{}],8:[function(e,t){t.exports=function(){if("undefined"==typeof globalThis)return null;var e={RTCPeerConnection:globalThis.RTCPeerConnection||globalThis.mozRTCPeerConnection||globalThis.webkitRTCPeerConnection,RTCSessionDescription:globalThis.RTCSessionDescription||globalThis.mozRTCSessionDescription||globalThis.webkitRTCSessionDescription,RTCIceCandidate:globalThis.RTCIceCandidate||globalThis.mozRTCIceCandidate||globalThis.webkitRTCIceCandidate};return e.RTCPeerConnection?e:null}},{}],9:[function(e,a,o){/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */o.read=function(t,n,a,o,l){var c,u,p=8*l-o-1,f=(1<<p)-1,g=f>>1,_=-7,h=a?l-1:0,b=a?-1:1,d=t[n+h];for(h+=b,c=d&(1<<-_)-1,d>>=-_,_+=p;0<_;c=256*c+t[n+h],h+=b,_-=8);for(u=c&(1<<-_)-1,c>>=-_,_+=o;0<_;u=256*u+t[n+h],h+=b,_-=8);if(0===c)c=1-g;else{if(c===f)return u?NaN:(d?-1:1)*(1/0);u+=r(2,o),c-=g}return(d?-1:1)*u*r(2,c-o)},o.write=function(a,o,l,u,p,f){var h,b,y,g=Math.LN2,_=Math.log,C=8*f-p-1,R=(1<<C)-1,E=R>>1,w=23===p?r(2,-24)-r(2,-77):0,S=u?0:f-1,T=u?1:-1,d=0>o||0===o&&0>1/o?1:0;for(o=n(o),isNaN(o)||o===1/0?(b=isNaN(o)?1:0,h=R):(h=t(_(o)/g),1>o*(y=r(2,-h))&&(h--,y*=2),o+=1<=h+E?w/y:w*r(2,1-E),2<=o*y&&(h++,y/=2),h+E>=R?(b=0,h=R):1<=h+E?(b=(o*y-1)*r(2,p),h+=E):(b=o*r(2,E-1)*r(2,p),h=0));8<=p;a[l+S]=255&b,S+=T,b/=256,p-=8);for(h=h<<p|b,C+=p;0<C;a[l+S]=255&h,S+=T,h/=256,C-=8);a[l+S-T]|=128*d}},{}],10:[function(e,t){t.exports="function"==typeof Object.create?function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:function(e,t){if(t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}}},{}],11:[function(e,t){var r=Math.round;function a(e){if(e+="",!(100<e.length)){var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(t){var r=parseFloat(t[1]),n=(t[2]||"ms").toLowerCase();return"years"===n||"year"===n||"yrs"===n||"yr"===n||"y"===n?31557600000*r:"weeks"===n||"week"===n||"w"===n?604800000*r:"days"===n||"day"===n||"d"===n?86400000*r:"hours"===n||"hour"===n||"hrs"===n||"hr"===n||"h"===n?3600000*r:"minutes"===n||"minute"===n||"mins"===n||"min"===n||"m"===n?60000*r:"seconds"===n||"second"===n||"secs"===n||"sec"===n||"s"===n?1000*r:"milliseconds"===n||"millisecond"===n||"msecs"===n||"msec"===n||"ms"===n?r:void 0}}}function o(e){var t=n(e);return 86400000<=t?r(e/86400000)+"d":3600000<=t?r(e/3600000)+"h":60000<=t?r(e/60000)+"m":1000<=t?r(e/1000)+"s":e+"ms"}function i(e){var t=n(e);return 86400000<=t?s(e,t,86400000,"day"):3600000<=t?s(e,t,3600000,"hour"):60000<=t?s(e,t,60000,"minute"):1000<=t?s(e,t,1000,"second"):e+" ms"}function s(e,t,a,n){return r(e/a)+" "+n+(t>=1.5*a?"s":"")}var l=24*(60*60000);t.exports=function(e,t){t=t||{};var n=typeof e;if("string"==n&&0<e.length)return a(e);if("number"===n&&isFinite(e))return t.long?i(e):o(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},{}],12:[function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function a(t){if(c===setTimeout)return setTimeout(t,0);if((c===n||!c)&&setTimeout)return c=setTimeout,setTimeout(t,0);try{return c(t,0)}catch(n){try{return c.call(null,t,0)}catch(n){return c.call(this,t,0)}}}function o(t){if(u===clearTimeout)return clearTimeout(t);if((u===r||!u)&&clearTimeout)return u=clearTimeout,clearTimeout(t);try{return u(t)}catch(n){try{return u.call(null,t)}catch(n){return u.call(this,t)}}}function i(){_&&f&&(_=!1,f.length?g=f.concat(g):h=-1,g.length&&d())}function d(){if(!_){var e=a(i);_=!0;for(var t=g.length;t;){for(f=g,g=[];++h<t;)f&&f[h].run();h=-1,t=g.length}f=null,_=!1,o(e)}}function s(e,t){this.fun=e,this.array=t}function l(){}var c,u,p=t.exports={};(function(){try{c="function"==typeof setTimeout?setTimeout:n}catch(t){c=n}try{u="function"==typeof clearTimeout?clearTimeout:r}catch(t){u=r}})();var f,g=[],_=!1,h=-1;p.nextTick=function(e){var t=Array(arguments.length-1);if(1<arguments.length)for(var n=1;n<arguments.length;n++)t[n-1]=arguments[n];g.push(new s(e,t)),1!==g.length||_||a(d)},s.prototype.run=function(){this.fun.apply(null,this.array)},p.title="browser",p.browser=!0,p.env={},p.argv=[],p.version="",p.versions={},p.on=l,p.addListener=l,p.once=l,p.off=l,p.removeListener=l,p.removeAllListeners=l,p.emit=l,p.prependListener=l,p.prependOnceListener=l,p.listeners=function(){return[]},p.binding=function(){throw new Error("process.binding is not supported")},p.cwd=function(){return"/"},p.chdir=function(){throw new Error("process.chdir is not supported")},p.umask=function(){return 0}},{}],13:[function(e,t){(function(e){(function(){/*! queue-microtask. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */let n;t.exports="function"==typeof queueMicrotask?queueMicrotask.bind("undefined"==typeof window?e:window):e=>
407(n||(n=Promise.resolve())).then(e).catch(e=>setTimeout(()=>{throw e},0))}).call(this)}).call(this,"undefined"==typeof __webpack_require__.g?"undefined"==typeof self?"undefined"==typeof window?{}:window:self:__webpack_require__.g)},{}],14:[function(e,t){(function(n,r){(function(){'use strict';var a=e("safe-buffer").Buffer,o=r.crypto||r.msCrypto;t.exports=o&&o.getRandomValues?function(e,t){if(e>4294967295)throw new RangeError("requested too many random bytes");var r=a.allocUnsafe(e);if(0<e)if(65536<e)for(var i=0;i<e;i+=65536)o.getRandomValues(r.slice(i,i+65536));else o.getRandomValues(r);return"function"==typeof t?n.nextTick(function(){t(null,r)}):r}:function(){throw new Error("Secure random number generation is not supported by this browser.\nUse Chrome, Firefox or Internet Explorer 11")}}).call(this)}).call(this,e("_process"),"undefined"==typeof __webpack_require__.g?"undefined"==typeof self?"undefined"==typeof window?{}:window:self:__webpack_require__.g)},{_process:12,"safe-buffer":30}],15:[function(e,t){'use strict';function n(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function r(e,t,r){function a(e,n,r){return"string"==typeof t?t:t(e,n,r)}r||(r=Error);var o=function(e){function t(t,n,r){return e.call(this,a(t,n,r))||this}return n(t,e),t}(r);o.prototype.name=r.name,o.prototype.code=e,s[e]=o}function a(e,t){if(Array.isArray(e)){var n=e.length;return e=e.map(function(e){return e+""}),2<n?"one of ".concat(t," ").concat(e.slice(0,n-1).join(", "),", or ")+e[n-1]:2===n?"one of ".concat(t," ").concat(e[0]," or ").concat(e[1]):"of ".concat(t," ").concat(e[0])}return"of ".concat(t," ").concat(e+"")}function o(e,t,n){return e.substr(!n||0>n?0:+n,t.length)===t}function i(e,t,n){return(void 0===n||n>e.length)&&(n=e.length),e.substring(n-t.length,n)===t}function d(e,t,n){return"number"!=typeof n&&(n=0),!(n+t.length>e.length)&&-1!==e.indexOf(t,n)}var s={};r("ERR_INVALID_OPT_VALUE",function(e,t){return"The value \""+t+"\" is invalid for option \""+e+"\""},TypeError),r("ERR_INVALID_ARG_TYPE",function(e,t,n){var r;"string"==typeof t&&o(t,"not ")?(r="must not be",t=t.replace(/^not /,"")):r="must be";var s;if(i(e," argument"))s="The ".concat(e," ").concat(r," ").concat(a(t,"type"));else{var l=d(e,".")?"property":"argument";s="The \"".concat(e,"\" ").concat(l," ").concat(r," ").concat(a(t,"type"))}return s+=". Received type ".concat(typeof n),s},TypeError),r("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF"),r("ERR_METHOD_NOT_IMPLEMENTED",function(e){return"The "+e+" method is not implemented"}),r("ERR_STREAM_PREMATURE_CLOSE","Premature close"),r("ERR_STREAM_DESTROYED",function(e){return"Cannot call "+e+" after a stream was destroyed"}),r("ERR_MULTIPLE_CALLBACK","Callback called multiple times"),r("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable"),r("ERR_STREAM_WRITE_AFTER_END","write after end"),r("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError),r("ERR_UNKNOWN_ENCODING",function(e){return"Unknown encoding: "+e},TypeError),r("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event"),t.exports.codes=s},{}],16:[function(e,t){(function(n){(function(){'use strict';function r(e){return this instanceof r?void(d.call(this,e),s.call(this,e),this.allowHalfOpen=!0,e&&(!1===e.readable&&(this.readable=!1),!1===e.writable&&(this.writable=!1),!1===e.allowHalfOpen&&(this.allowHalfOpen=!1,this.once("end",a)))):new r(e)}function a(){this._writableState.ended||n.nextTick(o,this)}function o(e){e.end()}var i=Object.keys||function(e){var t=[];for(var n in e)t.push(n);return t};t.exports=r;var d=e("./_stream_readable"),s=e("./_stream_writable");e("inherits")(r,d);for(var l,c=i(s.prototype),u=0;u<c.length;u++)l=c[u],r.prototype[l]||(r.prototype[l]=s.prototype[l]);Object.defineProperty(r.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),Object.defineProperty(r.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}}),Object.defineProperty(r.prototype,"writableLength",{enumerable:!1,get:function(){return this._writableState.length}}),Object.defineProperty(r.prototype,"destroyed",{enumerable:!1,get:function(){return void 0!==this._readableState&&void 0!==this._writableState&&this._readableState.destroyed&&this._writableState.destroyed},set:function(e){void 0===this._readableState||void 0===this._writableState||(this._readableState.destroyed=e,this._writableState.destroyed=e)}})}).call(this)}).call(this,e("_process"))},{"./_stream_readable":18,"./_stream_writable":20,_process:12,inherits:10}],17:[function(e,t){'use strict';function n(e){return this instanceof n?void r.call(this,e):new n(e)}t.exports=n;var r=e("./_stream_transform");e("inherits")(n,r),n.prototype._transform=function(e,t,n){n(null,e)}},{"./_stream_transform":19,inherits:10}],18:[function(e,t){(function(n,r){(function(){'use strict';function a(e){return P.from(e)}function o(e){return P.isBuffer(e)||e instanceof M}function i(e,t,n){return"function"==typeof e.prependListener?e.prependListener(t,n):void(e._events&&e._events[t]?Array.isArray(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]:e.on(t,n))}function d(t,n,r){A=A||e("./_stream_duplex"),t=t||{},"boolean"!=typeof r&&(r=n instanceof A),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.readableObjectMode),this.highWaterMark=H(this,t,"readableHighWaterMark",r),this.buffer=new j,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=!1!==t.emitClose,this.autoDestroy=!!t.autoDestroy,this.destroyed=!1,this.defaultEncoding=t.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,t.encoding&&(!F&&(F=e("string_decoder/").StringDecoder),this.decoder=new F(t.encoding),this.encoding=t.encoding)}function s(t){if(A=A||e("./_stream_duplex"),!(this instanceof s))return new s(t);var n=this instanceof A;this._readableState=new d(t,this,n),this.readable=!0,t&&("function"==typeof t.read&&(this._read=t.read),"function"==typeof t.destroy&&(this._destroy=t.destroy)),I.call(this)}function l(e,t,n,r,o){x("readableAddChunk",t);var i=e._readableState;if(null===t)i.reading=!1,g(e,i);else{var d;
407if(o||(d=u(i,t)),d)X(e,d);else if(!(i.objectMode||t&&0<t.length))r||(i.reading=!1,m(e,i));else if("string"==typeof t||i.objectMode||Object.getPrototypeOf(t)===P.prototype||(t=a(t)),r)i.endEmitted?X(e,new K):c(e,i,t,!0);else if(i.ended)X(e,new z);else{if(i.destroyed)return!1;i.reading=!1,i.decoder&&!n?(t=i.decoder.write(t),i.objectMode||0!==t.length?c(e,i,t,!1):m(e,i)):c(e,i,t,!1)}}return!i.ended&&(i.length<i.highWaterMark||0===i.length)}function c(e,t,n,r){t.flowing&&0===t.length&&!t.sync?(t.awaitDrain=0,e.emit("data",n)):(t.length+=t.objectMode?1:n.length,r?t.buffer.unshift(n):t.buffer.push(n),t.needReadable&&_(e)),m(e,t)}function u(e,t){var n;return o(t)||"string"==typeof t||void 0===t||e.objectMode||(n=new V("chunk",["string","Buffer","Uint8Array"],t)),n}function p(e){return 1073741824<=e?e=1073741824:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function f(e,t){return 0>=e||0===t.length&&t.ended?0:t.objectMode?1:e===e?(e>t.highWaterMark&&(t.highWaterMark=p(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0)):t.flowing&&t.length?t.buffer.head.data.length:t.length}function g(e,t){if(x("onEofChunk"),!t.ended){if(t.decoder){var n=t.decoder.end();n&&n.length&&(t.buffer.push(n),t.length+=t.objectMode?1:n.length)}t.ended=!0,t.sync?_(e):(t.needReadable=!1,!t.emittedReadable&&(t.emittedReadable=!0,h(e)))}}function _(e){var t=e._readableState;x("emitReadable",t.needReadable,t.emittedReadable),t.needReadable=!1,t.emittedReadable||(x("emitReadable",t.flowing),t.emittedReadable=!0,n.nextTick(h,e))}function h(e){var t=e._readableState;x("emitReadable_",t.destroyed,t.length,t.ended),!t.destroyed&&(t.length||t.ended)&&(e.emit("readable"),t.emittedReadable=!1),t.needReadable=!t.flowing&&!t.ended&&t.length<=t.highWaterMark,S(e)}function m(e,t){t.readingMore||(t.readingMore=!0,n.nextTick(b,e,t))}function b(e,t){for(;!t.reading&&!t.ended&&(t.length<t.highWaterMark||t.flowing&&0===t.length);){var n=t.length;if(x("maybeReadMore read 0"),e.read(0),n===t.length)break}t.readingMore=!1}function y(e){return function(){var t=e._readableState;x("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&D(e,"data")&&(t.flowing=!0,S(e))}}function C(e){var t=e._readableState;t.readableListening=0<e.listenerCount("readable"),t.resumeScheduled&&!t.paused?t.flowing=!0:0<e.listenerCount("data")&&e.resume()}function R(e){x("readable nexttick read 0"),e.read(0)}function E(e,t){t.resumeScheduled||(t.resumeScheduled=!0,n.nextTick(w,e,t))}function w(e,t){x("resume",t.reading),t.reading||e.read(0),t.resumeScheduled=!1,e.emit("resume"),S(e),t.flowing&&!t.reading&&e.read(0)}function S(e){var t=e._readableState;for(x("flow",t.flowing);t.flowing&&null!==e.read(););}function T(e,t){if(0===t.length)return null;var n;return t.objectMode?n=t.buffer.shift():!e||e>=t.length?(n=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.first():t.buffer.concat(t.length),t.buffer.clear()):n=t.buffer.consume(e,t.decoder),n}function v(e){var t=e._readableState;x("endReadable",t.endEmitted),t.endEmitted||(t.ended=!0,n.nextTick(k,t,e))}function k(e,t){if(x("endReadableNT",e.endEmitted,e.length),!e.endEmitted&&0===e.length&&(e.endEmitted=!0,t.readable=!1,t.emit("end"),e.autoDestroy)){var n=t._writableState;(!n||n.autoDestroy&&n.finished)&&t.destroy()}}function L(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1}t.exports=s;var A;s.ReadableState=d;var x,N=e("events").EventEmitter,D=function(e,t){return e.listeners(t).length},I=e("./internal/streams/stream"),P=e("buffer").Buffer,M=r.Uint8Array||function(){},O=e("util");x=O&&O.debuglog?O.debuglog("stream"):function(){};var F,B,U,j=e("./internal/streams/buffer_list"),q=e("./internal/streams/destroy"),W=e("./internal/streams/state"),H=W.getHighWaterMark,Y=e("../errors").codes,V=Y.ERR_INVALID_ARG_TYPE,z=Y.ERR_STREAM_PUSH_AFTER_EOF,G=Y.ERR_METHOD_NOT_IMPLEMENTED,K=Y.ERR_STREAM_UNSHIFT_AFTER_END_EVENT;e("inherits")(s,I);var X=q.errorOrDestroy,$=["error","close","destroy","pause","resume"];Object.defineProperty(s.prototype,"destroyed",{enumerable:!1,get:function(){return void 0!==this._readableState&&this._readableState.destroyed},set:function(e){this._readableState&&(this._readableState.destroyed=e)}}),s.prototype.destroy=q.destroy,s.prototype._undestroy=q.undestroy,s.prototype._destroy=function(e,t){t(e)},s.prototype.push=function(e,t){var n,r=this._readableState;return r.objectMode?n=!0:"string"==typeof e&&(t=t||r.defaultEncoding,t!==r.encoding&&(e=P.from(e,t),t=""),n=!0),l(this,e,t,!1,n)},s.prototype.unshift=function(e){return l(this,e,null,!0,!1)},s.prototype.isPaused=function(){return!1===this._readableState.flowing},s.prototype.setEncoding=function(t){F||(F=e("string_decoder/").StringDecoder);var n=new F(t);this._readableState.decoder=n,this._readableState.encoding=this._readableState.decoder.encoding;
407for(var r=this._readableState.buffer.head,a="";null!==r;)a+=n.write(r.data),r=r.next;return this._readableState.buffer.clear(),""!==a&&this._readableState.buffer.push(a),this._readableState.length=a.length,this};s.prototype.read=function(e){x("read",e),e=parseInt(e,10);var t=this._readableState,r=e;if(0!==e&&(t.emittedReadable=!1),0===e&&t.needReadable&&((0===t.highWaterMark?0<t.length:t.length>=t.highWaterMark)||t.ended))return x("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?v(this):_(this),null;if(e=f(e,t),0===e&&t.ended)return 0===t.length&&v(this),null;var a=t.needReadable;x("need readable",a),(0===t.length||t.length-e<t.highWaterMark)&&(a=!0,x("length less than watermark",a)),t.ended||t.reading?(a=!1,x("reading or ended",a)):a&&(x("do read"),t.reading=!0,t.sync=!0,0===t.length&&(t.needReadable=!0),this._read(t.highWaterMark),t.sync=!1,!t.reading&&(e=f(r,t)));var o;return o=0<e?T(e,t):null,null===o?(t.needReadable=t.length<=t.highWaterMark,e=0):(t.length-=e,t.awaitDrain=0),0===t.length&&(!t.ended&&(t.needReadable=!0),r!==e&&t.ended&&v(this)),null!==o&&this.emit("data",o),o},s.prototype._read=function(){X(this,new G("_read()"))},s.prototype.pipe=function(e,t){function r(e,t){x("onunpipe"),e===p&&t&&!1===t.hasUnpiped&&(t.hasUnpiped=!0,o())}function a(){x("onend"),e.end()}function o(){x("cleanup"),e.removeListener("close",l),e.removeListener("finish",c),e.removeListener("drain",h),e.removeListener("error",s),e.removeListener("unpipe",r),p.removeListener("end",a),p.removeListener("end",u),p.removeListener("data",d),m=!0,f.awaitDrain&&(!e._writableState||e._writableState.needDrain)&&h()}function d(t){x("ondata");var n=e.write(t);x("dest.write",n),!1===n&&((1===f.pipesCount&&f.pipes===e||1<f.pipesCount&&-1!==L(f.pipes,e))&&!m&&(x("false write response, pause",f.awaitDrain),f.awaitDrain++),p.pause())}function s(t){x("onerror",t),u(),e.removeListener("error",s),0===D(e,"error")&&X(e,t)}function l(){e.removeListener("finish",c),u()}function c(){x("onfinish"),e.removeListener("close",l),u()}function u(){x("unpipe"),p.unpipe(e)}var p=this,f=this._readableState;switch(f.pipesCount){case 0:f.pipes=e;break;case 1:f.pipes=[f.pipes,e];break;default:f.pipes.push(e);}f.pipesCount+=1,x("pipe count=%d opts=%j",f.pipesCount,t);var g=(!t||!1!==t.end)&&e!==n.stdout&&e!==n.stderr,_=g?a:u;f.endEmitted?n.nextTick(_):p.once("end",_),e.on("unpipe",r);var h=y(p);e.on("drain",h);var m=!1;return p.on("data",d),i(e,"error",s),e.once("close",l),e.once("finish",c),e.emit("pipe",p),f.flowing||(x("pipe resume"),p.resume()),e},s.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,n),this);if(!e){var r=t.pipes,a=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var o=0;o<a;o++)r[o].emit("unpipe",this,{hasUnpiped:!1});return this}var d=L(t.pipes,e);return-1===d?this:(t.pipes.splice(d,1),t.pipesCount-=1,1===t.pipesCount&&(t.pipes=t.pipes[0]),e.emit("unpipe",this,n),this)},s.prototype.on=function(e,t){var r=I.prototype.on.call(this,e,t),a=this._readableState;return"data"===e?(a.readableListening=0<this.listenerCount("readable"),!1!==a.flowing&&this.resume()):"readable"==e&&!a.endEmitted&&!a.readableListening&&(a.readableListening=a.needReadable=!0,a.flowing=!1,a.emittedReadable=!1,x("on readable",a.length,a.reading),a.length?_(this):!a.reading&&n.nextTick(R,this)),r},s.prototype.addListener=s.prototype.on,s.prototype.removeListener=function(e,t){var r=I.prototype.removeListener.call(this,e,t);return"readable"===e&&n.nextTick(C,this),r},s.prototype.removeAllListeners=function(e){var t=I.prototype.removeAllListeners.apply(this,arguments);return("readable"===e||void 0===e)&&n.nextTick(C,this),t},s.prototype.resume=function(){var e=this._readableState;return e.flowing||(x("resume"),e.flowing=!e.readableListening,E(this,e)),e.paused=!1,this},s.prototype.pause=function(){return x("call pause flowing=%j",this._readableState.flowing),!1!==this._readableState.flowing&&(x("pause"),this._readableState.flowing=!1,this.emit
vendor: 7,503 bytes, line 407
407("pause")),this._readableState.paused=!0,this},s.prototype.wrap=function(e){var t=this,r=this._readableState,a=!1;for(var o in e.on("end",function(){if(x("wrapped end"),r.decoder&&!r.ended){var e=r.decoder.end();e&&e.length&&t.push(e)}t.push(null)}),e.on("data",function(n){if((x("wrapped data"),r.decoder&&(n=r.decoder.write(n)),!(r.objectMode&&(null===n||void 0===n)))&&(r.objectMode||n&&n.length)){var o=t.push(n);o||(a=!0,e.pause())}}),e)void 0===this[o]&&"function"==typeof e[o]&&(this[o]=function(t){return function(){return e[t].apply(e,arguments)}}(o));for(var i=0;i<$.length;i++)e.on($[i],this.emit.bind(this,$[i]));return this._read=function(t){x("wrapped _read",t),a&&(a=!1,e.resume())},this},"function"==typeof Symbol&&(s.prototype[Symbol.asyncIterator]=function(){return void 0===B&&(B=e("./internal/streams/async_iterator")),B(this)}),Object.defineProperty(s.prototype,"readableHighWaterMark",{enumerable:!1,get:function(){return this._readableState.highWaterMark}}),Object.defineProperty(s.prototype,"readableBuffer",{enumerable:!1,get:function(){return this._readableState&&this._readableState.buffer}}),Object.defineProperty(s.prototype,"readableFlowing",{enumerable:!1,get:function(){return this._readableState.flowing},set:function(e){this._readableState&&(this._readableState.flowing=e)}}),s._fromList=T,Object.defineProperty(s.prototype,"readableLength",{enumerable:!1,get:function(){return this._readableState.length}}),"function"==typeof Symbol&&(s.from=function(t,n){return void 0===U&&(U=e("./internal/streams/from")),U(s,t,n)})}).call(this)}).call(this,e("_process"),"undefined"==typeof __webpack_require__.g?"undefined"==typeof self?"undefined"==typeof window?{}:window:self:__webpack_require__.g)},{"../errors":15,"./_stream_duplex":16,"./internal/streams/async_iterator":21,"./internal/streams/buffer_list":22,"./internal/streams/destroy":23,"./internal/streams/from":25,"./internal/streams/state":27,"./internal/streams/stream":28,_process:12,buffer:3,events:7,inherits:10,"string_decoder/":31,util:2}],19:[function(e,t){'use strict';function n(e,t){var n=this._transformState;n.transforming=!1;var r=n.writecb;if(null===r)return this.emit("error",new s);n.writechunk=null,n.writecb=null,null!=t&&this.push(t),r(e);var a=this._readableState;a.reading=!1,(a.needReadable||a.length<a.highWaterMark)&&this._read(a.highWaterMark)}function r(e){return this instanceof r?void(u.call(this,e),this._transformState={afterTransform:n.bind(this),needTransform:!1,transforming:!1,writecb:null,writechunk:null,writeencoding:null},this._readableState.needReadable=!0,this._readableState.sync=!1,e&&("function"==typeof e.transform&&(this._transform=e.transform),"function"==typeof e.flush&&(this._flush=e.flush)),this.on("prefinish",a)):new r(e)}function a(){var e=this;"function"!=typeof this._flush||this._readableState.destroyed?o(this,null,null):this._flush(function(t,n){o(e,t,n)})}function o(e,t,n){if(t)return e.emit("error",t);if(null!=n&&e.push(n),e._writableState.length)throw new c;if(e._transformState.transforming)throw new l;return e.push(null)}t.exports=r;var i=e("../errors").codes,d=i.ERR_METHOD_NOT_IMPLEMENTED,s=i.ERR_MULTIPLE_CALLBACK,l=i.ERR_TRANSFORM_ALREADY_TRANSFORMING,c=i.ERR_TRANSFORM_WITH_LENGTH_0,u=e("./_stream_duplex");e("inherits")(r,u),r.prototype.push=function(e,t){return this._transformState.needTransform=!1,u.prototype.push.call(this,e,t)},r.prototype._transform=function(e,t,n){n(new d("_transform()"))},r.prototype._write=function(e,t,n){var r=this._transformState;if(r.writecb=n,r.writechunk=e,r.writeencoding=t,!r.transforming){var a=this._readableState;(r.needTransform||a.needReadable||a.length<a.highWaterMark)&&this._read(a.highWaterMark)}},r.prototype._read=function(){var e=this._transformState;null===e.writechunk||e.transforming?e.needTransform=!0:(e.transforming=!0,this._transform(e.writechunk,e.writeencoding,e.afterTransform))},r.prototype._destroy=function(e,t){u.prototype._destroy.call(this,e,function(e){t(e)})}},{"../errors":15,"./_stream_duplex":16,inherits:10}],20:[function(e,t){(function(n,r){(function(){'use strict';function a(e){var t=this;this.next=null,this.entry=null,this.finish=function(){v(t,e)}}function o(e){return x.from(e)}function i(e){return x.isBuffer(e)||e instanceof N}function d(){}function s(t,n,r){k=k||e("./_stream_duplex"),t=t||{},"boolean"!=typeof r&&(r=n instanceof k),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.writableObjectMode),this.highWaterMark=P(this,t,"writableHighWaterMark",r),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var o=!1===t.decodeStrings;this.decodeStrings=!o,this.defaultEncoding=t.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){m(n,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=!1!==t.emitClose,this.autoDestroy=!!t.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new a(this)}function l(t){k=k||e("./_stream_duplex");var n=this instanceof k;return n||V.call(l,this)?void(this._writableState=new s(t,this,n),this.writable=!0,t&&("function"==typeof t.write&&(this._write=t.write),"function"==typeof t.writev&&(this._writev=t.writev),"function"==typeof t.destroy&&(this._destroy=t.destroy),"function"==typeof t.final&&(this._final=t.final)),A.call(this)):new l(t)}function c(e,t){var r=new W;Y(e,r),n.nextTick(t,r)}function u(e,t,r,a){var o;return null===r?o=new q:"string"!=typeof r&&!t.objectMode&&(o=new O("chunk",["string","Buffer"],r)),!o||(Y(e,o),n.nextTick(a,o),!1)}function p(e,t,n){return e.objectMode||!1===e.decodeStrings||"string"!=typeof t||(t=x.from(t,n)),t}function f(e,t,n,r,a,o){if(!n){var i=p(t,r,a);r!==i&&(n=!0,a="buffer",r=i)}var d=t.objectMode?1:r.length;t.length+=d;var s=t.length<t.highWaterMark;if(s||(t.needDrain=!0),t.writing||t.corked){var l=t.lastBufferedRequest;t.lastBufferedRequest={chunk:r,encoding:a,isBuf:n,callback:o,next:null},l?l.next=t.lastBufferedRequest:t.bufferedRequest=t.lastBufferedRequest,t.bufferedRequestCount+=1}else g(e,t,!1,d,r,a,o);return s}function g(e,t,n,r,a,o,i){t.writelen=r,t.writecb=i,t.writing=!0,t.sync=!0,t.destroyed?t.onwrite(new j("write")):n?e._writev(a,t.onwrite):e._write(a,o,t.onwrite),t.sync=!1}function _(e,t,r,a,o){--t.pendingcb,r?(n.nextTick(o,a),n.nextTick(S,e,t),e._writableState.errorEmitted=!0,Y(e,a)):(o(a),e._writableState.errorEmitted=!0,Y(e,a),S(e,t))}function h(e){e.writing=!1,e.writecb=null,e.length-=e.writelen,e.writelen=0}function m(e,t){var r=e._writableState,a=r.sync,o=r.writecb;if("function"!=typeof o)throw new B;if(h(r),t)_(e,r,a,t,o);else{var i=R(r)||e.destroyed;i||r.corked||r.bufferProcessing||!r.bufferedRequest||C(e,r),a?n.nextTick(b,e,r,i,o):b(e,r,i,o)}}function b(e,t,n,r){n||y(e,t),t.pendingcb--,r(),S(e,t)}function y(e,t){0===t.length&&t.needDrain&&(t.needDrain=!1,e.emit("drain"))}function C(e,t){t.bufferProcessing=!0;var n=t.bufferedRequest;if(e._writev&&n&&n.next){var r=t.bufferedRequestCount,o=Array(r),i=t.corkedRequestsFree;i.entry=n;for(var d=0,s=!0;n;)o[d]=n,n.isBuf||(s=!1),n=n.next,d+=1;o.allBuffers=s,g(e,t,!0,t.length,o,"",i.finish),t.pendingcb++,t.lastBufferedRequest=null,i.next?(t.corkedRequestsFree=i.next,i.next=null):t.corkedRequestsFree=new a(t),t.bufferedRequestCount=0}else{for(;n;){var l=n.chunk,c=n.encoding,u=n.callback,p=t.objectMode?1:l.length;
vendor: 4,172 bytes, line 407
407if(g(e,t,!1,p,l,c,u),n=n.next,t.bufferedRequestCount--,t.writing)break}null===n&&(t.lastBufferedRequest=null)}t.bufferedRequest=n,t.bufferProcessing=!1}function R(e){return e.ending&&0===e.length&&null===e.bufferedRequest&&!e.finished&&!e.writing}function E(e,t){e._final(function(n){t.pendingcb--,n&&Y(e,n),t.prefinished=!0,e.emit("prefinish"),S(e,t)})}function w(e,t){t.prefinished||t.finalCalled||("function"!=typeof e._final||t.destroyed?(t.prefinished=!0,e.emit("prefinish")):(t.pendingcb++,t.finalCalled=!0,n.nextTick(E,e,t)))}function S(e,t){var n=R(t);if(n&&(w(e,t),0===t.pendingcb&&(t.finished=!0,e.emit("finish"),t.autoDestroy))){var r=e._readableState;(!r||r.autoDestroy&&r.endEmitted)&&e.destroy()}return n}function T(e,t,r){t.ending=!0,S(e,t),r&&(t.finished?n.nextTick(r):e.once("finish",r)),t.ended=!0,e.writable=!1}function v(e,t,n){var r=e.entry;for(e.entry=null;r;){var a=r.callback;t.pendingcb--,a(n),r=r.next}t.corkedRequestsFree.next=e}t.exports=l;var k;l.WritableState=s;var L={deprecate:e("util-deprecate")},A=e("./internal/streams/stream"),x=e("buffer").Buffer,N=r.Uint8Array||function(){},D=e("./internal/streams/destroy"),I=e("./internal/streams/state"),P=I.getHighWaterMark,M=e("../errors").codes,O=M.ERR_INVALID_ARG_TYPE,F=M.ERR_METHOD_NOT_IMPLEMENTED,B=M.ERR_MULTIPLE_CALLBACK,U=M.ERR_STREAM_CANNOT_PIPE,j=M.ERR_STREAM_DESTROYED,q=M.ERR_STREAM_NULL_VALUES,W=M.ERR_STREAM_WRITE_AFTER_END,H=M.ERR_UNKNOWN_ENCODING,Y=D.errorOrDestroy;e("inherits")(l,A),s.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(s.prototype,"buffer",{get:L.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}();var V;"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(V=Function.prototype[Symbol.hasInstance],Object.defineProperty(l,Symbol.hasInstance,{value:function(e){return!!V.call(this,e)||!(this!==l)&&e&&e._writableState instanceof s}})):V=function(e){return e instanceof this},l.prototype.pipe=function(){Y(this,new U)},l.prototype.write=function(e,t,n){var r=this._writableState,a=!1,s=!r.objectMode&&i(e);return s&&!x.isBuffer(e)&&(e=o(e)),"function"==typeof t&&(n=t,t=null),s?t="buffer":!t&&(t=r.defaultEncoding),"function"!=typeof n&&(n=d),r.ending?c(this,n):(s||u(this,r,e,n))&&(r.pendingcb++,a=f(this,r,s,e,t,n)),a},l.prototype.cork=function(){this._writableState.corked++},l.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,!e.writing&&!e.corked&&!e.bufferProcessing&&e.bufferedRequest&&C(this,e))},l.prototype.setDefaultEncoding=function(e){if("string"==typeof e&&(e=e.toLowerCase()),!(-1<["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((e+"").toLowerCase())))throw new H(e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(l.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}}),Object.defineProperty(l.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),l.prototype._write=function(e,t,n){n(new F("_write()"))},l.prototype._writev=null,l.prototype.end=function(e,t,n){var r=this._writableState;return"function"==typeof e?(n=e,e=null,t=null):"function"==typeof t&&(n=t,t=null),null!==e&&void 0!==e&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||T(this,r,n),this},Object.defineProperty(l.prototype,"writableLength",{enumerable:!1,get:function(){return this._writableState.length}}),Object.defineProperty(l.prototype,"destroyed",{enumerable:!1,get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),l.prototype.destroy=D.destroy,l.prototype._undestroy=D.undestroy,l.prototype._destroy=function(e,t){t(e)}}).call(this)}).call(this,e("_process"),"undefined"==typeof __webpack_require__.g?"undefined"==typeof self?"undefined"==typeof window?{}:window:self:__webpack_require__.g)}
407,{"../errors":15,"./_stream_duplex":16,"./internal/streams/destroy":23,"./internal/streams/state":27,"./internal/streams/stream":28,_process:12,buffer:3,inherits:10,"util-deprecate":32}],21:[function(e,t){(function(n){(function(){'use strict';function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){return{value:e,done:t}}function o(e){var t=e[c];if(null!==t){var n=e[h].read();null!==n&&(e[g]=null,e[c]=null,e[u]=null,t(a(n,!1)))}}function i(e){n.nextTick(o,e)}function d(e,t){return function(n,r){e.then(function(){return t[f]?void n(a(void 0,!0)):void t[_](n,r)},r)}}var s,l=e("./end-of-stream"),c=Symbol("lastResolve"),u=Symbol("lastReject"),p=Symbol("error"),f=Symbol("ended"),g=Symbol("lastPromise"),_=Symbol("handlePromise"),h=Symbol("stream"),m=Object.getPrototypeOf(function(){}),b=Object.setPrototypeOf((s={get stream(){return this[h]},next:function(){var e=this,t=this[p];if(null!==t)return Promise.reject(t);if(this[f])return Promise.resolve(a(void 0,!0));if(this[h].destroyed)return new Promise(function(t,r){n.nextTick(function(){e[p]?r(e[p]):t(a(void 0,!0))})});var r,o=this[g];if(o)r=new Promise(d(o,this));else{var i=this[h].read();if(null!==i)return Promise.resolve(a(i,!1));r=new Promise(this[_])}return this[g]=r,r}},r(s,Symbol.asyncIterator,function(){return this}),r(s,"return",function(){var e=this;return new Promise(function(t,n){e[h].destroy(null,function(e){return e?void n(e):void t(a(void 0,!0))})})}),s),m);t.exports=function(e){var t,n=Object.create(b,(t={},r(t,h,{value:e,writable:!0}),r(t,c,{value:null,writable:!0}),r(t,u,{value:null,writable:!0}),r(t,p,{value:null,writable:!0}),r(t,f,{value:e._readableState.endEmitted,writable:!0}),r(t,_,{value:function(e,t){var r=n[h].read();r?(n[g]=null,n[c]=null,n[u]=null,e(a(r,!1))):(n[c]=e,n[u]=t)},writable:!0}),t));return n[g]=null,l(e,function(e){if(e&&"ERR_STREAM_PREMATURE_CLOSE"!==e.code){var t=n[u];return null!==t&&(n[g]=null,n[c]=null,n[u]=null,t(e)),void(n[p]=e)}var r=n[c];null!==r&&(n[g]=null,n[c]=null,n[u]=null,r(a(void 0,!0))),n[f]=!0}),e.on("readable",i.bind(null,n)),n}}).call(this)}).call(this,e("_process"))},{"./end-of-stream":24,_process:12}],22:[function(e,t){'use strict';function n(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function r(e){for(var t,r=1;r<arguments.length;r++)t=null==arguments[r]?{}:arguments[r],r%2?n(Object(t),!0).forEach(function(n){a(e,n,t[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):n(Object(t)).forEach(function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))});return e}function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){for(var n,r=0;r<t.length;r++)n=t[r],n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}function d(e,t,n){return t&&i(e.prototype,t),n&&i(e,n),e}function s(e,t,n){u.prototype.copy.call(e,t,n)}var l=e("buffer"),u=l.Buffer,p=e("util"),f=p.inspect,g=f&&f.custom||"inspect";t.exports=function(){function e(){o(this,e),this.head=null,this.tail=null,this.length=0}return d(e,[{key:"push",value:function(e){var t={data:e,next:null};0<this.length?this.tail.next=t:this.head=t,this.tail=t,++this.length}},{key:"unshift",value:function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length}},{key:"shift",value:function(){if(0!==this.length){var e=this.head.data;return this.head=1===this.length?this.tail=null:this.head.next,--this.length,e}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(e){if(0===this.length)return"";for(var t=this.head,n=""+t.data;t=t.next;)n+=e+t.data;return n}},{key:"concat",value:function(e){if(0===this.length)return u.alloc(0);for(var t=u.allocUnsafe(e>>>0),n=this.head,r=0;n;)s(n.data,t,r),r+=n.data.length,n=n.next;return t}},{key:"consume",value:function(e,t){var n;return e<this.head.data.length?(n=this.head.data.slice(0,e),this.head.data=this.head.data.slice(e)):e===this.head.data.length?n=this.shift():n=t?this._getString(e):this._getBuffer(e),n}},{key:"first",value:function(){return this.head.data}},{key:"_getString",value:function(e){var t=this.head,r=1,a=t.data;for(e-=a.length;t=t.next;){var o=t.data,i=e>o.length?o.length:e;if(a+=i===o.length?o:o.slice(0,e),e-=i,0===e){i===o.length?(++r,this.head=t.next?t.next:this.tail=null):(this.head=t,t.data=o.slice(i));break}++r}return this.length-=r,a}},{key:"_getBuffer",value:function(e){var t=u.allocUnsafe(e),r=this.head,a=1;for(r.data.copy(t),e-=r.data.length;r=r.next;){var o=r.data,i=e>o.length?o.length:e;if(o.copy(t,t.length-e,0,i),e-=i,0===e){i===o.length?(++a,this.head=r.next?r.next:this.tail=null):(this.head=r,r.data=o.slice(i));break}++a}return this.length-=a,t}},{key:g,value:function(e,t){return f(this,r({},t,{depth:0,customInspect:!1}))}}]),e}()},{buffer:3,util:2}],23:[function(e,t){(function(e){(function(){'use strict';function n(e,t){a(e,t),r(e)}function r(e){e._writableState&&!e._writableState.emitClose||e._readableState&&!e._readableState.emitClose||e.emit("close")}function a(e,t){e.emit("error",t)}t.exports={destroy:function(t,o){var i=this,d=this._readableState&&this._readableState.destroyed,s=this._writableState&&this._writableState.destroyed;return d||s?(o?o(t):t&&(this._writableState?!this._writableState.errorEmitted&&(this._writableState.errorEmitted=!0,e.nextTick(a,this,t)):e.nextTick(a,this,t)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(t||null,function(t){!o&&t?i._writableState?i._writableState.errorEmitted?e.nextTick(r,i):(i._writableState.errorEmitted=!0,e.nextTick(n,i,t)):e.nextTick(n,i,t):o?(e.nextTick(r,i),o(t)):e.nextTick(r,i)}),this)},undestroy:function(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)},errorOrDestroy:function(e,t){var n=e._readableState,r=e._writableState;n&&n.autoDestroy||r&&r.autoDestroy?e.destroy(t):e.emit("error",t)}}}).call(this)}).call(this,e("_process"))},{_process:12}],24:[function(e,t){'use strict';function n(e){var t=!1;return function(){if(!t){t=!0;for(var n=arguments.length,r=Array(n),a=0;a<n;a++)r[a]=arguments[a];e.apply(this,r)}}}function r(){}function a(e){return e.setHeader&&"function"==typeof e.abort}function o(e,t,d){if("function"==typeof t)return o(e,null,t);t||(t={}),d=n(d||r);var s=t.readable||!1!==t.readable&&e.readable,l=t.writable||!1!==t.writable&&e.writable,c=function(){e.writable||p()},u=e._writableState&&e._writableState.finished,p=function(){l=!1,u=!0,s||d.call(e)},f=e._readableState&&e._readableState.endEmitted,g=function(){s=!1,f=!0,l||d.call(e)},_=function(t){d.call(e,t)},h=function(){var t;return s&&!f?(e._readableState&&e._readableState.ended||(t=new i),d.call(e,t)):l&&!u?(e._writableState&&e._writableState.ended||(t=new i),d.call(e,t)):void 0},m=function(){e.req.on("finish",p)};return a(e)?(e.on("complete",p),e.on("abort",h),e.req?m():e.on("request",m)):l&&!e._writableState&&(e.on("end",c),e.on("close",c)),e.on("end",g),e.on("finish",p),!1!==t.error&&e.on("error",_),e.on("close",h),function(){e.removeListener("complete",p),e.removeListener("abort",h),e.removeListener("request",m),e.req&&e.req.removeListener("finish",p),e.removeListener("end",c),e.removeListener("close",c),e.removeListener("finish",p),e.removeListener("end",g),e.removeListener("error",_),e.removeListener("close",h)}}var i=e("../../../errors").codes.ERR_STREAM_PREMATURE_CLOSE;t.exports=o},{"../../../errors":15}],25:[function(e,t){t.exports=function(){throw new Error("Readable.from is not available in the browser")}},{}],26:[function(e,t){'use strict';function n(e){var t=!1;return function(){t||(t=!0,e.apply(void 0,arguments))}}function r(e){if(e)throw e}function a(e){return e.setHeader&&"function"==typeof e.abort}function o(t,r,o,i){i=n(i);var d=!1;t.on("close",function(){d=!0}),l===void 0&&(l=e("./end-of-stream")),l(t,{readable:r,writable:o},function(e){return e?i(e):void(d=!0,i())});var s=!1;return function(e){if(!d)return s?void 0:(s=!0,a(t)?t.abort():"function"==typeof t.destroy?t.destroy():void i(e||new p("pipe")))}}function i(e){e()}function d(e,t){return e.pipe(t)}function s(e){return e.length?"function"==typeof e[e.length-1]?e.pop():r:r}var l,c=e("../../../errors").codes,u=c.ERR_MISSING_ARGS,p=c.ERR_STREAM_DESTROYED;t.exports=function(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];var r=s(t);if(Array.isArray(t[0])&&(t=t[0]),2>t.length)throw new u("streams");var a,l=t.map(function(e,n){var d=n<t.length-1;return o(e,d,0<n,function(e){a||(a=e),e&&l.forEach(i),d||(l.forEach(i),r(a
407))})});return t.reduce(d)}},{"../../../errors":15,"./end-of-stream":24}],27:[function(e,n){'use strict';function r(e,t,n){return null==e.highWaterMark?t?e[n]:null:e.highWaterMark}var a=e("../../../errors").codes.ERR_INVALID_OPT_VALUE;n.exports={getHighWaterMark:function(e,n,o,i){var d=r(n,i,o);if(null!=d){if(!(isFinite(d)&&t(d)===d)||0>d){var s=i?o:"highWaterMark";throw new a(s,d)}return t(d)}return e.objectMode?16:16384}}},{"../../../errors":15}],28:[function(e,t){t.exports=e("events").EventEmitter},{events:7}],29:[function(e,t,n){n=t.exports=e("./lib/_stream_readable.js"),n.Stream=n,n.Readable=n,n.Writable=e("./lib/_stream_writable.js"),n.Duplex=e("./lib/_stream_duplex.js"),n.Transform=e("./lib/_stream_transform.js"),n.PassThrough=e("./lib/_stream_passthrough.js"),n.finished=e("./lib/internal/streams/end-of-stream.js"),n.pipeline=e("./lib/internal/streams/pipeline.js")},{"./lib/_stream_duplex.js":16,"./lib/_stream_passthrough.js":17,"./lib/_stream_readable.js":18,"./lib/_stream_transform.js":19,"./lib/_stream_writable.js":20,"./lib/internal/streams/end-of-stream.js":24,"./lib/internal/streams/pipeline.js":26}],30:[function(e,t,n){function r(e,t){for(var n in e)t[n]=e[n]}function a(e,t,n){return i(e,t,n)}/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */var o=e("buffer"),i=o.Buffer;i.from&&i.alloc&&i.allocUnsafe&&i.allocUnsafeSlow?t.exports=o:(r(o,n),n.Buffer=a),a.prototype=Object.create(i.prototype),r(i,a),a.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return i(e,t,n)},a.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var r=i(e);return void 0===t?r.fill(0):"string"==typeof n?r.fill(t,n):r.fill(t),r},a.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return i(e)},a.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o.SlowBuffer(e)}},{buffer:3}],31:[function(e,t,n){'use strict';function r(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0;}}function a(e){var t=r(e);if("string"!=typeof t&&(m.isEncoding===b||!b(e)))throw new Error("Unknown encoding: "+e);return t||e}function o(e){this.encoding=a(e);var t;switch(this.encoding){case"utf16le":this.text=u,this.end=p,t=4;break;case"utf8":this.fillLast=c,t=4;break;case"base64":this.text=f,this.end=g,t=3;break;default:return this.write=_,void(this.end=h);}this.lastNeed=0,this.lastTotal=0,this.lastChar=m.allocUnsafe(t)}function d(e){if(127>=e)return 0;return 6==e>>5?2:14==e>>4?3:30==e>>3?4:2==e>>6?-1:-2}function s(e,t,n){var r=t.length-1;if(r<n)return 0;var a=d(t[r]);return 0<=a?(0<a&&(e.lastNeed=a-1),a):--r<n||-2===a?0:(a=d(t[r]),0<=a)?(0<a&&(e.lastNeed=a-2),a):--r<n||-2===a?0:(a=d(t[r]),0<=a?(0<a&&(2===a?a=0:e.lastNeed=a-3),a):0)}function l(e,t){if(128!=(192&t[0]))return e.lastNeed=0,"\uFFFD";if(1<e.lastNeed&&1<t.length){if(128!=(192&t[1]))return e.lastNeed=1,"\uFFFD";if(2<e.lastNeed&&2<t.length&&128!=(192&t[2]))return e.lastNeed=2,"\uFFFD"}}function c(e){var t=this.lastTotal-this.lastNeed,n=l(this,e,t);return void 0===n?this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):void(e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length):n}function u(e,t){if(0==(e.length-t)%2){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(55296<=r&&56319>=r)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function p(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function f(e,t){var r=(e.length-t)%3;return 0==r?e.toString("base64",t):(this.lastNeed=3-r,this.lastTotal=3,1==r?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-r))}function g(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function _(e){return e.toString(this.encoding)}function h(e){return e&&e.length?this.write(e):""}var m=e("safe-buffer").Buffer,b=m.isEncoding||function(e){switch(e=""+e,e&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1;}};n.StringDecoder=o,o.prototype.write=function(e){if(0===e.length)return"";var t,n;if(this.lastNeed){if(t=this.fillLast(e),void 0===t)return"";n=this.lastNeed,this.lastNeed=0}else n=0;return n<e.length?t?t+this.text(e,n):this.text(e,n):t||""},o.prototype.end=function(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"\uFFFD":t},o.prototype.text=function(e,t){var n=s(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)},o.prototype.fillLast=function(e){return this.lastNeed<=e.length?(e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):void(e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,e.length),this.lastNeed-=e.length)}},{"safe-buffer":30}],32:[function(e,t){(function(e){(function(){function n(t){try{if(!e.localStorage)return!1}catch(e){return!1}var n=e.localStorage[t];return null!=n&&"true"===(n+"").toLowerCase()}t.exports=function(e,t){function r(){if(!a){if(n("throwDeprecation"))throw new Error(t);else n("traceDeprecation")?console.trace(t):console.warn(t);a=!0}return e.apply(this,arguments)}if(n("noDeprecation"))return e;var a=!1;return r}}).call(this)}).call(this,"undefined"==typeof __webpack_require__.g?"undefined"==typeof self?"undefined"==typeof window?{}:window:self:__webpack_require__.g)},{}],"/":[function(e,t){function n(e){return e.replace(/a=ice-options:trickle\s\n/g,"")}function r(e){console.warn(e)}/*! simple-peer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */const a=e("debug")("simple-peer"),o=e("get-browser-rtc"),i=e("randombytes"),d=e("readable-stream"),s=e("queue-microtask"),l=e("err-code"),{Buffer:c}=e("buffer"),u=65536;class p extends d.Duplex{constructor(e){if(e=Object.assign({allowHalfOpen:!1},e),super(e),this._id=i(4).toString("hex").slice(0,7),this._debug("new peer %o",e),this.channelName=e.initiator?e.channelName||i(20).toString("hex"):null,this.initiator=e.initiator||!1,this.channelConfig=e.channelConfig||p.channelConfig,this.channelNegotiated=this.channelConfig.negotiated,this.config=Object.assign({},p.config,e.config),this.offerOptions=e.offerOptions||{},this.answerOptions=e.answerOptions||{},this.sdpTransform=e.sdpTransform||(e=>e),this.streams=e.streams||(e.stream?[e.stream]:[]),this.trickle=void 0===e.trickle||e.trickle,this.allowHalfTrickle=void 0!==e.allowHalfTrickle&&e.allowHalfTrickle,this.iceCompleteTimeout=e.iceCompleteTimeout||5000,this.destroyed=!1,this.destroying=!1,this._connected=!1,this.remoteAddress=void 0,this.remoteFamily=void 0,this.remotePort=void 0,this.localAddress=void 0,this.localFamily=void 0,this.localPort=void 0,this._wrtc=e.wrtc&&"object"==typeof e.wrtc?e.wrtc:o(),!this._wrtc)if("undefined"==typeof window)throw l
vendor: 3,186 bytes, line 407
407(new Error("No WebRTC support: Specify `opts.wrtc` option in this environment"),"ERR_WEBRTC_SUPPORT");else throw l(new Error("No WebRTC support: Not a supported browser"),"ERR_WEBRTC_SUPPORT");this._pcReady=!1,this._channelReady=!1,this._iceComplete=!1,this._iceCompleteTimer=null,this._channel=null,this._pendingCandidates=[],this._isNegotiating=!1,this._firstNegotiation=!0,this._batchedNegotiation=!1,this._queuedNegotiation=!1,this._sendersAwaitingStable=[],this._senderMap=new Map,this._closingInterval=null,this._remoteTracks=[],this._remoteStreams=[],this._chunk=null,this._cb=null,this._interval=null;try{this._pc=new this._wrtc.RTCPeerConnection(this.config)}catch(e){return void this.destroy(l(e,"ERR_PC_CONSTRUCTOR"))}this._isReactNativeWebrtc="number"==typeof this._pc._peerConnectionId,this._pc.oniceconnectionstatechange=()=>{this._onIceStateChange()},this._pc.onicegatheringstatechange=()=>{this._onIceStateChange()},this._pc.onconnectionstatechange=()=>{this._onConnectionStateChange()},this._pc.onsignalingstatechange=()=>{this._onSignalingStateChange()},this._pc.onicecandidate=e=>{this._onIceCandidate(e)},"object"==typeof this._pc.peerIdentity&&this._pc.peerIdentity.catch(e=>{this.destroy(l(e,"ERR_PC_PEER_IDENTITY"))}),this.initiator||this.channelNegotiated?this._setupData({channel:this._pc.createDataChannel(this.channelName,this.channelConfig)}):this._pc.ondatachannel=e=>{this._setupData(e)},this.streams&&this.streams.forEach(e=>{this.addStream(e)}),this._pc.ontrack=e=>{this._onTrack(e)},this._debug("initial negotiation"),this._needsNegotiation(),this._onFinishBound=()=>{this._onFinish()},this.once("finish",this._onFinishBound)}get bufferSize(){return this._channel&&this._channel.bufferedAmount||0}get connected(){return this._connected&&"open"===this._channel.readyState}address(){return{port:this.localPort,family:this.localFamily,address:this.localAddress}}signal(e){if(!this.destroying){if(this.destroyed)throw l(new Error("cannot signal after peer is destroyed"),"ERR_DESTROYED");if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e={}}this._debug("signal()"),e.renegotiate&&this.initiator&&(this._debug("got request to renegotiate"),this._needsNegotiation()),e.transceiverRequest&&this.initiator&&(this._debug("got request for transceiver"),this.addTransceiver(e.transceiverRequest.kind,e.transceiverRequest.init)),e.candidate&&(this._pc.remoteDescription&&this._pc.remoteDescription.type?this._addIceCandidate(e.candidate):this._pendingCandidates.push(e.candidate)),e.sdp&&this._pc.setRemoteDescription(new this._wrtc.RTCSessionDescription(e)).then(()=>{this.destroyed||(this._pendingCandidates.forEach(e=>{this._addIceCandidate(e)}),this._pendingCandidates=[],"offer"===this._pc.remoteDescription.type&&this._createAnswer())}).catch(e=>{this.destroy(l(e,"ERR_SET_REMOTE_DESCRIPTION"))}),e.sdp||e.candidate||e.renegotiate||e.transceiverRequest||this.destroy(l(new Error("signal() called with invalid signal data"),"ERR_SIGNALING"))}}_addIceCandidate(e){const t=new this._wrtc.RTCIceCandidate(e);this._pc.addIceCandidate(t).catch(e=>{!t.address||t.address.endsWith(".local")?r("Ignoring unsupported ICE candidate."):this.destroy(l(e,"ERR_ADD_ICE_CA
407NDIDATE"))})}send(e){if(!this.destroying){if(this.destroyed)throw l(new Error("cannot send after peer is destroyed"),"ERR_DESTROYED");this._channel.send(e)}}addTransceiver(e,t){if(!this.destroying){if(this.destroyed)throw l(new Error("cannot addTransceiver after peer is destroyed"),"ERR_DESTROYED");if(this._debug("addTransceiver()"),this.initiator)try{this._pc.addTransceiver(e,t),this._needsNegotiation()}catch(e){this.destroy(l(e,"ERR_ADD_TRANSCEIVER"))}else this.emit("signal",{type:"transceiverRequest",transceiverRequest:{kind:e,init:t}})}}addStream(e){if(!this.destroying){if(this.destroyed)throw l(new Error("cannot addStream after peer is destroyed"),"ERR_DESTROYED");this._debug("addStream()"),e.getTracks().forEach(t=>{this.addTrack(t,e)})}}addTrack(e,t){if(this.destroying)return;if(this.destroyed)throw l(new Error("cannot addTrack after peer is destroyed"),"ERR_DESTROYED");this._debug("addTrack()");const n=this._senderMap.get(e)||new Map;let r=n.get(t);if(!r)r=this._pc.addTrack(e,t),n.set(t,r),this._senderMap.set(e,n),this._needsNegotiation();
407else if(r.removed)throw l(new Error("Track has been removed. You should enable/disable tracks that you want to re-add."),"ERR_SENDER_REMOVED");else throw l(new Error("Track has already been added to that stream."),"ERR_SENDER_ALREADY_ADDED")}replaceTrack(e,t,n){if(this.destroying)return;if(this.destroyed)throw l(new Error("cannot replaceTrack after peer is destroyed"),"ERR_DESTROYED");this._debug("replaceTrack()");const r=this._senderMap.get(e),a=r?r.get(n):null;if(!a)throw l(new Error("Cannot replace track that was never added."),"ERR_TRACK_NOT_ADDED");t&&this._senderMap.set(t,r),null==a.replaceTrack?this.destroy(l(new Error("replaceTrack is not supported in this browser"),"ERR_UNSUPPORTED_REPLACETRACK")):a.replaceTrack(t)}removeTrack(e,t){if(this.destroying)return;if(this.destroyed)throw l(new Error("cannot removeTrack after peer is destroyed"),"ERR_DESTROYED");this._debug("removeSender()");const n=this._senderMap.get(e),r=n?n.get(t):null;if(!r)throw l(new Error("Cannot remove track that was never added."),"ERR_TRACK_NOT_ADDED");try{r.removed=!0,this._pc.removeTrack(r)}catch(e){"NS_ERROR_UNEXPECTED"===e.name?this._sendersAwaitingStable.push(r):this.destroy(l(e,"ERR_REMOVE_TRACK"))}this._needsNegotiation()}removeStream(e){if(!this.destroying){if(this.destroyed)throw l(new Error("cannot removeStream after peer is destroyed"),"ERR_DESTROYED");this._debug("removeSenders()"),e.getTracks().forEach(t=>{this.removeTrack(t,e)})}}_needsNegotiation(){this._debug("_needsNegotiation"),this._batchedNegotiation||(this._batchedNegotiation=!0,s(()=>{this._batchedNegotiation=!1,this.initiator||!this._firstNegotiation?(this._debug("starting batched negotiation"),this.negotiate()):this._debug("non-initiator initial negotiation request discarded"),this._firstNegotiation=!1}))}negotiate(){if(!this.destroying){if(this.destroyed)throw l(new Error("cannot negotiate after peer is destroyed"),"ERR_DESTROYED");this.initiator?this._isNegotiating?(this._queuedNegotiation=!0,this._debug("already negotiating, queueing")):(this._debug("start negotiation"),setTimeout(()=>{this._createOffer()},0)):this._isNegotiating?(this._queuedNegotiation=!0,this._debug("already negotiating, queueing")):(this._debug("requesting negotiation from initiator"),this.emit("signal",{type:"renegotiate",renegotiate:!0})),this._isNegotiating=!0}}destroy(e){this._destroy(e,()=>{})}_destroy(e,t){this.destroyed||this.destroying||(this.destroying=!0,this._debug("destroying (error: %s)",e&&(e.message||e)),s(()=>{if(this.destroyed=!0,this.destroying=!1,this._debug("destroy (error: %s)",e&&(e.message||e)),this.readable=this.writable=!1,this._readableState.ended||this.push(null),this._writableState.finished||this.end(),this._connected=!1,this._pcReady=!1,this._channelReady=!1,this._remoteTracks=null,this._remoteStreams=null,this._senderMap=null,clearInterval(this._closingInterval),this._closingInterval=null,clearInterval(this._interval),this._interval=null,this._chunk=null,this._cb=null,this._onFinishBound&&this.removeListener("finish",this._onFinishBound),this._onFinishBound=null,this._channel){try{this._channel.close()}catch(e){}this._channel.onmessage=null,this._channel.onopen=null,this._channel.onclose=null,this._channel.onerror=null}if(this._pc){try{this._pc.close()}catch(e){}this._pc.oniceconnectionstatechange=null,this._pc.onicegatheringstatechange=null,this._pc.onsignalingstatechange=null,this._pc.onicecandidate=null,this._pc.ontrack=null,this._pc.ondatachannel=null}this._pc=null,this._channel=null,e&&this.emit("error",e),this.emit("close"),t()}))}_setupData(e){if(!e.channel)return this.destroy(l(new Error("Data channel event is missing `channel` property"),"ERR_DATA_CHANNEL"));this._channel=e.channel,this._channel.binaryType="arraybuffer","number"==typeof this._channel.bufferedAmountLowThreshold&&(this._channel.bufferedAmountLowThreshold=u),this.channelName=this._channel.label,this._channel.onmessage=e=>{this._onChannelMessage(e)},this._channel.onbufferedamountlow=()=>{this._onChannelBufferedAmountLow()},this._channel.onopen=()=>{this._onChannelOpen()},this._channel.onclose=()=>{this._onChannelClose()},this._channel.onerror=e=>{const t=e.error instanceof Error?e.error:new Error(`Datachannel error: ${e.message} ${e.filename}:${e.lineno}:${e.colno}`);this.destroy(l(t,"ERR_DATA_CHANNEL"))};let t=!1;this._closingInterval=setInterval(()=>{this._channel&&"closing"===this._channel.readyState?(t&&this._onChannelClose(),t=!0):t=!1},5000)}_read(){}_write(e,t,n){if(this.destroyed)return n(l(new Error("cannot write after peer is destroyed"),"ERR_DATA_CHANNEL"));if(this._connected){try{this.send(e)}catch(e){return this.destroy(l(e,"ERR_DATA_CHANNEL"))}this._channel.bufferedAmount>u?(this._debug("start backpressure: bufferedAmount %d",this._channel.bufferedAmount),this._cb=n):n(null)}else this._debug("write before connect"),this._chunk=e,this._cb=n}
407_onFinish(){if(!this.destroyed){const e=()=>{setTimeout(()=>this.destroy(),1e3)};this._connected?e():this.once("connect",e)}}_startIceCompleteTimeout(){this.destroyed||this._iceCompleteTimer||(this._debug("started iceComplete timeout"),this._iceCompleteTimer=setTimeout(()=>{this._iceComplete||(this._iceComplete=!0,this._debug("iceComplete timeout completed"),this.emit("iceTimeout"),this.emit("_iceComplete"))},this.iceCompleteTimeout))}_createOffer(){this.destroyed||this._pc.createOffer(this.offerOptions).then(e=>{if(this.destroyed)return;this.trickle||this.allowHalfTrickle||(e.sdp=n(e.sdp)),e.sdp=this.sdpTransform(e.sdp);const t=()=>{if(!this.destroyed){const t=this._pc.localDescription||e;this._debug("signal"),this.emit("signal",{type:t.type,sdp:t.sdp})}};this._pc.setLocalDescription(e).then(()=>{this._debug("createOffer success"),this.destroyed||(this.trickle||this._iceComplete?t():this.once("_iceComplete",t))}).catch(e=>{this.destroy(l(e,"ERR_SET_LOCAL_DESCRIPTION"))})}).catch(e=>{this.destroy(l(e,"ERR_CREATE_OFFER"))})}_requestMissingTransceivers(){this._pc.getTransceivers&&this._pc.getTransceivers().forEach(e=>{e.mid||!e.sender.track||e.requested||(e.requested=!0,this.addTransceiver(e.sender.track.kind))})}_createAnswer(){this.destroyed||this._pc.createAnswer(this.answerOptions).then(e=>{if(this.destroyed)return;this.trickle||this.allowHalfTrickle||(e.sdp=n(e.sdp)),e.sdp=this.sdpTransform(e.sdp);const t=()=>{if(!this.destroyed){const t=this._pc.localDescription||e;this._debug("signal"),this.emit("signal",{type:t.type,sdp:t.sdp}),this.initiator||this._requestMissingTransceivers()}};this._pc.setLocalDescription(e).then(()=>{this.destroyed||(this.trickle||this._iceComplete?t():this.once("_iceComplete",t))}).catch(e=>{this.destroy(l(e,"ERR_SET_LOCAL_DESCRIPTION"))})}).catch(e=>{this.destroy(l(e,"ERR_CREATE_ANSWER"))})}_onConnectionStateChange(){this.destroyed||"failed"===this._pc.connectionState&&this.destroy(l(new Error("Connection failed."),"ERR_CONNECTION_FAILURE"))}_onIceStateChange(){if(this.destroyed)return;const e=this._pc.iceConnectionState,t=this._pc.iceGatheringState;this._debug("iceStateChange (connection: %s) (gathering: %s)",e,t),this.emit("iceStateChange",e,t),("connected"===e||"completed"===e)&&(this._pcReady=!0,this._maybeReady()),"failed"===e&&this.destroy(l(new Error("Ice connection failed."),"ERR_ICE_CONNECTION_FAILURE")),"closed"===e&&this.destroy(l(new Error("Ice connection closed."),"ERR_ICE_CONNECTION_CLOSED"))}getStats(e){const t=e=>("[object Array]"===Object.prototype.toString.call(e.values)&&e.values.forEach(t=>{Object.assign(e,t)}),e);0===this._pc.getStats.length||this._isReactNativeWebrtc?this._pc.getStats().then(n=>{const r=[];n.forEach(e=>{r.push(t(e))}),e(null,r)},t=>e(t)):0<this._pc.getStats.length?this._pc.getStats(n=>{if(this.destroyed)return;const r=[];n.result().forEach(e=>{const n={};e.names().forEach(t=>{n[t]=e.stat(t)}),n.id=e.id,n.type=e.type,n.timestamp=e.timestamp,r.push(t(n))}),e(null,r)},t=>e(t)):e(null,[])}_maybeReady(){if(this._debug("maybeReady pc %s channel %s",this._pcReady,this._channelReady),this._connected||this._connecting||!this._pcReady||!this._channelReady)return;this._connecting=!0;const e=()=>{this.destroyed||this.getStats((t,n)=>{if(this.destroyed)return;t&&(n=[]);const r={},a={},o={};let i=!1;n.forEach(e=>{("remotecandidate"===e.type||"remote-candidate"===e.type)&&(r[e.id]=e),("localcandidate"===e.type||"local-candidate"===e.type)&&(a[e.id]=e),("candidatepair"===e.type||"candidate-pair"===e.type)&&(o[e.id]=e)});const d=e=>{i=!0;let t=a[e.localCandidateId];t&&(t.ip||t.address)?(this.localAddress=t.ip||t.address,this.localPort=+t.port):t&&t.ipAddress?(this.localAddress=t.ipAddress,this.localPort=+t.portNumber):"string"==typeof e.googLocalAddress&&(t=e.googLocalAddress.split(":"),this.localAddress=t[0],this.localPort=+t[1]),this.localAddress&&(this.localFamily=this.localAddress.includes(":")?"IPv6":"IPv4");let n=r[e.remoteCandidateId];n&&(n.ip||n.address)?(this.remoteAddress=n.ip||n.address,this.remotePort=+n.port):n&&n.ipAddress?(this.remoteAddress=n.ipAddress,this.remotePort=+n.portNumber):"string"==typeof e.googRemoteAddress&&(n=e.googRemoteAddress.split(":"),this.remoteAddress=n[0],this.remotePort=+n[1]),this.remoteAddress&&(this.remoteFamily=this.remoteAddress.includes(":")?"IPv6":"IPv4"),this._debug("connect local: %s:%s remote: %s:%s",this.localAddress,this.localPort,this.remoteAddress,this.remotePort)};
407if(n.forEach(e=>{"transport"===e.type&&e.selectedCandidatePairId&&d(o[e.selectedCandidatePairId]),("googCandidatePair"===e.type&&"true"===e.googActiveConnection||("candidatepair"===e.type||"candidate-pair"===e.type)&&e.selected)&&d(e)}),!i&&(!Object.keys(o).length||Object.keys(a).length))return void setTimeout(e,100);if(this._connecting=!1,this._connected=!0,this._chunk){try{this.send(this._chunk)}catch(e){return this.destroy(l(e,"ERR_DATA_CHANNEL"))}this._chunk=null,this._debug("sent chunk from \"write before connect\"");const e=this._cb;this._cb=null,e(null)}"number"!=typeof this._channel.bufferedAmountLowThreshold&&(this._interval=setInterval(()=>this._onInterval(),150),this._interval.unref&&this._interval.unref()),this._debug("connect"),this.emit("connect")})};e()}_onInterval(){this._cb&&this._channel&&!(this._channel.bufferedAmount>u)&&this._onChannelBufferedAmountLow()}_onSignalingStateChange(){this.destroyed||("stable"===this._pc.signalingState&&(this._isNegotiating=!1,this._debug("flushing sender queue",this._sendersAwaitingStable),this._sendersAwaitingStable.forEach(e=>{this._pc.removeTrack(e),this._queuedNegotiation=!0}),this._sendersAwaitingStable=[],this._queuedNegotiation?(this._debug("flushing negotiation queue"),this._queuedNegotiation=!1,this._needsNegotiation()):(this._debug("negotiated"),this.emit("negotiated"))),this._debug("signalingStateChange %s",this._pc.signalingState),this.emit("signalingStateChange",this._pc.signalingState))}_onIceCandidate(e){this.destroyed||(e.candidate&&this.trickle?this.emit("signal",{type:"candidate",candidate:{candidate:e.candidate.candidate,sdpMLineIndex:e.candidate.sdpMLineIndex,sdpMid:e.candidate.sdpMid}}):!e.candidate&&!this._iceComplete&&(this._iceComplete=!0,this.emit("_iceComplete")),e.candidate&&this._startIceCompleteTimeout())}_onChannelMessage(e){if(this.destroyed)return;let t=e.data;t instanceof ArrayBuffer&&(t=c.from(t)),this.push(t)}_onChannelBufferedAmountLow(){if(!this.destroyed&&this._cb){this._debug("ending backpressure: bufferedAmount %d",this._channel.bufferedAmount);const e=this._cb;this._cb=null,e(null)}}_onChannelOpen(){this._connected||this.destroyed||(this._debug("on channel open"),this._channelReady=!0,this._maybeReady())}_onChannelClose(){this.destroyed||(this._debug("on channel close"),this.destroy())}_onTrack(e){this.destroyed||e.streams.forEach(t=>{this._debug("on track"),this.emit("track",e.track,t),this._remoteTracks.push({track:e.track,stream:t}),this._remoteStreams.some(e=>e.id===t.id)||(this._remoteStreams.push(t),s(()=>{this._debug("on stream"),this.emit("stream",t)}))})}_debug(){const e=[].slice.call(arguments);e[0]="["+this._id+"] "+e[0],a.apply(null,e)}}p.WEBRTC_SUPPORT=!!o(),p.config={iceServers:[{urls:["stun:stun.l.google.com:19302","stun:global.stun.twilio.com:3478"]}],sdpSemantics:"unified-plan"},p.channelConfig={},t.exports=p},{buffer:3,debug:4,"err-code":6,"get-browser-rtc":8,"queue-microtask":13,randombytes:14,"readable-stream":29}]},{},[])("/")}); 408 409/***/ }) 410 411/******/ }); 412/************************************************************************/ 413/******/ // The module cache 414/******/ var __webpack_module_cache__ = {}; 415/******/ 416/******/ // The require function 417/******/ function __webpack_require__(moduleId) { 418/******/ // Check if module is in cache 419/******/ var cachedModule = __webpack_module_cache__[moduleId]; 420/******/ if (cachedModule !== undefined) { 421/******/ return cachedModule.exports; 422/******/ } 423/******/ // Create a new module (and put it into the cache) 424/******/ var module = __webpack_module_cache__[moduleId] = { 425/******/ // no module.id needed 426/******/ // no module.loaded needed 427/******/ exports: {} 428/******/ }; 429/******/ 430/******/ // Execute the module function 431/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); 432/******/ 433/******/ // Return the exports of the module 434/******/ return module.exports; 435/******/ } 436/******/ 437/************************************************************************/ 438/******/ /* webpack/runtime/compat get default export */ 439/******/ (() => { 440/******/ // getDefaultExport function for compatibility with non-harmony modules 441/******/ __webpack_require__.n = (module) => {
vendor: 2,010 bytes, lines 442-494
442/******/ var getter = module && module.__esModule ? 443/******/ () => (module['default']) : 444/******/ () => (module); 445/******/ __webpack_require__.d(getter, { a: getter }); 446/******/ return getter; 447/******/ }; 448/******/ })(); 449/******/ 450/******/ /* webpack/runtime/define property getters */ 451/******/ (() => { 452/******/ // define getter functions for harmony exports 453/******/ __webpack_require__.d = (exports, definition) => { 454/******/ for(var key in definition) { 455/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { 456/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); 457/******/ } 458/******/ } 459/******/ }; 460/******/ })(); 461/******/ 462/******/ /* webpack/runtime/global */ 463/******/ (() => { 464/******/ __webpack_require__.g = (function() { 465/******/ if (typeof globalThis === 'object') return globalThis; 466/******/ try { 467/******/ return this || new Function('return this')(); 468/******/ } catch (e) { 469/******/ if (typeof window === 'object') return window; 470/******/ } 471/******/ })(); 472/******/ })(); 473/******/ 474/******/ /* webpack/runtime/hasOwnProperty shorthand */ 475/******/ (() => { 476/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) 477/******/ })(); 478/******/ 479/******/ /* webpack/runtime/make namespace object */ 480/******/ (() => { 481/******/ // define __esModule on exports 482/******/ __webpack_require__.r = (exports) => { 483/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 484/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 485/******/ } 486/******/ Object.defineProperty(exports, '__esModule', { value: true }); 487/******/ }; 488/******/ })(); 489/******/ 490/************************************************************************/ 491var __webpack_exports__ = {}; 492// This entry need to be wrapped in an IIFE because it need to be in strict mode. 493(() => { 494"use strict";
495// ESM COMPAT FLAG 496__webpack_require__.r(__webpack_exports__); 497 498// EXPORTS 499__webpack_require__.d(__webpack_exports__, { 500 "EntityProvider": () => (/* reexport */ EntityProvider), 501 "__experimentalFetchLinkSuggestions": () => (/* reexport */ _experimental_fetch_link_suggestions), 502 "__experimentalFetchUrlData": () => (/* reexport */ _experimental_fetch_url_data), 503 "__experimentalUseEntityRecord": () => (/* reexport */ __experimentalUseEntityRecord), 504 "__experimentalUseEntityRecords": () => (/* reexport */ __experimentalUseEntityRecords), 505 "__experimentalUseResourcePermissions": () => (/* reexport */ __experimentalUseResourcePermissions), 506 "store": () => (/* binding */ store), 507 "useEntityBlockEditor": () => (/* reexport */ useEntityBlockEditor), 508 "useEntityId": () => (/* reexport */ useEntityId), 509 "useEntityProp": () => (/* reexport */ useEntityProp), 510 "useEntityRecord": () => (/* reexport */ useEntityRecord), 511 "useEntityRecords": () => (/* reexport */ useEntityRecords), 512 "useResourcePermissions": () => (/* reexport */ useResourcePermissions) 513}); 514 515// NAMESPACE OBJECT: ./packages/core-data/build-module/actions.js 516var build_module_actions_namespaceObject = {}; 517__webpack_require__.r(build_module_actions_namespaceObject); 518__webpack_require__.d(build_module_actions_namespaceObject, { 519 "__experimentalBatch": () => (__experimentalBatch), 520 "__experimentalReceiveCurrentGlobalStylesId": () => (__experimentalReceiveCurrentGlobalStylesId), 521 "__experimentalReceiveThemeBaseGlobalStyles": () => (__experimentalReceiveThemeBaseGlobalStyles), 522 "__experimentalReceiveThemeGlobalStyleVariations": () => (__experimentalReceiveThemeGlobalStyleVariations), 523 "__experimentalSaveSpecifiedEntityEdits": () => (__experimentalSaveSpecifiedEntityEdits), 524 "__unstableCreateUndoLevel": () => (__unstableCreateUndoLevel), 525 "addEntities": () => (addEntities), 526 "deleteEntityRecord": () => (deleteEntityRecord), 527 "editEntityRecord": () => (editEntityRecord), 528 "receiveAutosaves": () => (receiveAutosaves), 529 "receiveCurrentTheme": () => (receiveCurrentTheme), 530 "receiveCurrentUser": () => (receiveCurrentUser), 531 "receiveEmbedPreview": () => (receiveEmbedPreview), 532 "receiveEntityRecords": () => (receiveEntityRecords), 533 "receiveNavigationFallbackId": () => (receiveNavigationFallbackId), 534 "receiveThemeGlobalStyleRevisions": () => (receiveThemeGlobalStyleRevisions), 535 "receiveThemeSupports": () => (receiveThemeSupports), 536 "receiveUploadPermissions": () => (receiveUploadPermissions), 537 "receiveUserPermission": () => (receiveUserPermission), 538 "receiveUserQuery": () => (receiveUserQuery), 539 "redo": () => (redo), 540 "saveEditedEntityRecord": () => (saveEditedEntityRecord), 541 "saveEntityRecord": () => (saveEntityRecord), 542 "undo": () => (undo) 543}); 544 545// NAMESPACE OBJECT: ./packages/core-data/build-module/selectors.js 546var build_module_selectors_namespaceObject = {}; 547__webpack_require__.r(build_module_selectors_namespaceObject); 548__webpack_require__.d(build_module_selectors_namespaceObject, { 549 "__experimentalGetCurrentGlobalStylesId": () => (__experimentalGetCurrentGlobalStylesId), 550 "__experimentalGetCurrentThemeBaseGlobalStyles": () => (__experimentalGetCurrentThemeBaseGlobalStyles), 551 "__experimentalGetCurrentThemeGlobalStylesVariations": () => (__experimentalGetCurrentThemeGlobalStylesVariations), 552 "__experimentalGetDirtyEntityRecords": () => (__experimentalGetDirtyEntityRecords), 553 "__experimentalGetEntitiesBeingSaved": () => (__experimentalGetEntitiesBeingSaved), 554 "__experimentalGetEntityRecordNoResolver": () => (__experimentalGetEntityRecordNoResolver), 555 "__experimentalGetTemplateForLink": () => (__experimentalGetTemplateForLink), 556 "canUser": () => (canUser), 557 "canUserEditEntityRecord": () => (canUserEditEntityRecord), 558 "getAuthors": () => (getAuthors), 559 "getAutosave": () => (getAutosave), 560 "getAutosaves": () => (getAutosaves), 561 "getBlockPatternCategories": () => (getBlockPatternCategories), 562 "getBlockPatterns": () => (getBlockPatterns), 563 "getCurrentTheme": () => (getCurrentTheme), 564 "getCurrentThemeGlobalStylesRevisions": () => (getCurrentThemeGlobalStylesRevisions), 565 "getCurrentUser": () => (getCurrentUser), 566 "getEditedEntityRecord": () => (getEditedEntityRecord), 567 "getEmbedPreview": () => (getEmbedPreview), 568 "getEntitiesByKind": () => (getEntitiesByKind), 569 "getEntitiesConfig": () => (getEntitiesConfig), 570 "getEntity": () => (getEntity), 571 "getEntityConfig": () => (getEntityConfig), 572 "getEntityRecord": () => (getEntityRecord), 573 "getEntityRecordEdits": () => (getEntityRecordEdits), 574 "getEntityRecordNonTransientEdits": () => (getEntityRecordNonTransientEdits), 575 "getEntityRecords": () => (getEntityRecords), 576 "getLastEntityDeleteError": () => (getLastEntityDeleteError), 577 "getLastEntitySaveError": () => (getLastEntitySaveError), 578 "getRawEntityRecord": () => (getRawEntityRecord), 579 "getRedoEdit": () => (getRedoEdit), 580 "getReferenceByDistinctEdits": () => (getReferenceByDistinctEdits), 581 "getThemeSupports": () => (getThemeSupports), 582 "getUndoEdit": () => (getUndoEdit), 583 "getUserPatternCategories": () => (getUserPatternCategories), 584 "getUserQueryResults": () => (getUserQueryResults), 585 "hasEditsForEntityRecord": () => (hasEditsForEntityRecord), 586 "hasEntityRecords": () => (hasEntityRecords), 587 "hasFetchedAutosaves": () => (hasFetchedAutosaves), 588 "hasRedo": () => (hasRedo), 589 "hasUndo": () => (hasUndo), 590 "isAutosavingEntityRecord": () => (isAutosavingEntityRecord), 591 "isDeletingEntityRecord": () => (isDeletingEntityRecord), 592 "isPreviewEmbedFallback": () => (isPreviewEmbedFallback), 593 "isRequestingEmbedPreview": () => (isRequestingEmbedPreview), 594 "isSavingEntityRecord": () => (isSavingEntityRecord) 595}); 596 597// NAMESPACE OBJECT: ./packages/core-data/build-module/private-selectors.js 598var private_selectors_namespaceObject = {}; 599__webpack_require__.r(private_selectors_namespaceObject); 600__webpack_require__.d(private_selectors_namespaceObject, { 601 "getNavigationFallbackId": () => (getNavigationFallbackId), 602 "getUndoManager": () => (getUndoManager) 603}); 604 605// NAMESPACE OBJECT: ./packages/core-data/build-module/resolvers.js 606var resolvers_namespaceObject = {}; 607__webpack_require__.r(resolvers_namespaceObject); 608__webpack_require__.d(resolvers_namespaceObject, { 609 "__experimentalGetCurrentGlobalStylesId": () => (resolvers_experimentalGetCurrentGlobalStylesId), 610 "__experimentalGetCurrentThemeBaseGlobalStyles": () => (resolvers_experimentalGetCurrentThemeBaseGlobalStyles), 611 "__experimentalGetCurrentThemeGlobalStylesVariations": () => (resolvers_experimentalGetCurrentThemeGlobalStylesVariations), 612 "__experimentalGetTemplateForLink": () => (resolvers_experimentalGetTemplateForLink), 613 "canUser": () => (resolvers_canUser), 614 "canUserEditEntityRecord": () => (resolvers_canUserEditEntityRecord), 615 "getAuthors": () => (resolvers_getAuthors), 616 "getAutosave": () => (resolvers_getAutosave), 617 "getAutosaves": () => (resolvers_getAutosaves), 618 "getBlockPatternCategories": () => (resolvers_getBlockPatternCategories), 619 "getBlockPatterns": () => (resolvers_getBlockPatterns), 620 "getCurrentTheme": () => (resolvers_getCurrentTheme), 621 "getCurrentThemeGlobalStylesRevisions": () => (resolvers_getCurrentThemeGlobalStylesRevisions), 622 "getCurrentUser": () => (resolvers_getCurrentUser), 623 "getEditedEntityRecord": () => (resolvers_getEditedEntityRecord), 624 "getEmbedPreview": () => (resolvers_getEmbedPreview), 625 "getEntityRecord": () => (resolvers_getEntityRecord), 626 "getEntityRecords": () => (resolvers_getEntityRecords), 627 "getNavigationFallbackId": () => (resolvers_getNavigationFallbackId), 628 "getRawEntityRecord": () => (resolvers_getRawEntityRecord), 629 "getThemeSupports": () => (resolvers_getThemeSupports), 630 "getUserPatternCategories": () => (resolvers_getUserPatternCategories) 631}); 632 633;
633// CONCATENATED MODULE: external ["wp","data"] 634const external_wp_data_namespaceObject = window["wp"]["data"]; 635// EXTERNAL MODULE: ./node_modules/fast-deep-equal/es6/index.js 636var es6 = __webpack_require__(5619); 637var es6_default = /*#__PURE__*/__webpack_require__.n(es6); 638;// CONCATENATED MODULE: external ["wp","compose"] 639const external_wp_compose_namespaceObject = window["wp"]["compose"]; 640;// CONCATENATED MODULE: external ["wp","isShallowEqual"] 641const external_wp_isShallowEqual_namespaceObject = window["wp"]["isShallowEqual"]; 642var external_wp_isShallowEqual_default = /*#__PURE__*/__webpack_require__.n(external_wp_isShallowEqual_namespaceObject); 643;// CONCATENATED MODULE: ./packages/undo-manager/build-module/index.js 644/** 645 * WordPress dependencies 646 */ 647 648 649/** @typedef {import('./types').HistoryRecord} HistoryRecord */ 650/** @typedef {import('./types').HistoryChange} HistoryChange */ 651/** @typedef {import('./types').HistoryChanges} HistoryChanges */ 652/** @typedef {import('./types').UndoManager} UndoManager */ 653 654/** 655 * Merge changes for a single item into a record of changes. 656 * 657 * @param {Record< string, HistoryChange >} changes1 Previous changes 658 * @param {Record< string, HistoryChange >} changes2 NextChanges 659 * 660 * @return {Record< string, HistoryChange >} Merged changes 661 */ 662function mergeHistoryChanges(changes1, changes2) { 663 /** 664 * @type {Record< string, HistoryChange >} 665 */ 666 const newChanges = { 667 ...changes1 668 }; 669 Object.entries(changes2).forEach(([key, value]) => { 670 if (newChanges[key]) { 671 newChanges[key] = { 672 ...newChanges[key], 673 to: value.to 674 }; 675 } else { 676 newChanges[key] = value; 677 } 678 }); 679 return newChanges; 680} 681 682/** 683 * Adds history changes for a single item into a record of changes. 684 * 685 * @param {HistoryRecord} record The record to merge into. 686 * @param {HistoryChanges} changes The changes to merge. 687 */ 688const addHistoryChangesIntoRecord = (record, changes) => { 689 const existingChangesIndex = record?.findIndex(({ 690 id: recordIdentifier 691 }) => { 692 return typeof recordIdentifier === 'string' ? recordIdentifier === changes.id : external_wp_isShallowEqual_default()(recordIdentifier, changes.id); 693 }); 694 const nextRecord = [...record]; 695 if (existingChangesIndex !== -1) { 696 // If the edit is already in the stack leave the initial "from" value. 697 nextRecord[existingChangesIndex] = { 698 id: changes.id, 699 changes: mergeHistoryChanges(nextRecord[existingChangesIndex].changes, changes.changes) 700 }; 701 } else { 702 nextRecord.push(changes); 703 } 704 return nextRecord; 705}; 706 707/** 708 * Creates an undo manager. 709 * 710 * @return {UndoManager} Undo manager. 711 */ 712function createUndoManager() { 713 /** 714 * @type {HistoryRecord[]} 715 */ 716 let history = []; 717 /** 718 * @type {HistoryRecord} 719 */ 720 let stagedRecord = []; 721 /** 722 * @type {number} 723 */ 724 let offset = 0; 725 const dropPendingRedos = () => { 726 history = history.slice(0, offset || undefined); 727 offset = 0; 728 }; 729 const appendStagedRecordToLatestHistoryRecord = () => { 730 var _history$index; 731 const index = history.length === 0 ? 0 : history.length - 1; 732 let latestRecord = (_history$index = history[index]) !== null && _history$index !== void 0 ? _history$index : []; 733 stagedRecord.forEach(changes => { 734 latestRecord = addHistoryChangesIntoRecord(latestRecord, changes); 735 }); 736 stagedRecord = []; 737 history[index] = latestRecord; 738 }; 739 740 /** 741 * Checks whether a record is empty. 742 * A record is considered empty if it the changes keep the same values. 743 * Also updates to function values are ignored. 744 * 745 * @param {HistoryRecord} record 746 * @return {boolean} Whether the record is empty. 747 */ 748 const isRecordEmpty = record => { 749 const filteredRecord = record.filter(({ 750 changes 751 }) => { 752 return Object.values(changes).some(({ 753 from, 754 to 755 }) => typeof from !== 'function' && typeof to !== 'function' && !external_wp_isShallowEqual_default()(from, to)); 756 }); 757 return !filteredRecord.length; 758 }; 759 return { 760 /** 761 * Record changes into the history. 762 * 763 * @param {HistoryRecord=} record A record of changes to record. 764 * @param {boolean} isStaged Whether to immediately create an undo point or not. 765 */ 766 addRecord(record, isStaged = false) { 767 const isEmpty = !record || isRecordEmpty(record); 768 if (isStaged) { 769 if (isEmpty) { 770 return; 771 } 772 record.forEach(changes => { 773 stagedRecord = addHistoryChangesIntoRecord(stagedRecord, changes); 774 }); 775 } else { 776 dropPendingRedos(); 777 if (stagedRecord.length) { 778 appendStagedRecordToLatestHistoryRecord(); 779 } 780 if (isEmpty) { 781 return; 782 } 783 history.push(record); 784 } 785 }, 786 undo() { 787 if (stagedRecord.length) { 788 dropPendingRedos(); 789 appendStagedRecordToLatestHistoryRecord(); 790 } 791 const undoRecord = history[history.length - 1 + offset]; 792 if (!undoRecord) { 793 return; 794 } 795 offset -= 1; 796 return undoRecord; 797 }, 798 redo() { 799 const redoRecord = history[history.length + offset]; 800 if (!redoRecord) { 801 return; 802 } 803 offset += 1; 804 return redoRecord; 805 }, 806 hasUndo() { 807 return !!history[history.length - 1 + offset]; 808 }, 809 hasRedo() { 810 return !!history[history.length + offset]; 811 } 812 }; 813} 814 815;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/if-matching-action.js 816/** @typedef {import('../types').AnyFunction} AnyFunction */ 817 818/** 819 * A higher-order reducer creator which invokes the original reducer only if 820 * the dispatching action matches the given predicate, **OR** if state is 821 * initializing (undefined). 822 * 823 * @param {AnyFunction} isMatch Function predicate for allowing reducer call. 824 * 825 * @return {AnyFunction} Higher-order reducer. 826 */ 827const ifMatchingAction = isMatch => reducer => (state, action) => { 828 if (state === undefined || isMatch(action)) { 829 return reducer(state, action); 830 } 831 return state; 832}; 833/* harmony default export */ const if_matching_action = (ifMatchingAction); 834 835;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/replace-action.js 836/** @typedef {import('../types').AnyFunction} AnyFunction */ 837 838/** 839 * Higher-order reducer creator which substitutes the action object before 840 * passing to the original reducer. 841 * 842 * @param {AnyFunction} replacer Function mapping original action to replacement. 843 * 844 * @return {AnyFunction} Higher-order reducer. 845 */ 846const replaceAction = replacer => reducer => (state, action) => { 847 return reducer(state, replacer(action)); 848}; 849/* harmony default export */ const replace_action = (replaceAction); 850 851;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/conservative-map-item.js 852/** 853 * External dependencies 854 */ 855 856 857/** 858 * Given the current and next item entity record, returns the minimally "modified" 859 * result of the next item, preferring value references from the original item 860 * if equal. If all values match, the original item is returned. 861 * 862 * @param {Object} item Original item. 863 * @param {Object} nextItem Next item. 864 * 865 * @return {Object} Minimally modified merged item. 866 */ 867function conservativeMapItem(item, nextItem) { 868 // Return next item in its entirety if there is no original item. 869 if (!item) { 870 return nextItem; 871 } 872 let hasChanges = false;
873 const result = {}; 874 for (const key in nextItem) { 875 if (es6_default()(item[key], nextItem[key])) { 876 result[key] = item[key]; 877 } else { 878 hasChanges = true; 879 result[key] = nextItem[key]; 880 } 881 } 882 if (!hasChanges) { 883 return item; 884 } 885 886 // Only at this point, backfill properties from the original item which 887 // weren't explicitly set into the result above. This is an optimization 888 // to allow `hasChanges` to return early. 889 for (const key in item) { 890 if (!result.hasOwnProperty(key)) { 891 result[key] = item[key]; 892 } 893 } 894 return result; 895} 896 897;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/on-sub-key.js 898/** @typedef {import('../types').AnyFunction} AnyFunction */ 899 900/** 901 * Higher-order reducer creator which creates a combined reducer object, keyed 902 * by a property on the action object. 903 * 904 * @param {string} actionProperty Action property by which to key object. 905 * 906 * @return {AnyFunction} Higher-order reducer. 907 */ 908const onSubKey = actionProperty => reducer => (state = {}, action) => { 909 // Retrieve subkey from action. Do not track if undefined; useful for cases 910 // where reducer is scoped by action shape. 911 const key = action[actionProperty]; 912 if (key === undefined) { 913 return state; 914 } 915 916 // Avoid updating state if unchanged. Note that this also accounts for a 917 // reducer which returns undefined on a key which is not yet tracked. 918 const nextKeyState = reducer(state[key], action); 919 if (nextKeyState === state[key]) { 920 return state; 921 } 922 return { 923 ...state, 924 [key]: nextKeyState 925 }; 926}; 927/* harmony default export */ const on_sub_key = (onSubKey); 928 929;// CONCATENATED MODULE: ./node_modules/tslib/tslib.es6.mjs 930/****************************************************************************** 931Copyright (c) Microsoft Corporation. 932 933Permission to use, copy, modify, and/or distribute this software for any 934purpose with or without fee is hereby granted. 935 936THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 937REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 938AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 939INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 940LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 941OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 942PERFORMANCE OF THIS SOFTWARE. 943***************************************************************************** */ 944/* global Reflect, Promise, SuppressedError, Symbol */ 945 946var extendStatics = function(d, b) { 947 extendStatics = Object.setPrototypeOf || 948 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 949 function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; 950 return extendStatics(d, b); 951}; 952 953function __extends(d, b) { 954 if (typeof b !== "function" && b !== null) 955 throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); 956 extendStatics(d, b); 957 function __() { this.constructor = d; } 958 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 959} 960 961var __assign = function() { 962 __assign = Object.assign || function __assign(t) { 963 for (var s, i = 1, n = arguments.length; i < n; i++) { 964 s = arguments[i]; 965 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; 966 } 967 return t; 968 } 969 return __assign.apply(this, arguments); 970} 971 972function __rest(s, e) { 973 var t = {}; 974 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) 975 t[p] = s[p]; 976 if (s != null && typeof Object.getOwnPropertySymbols === "function") 977 for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { 978 if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) 979 t[p[i]] = s[p[i]]; 980 } 981 return t; 982} 983 984function __decorate(decorators, target, key, desc) { 985 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 986 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 987 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c >
vendor: 5,049 bytes, lines 987-1078
987 3 ? d(target, key, r) : d(target, key)) || r; 988 return c > 3 && r && Object.defineProperty(target, key, r), r; 989} 990 991function __param(paramIndex, decorator) { 992 return function (target, key) { decorator(target, key, paramIndex); } 993} 994 995function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { 996 function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } 997 var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; 998 var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; 999 var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); 1000 var _, done = false; 1001 for (var i = decorators.length - 1; i >= 0; i--) { 1002 var context = {}; 1003 for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; 1004 for (var p in contextIn.access) context.access[p] = contextIn.access[p]; 1005 context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; 1006 var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); 1007 if (kind === "accessor") { 1008 if (result === void 0) continue; 1009 if (result === null || typeof result !== "object") throw new TypeError("Object expected"); 1010 if (_ = accept(result.get)) descriptor.get = _; 1011 if (_ = accept(result.set)) descriptor.set = _; 1012 if (_ = accept(result.init)) initializers.unshift(_); 1013 } 1014 else if (_ = accept(result)) { 1015 if (kind === "field") initializers.unshift(_); 1016 else descriptor[key] = _; 1017 } 1018 } 1019 if (target) Object.defineProperty(target, contextIn.name, descriptor); 1020 done = true; 1021}; 1022 1023function __runInitializers(thisArg, initializers, value) { 1024 var useValue = arguments.length > 2; 1025 for (var i = 0; i < initializers.length; i++) { 1026 value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); 1027 } 1028 return useValue ? value : void 0; 1029}; 1030 1031function __propKey(x) { 1032 return typeof x === "symbol" ? x : "".concat(x); 1033}; 1034 1035function __setFunctionName(f, name, prefix) { 1036 if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; 1037 return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); 1038}; 1039 1040function __metadata(metadataKey, metadataValue) { 1041 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); 1042} 1043 1044function __awaiter(thisArg, _arguments, P, generator) { 1045 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 1046 return new (P || (P = Promise))(function (resolve, reject) { 1047 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 1048 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 1049 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 1050 step((generator = generator.apply(thisArg, _arguments || [])).next()); 1051 }); 1052} 1053 1054function __generator(thisArg, body) { 1055 var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 1056 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 1057 function verb(n) { return function (v) { return step([n, v]); }; } 1058 function step(op) { 1059 if (f) throw new TypeError("Generator is already executing."); 1060 while (g && (g = 0, op[0] && (_ = 0)), _) try { 1061 if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 1062 if (y = 0, t) op = [op[0] & 2, t.value]; 1063 switch (op[0]) { 1064 case 0: case 1: t = op; break; 1065 case 4: _.label++; return { value: op[1], done: false }; 1066 case 5: _.label++; y = op[1]; op = [0]; continue; 1067 case 7: op = _.ops.pop(); _.trys.pop(); continue; 1068 default: 1069 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 1070 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 1071 if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 1072 if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 1073 if (t[2]) _.ops.pop(); 1074 _.trys.pop(); continue; 1075 } 1076 op = body.call(thisArg, _); 1077 } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 1078 if (op[0] & 5) throw op[1];
vendor: 4,219 bytes, lines 1078-1182
1078 return { value: op[0] ? op[1] : void 0, done: true }; 1079 } 1080} 1081 1082var __createBinding = Object.create ? (function(o, m, k, k2) { 1083 if (k2 === undefined) k2 = k; 1084 var desc = Object.getOwnPropertyDescriptor(m, k); 1085 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 1086 desc = { enumerable: true, get: function() { return m[k]; } }; 1087 } 1088 Object.defineProperty(o, k2, desc); 1089}) : (function(o, m, k, k2) { 1090 if (k2 === undefined) k2 = k; 1091 o[k2] = m[k]; 1092}); 1093 1094function __exportStar(m, o) { 1095 for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); 1096} 1097 1098function __values(o) { 1099 var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; 1100 if (m) return m.call(o); 1101 if (o && typeof o.length === "number") return { 1102 next: function () { 1103 if (o && i >= o.length) o = void 0; 1104 return { value: o && o[i++], done: !o }; 1105 } 1106 }; 1107 throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); 1108} 1109 1110function __read(o, n) { 1111 var m = typeof Symbol === "function" && o[Symbol.iterator]; 1112 if (!m) return o; 1113 var i = m.call(o), r, ar = [], e; 1114 try { 1115 while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); 1116 } 1117 catch (error) { e = { error: error }; } 1118 finally { 1119 try { 1120 if (r && !r.done && (m = i["return"])) m.call(i); 1121 } 1122 finally { if (e) throw e.error; } 1123 } 1124 return ar; 1125} 1126 1127/** @deprecated */ 1128function __spread() { 1129 for (var ar = [], i = 0; i < arguments.length; i++) 1130 ar = ar.concat(__read(arguments[i])); 1131 return ar; 1132} 1133 1134/** @deprecated */ 1135function __spreadArrays() { 1136 for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; 1137 for (var r = Array(s), k = 0, i = 0; i < il; i++) 1138 for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) 1139 r[k] = a[j]; 1140 return r; 1141} 1142 1143function __spreadArray(to, from, pack) { 1144 if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { 1145 if (ar || !(i in from)) { 1146 if (!ar) ar = Array.prototype.slice.call(from, 0, i); 1147 ar[i] = from[i]; 1148 } 1149 } 1150 return to.concat(ar || Array.prototype.slice.call(from)); 1151} 1152 1153function __await(v) { 1154 return this instanceof __await ? (this.v = v, this) : new __await(v); 1155} 1156 1157function __asyncGenerator(thisArg, _arguments, generator) { 1158 if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); 1159 var g = generator.apply(thisArg, _arguments || []), i, q = []; 1160 return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; 1161 function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } 1162 function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } 1163 function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } 1164 function fulfill(value) { resume("next", value); } 1165 function reject(value) { resume("throw", value); } 1166 function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } 1167} 1168 1169function __asyncDelegator(o) { 1170 var i, p; 1171 return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; 1172 function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; } 1173} 1174 1175function __asyncValues(o) { 1176 if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); 1177 var m = o[Symbol.asyncIterator], i; 1178 return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); 1179 function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } 1180 function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } 1181} 1182
vendor: 3,932 bytes, lines 1183-1290
1183function __makeTemplateObject(cooked, raw) { 1184 if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 1185 return cooked; 1186}; 1187 1188var __setModuleDefault = Object.create ? (function(o, v) { 1189 Object.defineProperty(o, "default", { enumerable: true, value: v }); 1190}) : function(o, v) { 1191 o["default"] = v; 1192}; 1193 1194function __importStar(mod) { 1195 if (mod && mod.__esModule) return mod; 1196 var result = {}; 1197 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 1198 __setModuleDefault(result, mod); 1199 return result; 1200} 1201 1202function __importDefault(mod) { 1203 return (mod && mod.__esModule) ? mod : { default: mod }; 1204} 1205 1206function __classPrivateFieldGet(receiver, state, kind, f) { 1207 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); 1208 if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); 1209 return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); 1210} 1211 1212function __classPrivateFieldSet(receiver, state, value, kind, f) { 1213 if (kind === "m") throw new TypeError("Private method is not writable"); 1214 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); 1215 if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); 1216 return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; 1217} 1218 1219function __classPrivateFieldIn(state, receiver) { 1220 if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object"); 1221 return typeof state === "function" ? receiver === state : state.has(receiver); 1222} 1223 1224function __addDisposableResource(env, value, async) { 1225 if (value !== null && value !== void 0) { 1226 if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); 1227 var dispose; 1228 if (async) { 1229 if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); 1230 dispose = value[Symbol.asyncDispose]; 1231 } 1232 if (dispose === void 0) { 1233 if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); 1234 dispose = value[Symbol.dispose]; 1235 } 1236 if (typeof dispose !== "function") throw new TypeError("Object not disposable."); 1237 env.stack.push({ value: value, dispose: dispose, async: async }); 1238 } 1239 else if (async) { 1240 env.stack.push({ async: true }); 1241 } 1242 return value; 1243} 1244 1245var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { 1246 var e = new Error(message); 1247 return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; 1248}; 1249 1250function __disposeResources(env) { 1251 function fail(e) { 1252 env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; 1253 env.hasError = true; 1254 } 1255 function next() { 1256 while (env.stack.length) { 1257 var rec = env.stack.pop(); 1258 try { 1259 var result = rec.dispose && rec.dispose.call(rec.value); 1260 if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); 1261 } 1262 catch (e) { 1263 fail(e); 1264 } 1265 } 1266 if (env.hasError) throw env.error; 1267 } 1268 return next(); 1269} 1270 1271/* harmony default export */ const tslib_es6 = ({ 1272 __extends, 1273 __assign, 1274 __rest, 1275 __decorate, 1276 __param, 1277 __metadata, 1278 __awaiter, 1279 __generator, 1280 __createBinding, 1281 __exportStar, 1282 __values, 1283 __read, 1284 __spread, 1285 __spreadArrays, 1286 __spreadArray, 1287 __await, 1288 __asyncGenerator, 1289 __asyncDelegator, 1290 __asyncValues,
1291 __makeTemplateObject, 1292 __importStar, 1293 __importDefault, 1294 __classPrivateFieldGet, 1295 __classPrivateFieldSet, 1296 __classPrivateFieldIn, 1297 __addDisposableResource, 1298 __disposeResources, 1299}); 1300 1301;// CONCATENATED MODULE: ./node_modules/lower-case/dist.es2015/index.js 1302/** 1303 * Source: ftp://ftp.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt 1304 */ 1305var SUPPORTED_LOCALE = { 1306 tr: { 1307 regexp: /\u0130|\u0049|\u0049\u0307/g, 1308 map: { 1309 İ: "\u0069", 1310 I: "\u0131", 1311 IÌ: "\u0069", 1312 }, 1313 }, 1314 az: { 1315 regexp: /\u0130/g, 1316 map: { 1317 İ: "\u0069", 1318 I: "\u0131", 1319 IÌ: "\u0069", 1320 }, 1321 }, 1322 lt: { 1323 regexp: /\u0049|\u004A|\u012E|\u00CC|\u00CD|\u0128/g, 1324 map: { 1325 I: "\u0069\u0307", 1326 J: "\u006A\u0307", 1327 Ä®: "\u012F\u0307", 1328 Ã: "\u0069\u0307\u0300", 1329 Ã: "\u0069\u0307\u0301", 1330 Ĩ: "\u0069\u0307\u0303", 1331 }, 1332 }, 1333}; 1334/** 1335 * Localized lower case. 1336 */ 1337function localeLowerCase(str, locale) {
1338 var lang = SUPPORTED_LOCALE[locale.toLowerCase()]; 1339 if (lang) 1340 return lowerCase(str.replace(lang.regexp, function (m) { return lang.map[m]; })); 1341 return lowerCase(str); 1342} 1343/** 1344 * Lower case as a function. 1345 */ 1346function lowerCase(str) { 1347 return str.toLowerCase(); 1348} 1349 1350;// CONCATENATED MODULE: ./node_modules/no-case/dist.es2015/index.js 1351 1352// Support camel case ("camelCase" -> "camel Case" and "CAMELCase" -> "CAMEL Case"). 1353var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g]; 1354// Remove all non-word characters. 1355var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi; 1356/** 1357 * Normalize the string into something other libraries can manipulate easier. 1358 */ 1359function noCase(input, options) { 1360 if (options === void 0) { options = {}; } 1361 var _a = options.splitRegexp, splitRegexp = _a === void 0 ? DEFAULT_SPLIT_REGEXP : _a, _b = options.stripRegexp, stripRegexp = _b === void 0 ? DEFAULT_STRIP_REGEXP : _b, _c = options.transform, transform = _c === void 0 ? lowerCase : _c, _d = options.delimiter, delimiter = _d === void 0 ? " " : _d; 1362 var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0"); 1363 var start = 0; 1364 var end = result.length; 1365 // Trim the delimiter from around the output string. 1366 while (result.charAt(start) === "\0") 1367 start++; 1368 while (result.charAt(end - 1) === "\0") 1369 end--; 1370 // Transform each token independently. 1371 return result.slice(start, end).split("\0").map(transform).join(delimiter); 1372} 1373/** 1374 * Replace `re` in the input string with the replacement value. 1375 */ 1376function replace(input, re, value) { 1377 if (re instanceof RegExp) 1378 return input.replace(re, value); 1379 return re.reduce(function (input, re) { return input.replace(re, value); }, input); 1380} 1381 1382;// CONCATENATED MODULE: ./node_modules/upper-case-first/dist.es2015/index.js 1383/** 1384 * Upper case the first character of an input string. 1385 */ 1386function upperCaseFirst(input) { 1387 return input.charAt(0).toUpperCase() + input.substr(1); 1388} 1389 1390;// CONCATENATED MODULE: ./node_modules/capital-case/dist.es2015/index.js 1391 1392 1393 1394function capitalCaseTransform(input) { 1395 return upperCaseFirst(input.toLowerCase()); 1396} 1397function capitalCase(input, options) { 1398 if (options === void 0) { options = {}; } 1399 return noCase(input, __assign({ delimiter: " ", transform: capitalCaseTransform }, options)); 1400} 1401 1402;// CONCATENATED MODULE: ./node_modules/pascal-case/dist.es2015/index.js 1403 1404 1405function pascalCaseTransform(input, index) { 1406 var firstChar = input.charAt(0); 1407 var lowerChars = input.substr(1).toLowerCase(); 1408 if (index > 0 && firstChar >= "0" && firstChar <= "9") { 1409 return "_" + firstChar + lowerChars; 1410 } 1411 return "" + firstChar.toUpperCase() + lowerChars; 1412} 1413function dist_es2015_pascalCaseTransformMerge(input) { 1414 return input.charAt(0).toUpperCase() + input.slice(1).toLowerCase(); 1415} 1416function pascalCase(input, options) { 1417 if (options === void 0) { options = {}; } 1418 return noCase(input, __assign({ delimiter: "", transform: pascalCaseTransform }, options)); 1419} 1420 1421;// CONCATENATED MODULE: external ["wp","apiFetch"] 1422const external_wp_apiFetch_namespaceObject = window["wp"]["apiFetch"]; 1423var external_wp_apiFetch_default = /*#__PURE__*/__webpack_require__.n(external_wp_apiFetch_namespaceObject); 1424;// CONCATENATED MODULE: external ["wp","i18n"] 1425const external_wp_i18n_namespaceObject = window["wp"]["i18n"]; 1426;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/rng.js 1427// Unique ID creation requires a high quality random # generator. In the browser we therefore 1428// require the crypto API and do not support built-in fallback to lower quality random number 1429// generators (like Math.random()). 1430var rng_getRandomValues; 1431var rnds8 = new Uint8Array(16); 1432function rng() { 1433 // lazy load so that environments that need to polyfill have a chance to do so 1434 if (!rng_getRandomValues) { 1435 // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also, 1436 // find the complete implementation of crypto (msCrypto) on IE11. 1437 rng_getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto); 1438 1439 if (!rng_getRandomValues) { 1440 throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); 1441 } 1442 } 1443 1444 return rng_getRandomValues(rnds8); 1445} 1446;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/regex.js 1447/* harmony default export */ const regex = (/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i); 1448;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/validate.js 1449 1450 1451function validate(uuid) { 1452 return typeof uuid === 'string' && regex.test(uuid); 1453} 1454 1455/* harmony default export */ const esm_browser_validate = (validate); 1456;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/stringify.js 1457 1458/** 1459 * Convert array of 16 byte values to UUID string format of the form: 1460 * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 1461 */ 1462 1463var byteToHex = []; 1464 1465for (var i = 0; i < 256; ++i) { 1466 byteToHex.push((i + 0x100).toString(16).substr(1)); 1467} 1468 1469function stringify(arr) { 1470 var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; 1471 // Note: Be careful editing this code! It's been tuned for performance
1472 // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 1473 var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one 1474 // of the following: 1475 // - One or more input array values don't map to a hex octet (leading to 1476 // "undefined" in the uuid) 1477 // - Invalid input values for the RFC `version` or `variant` fields 1478 1479 if (!esm_browser_validate(uuid)) { 1480 throw TypeError('Stringified UUID is invalid'); 1481 } 1482 1483 return uuid; 1484} 1485 1486/* harmony default export */ const esm_browser_stringify = (stringify); 1487;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/v4.js 1488 1489 1490 1491function v4(options, buf, offset) { 1492 options = options || {}; 1493 var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` 1494 1495 rnds[6] = rnds[6] & 0x0f | 0x40; 1496 rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided 1497 1498 if (buf) { 1499 offset = offset || 0; 1500 1501 for (var i = 0; i < 16; ++i) { 1502 buf[offset + i] = rnds[i]; 1503 } 1504 1505 return buf; 1506 } 1507 1508 return esm_browser_stringify(rnds); 1509} 1510 1511/* harmony default export */ const esm_browser_v4 = (v4); 1512;// CONCATENATED MODULE: external ["wp","url"] 1513const external_wp_url_namespaceObject = window["wp"]["url"]; 1514;// CONCATENATED MODULE: external ["wp","deprecated"] 1515const external_wp_deprecated_namespaceObject = window["wp"]["deprecated"]; 1516var external_wp_deprecated_default = /*#__PURE__*/__webpack_require__.n(external_wp_deprecated_namespaceObject); 1517;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/set-nested-value.js 1518/** 1519 * Sets the value at path of object. 1520 * If a portion of path doesnât exist, itâs created. 1521 * Arrays are created for missing index properties while objects are created 1522 * for all other missing properties. 1523 * 1524 * Path is specified as either: 1525 * - a string of properties, separated by dots, for example: "x.y". 1526 * - an array of properties, for example `[ 'x', 'y' ]`. 1527 * 1528 * This function intentionally mutates the input object. 1529 * 1530 * Inspired by _.set(). 1531 * 1532 * @see https://lodash.com/docs/4.17.15#set 1533 * 1534 * @todo Needs to be deduplicated with its copy in `@wordpress/edit-site`. 1535 * 1536 * @param {Object} object Object to modify 1537 * @param {Array|string} path Path of the property to set. 1538 * @param {*} value Value to set. 1539 */ 1540function setNestedValue(object, path, value) { 1541 if (!object || typeof object !== 'object') { 1542 return object; 1543 } 1544 const normalizedPath = Array.isArray(path) ? path : path.split('.'); 1545 normalizedPath.reduce((acc, key, idx) => { 1546 if (acc[key] === undefined) { 1547 if (Number.isInteger(normalizedPath[idx + 1])) { 1548 acc[key] = []; 1549 } else { 1550 acc[key] = {}; 1551 } 1552 } 1553 if (idx === normalizedPath.length - 1) { 1554 acc[key] = value; 1555 } 1556 return acc[key]; 1557 }, object); 1558 return object; 1559} 1560 1561;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/get-nested-value.js 1562/** 1563 * Helper util to return a value from a certain path of the object. 1564 * Path is specified as either: 1565 * - a string of properties, separated by dots, for example: "x.y". 1566 * - an array of properties, for example `[ 'x', 'y' ]`. 1567 * You can also specify a default value in case the result is nullish. 1568 * 1569 * @param {Object} object Input object. 1570 * @param {string|Array} path Path to the object property. 1571 * @param {*} defaultValue Default value if the value at the specified path is undefined. 1572 * @return {*} Value of the object property at the specified path. 1573 */ 1574function getNestedValue(object, path, defaultValue) { 1575 if (!object || typeof object !== 'object' || typeof path !== 'string' && !Array.isArray(path)) { 1576 return object; 1577 } 1578 const normalizedPath = Array.isArray(path) ? path : path.split('.'); 1579 let value = object; 1580 normalizedPath.forEach(fieldName => { 1581 value = value?.[fieldName]; 1582 }); 1583 return value !== undefined ? value : defaultValue; 1584} 1585 1586;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/actions.js 1587/** 1588 * Returns an action object used in signalling that items have been received. 1589 * 1590 * @param {Array} items Items received. 1591 * @param {?Object} edits Optional edits to reset. 1592 * 1593 * @return {Object} Action object. 1594 */ 1595function receiveItems(items, edits) { 1596 return { 1597 type: 'RECEIVE_ITEMS', 1598 items: Array.isArray(items) ? items : [items], 1599 persistedEdits: edits 1600 }; 1601} 1602 1603/** 1604 * Returns an action object used in signalling that entity records have been 1605 * deleted and they need to be removed from entities state. 1606 * 1607 * @param {string} kind Kind of the removed entities. 1608 * @param {string} name Name of the removed entities. 1609 * @param {Array|number|string} records Record IDs of the removed entities. 1610 * @param {boolean}
1610 invalidateCache Controls whether we want to invalidate the cache. 1611 * @return {Object} Action object. 1612 */ 1613function removeItems(kind, name, records, invalidateCache = false) { 1614 return { 1615 type: 'REMOVE_ITEMS', 1616 itemIds: Array.isArray(records) ? records : [records], 1617 kind, 1618 name, 1619 invalidateCache 1620 }; 1621} 1622 1623/** 1624 * Returns an action object used in signalling that queried data has been 1625 * received. 1626 * 1627 * @param {Array} items Queried items received. 1628 * @param {?Object} query Optional query object. 1629 * @param {?Object} edits Optional edits to reset. 1630 * 1631 * @return {Object} Action object. 1632 */ 1633function receiveQueriedItems(items, query = {}, edits) { 1634 return { 1635 ...receiveItems(items, edits), 1636 query 1637 }; 1638} 1639 1640;// CONCATENATED MODULE: ./packages/core-data/build-module/batch/default-processor.js 1641/** 1642 * WordPress dependencies 1643 */ 1644 1645 1646/** 1647 * Maximum number of requests to place in a single batch request. Obtained by 1648 * sending a preflight OPTIONS request to /batch/v1/. 1649 * 1650 * @type {number?} 1651 */ 1652let maxItems = null; 1653function chunk(arr, chunkSize) { 1654 const tmp = [...arr]; 1655 const cache = []; 1656 while (tmp.length) { 1657 cache.push(tmp.splice(0, chunkSize)); 1658 } 1659 return cache; 1660} 1661 1662/** 1663 * Default batch processor. Sends its input requests to /batch/v1. 1664 * 1665 * @param {Array} requests List of API requests to perform at once. 1666 * 1667 * @return {Promise} Promise that resolves to a list of objects containing 1668 * either `output` (if that request was successful) or `error` 1669 * (if not ). 1670 */ 1671async function defaultProcessor(requests) { 1672 if (maxItems === null) { 1673 const preflightResponse = await external_wp_apiFetch_default()({ 1674 path: '/batch/v1', 1675 method: 'OPTIONS' 1676 }); 1677 maxItems = preflightResponse.endpoints[0].args.requests.maxItems; 1678 } 1679 const results = []; 1680 1681 // @ts-ignore We would have crashed or never gotten to this point if we hadn't received the maxItems count. 1682 for (const batchRequests of chunk(requests, maxItems)) { 1683 const batchResponse = await external_wp_apiFetch_default()({ 1684 path: '/batch/v1', 1685 method: 'POST', 1686 data: { 1687 validation: 'require-all-validate', 1688 requests: batchRequests.map(request => ({ 1689 path: request.path, 1690 body: request.data, 1691 // Rename 'data' to 'body'. 1692 method: request.method, 1693 headers: request.headers 1694 })) 1695 } 1696 }); 1697 let batchResults; 1698 if (batchResponse.failed) { 1699 batchResults = batchResponse.responses.map(response => ({ 1700 error: response?.body 1701 })); 1702 } else { 1703 batchResults = batchResponse.responses.map(response => { 1704 const result = {}; 1705 if (response.status >= 200 && response.status < 300) { 1706 result.output = response.body; 1707 } else { 1708 result.error = response.body; 1709 } 1710 return result; 1711 }); 1712 } 1713 results.push(...batchResults); 1714 } 1715 return results; 1716} 1717 1718;// CONCATENATED MODULE: ./packages/core-data/build-module/batch/create-batch.js 1719/** 1720 * Internal dependencies 1721 */ 1722 1723 1724/** 1725 * Creates a batch, which can be used to combine multiple API requests into one 1726 * API request using the WordPress batch processing API (/v1/batch). 1727 * 1728 * ``` 1729 * const batch = createBatch(); 1730 * const dunePromise = batch.add( { 1731 * path: '/v1/books', 1732 * method: 'POST', 1733 * data: { title: 'Dune' } 1734 * } ); 1735 * const lotrPromise = batch.add( { 1736 * path: '/v1/books', 1737 * method: 'POST', 1738 * data: { title: 'Lord of the Rings' } 1739 * } ); 1740 * const isSuccess = await batch.run(); // Sends one POST to /v1/batch. 1741 * if ( isSuccess ) { 1742 * console.log( 1743 * 'Saved two books:', 1744 * await dunePromise, 1745 * await lotrPromise 1746 * ); 1747 * } 1748 * ``` 1749 * 1750 * @param {Function} [processor] Processor function. Can be used to replace the 1751 * default functionality which is to send an API 1752 * request to /v1/batch. Is given an array of 1753 * inputs and must return a promise that 1754 * resolves to an array of objects containing 1755 * either `output` or `error`. 1756 */ 1757function createBatch(processor = defaultProcessor) { 1758 let lastId = 0; 1759 /** @type {Array<{ input: any; resolve: ( value: any ) => void; reject: ( error: any ) => void }>} */ 1760 let queue = []; 1761 const pending = new ObservableSet(); 1762 return { 1763 /** 1764 * Adds an input to the batch and returns a promise that is resolved or 1765 * rejected when the input is processed by `batch.run()`. 1766 * 1767 * You may also pass a thunk which allows inputs to be added 1768 * asychronously. 1769 * 1770 * ``` 1771 * // Both are allowed: 1772 * batch.add( { path: '/v1/books', ... } ); 1773 * batch.add( ( add ) => add( { path: '/v1/books', ... } ) ); 1774 * ``` 1775 * 1776 * If a thunk is passed, `batch.run()` will pause until either: 1777 *
1778 * - The thunk calls its `add` argument, or; 1779 * - The thunk returns a promise and that promise resolves, or; 1780 * - The thunk returns a non-promise. 1781 * 1782 * @param {any|Function} inputOrThunk Input to add or thunk to execute. 1783 * 1784 * @return {Promise|any} If given an input, returns a promise that 1785 * is resolved or rejected when the batch is 1786 * processed. If given a thunk, returns the return 1787 * value of that thunk. 1788 */ 1789 add(inputOrThunk) { 1790 const id = ++lastId; 1791 pending.add(id); 1792 const add = input => new Promise((resolve, reject) => { 1793 queue.push({ 1794 input, 1795 resolve, 1796 reject 1797 }); 1798 pending.delete(id); 1799 }); 1800 if (typeof inputOrThunk === 'function') { 1801 return Promise.resolve(inputOrThunk(add)).finally(() => { 1802 pending.delete(id); 1803 }); 1804 } 1805 return add(inputOrThunk); 1806 }, 1807 /** 1808 * Runs the batch. This calls `batchProcessor` and resolves or rejects 1809 * all promises returned by `add()`. 1810 * 1811 * @return {Promise<boolean>} A promise that resolves to a boolean that is true 1812 * if the processor returned no errors. 1813 */ 1814 async run() { 1815 if (pending.size) { 1816 await new Promise(resolve => { 1817 const unsubscribe = pending.subscribe(() => { 1818 if (!pending.size) { 1819 unsubscribe(); 1820 resolve(undefined); 1821 } 1822 }); 1823 }); 1824 } 1825 let results; 1826 try { 1827 results = await processor(queue.map(({ 1828 input 1829 }) => input)); 1830 if (results.length !== queue.length) { 1831 throw new Error('run: Array returned by processor must be same size as input array.'); 1832 } 1833 } catch (error) { 1834 for (const { 1835 reject 1836 } of queue) { 1837 reject(error); 1838 } 1839 throw error; 1840 } 1841 let isSuccess = true; 1842 results.forEach((result, key) => { 1843 const queueItem = queue[key]; 1844 if (result?.error) { 1845 queueItem?.reject(result.error); 1846 isSuccess = false; 1847 } else { 1848 var _result$output; 1849 queueItem?.resolve((_result$output = result?.output) !== null && _result$output !== void 0 ? _result$output : result); 1850 } 1851 }); 1852 queue = []; 1853 return isSuccess; 1854 } 1855 }; 1856} 1857class ObservableSet { 1858 constructor(...args) { 1859 this.set = new Set(...args); 1860 this.subscribers = new Set(); 1861 } 1862 get size() { 1863 return this.set.size; 1864 } 1865 add(value) { 1866 this.set.add(value); 1867 this.subscribers.forEach(subscriber => subscriber()); 1868 return this; 1869 } 1870 delete(value) { 1871 const isSuccess = this.set.delete(value); 1872 this.subscribers.forEach(subscriber => subscriber()); 1873 return isSuccess; 1874 } 1875 subscribe(subscriber) { 1876 this.subscribers.add(subscriber); 1877 return () => { 1878 this.subscribers.delete(subscriber); 1879 }; 1880 } 1881} 1882 1883;// CONCATENATED MODULE: ./packages/core-data/build-module/name.js 1884/** 1885 * The reducer key used by core data in store registration. 1886 * This is defined in a separate file to avoid cycle-dependency 1887 * 1888 * @type {string} 1889 */ 1890const STORE_NAME = 'core'; 1891 1892;// CONCATENATED MODULE: ./node_modules/lib0/map.js 1893/** 1894 * Utility module to work with key-value stores. 1895 * 1896 * @module map 1897 */ 1898 1899/** 1900 * Creates a new Map instance. 1901 * 1902 * @function 1903 * @return {Map<any, any>} 1904 * 1905 * @function 1906 */ 1907const create = () => new Map() 1908 1909/** 1910 * Copy a Map object into a fresh Map object. 1911 * 1912 * @function 1913 * @template X,Y 1914 * @param {Map<X,Y>} m 1915 * @return {Map<X,Y>} 1916 */ 1917const copy = m => { 1918 const r = create() 1919 m.forEach((v, k) => { r.set(k, v) }) 1920 return r 1921} 1922 1923/** 1924 * Get map property. Create T if property is undefined and set T on map. 1925 * 1926 * ```js 1927 * const listeners = map.setIfUndefined(events, 'eventName', set.create) 1928 * listeners.add(listener) 1929 * ``` 1930 * 1931 * @function 1932 * @template V,K 1933 * @template {Map<K,V>} MAP 1934 * @param {MAP} map 1935 * @param {K} key 1936 * @param {function():V} createT 1937 * @return {V} 1938 */ 1939const setIfUndefined = (map, key, createT) => { 1940 let set = map.get(key) 1941 if (set === undefined) { 1942 map.set(key, set = createT()) 1943 } 1944 return set 1945} 1946 1947/** 1948 * Creates an Array and populates it with the content of all key-value pairs using the `f(value, key)` function. 1949 * 1950 * @function 1951 * @template K 1952 * @template V 1953 * @template R 1954 * @param {Map<K,V>} m 1955 * @param {function(V,K):R} f 1956 * @return {Array<R>} 1957 */ 1958const map_map = (m, f) => { 1959 const res = [] 1960 for (const [key, value] of m) { 1961 res.push(f(value, key)) 1962 } 1963 return res 1964} 1965 1966/** 1967 * Tests whether any key-value pairs pass the test implemented by `f(value, key)`. 1968 * 1969 * @todo should rename to some - similarly to Array.some 1970 * 1971 * @function 1972 * @template K 1973 * @template V 1974 * @param {Map<K,V>} m 1975 * @param {function(V,K):boolean} f 1976 * @return {boolean} 1977 */ 1978const any = (m, f) => { 1979 for (const [key, value] of m) { 1980 if (f(value, key)) { 1981 return true 1982 } 1983 } 1984 return false 1985} 1986 1987/** 1988 * Tests whether all key-value pairs pass the test implemented by `f(value, key)`. 1989 * 1990 * @function 1991 * @template K 1992 * @template V 1993 * @param {Map<K,V>} m 1994 * @param {function(V,K):boolean} f 1995 * @return {boolean} 1996 */ 1997const map_all = (m, f) => { 1998 for (const [key, value] of m) { 1999 if (!f(value, key)) { 2000 return false 2001 } 2002 } 2003 return true 2004} 2005 2006;// CONCATENATED MODULE: ./node_modules/lib0/set.js 2007/** 2008 * Utility module to work with sets. 2009 * 2010 * @module set 2011 */ 2012 2013const set_create = () => new Set() 2014 2015/** 2016 * @template T 2017 * @param {Set<T>} set 2018 * @return {Array<T>} 2019 */ 2020const toArray = set => Array.from(set) 2021 2022/** 2023 * @template T 2024 * @param {Set<T>} set 2025 * @return {T} 2026 */ 2027const first = set => 2028 set.values().next().value || undefined 2029 2030/** 2031 * @template T 2032 * @param {Iterable<T>} entries 2033 * @return {Set<T>} 2034 */ 2035const from = entries => new Set(entries) 2036 2037;// CONCATENATED MODULE: ./node_modules/lib0/array.js 2038/** 2039 * Utility module to work with Arrays. 2040 * 2041 * @module array 2042 */ 2043 2044 2045 2046/** 2047 * Return the last element of an array. The element must exist 2048 * 2049 * @template L 2050 * @param {ArrayLike<L>} arr 2051 * @return {L} 2052 */ 2053const last = arr => arr[arr.length - 1] 2054 2055/** 2056 * @template C 2057 * @return {Array<C>} 2058 */ 2059const array_create = () => /** @type {Array<C>} */ ([]) 2060 2061/** 2062 * @template D 2063 * @param {Array<D>} a 2064 * @return {Array<D>} 2065 */ 2066const array_copy = a => /** @type {Array<D>} */ (a.slice()) 2067 2068/** 2069 * Append elements from src to dest 2070 * 2071 * @template M 2072 * @param {Array<M>} dest 2073 * @param {Array<M>} src 2074 */ 2075const appendTo = (dest, src) => { 2076 for (let i = 0; i < src.length; i++) { 2077 dest.push(src[i]) 2078 } 2079} 2080 2081/** 2082 * Transforms something array-like to an actual Array. 2083 * 2084 * @function 2085 * @template T 2086 * @param {ArrayLike<T>|Iterable<T>} arraylike 2087 * @return {T} 2088 */ 2089const array_from = Array.from 2090 2091/** 2092 * True iff condition holds on every element in the Array. 2093 * 2094 * @function 2095 * @template ITEM 2096 * @template {ArrayLike<ITEM>} ARR 2097 * 2098 * @param {ARR} arr 2099 * @param {function(ITEM, number, ARR):boolean} f 2100 * @return {boolean} 2101 */ 2102const every = (arr, f) => { 2103 for (let i = 0; i < arr.length; i++) { 2104 if (!f(arr[i], i, arr)) { 2105 return false 2106 } 2107 } 2108 return true 2109} 2110
2111/** 2112 * True iff condition holds on some element in the Array. 2113 * 2114 * @function 2115 * @template S 2116 * @template {ArrayLike<S>} ARR 2117 * @param {ARR} arr 2118 * @param {function(S, number, ARR):boolean} f 2119 * @return {boolean} 2120 */ 2121const some = (arr, f) => { 2122 for (let i = 0; i < arr.length; i++) { 2123 if (f(arr[i], i, arr)) { 2124 return true 2125 } 2126 } 2127 return false 2128} 2129 2130/** 2131 * @template ELEM 2132 * 2133 * @param {ArrayLike<ELEM>} a 2134 * @param {ArrayLike<ELEM>} b 2135 * @return {boolean} 2136 */ 2137const equalFlat = (a, b) => a.length === b.length && every(a, (item, index) => item === b[index]) 2138 2139/** 2140 * @template ELEM 2141 * @param {Array<Array<ELEM>>} arr 2142 * @return {Array<ELEM>} 2143 */ 2144const flatten = arr => fold(arr, /** @type {Array<ELEM>} */ ([]), (acc, val) => acc.concat(val)) 2145 2146/** 2147 * @template T 2148 * @param {number} len 2149 * @param {function(number, Array<T>):T} f 2150 * @return {Array<T>} 2151 */ 2152const unfold = (len, f) => { 2153 const array = new Array(len) 2154 for (let i = 0; i < len; i++) { 2155 array[i] = f(i, array) 2156 } 2157 return array 2158} 2159 2160/** 2161 * @template T 2162 * @template RESULT 2163 * @param {Array<T>} arr 2164 * @param {RESULT} seed 2165 * @param {function(RESULT, T, number):RESULT} folder 2166 */ 2167const fold = (arr, seed, folder) => arr.reduce(folder, seed) 2168 2169const isArray = Array.isArray 2170 2171/** 2172 * @template T 2173 * @param {Array<T>} arr 2174 * @return {Array<T>} 2175 */ 2176const unique = arr => array_from(set.from(arr)) 2177 2178/** 2179 * @template T 2180 * @template M 2181 * @param {ArrayLike<T>} arr 2182 * @param {function(T):M} mapper 2183 * @return {Array<T>} 2184 */ 2185const uniqueBy = (arr, mapper) => { 2186 /** 2187 * @type {Set<M>} 2188 */ 2189 const happened = set.create() 2190 /** 2191 * @type {Array<T>} 2192 */ 2193 const result = [] 2194 for (let i = 0; i < arr.length; i++) { 2195 const el = arr[i] 2196 const mapped = mapper(el) 2197 if (!happened.has(mapped)) { 2198 happened.add(mapped) 2199 result.push(el) 2200 } 2201 } 2202 return result 2203} 2204 2205/** 2206 * @template {ArrayLike<any>} ARR 2207 * @template {function(ARR extends ArrayLike<infer T> ? T : never, number, ARR):any} MAPPER 2208 * @param {ARR} arr 2209 * @param {MAPPER} mapper 2210 * @return {Array<MAPPER extends function(...any): infer M ? M : never>} 2211 */ 2212const array_map = (arr, mapper) => { 2213 /** 2214 * @type {Array<any>} 2215 */ 2216 const res = Array(arr.length) 2217 for (let i = 0; i < arr.length; i++) { 2218 res[i] = mapper(/** @type {any} */ (arr[i]), i, /** @type {any} */ (arr)) 2219 } 2220 return /** @type {any} */ (res) 2221} 2222 2223;// CONCATENATED MODULE: ./node_modules/lib0/observable.js 2224/** 2225 * Observable class prototype. 2226 * 2227 * @module observable 2228 */ 2229 2230 2231 2232 2233 2234/** 2235 * Handles named events. 2236 * 2237 * @template N 2238 */ 2239class observable_Observable { 2240 constructor () { 2241 /** 2242 * Some desc. 2243 * @type {Map<N, any>} 2244 */ 2245 this._observers = create() 2246 } 2247 2248 /** 2249 * @param {N} name 2250 * @param {function} f 2251 */ 2252 on (name, f) { 2253 setIfUndefined(this._observers, name, set_create).add(f) 2254 } 2255 2256 /** 2257 * @param {N} name 2258 * @param {function} f 2259 */ 2260 once (name, f) { 2261 /** 2262 * @param {...any} args 2263 */ 2264 const _f = (...args) => { 2265 this.off(name, _f) 2266 f(...args) 2267 } 2268 this.on(name, _f) 2269 } 2270 2271 /** 2272 * @param {N} name 2273 * @param {function} f 2274 */ 2275 off (name, f) { 2276 const observers = this._observers.get(name) 2277 if (observers !== undefined) { 2278 observers.delete(f) 2279 if (observers.size === 0) { 2280 this._observers.delete(name) 2281 } 2282 } 2283 } 2284 2285 /** 2286 * Emit a named event. All registered event listeners that listen to the 2287 * specified name will receive the event. 2288 * 2289 * @todo This should catch exceptions 2290 * 2291 * @param {N} name The event name. 2292 * @param {Array<any>} args The arguments that are applied to the event listener. 2293 */ 2294 emit (name, args) { 2295 // copy all listeners to an array first to make sure that no event is emitted to listeners that are subscribed while the event handler is called. 2296 return array_from((this._observers.get(name) || create()).values()).forEach(f => f(...args)) 2297 } 2298 2299 destroy () { 2300 this._observers = create() 2301 } 2302} 2303 2304;// CONCATENATED MODULE: ./node_modules/lib0/math.js 2305/** 2306 * Common Math expressions. 2307 * 2308 * @module math 2309 */ 2310 2311const floor = Math.floor
2312const ceil = Math.ceil 2313const abs = Math.abs 2314const imul = Math.imul 2315const round = Math.round 2316const log10 = Math.log10 2317const log2 = Math.log2 2318const log = Math.log 2319const sqrt = Math.sqrt 2320 2321/** 2322 * @function 2323 * @param {number} a 2324 * @param {number} b 2325 * @return {number} The sum of a and b 2326 */ 2327const add = (a, b) => a + b 2328 2329/** 2330 * @function 2331 * @param {number} a 2332 * @param {number} b 2333 * @return {number} The smaller element of a and b 2334 */ 2335const min = (a, b) => a < b ? a : b 2336 2337/** 2338 * @function 2339 * @param {number} a 2340 * @param {number} b 2341 * @return {number} The bigger element of a and b 2342 */ 2343const max = (a, b) => a > b ? a : b 2344 2345const math_isNaN = Number.isNaN 2346 2347const pow = Math.pow 2348/** 2349 * Base 10 exponential function. Returns the value of 10 raised to the power of pow. 2350 * 2351 * @param {number} exp 2352 * @return {number} 2353 */ 2354const exp10 = exp => Math.pow(10, exp) 2355 2356const sign = Math.sign 2357 2358/** 2359 * @param {number} n 2360 * @return {boolean} Wether n is negative. This function also differentiates between -0 and +0 2361 */ 2362const isNegativeZero = n => n !== 0 ? n < 0 : 1 / n < 0 2363 2364;// CONCATENATED MODULE: ./node_modules/lib0/string.js 2365 2366 2367/** 2368 * Utility module to work with strings. 2369 * 2370 * @module string 2371 */ 2372 2373const fromCharCode = String.fromCharCode 2374const fromCodePoint = String.fromCodePoint 2375 2376/** 2377 * The largest utf16 character. 2378 * Corresponds to Uint8Array([255, 255]) or charcodeof(2x2^8) 2379 */ 2380const MAX_UTF16_CHARACTER = fromCharCode(65535) 2381 2382/** 2383 * @param {string} s 2384 * @return {string} 2385 */ 2386const toLowerCase = s => s.toLowerCase() 2387 2388const trimLeftRegex = /^\s*/g 2389 2390/** 2391 * @param {string} s 2392 * @return {string} 2393 */ 2394const trimLeft = s => s.replace(trimLeftRegex, '') 2395 2396const fromCamelCaseRegex = /([A-Z])/g 2397 2398/** 2399 * @param {string} s 2400 * @param {string} separator 2401 * @return {string} 2402 */ 2403const fromCamelCase = (s, separator) => trimLeft(s.replace(fromCamelCaseRegex, match => `${separator}${toLowerCase(match)}`)) 2404 2405/** 2406 * Compute the utf8ByteLength 2407 * @param {string} str 2408 * @return {number} 2409 */ 2410const utf8ByteLength = str => unescape(encodeURIComponent(str)).length 2411 2412/** 2413 * @param {string} str 2414 * @return {Uint8Array} 2415 */ 2416const _encodeUtf8Polyfill = str => { 2417 const encodedString = unescape(encodeURIComponent(str)) 2418 const len = encodedString.length 2419 const buf = new Uint8Array(len) 2420 for (let i = 0; i < len; i++) { 2421 buf[i] = /** @type {number} */ (encodedString.codePointAt(i)) 2422 } 2423 return buf 2424} 2425 2426/* c8 ignore next */ 2427const utf8TextEncoder = /** @type {TextEncoder} */ (typeof TextEncoder !== 'undefined' ? new TextEncoder() : null) 2428 2429/** 2430 * @param {string} str 2431 * @return {Uint8Array} 2432 */ 2433const _encodeUtf8Native = str => utf8TextEncoder.encode(str) 2434 2435/** 2436 * @param {string} str 2437 * @return {Uint8Array} 2438 */ 2439/* c8 ignore next */ 2440const encodeUtf8 = utf8TextEncoder ? _encodeUtf8Native : _encodeUtf8Polyfill 2441 2442/** 2443 * @param {Uint8Array} buf 2444 * @return {string} 2445 */ 2446const _decodeUtf8Polyfill = buf => { 2447 let remainingLen = buf.length 2448 let encodedString = '' 2449 let bufPos = 0 2450 while (remainingLen > 0) { 2451 const nextLen = remainingLen < 10000 ? remainingLen : 10000 2452 const bytes = buf.subarray(bufPos, bufPos + nextLen) 2453 bufPos += nextLen 2454 // Starting with ES5.1 we can supply a generic array-like object as arguments 2455 encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes)) 2456 remainingLen -= nextLen 2457 } 2458 return decodeURIComponent(escape(encodedString)) 2459} 2460 2461/* c8 ignore next */ 2462let utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }) 2463 2464/* c8 ignore start */ 2465if (utf8TextDecoder && utf8TextDecoder.decode(new Uint8Array()).length === 1) { 2466 // Safari doesn't handle BOM correctly. 2467 // This fixes a bug in Safari 13.0.5 where it produces a BOM the first time it is called. 2468 // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the first call and 2469 // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the second call 2470 // Another issue is that from then on no BOM chars are recognized anymore 2471 /* c8 ignore next */ 2472 utf8TextDecoder = null 2473} 2474/* c8 ignore stop */ 2475 2476/** 2477 * @param {Uint8Array} buf 2478 * @return {string} 2479 */ 2480const _decodeUtf8Native = buf => /** @type {TextDecoder} */ (utf8TextDecoder).decode(buf) 2481 2482/** 2483 * @param {Uint8Array} buf 2484 * @return {string} 2485 */ 2486/* c8 ignore next */ 2487const decodeUtf8 = (/* unused pure expression or super */ null && (utf8TextDecoder ? _decodeUtf8Native : _decodeUtf8Polyfill)) 2488 2489/** 2490 * @param {string} str The initial string 2491 * @param {number} index Starting position 2492 * @param {number} remove Number of characters to remove 2493 * @param {string} insert New content to insert 2494 */ 2495const splice = (str, index, remove, insert = '') => str.slice(0, index) + insert + str.slice(index + remove) 2496 2497/** 2498 * @param {string} source 2499 * @param {number} n 2500 */ 2501const repeat = (source, n) => array.unfold(n, () => source).join('') 2502 2503;// CONCATENATED MODULE: ./node_modules/lib0/conditions.js 2504/** 2505 * Often used conditions. 2506 * 2507 * @module conditions 2508 */ 2509 2510/** 2511 * @template T 2512 * @param {T|null|undefined} v 2513 * @return {T|null} 2514 */ 2515/* c8 ignore next */ 2516const undefinedToNull = v => v === undefined ? null : v 2517 2518;// CONCATENATED MODULE: ./node_modules/lib0/storage.js 2519/* eslint-env browser */ 2520 2521/** 2522 * Isomorphic variable storage. 2523 * 2524 * Uses LocalStorage in the browser and falls back to in-memory storage. 2525 * 2526 * @module storage 2527 */ 2528 2529/* c8 ignore start */ 2530class VarStoragePolyfill { 2531 constructor () { 2532 this.map = new Map() 2533 } 2534 2535 /** 2536 * @param {string} key 2537 * @param {any} newValue 2538 */ 2539 setItem (key, newValue) { 2540 this.map.set(key, newValue) 2541 } 2542 2543 /** 2544 * @param {string} key 2545 */
2546 getItem (key) { 2547 return this.map.get(key) 2548 } 2549} 2550/* c8 ignore stop */ 2551 2552/** 2553 * @type {any} 2554 */ 2555let _localStorage = new VarStoragePolyfill() 2556let usePolyfill = true 2557 2558/* c8 ignore start */ 2559try { 2560 // if the same-origin rule is violated, accessing localStorage might thrown an error 2561 if (typeof localStorage !== 'undefined') { 2562 _localStorage = localStorage 2563 usePolyfill = false 2564 } 2565} catch (e) { } 2566/* c8 ignore stop */ 2567 2568/** 2569 * This is basically localStorage in browser, or a polyfill in nodejs 2570 */ 2571/* c8 ignore next */ 2572const varStorage = _localStorage 2573 2574/** 2575 * A polyfill for `addEventListener('storage', event => {..})` that does nothing if the polyfill is being used. 2576 * 2577 * @param {function({ key: string, newValue: string, oldValue: string }): void} eventHandler 2578 * @function 2579 */ 2580/* c8 ignore next */ 2581const onChange = eventHandler => usePolyfill || addEventListener('storage', /** @type {any} */ (eventHandler)) 2582 2583/** 2584 * A polyfill for `removeEventListener('storage', event => {..})` that does nothing if the polyfill is being used. 2585 * 2586 * @param {function({ key: string, newValue: string, oldValue: string }): void} eventHandler 2587 * @function 2588 */ 2589/* c8 ignore next */ 2590const offChange = eventHandler => usePolyfill || removeEventListener('storage', /** @type {any} */ (eventHandler)) 2591 2592;// CONCATENATED MODULE: ./node_modules/lib0/object.js 2593/** 2594 * Utility functions for working with EcmaScript objects. 2595 * 2596 * @module object 2597 */ 2598 2599/** 2600 * @return {Object<string,any>} obj 2601 */ 2602const object_create = () => Object.create(null) 2603 2604/** 2605 * Object.assign 2606 */ 2607const object_assign = Object.assign 2608 2609/** 2610 * @param {Object<string,any>} obj 2611 */ 2612const keys = Object.keys 2613 2614/** 2615 * @template V 2616 * @param {{[k:string]:V}} obj 2617 * @param {function(V,string):any} f 2618 */ 2619const forEach = (obj, f) => { 2620 for (const key in obj) { 2621 f(obj[key], key) 2622 } 2623} 2624 2625/** 2626 * @todo implement mapToArray & map 2627 * 2628 * @template R 2629 * @param {Object<string,any>} obj 2630 * @param {function(any,string):R} f 2631 * @return {Array<R>} 2632 */ 2633const object_map = (obj, f) => { 2634 const results = [] 2635 for (const key in obj) { 2636 results.push(f(obj[key], key)) 2637 } 2638 return results 2639} 2640 2641/** 2642 * @param {Object<string,any>} obj 2643 * @return {number} 2644 */ 2645const object_length = obj => keys(obj).length 2646 2647/** 2648 * @param {Object<string,any>} obj 2649 * @param {function(any,string):boolean} f 2650 * @return {boolean} 2651 */ 2652const object_some = (obj, f) => { 2653 for (const key in obj) { 2654 if (f(obj[key], key)) { 2655 return true 2656 } 2657 } 2658 return false 2659} 2660 2661/** 2662 * @param {Object|undefined} obj 2663 */ 2664const isEmpty = obj => { 2665 // eslint-disable-next-line 2666 for (const _k in obj) { 2667 return false 2668 } 2669 return true 2670} 2671 2672/** 2673 * @param {Object<string,any>} obj 2674 * @param {function(any,string):boolean} f 2675 * @return {boolean} 2676 */ 2677const object_every = (obj, f) => { 2678 for (const key in obj) { 2679 if (!f(obj[key], key)) { 2680 return false 2681 } 2682 } 2683 return true 2684} 2685 2686/** 2687 * Calls `Object.prototype.hasOwnProperty`. 2688 * 2689 * @param {any} obj 2690 * @param {string|symbol} key 2691 * @return {boolean} 2692 */ 2693const hasProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key) 2694 2695/** 2696 * @param {Object<string,any>} a 2697 * @param {Object<string,any>} b 2698 * @return {boolean} 2699 */ 2700const object_equalFlat = (a, b) => a === b || (object_length(a) === object_length(b) && object_every(a, (val, key) => (val !== undefined || hasProperty(b, key)) && b[key] === val)) 2701 2702;// CONCATENATED MODULE: ./node_modules/lib0/function.js 2703/** 2704 * Common functions and function call helpers. 2705 * 2706 * @module function 2707 */ 2708 2709 2710 2711 2712/** 2713 * Calls all functions in `fs` with args. Only throws after all functions were called. 2714 * 2715 * @param {Array<function>} fs 2716 * @param {Array<any>} args 2717 */ 2718const callAll = (fs, args, i = 0) => { 2719 try { 2720 for (; i < fs.length; i++) { 2721 fs[i](...args) 2722 } 2723 } finally { 2724 if (i < fs.length) { 2725 callAll(fs, args, i + 1) 2726 } 2727 } 2728} 2729 2730const nop = () => {} 2731 2732/** 2733 * @template T 2734 * @param {function():T} f 2735 * @return {T} 2736 */ 2737const apply = f => f() 2738 2739/** 2740 * @template A 2741 * 2742 * @param {A} a 2743 * @return {A} 2744 */ 2745const id = a => a 2746 2747/** 2748 * @template T 2749 * 2750 * @param {T} a 2751 * @param {T} b 2752 * @return {boolean} 2753 */ 2754const equalityStrict = (a, b) => a === b 2755 2756/** 2757 * @template T 2758 * 2759 * @param {Array<T>|object} a 2760 * @param {Array<T>|object} b 2761 * @return {boolean} 2762 */ 2763const equalityFlat = (a, b) => a === b || (a != null && b != null && a.constructor === b.constructor && ((array.isArray(a) && array.equalFlat(a, /** @type {Array<T>} */ (b))) || (typeof a === 'object' && object.equalFlat(a, b)))) 2764 2765/* c8 ignore start */ 2766 2767/** 2768 * @param {any} a 2769 * @param {any} b 2770 * @return {boolean} 2771 */ 2772const equalityDeep = (a, b) => { 2773 if (a == null || b == null) { 2774 return equalityStrict(a, b) 2775 } 2776 if (a.constructor !== b.constructor) { 2777 return false 2778 } 2779 if (a === b) { 2780 return true 2781 } 2782 switch (a.constructor) { 2783 case ArrayBuffer: 2784 a = new Uint8Array(a) 2785 b = new Uint8Array(b) 2786 // eslint-disable-next-line no-fallthrough 2787 case Uint8Array: { 2788 if (a.byteLength !== b.byteLength) { 2789 return false 2790 } 2791 for (let i = 0; i < a.length; i++) { 2792 if (a[i] !== b[i]) { 2793 return false 2794 } 2795 } 2796 break 2797 } 2798 case Set: { 2799 if (a.size !== b.size) { 2800 return false 2801 } 2802 for (const value of a) { 2803 if (!b.has(value)) { 2804 return false 2805 } 2806 } 2807 break 2808 } 2809 case Map: { 2810 if (a.size !== b.size) { 2811 return false 2812 } 2813 for (const key of a.keys()) { 2814 if (!b.has(key) || !equalityDeep(a.get(key), b.get(key))) { 2815 return false 2816 } 2817 } 2818 break 2819 } 2820 case Object: 2821 if (object_length(a) !== object_length(b)) { 2822 return false 2823 } 2824 for (const key in a) { 2825 if (!hasProperty(a, key) || !equalityDeep(a[key], b[key])) { 2826 return false 2827 } 2828 } 2829 break 2830 case Array: 2831 if (a.length !== b.length) { 2832 return false 2833 } 2834 for (let i = 0; i < a.length; i++) { 2835 if (!equalityDeep(a[i], b[i])) { 2836 return false 2837 } 2838 } 2839 break 2840 default: 2841 return false 2842 } 2843 return true 2844} 2845
2846/** 2847 * @template V 2848 * @template {V} OPTS 2849 * 2850 * @param {V} value 2851 * @param {Array<OPTS>} options 2852 */ 2853// @ts-ignore 2854const isOneOf = (value, options) => options.includes(value) 2855/* c8 ignore stop */ 2856 2857const function_isArray = isArray 2858 2859/** 2860 * @param {any} s 2861 * @return {s is String} 2862 */ 2863const isString = (s) => s && s.constructor === String 2864 2865/** 2866 * @param {any} n 2867 * @return {n is Number} 2868 */ 2869const isNumber = n => n != null && n.constructor === Number 2870 2871/** 2872 * @template {abstract new (...args: any) => any} TYPE 2873 * @param {any} n 2874 * @param {TYPE} T 2875 * @return {n is InstanceType<TYPE>} 2876 */ 2877const is = (n, T) => n && n.constructor === T 2878 2879/** 2880 * @template {abstract new (...args: any) => any} TYPE 2881 * @param {TYPE} T 2882 */ 2883const isTemplate = (T) => 2884 /** 2885 * @param {any} n 2886 * @return {n is InstanceType<TYPE>} 2887 **/ 2888 n => n && n.constructor === T 2889 2890;// CONCATENATED MODULE: ./node_modules/lib0/environment.js 2891/** 2892 * Isomorphic module to work access the environment (query params, env variables). 2893 * 2894 * @module map 2895 */ 2896 2897 2898 2899 2900 2901 2902 2903/* c8 ignore next */ 2904// @ts-ignore 2905const isNode = typeof process !== 'undefined' && process.release && 2906 /node|io\.js/.test(process.release.name) 2907/* c8 ignore next */ 2908const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && !isNode 2909/* c8 ignore next 3 */ 2910const isMac = typeof navigator !== 'undefined' 2911 ? /Mac/.test(navigator.platform) 2912 : false 2913 2914/** 2915 * @type {Map<string,string>} 2916 */ 2917let params 2918const args = [] 2919 2920/* c8 ignore start */ 2921const computeParams = () => { 2922 if (params === undefined) { 2923 if (isNode) { 2924 params = create() 2925 const pargs = process.argv 2926 let currParamName = null 2927 for (let i = 0; i < pargs.length; i++) { 2928 const parg = pargs[i] 2929 if (parg[0] === '-') { 2930 if (currParamName !== null) { 2931 params.set(currParamName, '') 2932 } 2933 currParamName = parg 2934 } else { 2935 if (currParamName !== null) { 2936 params.set(currParamName, parg) 2937 currParamName = null 2938 } else { 2939 args.push(parg) 2940 } 2941 } 2942 } 2943 if (currParamName !== null) { 2944 params.set(currParamName, '') 2945 } 2946 // in ReactNative for example this would not be true (unless connected to the Remote Debugger) 2947 } else if (typeof location === 'object') { 2948 params = create(); // eslint-disable-next-line no-undef 2949 (location.search || '?').slice(1).split('&').forEach((kv) => { 2950 if (kv.length !== 0) { 2951 const [key, value] = kv.split('=') 2952 params.set(`--${fromCamelCase(key, '-')}`, value) 2953 params.set(`-${fromCamelCase(key, '-')}`, value) 2954 } 2955 }) 2956 } else { 2957 params = create() 2958 } 2959 } 2960 return params 2961} 2962/* c8 ignore stop */ 2963 2964/** 2965 * @param {string} name 2966 * @return {boolean} 2967 */ 2968/* c8 ignore next */ 2969const hasParam = (name) => computeParams().has(name) 2970 2971/** 2972 * @param {string} name 2973 * @param {string} defaultVal 2974 * @return {string} 2975 */ 2976/* c8 ignore next 2 */ 2977const getParam = (name, defaultVal) => 2978 computeParams().get(name) || defaultVal 2979 2980/** 2981 * @param {string} name 2982 * @return {string|null} 2983 */ 2984/* c8 ignore next 4 */ 2985const getVariable = (name) => 2986 isNode 2987 ? undefinedToNull(process.env[name.toUpperCase()]) 2988 : undefinedToNull(varStorage.getItem(name)) 2989 2990/** 2991 * @param {string} name 2992 * @return {string|null} 2993 */ 2994/* c8 ignore next 2 */ 2995const getConf = (name) => 2996 computeParams().get('--' + name) || getVariable(name) 2997 2998/** 2999 * @param {string} name 3000 * @return {boolean} 3001 */ 3002/* c8 ignore next 2 */ 3003const hasConf = (name) => 3004 hasParam('--' + name) || getVariable(name) !== null 3005 3006/* c8 ignore next */ 3007const production = hasConf('production') 3008 3009/* c8 ignore next 2 */ 3010const forceColor = isNode && 3011 isOneOf(process.env.FORCE_COLOR, ['true', '1', '2']) 3012 3013/* c8 ignore start */ 3014const supportsColor = !hasParam('no-colors') && 3015 (!isNode || process.stdout.isTTY || forceColor) && ( 3016 !isNode || hasParam('color') || forceColor || 3017 getVariable('COLORTERM') !== null || 3018 (getVariable('TERM') || '').includes('color') 3019) 3020/* c8 ignore stop */ 3021 3022;// CONCATENATED MODULE: ./node_modules/lib0/buffer.js 3023/** 3024 * Utility functions to work with buffers (Uint8Array). 3025 * 3026 * @module buffer 3027 */ 3028 3029 3030 3031 3032 3033 3034 3035 3036/** 3037 * @param {number} len 3038 */ 3039const createUint8ArrayFromLen = len => new Uint8Array(len) 3040 3041/** 3042 * Create Uint8Array with initial content from buffer 3043 * 3044 * @param {ArrayBuffer} buffer 3045 * @param {number} byteOffset 3046 * @param {number} length 3047 */ 3048const createUint8ArrayViewFromArrayBuffer = (buffer, byteOffset, length) => new Uint8Array(buffer, byteOffset, length) 3049 3050/** 3051 * Create Uint8Array with initial content from buffer 3052 * 3053 * @param {ArrayBuffer} buffer 3054 */ 3055const createUint8ArrayFromArrayBuffer = buffer => new Uint8Array(buffer) 3056 3057/* c8 ignore start */ 3058/** 3059 * @param {Uint8Array} bytes 3060 * @return {string} 3061 */ 3062const toBase64Browser = bytes => { 3063 let s = '' 3064 for (let i = 0; i < bytes.byteLength; i++) { 3065 s += fromCharCode(bytes[i]) 3066 } 3067 // eslint-disable-next-line no-undef 3068 return btoa(s) 3069} 3070/* c8 ignore stop */ 3071 3072/** 3073 * @param {Uint8Array} bytes 3074 * @return {string} 3075 */ 3076const toBase64Node = bytes => Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64') 3077 3078/* c8 ignore start */ 3079/** 3080 * @param {string} s 3081 * @return {Uint8Array} 3082 */ 3083const fromBase64Browser = s => { 3084 // eslint-disable-next-line no-undef 3085 const a = atob(s) 3086 const bytes = createUint8ArrayFromLen(a.length) 3087 for (let i = 0; i < a.length; i++) { 3088 bytes[i] = a.charCodeAt(i) 3089 } 3090 return bytes 3091} 3092/* c8 ignore stop */ 3093 3094/** 3095 * @param {string} s 3096 */ 3097const fromBase64Node = s => { 3098 const buf = Buffer.from(s, 'base64') 3099 return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength) 3100} 3101 3102/* c8 ignore next */ 3103const toBase64 = isBrowser ? toBase64Browser : toBase64Node 3104 3105/* c8 ignore next */ 3106const fromBase64 = isBrowser ? fromBase64Browser : fromBase64Node 3107 3108/** 3109 * Base64 is always a more efficient choice. This exists for utility purposes only. 3110 * 3111 * @param {Uint8Array} buf 3112 */ 3113const toHexString = buf => array.map(buf, b => b.toString(16).padStart(2, '0')).join('') 3114 3115/** 3116 * Note: This function expects that the hex doesn't start with 0x.. 3117 * 3118 * @param {string} hex 3119 */ 3120const fromHexString = hex => { 3121 const hlen = hex.length 3122 const buf = new Uint8Array(math.ceil(hlen / 2)) 3123 for (let i = 0; i < hlen; i += 2) {
3124 buf[buf.length - i / 2 - 1] = Number.parseInt(hex.slice(hlen - i - 2, hlen - i), 16) 3125 } 3126 return buf 3127} 3128 3129/** 3130 * Copy the content of an Uint8Array view to a new ArrayBuffer. 3131 * 3132 * @param {Uint8Array} uint8Array 3133 * @return {Uint8Array} 3134 */ 3135const copyUint8Array = uint8Array => { 3136 const newBuf = createUint8ArrayFromLen(uint8Array.byteLength) 3137 newBuf.set(uint8Array) 3138 return newBuf 3139} 3140 3141/** 3142 * Encode anything as a UInt8Array. It's a pun on typescripts's `any` type. 3143 * See encoding.writeAny for more information. 3144 * 3145 * @param {any} data 3146 * @return {Uint8Array} 3147 */ 3148const encodeAny = data => { 3149 const encoder = encoding.createEncoder() 3150 encoding.writeAny(encoder, data) 3151 return encoding.toUint8Array(encoder) 3152} 3153 3154/** 3155 * Decode an any-encoded value. 3156 * 3157 * @param {Uint8Array} buf 3158 * @return {any} 3159 */ 3160const decodeAny = buf => decoding.readAny(decoding.createDecoder(buf)) 3161 3162/** 3163 * Shift Byte Array {N} bits to the left. Does not expand byte array. 3164 * 3165 * @param {Uint8Array} bs 3166 * @param {number} N should be in the range of [0-7] 3167 */ 3168const shiftNBitsLeft = (bs, N) => { 3169 if (N === 0) return bs 3170 bs = new Uint8Array(bs) 3171 bs[0] <<= N 3172 for (let i = 1; i < bs.length; i++) { 3173 bs[i - 1] |= bs[i] >>> (8 - N) 3174 bs[i] <<= N 3175 } 3176 return bs 3177} 3178 3179;// CONCATENATED MODULE: ./node_modules/lib0/binary.js 3180/* eslint-env browser */ 3181 3182/** 3183 * Binary data constants. 3184 * 3185 * @module binary 3186 */ 3187 3188/** 3189 * n-th bit activated. 3190 * 3191 * @type {number} 3192 */ 3193const BIT1 = 1 3194const BIT2 = 2 3195const BIT3 = 4 3196const BIT4 = 8 3197const BIT5 = 16 3198const BIT6 = 32 3199const BIT7 = 64 3200const BIT8 = 128 3201const BIT9 = 256 3202const BIT10 = 512 3203const BIT11 = 1024 3204const BIT12 = 2048 3205const BIT13 = 4096 3206const BIT14 = 8192 3207const BIT15 = 16384 3208const BIT16 = 32768 3209const BIT17 = 65536 3210const BIT18 = 1 << 17 3211const BIT19 = 1 << 18 3212const BIT20 = 1 << 19 3213const BIT21 = 1 << 20 3214const BIT22 = 1 << 21 3215const BIT23 = 1 << 22 3216const BIT24 = 1 << 23 3217const BIT25 = 1 << 24 3218const BIT26 = 1 << 25 3219const BIT27 = 1 << 26 3220const BIT28 = 1 << 27 3221const BIT29 = 1 << 28 3222const BIT30 = 1 << 29 3223const BIT31 = 1 << 30 3224const BIT32 = (/* unused pure expression or super */ null && (1 << 31)) 3225 3226/** 3227 * First n bits activated. 3228 * 3229 * @type {number} 3230 */ 3231const BITS0 = 0 3232const BITS1 = 1 3233const BITS2 = 3 3234const BITS3 = 7 3235const BITS4 = 15 3236const BITS5 = 31 3237const BITS6 = 63 3238const BITS7 = 127 3239const BITS8 = 255 3240const BITS9 = 511 3241const BITS10 = 1023 3242const BITS11 = 2047 3243const BITS12 = 4095 3244const BITS13 = 8191 3245const BITS14 = 16383 3246const BITS15 = 32767 3247const BITS16 = 65535 3248const BITS17 = BIT18 - 1 3249const BITS18 = BIT19 - 1 3250const BITS19 = BIT20 - 1 3251const BITS20 = BIT21 - 1 3252const BITS21 = BIT22 - 1 3253const BITS22 = BIT23 - 1 3254const BITS23 = BIT24 - 1 3255const BITS24 = BIT25 - 1 3256const BITS25 = BIT26 - 1 3257const BITS26 = BIT27 - 1 3258const BITS27 = BIT28 - 1 3259const BITS28 = BIT29 - 1 3260const BITS29 = BIT30 - 1 3261const BITS30 = BIT31 - 1 3262/** 3263 * @type {number} 3264 */ 3265const BITS31 = 0x7FFFFFFF 3266/** 3267 * @type {number} 3268 */ 3269const BITS32 = 0xFFFFFFFF 3270 3271;// CONCATENATED MODULE: ./node_modules/lib0/number.js 3272/** 3273 * Utility helpers for working with numbers. 3274 * 3275 * @module number 3276 */ 3277 3278 3279 3280 3281const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER 3282const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER 3283 3284const LOWEST_INT32 = (/* unused pure expression or super */ null && (1 << 31)) 3285const HIGHEST_INT32 = BITS31 3286const HIGHEST_UINT32 = BITS32 3287 3288/* c8 ignore next */ 3289const isInteger = Number.isInteger || (num => typeof num === 'number' && isFinite(num) && floor(num) === num) 3290const number_isNaN = Number.isNaN 3291const number_parseInt = Number.parseInt 3292 3293/** 3294 * Count the number of "1" bits in an unsigned 32bit number. 3295 * 3296 * Super fun bitcount algorithm by Brian Kernighan. 3297 * 3298 * @param {number} n 3299 */ 3300const countBits = n => { 3301 n &= binary.BITS32 3302 let count = 0 3303 while (n) { 3304 n &= (n - 1) 3305 count++ 3306 } 3307 return count 3308} 3309 3310;// CONCATENATED MODULE: ./node_modules/lib0/encoding.js 3311/** 3312 * Efficient schema-less binary encoding with support for variable length encoding. 3313 * 3314 * Use [lib0/encoding] with [lib0/decoding]. Every encoding function has a corresponding decoding function. 3315 * 3316 * Encodes numbers in little-endian order (least to most significant byte order) 3317 * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/) 3318 * which is also used in Protocol Buffers. 3319 * 3320 * ```js 3321 * // encoding step 3322 * const encoder = encoding.createEncoder() 3323 * encoding.writeVarUint(encoder, 256) 3324 * encoding.writeVarString(encoder, 'Hello world!') 3325 * const buf = encoding.toUint8Array(encoder) 3326 * ``` 3327 * 3328 * ```js 3329 * // decoding step 3330 * const decoder = decoding.createDecoder(buf) 3331 * decoding.readVarUint(decoder) // => 256 3332 * decoding.readVarString(decoder) // => 'Hello world!' 3333 * decoding.hasContent(decoder) // => false - all data is read 3334 * ``` 3335 * 3336 * @module encoding 3337 */ 3338 3339 3340 3341 3342 3343 3344 3345 3346/** 3347 * A BinaryEncoder handles the encoding to an Uint8Array. 3348 */ 3349class Encoder { 3350 constructor () { 3351 this.cpos = 0 3352 this.cbuf = new Uint8Array(100) 3353 /** 3354 * @type {Array<Uint8Array>} 3355 */ 3356 this.bufs = [] 3357 } 3358} 3359 3360/** 3361 * @function 3362 * @return {Encoder} 3363 */ 3364const createEncoder = () => new Encoder() 3365 3366/** 3367 * @param {function(Encoder):void} f 3368 */ 3369const encode = (f) => { 3370 const encoder = createEncoder() 3371 f(encoder) 3372 return toUint8Array(encoder) 3373} 3374 3375/** 3376 * The current length of the encoded data. 3377 * 3378 * @function 3379 * @param {Encoder} encoder 3380 * @return {number} 3381 */ 3382const encoding_length = encoder => { 3383 let len = encoder.cpos 3384 for (let i = 0; i < encoder.bufs.length; i++) { 3385 len += encoder.bufs[i].length 3386 } 3387 return len 3388} 3389 3390/** 3391 * Check whether encoder is empty. 3392 * 3393 * @function 3394 * @param {Encoder} encoder 3395 * @return {boolean} 3396 */ 3397const hasContent = encoder => encoder.cpos > 0 || encoder.bufs.length > 0 3398 3399/** 3400 * Transform to Uint8Array. 3401 * 3402 * @function 3403 * @param {Encoder} encoder 3404 * @return {Uint8Array} The created ArrayBuffer. 3405 */ 3406const toUint8Array = encoder => { 3407 const uint8arr = new Uint8Array(encoding_length(encoder)) 3408 let curPos = 0 3409 for (let i = 0; i < encoder.bufs.length; i++) { 3410 const d = encoder.bufs[i] 3411 uint8arr.set(d, curPos) 3412 curPos += d.length 3413 } 3414 uint8arr.set(createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos), curPos) 3415 return uint8arr 3416} 3417 3418/** 3419 * Verify that it is possible to write `len` bytes wtihout checking. If 3420 * necessary, a new Buffer with the required length is attached.
3421 * 3422 * @param {Encoder} encoder 3423 * @param {number} len 3424 */ 3425const verifyLen = (encoder, len) => { 3426 const bufferLen = encoder.cbuf.length 3427 if (bufferLen - encoder.cpos < len) { 3428 encoder.bufs.push(createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos)) 3429 encoder.cbuf = new Uint8Array(max(bufferLen, len) * 2) 3430 encoder.cpos = 0 3431 } 3432} 3433 3434/** 3435 * Write one byte to the encoder. 3436 * 3437 * @function 3438 * @param {Encoder} encoder 3439 * @param {number} num The byte that is to be encoded. 3440 */ 3441const write = (encoder, num) => { 3442 const bufferLen = encoder.cbuf.length 3443 if (encoder.cpos === bufferLen) { 3444 encoder.bufs.push(encoder.cbuf) 3445 encoder.cbuf = new Uint8Array(bufferLen * 2) 3446 encoder.cpos = 0 3447 } 3448 encoder.cbuf[encoder.cpos++] = num 3449} 3450 3451/** 3452 * Write one byte at a specific position. 3453 * Position must already be written (i.e. encoder.length > pos) 3454 * 3455 * @function 3456 * @param {Encoder} encoder 3457 * @param {number} pos Position to which to write data 3458 * @param {number} num Unsigned 8-bit integer 3459 */ 3460const encoding_set = (encoder, pos, num) => { 3461 let buffer = null 3462 // iterate all buffers and adjust position 3463 for (let i = 0; i < encoder.bufs.length && buffer === null; i++) { 3464 const b = encoder.bufs[i] 3465 if (pos < b.length) { 3466 buffer = b // found buffer 3467 } else { 3468 pos -= b.length 3469 } 3470 } 3471 if (buffer === null) { 3472 // use current buffer 3473 buffer = encoder.cbuf 3474 } 3475 buffer[pos] = num 3476} 3477 3478/** 3479 * Write one byte as an unsigned integer. 3480 * 3481 * @function 3482 * @param {Encoder} encoder 3483 * @param {number} num The number that is to be encoded. 3484 */ 3485const writeUint8 = write 3486 3487/** 3488 * Write one byte as an unsigned Integer at a specific location. 3489 * 3490 * @function 3491 * @param {Encoder} encoder 3492 * @param {number} pos The location where the data will be written. 3493 * @param {number} num The number that is to be encoded. 3494 */ 3495const setUint8 = (/* unused pure expression or super */ null && (encoding_set)) 3496 3497/** 3498 * Write two bytes as an unsigned integer. 3499 * 3500 * @function 3501 * @param {Encoder} encoder 3502 * @param {number} num The number that is to be encoded. 3503 */ 3504const writeUint16 = (encoder, num) => { 3505 write(encoder, num & binary.BITS8) 3506 write(encoder, (num >>> 8) & binary.BITS8) 3507} 3508/** 3509 * Write two bytes as an unsigned integer at a specific location. 3510 * 3511 * @function 3512 * @param {Encoder} encoder 3513 * @param {number} pos The location where the data will be written. 3514 * @param {number} num The number that is to be encoded. 3515 */ 3516const setUint16 = (encoder, pos, num) => { 3517 encoding_set(encoder, pos, num & binary.BITS8) 3518 encoding_set(encoder, pos + 1, (num >>> 8) & binary.BITS8) 3519} 3520 3521/** 3522 * Write two bytes as an unsigned integer 3523 * 3524 * @function 3525 * @param {Encoder} encoder 3526 * @param {number} num The number that is to be encoded. 3527 */ 3528const writeUint32 = (encoder, num) => { 3529 for (let i = 0; i < 4; i++) { 3530 write(encoder, num & binary.BITS8) 3531 num >>>= 8 3532 } 3533} 3534 3535/** 3536 * Write two bytes as an unsigned integer in big endian order. 3537 * (most significant byte first) 3538 * 3539 * @function 3540 * @param {Encoder} encoder 3541 * @param {number} num The number that is to be encoded. 3542 */ 3543const writeUint32BigEndian = (encoder, num) => { 3544 for (let i = 3; i >= 0; i--) { 3545 write(encoder, (num >>> (8 * i)) & binary.BITS8) 3546 } 3547} 3548 3549/** 3550 * Write two bytes as an unsigned integer at a specific location. 3551 * 3552 * @function 3553 * @param {Encoder} encoder 3554 * @param {number} pos The location where the data will be written. 3555 * @param {number} num The number that is to be encoded. 3556 */ 3557const setUint32 = (encoder, pos, num) => { 3558 for (let i = 0; i < 4; i++) { 3559 encoding_set(encoder, pos + i, num & binary.BITS8) 3560 num >>>= 8 3561 } 3562} 3563 3564/** 3565 * Write a variable length unsigned integer. Max encodable integer is 2^53. 3566 * 3567 * @function 3568 * @param {Encoder} encoder 3569 * @param {number} num The number that is to be encoded. 3570 */ 3571const writeVarUint = (encoder, num) => { 3572 while (num > BITS7) { 3573 write(encoder, BIT8 | (BITS7 & num)) 3574 num = floor(num / 128) // shift >>> 7 3575 } 3576 write(encoder, BITS7 & num) 3577} 3578 3579/** 3580 * Write a variable length integer. 3581 * 3582 * We use the 7th bit instead for signaling that this is a negative number. 3583 * 3584 * @function 3585 * @param {Encoder} encoder 3586 * @param {number} num The number that is to be encoded. 3587 */ 3588const writeVarInt = (encoder, num) => { 3589 const isNegative = isNegativeZero(num) 3590 if (isNegative) { 3591 num = -num 3592 } 3593 // |- whether to continue reading |- whether is negative |- number 3594 write(encoder, (num >
3594 BITS6 ? BIT8 : 0) | (isNegative ? BIT7 : 0) | (BITS6 & num)) 3595 num = floor(num / 64) // shift >>> 6 3596 // We don't need to consider the case of num === 0 so we can use a different 3597 // pattern here than above. 3598 while (num > 0) { 3599 write(encoder, (num > BITS7 ? BIT8 : 0) | (BITS7 & num)) 3600 num = floor(num / 128) // shift >>> 7 3601 } 3602} 3603 3604/** 3605 * A cache to store strings temporarily 3606 */ 3607const _strBuffer = new Uint8Array(30000) 3608const _maxStrBSize = _strBuffer.length / 3 3609 3610/** 3611 * Write a variable length string. 3612 * 3613 * @function 3614 * @param {Encoder} encoder 3615 * @param {String} str The string that is to be encoded. 3616 */ 3617const _writeVarStringNative = (encoder, str) => { 3618 if (str.length < _maxStrBSize) { 3619 // We can encode the string into the existing buffer 3620 /* c8 ignore next */ 3621 const written = utf8TextEncoder.encodeInto(str, _strBuffer).written || 0 3622 writeVarUint(encoder, written) 3623 for (let i = 0; i < written; i++) { 3624 write(encoder, _strBuffer[i]) 3625 } 3626 } else { 3627 writeVarUint8Array(encoder, encodeUtf8(str)) 3628 } 3629} 3630 3631/** 3632 * Write a variable length string. 3633 * 3634 * @function 3635 * @param {Encoder} encoder 3636 * @param {String} str The string that is to be encoded. 3637 */ 3638const _writeVarStringPolyfill = (encoder, str) => { 3639 const encodedString = unescape(encodeURIComponent(str)) 3640 const len = encodedString.length 3641 writeVarUint(encoder, len) 3642 for (let i = 0; i < len; i++) { 3643 write(encoder, /** @type {number} */ (encodedString.codePointAt(i))) 3644 } 3645} 3646 3647/** 3648 * Write a variable length string. 3649 * 3650 * @function 3651 * @param {Encoder} encoder 3652 * @param {String} str The string that is to be encoded. 3653 */ 3654/* c8 ignore next */ 3655const writeVarString = (utf8TextEncoder && /** @type {any} */ utf8TextEncoder.encodeInto) ? _writeVarStringNative : _writeVarStringPolyfill 3656 3657/** 3658 * Write a string terminated by a special byte sequence. This is not very performant and is 3659 * generally discouraged. However, the resulting byte arrays are lexiographically ordered which 3660 * makes this a nice feature for databases. 3661 * 3662 * The string will be encoded using utf8 and then terminated and escaped using writeTerminatingUint8Array. 3663 * 3664 * @function 3665 * @param {Encoder} encoder 3666 * @param {String} str The string that is to be encoded. 3667 */ 3668const writeTerminatedString = (encoder, str) => 3669 writeTerminatedUint8Array(encoder, string.encodeUtf8(str)) 3670 3671/** 3672 * Write a terminating Uint8Array. Note that this is not performant and is generally 3673 * discouraged. There are few situations when this is needed. 3674 * 3675 * We use 0x0 as a terminating character. 0x1 serves as an escape character for 0x0 and 0x1. 3676 * 3677 * Example: [0,1,2] is encoded to [1,0,1,1,2,0]. 0x0, and 0x1 needed to be escaped using 0x1. Then 3678 * the result is terminated using the 0x0 character. 3679 * 3680 * This is basically how many systems implement null terminated strings. However, we use an escape 3681 * character 0x1 to avoid issues and potenial attacks on our database (if this is used as a key 3682 * encoder for NoSql databases). 3683 * 3684 * @function 3685 * @param {Encoder} encoder 3686 * @param {Uint8Array} buf The string that is to be encoded. 3687 */ 3688const writeTerminatedUint8Array = (encoder, buf) => { 3689 for (let i = 0; i < buf.length; i++) { 3690 const b = buf[i] 3691 if (b === 0 || b === 1) { 3692 write(encoder, 1) 3693 } 3694 write(encoder, buf[i]) 3695 } 3696 write(encoder, 0) 3697} 3698 3699/** 3700 * Write the content of another Encoder. 3701 * 3702 * @TODO: can be improved! 3703 * - Note: Should consider that when appending a lot of small Encoders, we should rather clone than referencing the old structure. 3704 * Encoders start with a rather big initial buffer. 3705 * 3706 * @function 3707 * @param {Encoder} encoder The enUint8Arr 3708 * @param {Encoder} append The BinaryEncoder to be written. 3709 */ 3710const writeBinaryEncoder = (encoder, append) => writeUint8Array(encoder, toUint8Array(append)) 3711 3712/** 3713 * Append fixed-length Uint8Array to the encoder. 3714 * 3715 * @function 3716 * @param {Encoder} encoder 3717 * @param {Uint8Array} uint8Array 3718 */ 3719const writeUint8Array = (encoder, uint8Array) => { 3720 const bufferLen = encoder.cbuf.length 3721 const cpos = encoder.cpos 3722 const leftCopyLen = min(bufferLen - cpos, uint8Array.length) 3723 const rightCopyLen = uint8Array.length - leftCopyLen 3724 encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos) 3725 encoder.cpos += leftCopyLen 3726 if (rightCopyLen > 0) { 3727 // Still something to write, write right half.. 3728 // Append new buffer 3729 encoder.bufs.push(encoder.cbuf) 3730 // must have at least size of remaining buffer 3731 encoder.cbuf = new Uint8Array(max(bufferLen * 2, rightCopyLen)) 3732 // copy array 3733 encoder.cbuf.set(uint8Array.subarray(leftCopyLen)) 3734 encoder.cpos = rightCopyLen 3735 } 3736} 3737 3738/** 3739 * Append an Uint8Array to Encoder. 3740 * 3741 * @function 3742 * @param {Encoder} encoder 3743 * @param {Uint8Array} uint8Array 3744 */ 3745const writeVarUint8Array = (encoder, uint8Array) => { 3746 writeVarUint(encoder, uint8Array.byteLength) 3747 writeUint8Array(encoder, uint8Array) 3748} 3749 3750/** 3751 * Create an DataView of the next `len` bytes. Use it to write data after 3752 * calling this function. 3753 * 3754 * ```js 3755 * // write float32 using DataView 3756 * const dv = writeOnDataView(encoder, 4) 3757 * dv.setFloat32(0, 1.1) 3758 * // read float32 using DataView 3759 * const dv = readFromDataView(encoder, 4) 3760 * dv.getFloat32(0) // => 1.100000023841858 (leaving it to the reader to find out why this is the correct result) 3761 * ``` 3762 * 3763 * @param {Encoder} encoder 3764 * @param {number} len 3765 * @return {DataView} 3766 */ 3767const writeOnDataView = (encoder, len) => { 3768 verifyLen(encoder, len) 3769 const dview = new DataView(encoder.cbuf.buffer, encoder.cpos, len) 3770 encoder.cpos += len 3771 return dview 3772} 3773 3774/** 3775 * @param {Encoder} encoder 3776 * @param {number} num 3777 */ 3778const writeFloat32 = (encoder, num) => writeOnDataView(encoder, 4).setFloat32(0, num, false) 3779 3780/** 3781 * @param {Encoder} encoder 3782 * @param {number} num 3783 */ 3784const writeFloat64 = (encoder, num) => writeOnDataView(encoder, 8).setFloat64(0, num, false) 3785 3786/** 3787 * @param {Encoder} encoder 3788 * @param {bigint} num 3789 */ 3790const writeBigInt64 = (encoder, num) => /** @type {any} */ (writeOnDataView(encoder, 8)).setBigInt64(0, num, false) 3791 3792/** 3793 * @param {Encoder} encoder 3794 * @param {bigint} num 3795 */ 3796const writeBigUint64 = (encoder, num) => /** @type {any} */ (writeOnDataView(encoder, 8)).setBigUint64(0, num, false) 3797 3798const floatTestBed = new DataView(new ArrayBuffer(4)) 3799/** 3800 * Check if a number can be encoded as a 32 bit float. 3801 * 3802 * @param {number} num 3803 * @return {boolean} 3804 */ 3805const isFloat32 = num => { 3806 floatTestBed.setFloat32(0, num) 3807 return floatTestBed.getFloat32(0) === num 3808} 3809 3810/**
3811 * Encode data with efficient binary format. 3812 * 3813 * Differences to JSON: 3814 * ⢠Transforms data to a binary format (not to a string) 3815 * ⢠Encodes undefined, NaN, and ArrayBuffer (these can't be represented in JSON) 3816 * ⢠Numbers are efficiently encoded either as a variable length integer, as a 3817 * 32 bit float, as a 64 bit float, or as a 64 bit bigint. 3818 * 3819 * Encoding table: 3820 * 3821 * | Data Type | Prefix | Encoding Method | Comment | 3822 * | ------------------- | -------- | ------------------ | ------- | 3823 * | undefined | 127 | | Functions, symbol, and everything that cannot be identified is encoded as undefined | 3824 * | null | 126 | | | 3825 * | integer | 125 | writeVarInt | Only encodes 32 bit signed integers | 3826 * | float32 | 124 | writeFloat32 | | 3827 * | float64 | 123 | writeFloat64 | | 3828 * | bigint | 122 | writeBigInt64 | | 3829 * | boolean (false) | 121 | | True and false are different data types so we save the following byte | 3830 * | boolean (true) | 120 | | - 0b01111000 so the last bit determines whether true or false | 3831 * | string | 119 | writeVarString | | 3832 * | object<string,any> | 118 | custom | Writes {length} then {length} key-value pairs | 3833 * | array<any> | 117 | custom | Writes {length} then {length} json values | 3834 * | Uint8Array | 116 | writeVarUint8Array | We use Uint8Array for any kind of binary data | 3835 * 3836 * Reasons for the decreasing prefix: 3837 * We need the first bit for extendability (later we may want to encode the 3838 * prefix with writeVarUint). The remaining 7 bits are divided as follows: 3839 * [0-30] the beginning of the data range is used for custom purposes 3840 * (defined by the function that uses this library) 3841 * [31-127] the end of the data range is used for data encoding by 3842 * lib0/encoding.js 3843 * 3844 * @param {Encoder} encoder 3845 * @param {undefined|null|number|bigint|boolean|string|Object<string,any>|Array<any>|Uint8Array} data 3846 */ 3847const writeAny = (encoder, data) => { 3848 switch (typeof data) { 3849 case 'string': 3850 // TYPE 119: STRING 3851 write(encoder, 119) 3852 writeVarString(encoder, data) 3853 break 3854 case 'number': 3855 if (isInteger(data) && abs(data) <= BITS31) { 3856 // TYPE 125: INTEGER 3857 write(encoder, 125) 3858 writeVarInt(encoder, data) 3859 } else if (isFloat32(data)) { 3860 // TYPE 124: FLOAT32 3861 write(encoder, 124) 3862 writeFloat32(encoder, data) 3863 } else { 3864 // TYPE 123: FLOAT64 3865 write(encoder, 123) 3866 writeFloat64(encoder, data) 3867 } 3868 break 3869 case 'bigint': 3870 // TYPE 122: BigInt 3871 write(encoder, 122) 3872 writeBigInt64(encoder, data) 3873 break 3874 case 'object': 3875 if (data === null) { 3876 // TYPE 126: null 3877 write(encoder, 126) 3878 } else if (isArray(data)) { 3879 // TYPE 117: Array 3880 write(encoder, 117) 3881 writeVarUint(encoder, data.length) 3882 for (let i = 0; i < data.length; i++) { 3883 writeAny(encoder, data[i]) 3884 } 3885 } else if (data instanceof Uint8Array) { 3886 // TYPE 116: ArrayBuffer 3887 write(encoder, 116) 3888 writeVarUint8Array(encoder, data) 3889 } else { 3890 // TYPE 118: Object 3891 write(encoder, 118) 3892 const keys = Object.keys(data) 3893 writeVarUint(encoder, keys.length) 3894 for (let i = 0; i < keys.length; i++) { 3895 const key = keys[i] 3896 writeVarString(encoder, key) 3897 writeAny(encoder, data[key]) 3898 } 3899 } 3900 break 3901 case 'boolean': 3902 // TYPE 120/121: boolean (true/false) 3903 write(encoder, data ? 120 : 121) 3904 break 3905 default: 3906 // TYPE 127: undefined 3907 write(encoder, 127) 3908 } 3909} 3910 3911/** 3912 * Now come a few stateful encoder that have their own classes. 3913 */ 3914 3915/** 3916 * Basic Run Length Encoder - a basic compression implementation. 3917 * 3918 * Encodes [1,1,1,7] to [1,3,7,1] (3 times 1, 1 time 7). This encoder might do more harm than good if there are a lot of values that are not repeated. 3919 * 3920 * It was originally used for image compression. Cool .. article http://csbruce.com/cbm/transactor/pdfs/trans_v7_i06.pdf 3921 * 3922 * @note T must not be null! 3923 * 3924 * @template T 3925 */
vendor: 5,656 bytes, lines 3926-4145
3926class RleEncoder extends Encoder { 3927 /** 3928 * @param {function(Encoder, T):void} writer 3929 */ 3930 constructor (writer) { 3931 super() 3932 /** 3933 * The writer 3934 */ 3935 this.w = writer 3936 /** 3937 * Current state 3938 * @type {T|null} 3939 */ 3940 this.s = null 3941 this.count = 0 3942 } 3943 3944 /** 3945 * @param {T} v 3946 */ 3947 write (v) { 3948 if (this.s === v) { 3949 this.count++ 3950 } else { 3951 if (this.count > 0) { 3952 // flush counter, unless this is the first value (count = 0) 3953 writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw 3954 } 3955 this.count = 1 3956 // write first value 3957 this.w(this, v) 3958 this.s = v 3959 } 3960 } 3961} 3962 3963/** 3964 * Basic diff decoder using variable length encoding. 3965 * 3966 * Encodes the values [3, 1100, 1101, 1050, 0] to [3, 1097, 1, -51, -1050] using writeVarInt. 3967 */ 3968class IntDiffEncoder extends (/* unused pure expression or super */ null && (Encoder)) { 3969 /** 3970 * @param {number} start 3971 */ 3972 constructor (start) { 3973 super() 3974 /** 3975 * Current state 3976 * @type {number} 3977 */ 3978 this.s = start 3979 } 3980 3981 /** 3982 * @param {number} v 3983 */ 3984 write (v) { 3985 writeVarInt(this, v - this.s) 3986 this.s = v 3987 } 3988} 3989 3990/** 3991 * A combination of IntDiffEncoder and RleEncoder. 3992 * 3993 * Basically first writes the IntDiffEncoder and then counts duplicate diffs using RleEncoding. 3994 * 3995 * Encodes the values [1,1,1,2,3,4,5,6] as [1,1,0,2,1,5] (RLE([1,0,0,1,1,1,1,1]) â RleIntDiff[1,1,0,2,1,5]) 3996 */ 3997class RleIntDiffEncoder extends (/* unused pure expression or super */ null && (Encoder)) { 3998 /** 3999 * @param {number} start 4000 */ 4001 constructor (start) { 4002 super() 4003 /** 4004 * Current state 4005 * @type {number} 4006 */ 4007 this.s = start 4008 this.count = 0 4009 } 4010 4011 /** 4012 * @param {number} v 4013 */ 4014 write (v) { 4015 if (this.s === v && this.count > 0) { 4016 this.count++ 4017 } else { 4018 if (this.count > 0) { 4019 // flush counter, unless this is the first value (count = 0) 4020 writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw 4021 } 4022 this.count = 1 4023 // write first value 4024 writeVarInt(this, v - this.s) 4025 this.s = v 4026 } 4027 } 4028} 4029 4030/** 4031 * @param {UintOptRleEncoder} encoder 4032 */ 4033const flushUintOptRleEncoder = encoder => { 4034 if (encoder.count > 0) { 4035 // flush counter, unless this is the first value (count = 0) 4036 // case 1: just a single value. set sign to positive 4037 // case 2: write several values. set sign to negative to indicate that there is a length coming 4038 writeVarInt(encoder.encoder, encoder.count === 1 ? encoder.s : -encoder.s) 4039 if (encoder.count > 1) { 4040 writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw 4041 } 4042 } 4043} 4044 4045/** 4046 * Optimized Rle encoder that does not suffer from the mentioned problem of the basic Rle encoder. 4047 * 4048 * Internally uses VarInt encoder to write unsigned integers. If the input occurs multiple times, we write 4049 * write it as a negative number. The UintOptRleDecoder then understands that it needs to read a count. 4050 * 4051 * Encodes [1,2,3,3,3] as [1,2,-3,3] (once 1, once 2, three times 3) 4052 */ 4053class UintOptRleEncoder { 4054 constructor () { 4055 this.encoder = new Encoder() 4056 /** 4057 * @type {number} 4058 */ 4059 this.s = 0 4060 this.count = 0 4061 } 4062 4063 /** 4064 * @param {number} v 4065 */ 4066 write (v) { 4067 if (this.s === v) { 4068 this.count++ 4069 } else { 4070 flushUintOptRleEncoder(this) 4071 this.count = 1 4072 this.s = v 4073 } 4074 } 4075 4076 toUint8Array () { 4077 flushUintOptRleEncoder(this) 4078 return toUint8Array(this.encoder) 4079 } 4080} 4081 4082/** 4083 * Increasing Uint Optimized RLE Encoder 4084 * 4085 * The RLE encoder counts the number of same occurences of the same value. 4086 * The IncUintOptRle encoder counts if the value increases. 4087 * I.e. 7, 8, 9, 10 will be encoded as [-7, 4]. 1, 3, 5 will be encoded 4088 * as [1, 3, 5]. 4089 */ 4090class IncUintOptRleEncoder { 4091 constructor () { 4092 this.encoder = new Encoder() 4093 /** 4094 * @type {number} 4095 */ 4096 this.s = 0 4097 this.count = 0 4098 } 4099 4100 /** 4101 * @param {number} v 4102 */ 4103 write (v) { 4104 if (this.s + this.count === v) { 4105 this.count++ 4106 } else { 4107 flushUintOptRleEncoder(this) 4108 this.count = 1 4109 this.s = v 4110 } 4111 } 4112 4113 toUint8Array () { 4114 flushUintOptRleEncoder(this) 4115 return toUint8Array(this.encoder) 4116 } 4117} 4118 4119/** 4120 * @param {IntDiffOptRleEncoder} encoder 4121 */ 4122const flushIntDiffOptRleEncoder = encoder => { 4123 if (encoder.count > 0) { 4124 // 31 bit making up the diff | wether to write the counter 4125 // const encodedDiff = encoder.diff << 1 | (encoder.count === 1 ? 0 : 1) 4126 const encodedDiff = encoder.diff * 2 + (encoder.count === 1 ? 0 : 1) 4127 // flush counter, unless this is the first value (count = 0) 4128 // case 1: just a single value. set first bit to positive 4129 // case 2: write several values. set first bit to negative to indicate that there is a length coming 4130 writeVarInt(encoder.encoder, encodedDiff) 4131 if (encoder.count > 1) { 4132 writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw 4133 } 4134 } 4135} 4136 4137/** 4138 * A combination of the IntDiffEncoder and the UintOptRleEncoder. 4139 * 4140 * The count approach is similar to the UintDiffOptRleEncoder, but instead of using the negative bitflag, it encodes 4141 * in the LSB whether a count is to be read. Therefore this Encoder only supports 31 bit integers! 4142 * 4143 * Encodes [1, 2, 3, 2] as [3, 1, 6, -1] (more specifically [(1 << 1) | 1, (3 << 0) | 0, -1]) 4144 * 4145 * Internally uses variable length encoding. Contrary to normal UintV
4145ar encoding, the first byte contains: 4146 * * 1 bit that denotes whether the next value is a count (LSB) 4147 * * 1 bit that denotes whether this value is negative (MSB - 1) 4148 * * 1 bit that denotes whether to continue reading the variable length integer (MSB) 4149 * 4150 * Therefore, only five bits remain to encode diff ranges. 4151 * 4152 * Use this Encoder only when appropriate. In most cases, this is probably a bad idea. 4153 */ 4154class IntDiffOptRleEncoder { 4155 constructor () { 4156 this.encoder = new Encoder() 4157 /** 4158 * @type {number} 4159 */ 4160 this.s = 0 4161 this.count = 0 4162 this.diff = 0 4163 } 4164 4165 /** 4166 * @param {number} v 4167 */ 4168 write (v) { 4169 if (this.diff === v - this.s) { 4170 this.s = v 4171 this.count++ 4172 } else { 4173 flushIntDiffOptRleEncoder(this) 4174 this.count = 1 4175 this.diff = v - this.s 4176 this.s = v 4177 } 4178 } 4179 4180 toUint8Array () { 4181 flushIntDiffOptRleEncoder(this) 4182 return toUint8Array(this.encoder) 4183 } 4184} 4185 4186/** 4187 * Optimized String Encoder. 4188 * 4189 * Encoding many small strings in a simple Encoder is not very efficient. The function call to decode a string takes some time and creates references that must be eventually deleted. 4190 * In practice, when decoding several million small strings, the GC will kick in more and more often to collect orphaned string objects (or maybe there is another reason?). 4191 * 4192 * This string encoder solves the above problem. All strings are concatenated and written as a single string using a single encoding call. 4193 * 4194 * The lengths are encoded using a UintOptRleEncoder. 4195 */ 4196class StringEncoder { 4197 constructor () { 4198 /** 4199 * @type {Array<string>} 4200 */ 4201 this.sarr = [] 4202 this.s = '' 4203 this.lensE = new UintOptRleEncoder() 4204 } 4205 4206 /** 4207 * @param {string} string 4208 */ 4209 write (string) { 4210 this.s += string 4211 if (this.s.length > 19) { 4212 this.sarr.push(this.s) 4213 this.s = '' 4214 } 4215 this.lensE.write(string.length) 4216 } 4217 4218 toUint8Array () { 4219 const encoder = new Encoder() 4220 this.sarr.push(this.s) 4221 this.s = '' 4222 writeVarString(encoder, this.sarr.join('')) 4223 writeUint8Array(encoder, this.lensE.toUint8Array()) 4224 return toUint8Array(encoder) 4225 } 4226} 4227 4228;// CONCATENATED MODULE: ./node_modules/lib0/error.js 4229/** 4230 * Error helpers. 4231 * 4232 * @module error 4233 */ 4234 4235/** 4236 * @param {string} s 4237 * @return {Error} 4238 */ 4239/* c8 ignore next */ 4240const error_create = s => new Error(s) 4241 4242/** 4243 * @throws {Error} 4244 * @return {never} 4245 */ 4246/* c8 ignore next 3 */ 4247const methodUnimplemented = () => { 4248 throw error_create('Method unimplemented') 4249} 4250 4251/** 4252 * @throws {Error} 4253 * @return {never} 4254 */ 4255/* c8 ignore next 3 */ 4256const unexpectedCase = () => { 4257 throw error_create('Unexpected case') 4258} 4259 4260;// CONCATENATED MODULE: ./node_modules/lib0/decoding.js 4261/** 4262 * Efficient schema-less binary decoding with support for variable length encoding. 4263 * 4264 * Use [lib0/decoding] with [lib0/encoding]. Every encoding function has a corresponding decoding function. 4265 * 4266 * Encodes numbers in little-endian order (least to most significant byte order) 4267 * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/) 4268 * which is also used in Protocol Buffers. 4269 * 4270 * ```js 4271 * // encoding step 4272 * const encoder = encoding.createEncoder() 4273 * encoding.writeVarUint(encoder, 256) 4274 * encoding.writeVarString(encoder, 'Hello world!') 4275 * const buf = encoding.toUint8Array(encoder) 4276 * ``` 4277 * 4278 * ```js 4279 * // decoding step 4280 * const decoder = decoding.createDecoder(buf) 4281 * decoding.readVarUint(decoder) // => 256 4282 * decoding.readVarString(decoder) // => 'Hello world!' 4283 * decoding.hasContent(decoder) // => false - all data is read 4284 * ``` 4285 * 4286 * @module decoding 4287 */ 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297const errorUnexpectedEndOfArray = error_create('Unexpected end of array') 4298const errorIntegerOutOfRange = error_create('Integer out of Range') 4299 4300/** 4301 * A Decoder handles the decoding of an Uint8Array. 4302 */ 4303class Decoder { 4304 /** 4305 * @param {Uint8Array} uint8Array Binary data to decode 4306 */ 4307 constructor (uint8Array) { 4308 /** 4309 * Decoding target. 4310 * 4311 * @type {Uint8Array} 4312 */ 4313 this.arr = uint8Array 4314 /** 4315 * Current decoding position. 4316 * 4317 * @type {number} 4318 */ 4319 this.pos = 0 4320 } 4321} 4322 4323/** 4324 * @function 4325 * @param {Uint8Array} uint8Array 4326 * @return {Decoder} 4327 */ 4328const createDecoder = uint8Array => new Decoder(uint8Array) 4329 4330/** 4331 * @function 4332 * @param {Decoder} decoder 4333 * @return {boolean} 4334 */ 4335const decoding_hasContent = decoder => decoder.pos !== decoder.arr.length 4336 4337/** 4338 * Clone a decoder instance. 4339 * Optionally set a new position parameter. 4340 * 4341 * @function 4342 * @param {Decoder} decoder The decoder instance 4343 * @param {number} [newPos] Defaults to current position 4344 * @return {Decoder} A clone of `decoder` 4345 */ 4346const clone = (decoder, newPos = decoder.pos) => { 4347 const _decoder = createDecoder(decoder.arr) 4348 _decoder.pos = newPos 4349 return _decoder 4350} 4351 4352/** 4353 * Create an Uint8Array view of the next `len` bytes and advance the position by `len`. 4354 * 4355 * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks. 4356 * Use `buffer.copyUint8Array` to copy the result into a
4356new Uint8Array. 4357 * 4358 * @function 4359 * @param {Decoder} decoder The decoder instance 4360 * @param {number} len The length of bytes to read 4361 * @return {Uint8Array} 4362 */ 4363const readUint8Array = (decoder, len) => { 4364 const view = createUint8ArrayViewFromArrayBuffer(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len) 4365 decoder.pos += len 4366 return view 4367} 4368 4369/** 4370 * Read variable length Uint8Array. 4371 * 4372 * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks. 4373 * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array. 4374 * 4375 * @function 4376 * @param {Decoder} decoder 4377 * @return {Uint8Array} 4378 */ 4379const readVarUint8Array = decoder => readUint8Array(decoder, readVarUint(decoder)) 4380 4381/** 4382 * Read the rest of the content as an ArrayBuffer 4383 * @function 4384 * @param {Decoder} decoder 4385 * @return {Uint8Array} 4386 */ 4387const readTailAsUint8Array = decoder => readUint8Array(decoder, decoder.arr.length - decoder.pos) 4388 4389/** 4390 * Skip one byte, jump to the next position. 4391 * @function 4392 * @param {Decoder} decoder The decoder instance 4393 * @return {number} The next position 4394 */ 4395const skip8 = decoder => decoder.pos++ 4396 4397/** 4398 * Read one byte as unsigned integer. 4399 * @function 4400 * @param {Decoder} decoder The decoder instance 4401 * @return {number} Unsigned 8-bit integer 4402 */ 4403const readUint8 = decoder => decoder.arr[decoder.pos++] 4404 4405/** 4406 * Read 2 bytes as unsigned integer. 4407 * 4408 * @function 4409 * @param {Decoder} decoder 4410 * @return {number} An unsigned integer. 4411 */ 4412const readUint16 = decoder => { 4413 const uint = 4414 decoder.arr[decoder.pos] + 4415 (decoder.arr[decoder.pos + 1] << 8) 4416 decoder.pos += 2 4417 return uint 4418} 4419 4420/** 4421 * Read 4 bytes as unsigned integer. 4422 * 4423 * @function 4424 * @param {Decoder} decoder 4425 * @return {number} An unsigned integer. 4426 */ 4427const readUint32 = decoder => { 4428 const uint = 4429 (decoder.arr[decoder.pos] + 4430 (decoder.arr[decoder.pos + 1] << 8) + 4431 (decoder.arr[decoder.pos + 2] << 16) + 4432 (decoder.arr[decoder.pos + 3] << 24)) >>> 0 4433 decoder.pos += 4 4434 return uint 4435} 4436 4437/** 4438 * Read 4 bytes as unsigned integer in big endian order. 4439 * (most significant byte first) 4440 * 4441 * @function 4442 * @param {Decoder} decoder 4443 * @return {number} An unsigned integer. 4444 */ 4445const readUint32BigEndian = decoder => { 4446 const uint = 4447 (decoder.arr[decoder.pos + 3] + 4448 (decoder.arr[decoder.pos + 2] << 8) + 4449 (decoder.arr[decoder.pos + 1] << 16) + 4450 (decoder.arr[decoder.pos] << 24)) >>> 0 4451 decoder.pos += 4 4452 return uint 4453} 4454 4455/** 4456 * Look ahead without incrementing the position 4457 * to the next byte and read it as unsigned integer. 4458 * 4459 * @function 4460 * @param {Decoder} decoder 4461 * @return {number} An unsigned integer. 4462 */ 4463const peekUint8 = decoder => decoder.arr[decoder.pos] 4464 4465/** 4466 * Look ahead without incrementing the position 4467 * to the next byte and read it as unsigned integer. 4468 * 4469 * @function 4470 * @param {Decoder} decoder 4471 * @return {number} An unsigned integer. 4472 */ 4473const peekUint16 = decoder => 4474 decoder.arr[decoder.pos] + 4475 (decoder.arr[decoder.pos + 1] << 8) 4476 4477/** 4478 * Look ahead without incrementing the position 4479 * to the next byte and read it as unsigned integer. 4480 * 4481 * @function 4482 * @param {Decoder} decoder 4483 * @return {number} An unsigned integer. 4484 */ 4485const peekUint32 = decoder => ( 4486 decoder.arr[decoder.pos] + 4487 (decoder.arr[decoder.pos + 1] << 8) + 4488 (decoder.arr[decoder.pos + 2] << 16) + 4489 (decoder.arr[decoder.pos + 3] << 24) 4490) >>> 0 4491 4492/** 4493 * Read unsigned integer (32bit) with variable length. 4494 * 1/8th of the storage is used as encoding overhead. 4495 * * numbers < 2^7 is stored in one bytlength 4496 * * numbers < 2^14 is stored in two bylength 4497 * 4498 * @function 4499 * @param {Decoder} decoder 4500 * @return {number} An unsigned integer.length 4501 */ 4502const readVarUint = decoder => { 4503 let num = 0 4504 let mult = 1 4505 const len = decoder.arr.length 4506 while (decoder.pos < len) { 4507 const r = decoder.arr[decoder.pos++] 4508 // num = num | ((r & binary.BITS7) << len) 4509 num = num + (r & BITS7) * mult // shift $r << (7*#iterations) and add it to num 4510 mult *= 128 // next iteration, shift 7 "more" to the left 4511 if (r < BIT8) { 4512 return num 4513 } 4514 /* c8 ignore start */ 4515 if (num > MAX_SAFE_INTEGER) { 4516 throw errorIntegerOutOfRange 4517 } 4518 /* c8 ignore stop */ 4519 } 4520 throw errorUnexpectedEndOfArray 4521} 4522 4523/** 4524 * Read signed integer (32bit) with variable length. 4525 * 1/8th of the storage is used as encoding overhead. 4526 * * numbers < 2^7 is stored in one bytlength 4527 * * numbers < 2^14 is stored in two bylength 4528 * @todo This should probably create the inverse ~num if number is negative - but this would be a breaking change. 4529 * 4530 * @function 4531 * @param {Decoder} decoder 4532 * @return {number} An unsigned integer.length 4533 */ 4534const readVarInt = decoder => { 4535 let r = decoder.arr[decoder.pos++] 4536 let num = r & BITS6 4537 let mult = 64 4538 const sign = (r & BIT7) > 0 ? -1 : 1 4539 if ((r & BIT8) === 0) { 4540 // don't continue reading 4541 return sign * num 4542 } 4543 const len = decoder.arr.length 4544 while (decoder.pos < len) { 4545 r = decoder.arr[decoder.pos++] 4546 // num = num | ((r & binary.BITS7) << len) 4547 num = num + (r & BITS7) * mult 4548 mult *= 128 4549 if (r < BIT8) { 4550 return sign * num 4551 } 4552 /* c8 ignore start */ 4553 if (num > MAX_SAFE_INTEGER) { 4554 throw errorIntegerOutOfRange 4555 } 4556 /* c8 ignore stop */ 4557 } 4558 throw errorUnexpectedEndOfArray 4559} 4560 4561/** 4562 * Look ahead and read varUint without incrementing position 4563 * 4564 * @function 4565 * @param {Decoder} decoder 4566 * @return {number} 4567 */ 4568const peekVarUint = decoder => { 4569 const pos = decoder.pos 4570 const s = readVarUint(decoder) 4571 decoder.pos = pos 4572 return s 4573} 4574 4575/** 4576 * Look ahead and read varUint without incrementing position 4577 * 4578 * @function 4579 * @param {Decoder} decoder 4580 * @return {number} 4581 */ 4582const peekVarInt = decoder => { 4583 const pos = decoder.pos 4584 const s = readVarInt(decoder) 4585 decoder.pos = pos 4586 return s 4587} 4588 4589/** 4590 * We don't test this function anymore as we use native decoding/encoding by default now. 4591 * Better not modify this anymore.. 4592 * 4593 * Transforming utf8 to a string is pretty expensive. The code performs 10x better 4594 * when String.fromCodePoint is fed with all characters as arguments. 4595 * But most environments have a maximum number of arguments per functions. 4596 * For effiency reasons we apply a maximum of 10000 characters at once. 4597 * 4598 * @function 4599 * @param {Decoder} decoder 4600 * @return {String} The read String. 4601 */ 4602/* c8 ignore start */ 4603const _readVarStringPolyfill = decoder => { 4604 let remainingLen = readVarUint(decoder) 4605 if (remainingLen === 0) { 4606 return '' 4607 } else { 4608 let encodedString = String.fromCodePoint(readUint8(decoder)) // remember to decrease remainingLen 4609 if (--remainingLen < 100) { // do not create a Uint8Array for small strings 4610 while (remainingLen--) { 4611 encodedString += String.fromCodePoint(readUint8(decoder)) 4612 } 4613 } else { 4614 while (remainingLen > 0) { 4615 const nextLen = remainingLen < 10000 ? remainingLen : 10000 4616 // this is dangerous, we create a fresh array view from the existing buffer 4617 const bytes = decoder.arr.subarray(decoder.pos, decoder.pos + nextLen) 4618 decoder.pos += nextLen 4619 // Starting with ES5.1 we can supply a generic array-like object as arguments 4620 encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes)) 4621 remainingLen -= nextLen 4622 } 4623 } 4624 return decodeURIComponent(escape(encodedString)) 4625 } 4626} 4627/* c8 ignore stop */ 4628 4629/** 4630 * @function 4631 * @param {Decoder} decoder 4632 * @return {String} The read String 4633 */ 4634const _readVarStringNative = decoder => 4635 /** @type any */ utf8TextDecoder.decode(readVarUint8Array(decoder)) 4636 4637/** 4638 * Read string of variable length 4639 * * varUint is used to store the length of the string 4640 * 4641 * @function 4642 * @param {Decoder} decoder 4643 * @return {String} The read String 4644 * 4645 */ 4646/* c8 ignore next */ 4647const readVarString = utf8TextDecoder ? _readVarStringNative : _readVarStringPolyfill 4648 4649/** 4650 * @param {Decoder} decoder 4651 * @return {Uint8Array} 4652 */ 4653const readTerminatedUint8Array = decoder => { 4654 const encoder = encoding.createEncoder() 4655 let b 4656 while (true) { 4657 b = readUint8(decoder) 4658 if (b === 0) { 4659 return encoding.toUint8Array(encoder) 4660 } 4661 if (b === 1) { 4662 b = readUint8(decoder) 4663 } 4664 encoding.write(encoder, b) 4665 } 4666} 4667 4668/** 4669 * @param {Decoder} decoder 4670 * @return {string} 4671 */ 4672const readTerminatedString = decoder =>
4672 string.decodeUtf8(readTerminatedUint8Array(decoder)) 4673 4674/** 4675 * Look ahead and read varString without incrementing position 4676 * 4677 * @function 4678 * @param {Decoder} decoder 4679 * @return {string} 4680 */ 4681const peekVarString = decoder => { 4682 const pos = decoder.pos 4683 const s = readVarString(decoder) 4684 decoder.pos = pos 4685 return s 4686} 4687 4688/** 4689 * @param {Decoder} decoder 4690 * @param {number} len 4691 * @return {DataView} 4692 */ 4693const readFromDataView = (decoder, len) => { 4694 const dv = new DataView(decoder.arr.buffer, decoder.arr.byteOffset + decoder.pos, len) 4695 decoder.pos += len 4696 return dv 4697} 4698 4699/** 4700 * @param {Decoder} decoder 4701 */ 4702const readFloat32 = decoder => readFromDataView(decoder, 4).getFloat32(0, false) 4703 4704/** 4705 * @param {Decoder} decoder 4706 */ 4707const readFloat64 = decoder => readFromDataView(decoder, 8).getFloat64(0, false) 4708 4709/** 4710 * @param {Decoder} decoder 4711 */ 4712const readBigInt64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigInt64(0, false) 4713 4714/** 4715 * @param {Decoder} decoder 4716 */ 4717const readBigUint64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigUint64(0, false) 4718 4719/** 4720 * @type {Array<function(Decoder):any>} 4721 */ 4722const readAnyLookupTable = [ 4723 decoder => undefined, // CASE 127: undefined 4724 decoder => null, // CASE 126: null 4725 readVarInt, // CASE 125: integer 4726 readFloat32, // CASE 124: float32 4727 readFloat64, // CASE 123: float64 4728 readBigInt64, // CASE 122: bigint 4729 decoder => false, // CASE 121: boolean (false) 4730 decoder => true, // CASE 120: boolean (true) 4731 readVarString, // CASE 119: string 4732 decoder => { // CASE 118: object<string,any> 4733 const len = readVarUint(decoder) 4734 /** 4735 * @type {Object<string,any>} 4736 */ 4737 const obj = {} 4738 for (let i = 0; i < len; i++) { 4739 const key = readVarString(decoder) 4740 obj[key] = readAny(decoder) 4741 } 4742 return obj 4743 }, 4744 decoder => { // CASE 117: array<any> 4745 const len = readVarUint(decoder) 4746 const arr = [] 4747 for (let i = 0; i < len; i++) { 4748 arr.push(readAny(decoder)) 4749 } 4750 return arr 4751 }, 4752 readVarUint8Array // CASE 116: Uint8Array 4753] 4754 4755/** 4756 * @param {Decoder} decoder 4757 */ 4758const readAny = decoder => readAnyLookupTable[127 - readUint8(decoder)](decoder) 4759 4760/** 4761 * T must not be null. 4762 * 4763 * @template T 4764 */ 4765class RleDecoder extends Decoder { 4766 /** 4767 * @param {Uint8Array} uint8Array 4768 * @param {function(Decoder):T} reader 4769 */ 4770 constructor (uint8Array, reader) { 4771 super(uint8Array) 4772 /** 4773 * The reader 4774 */ 4775 this.reader = reader 4776 /** 4777 * Current state 4778 * @type {T|null} 4779 */ 4780 this.s = null 4781 this.count = 0 4782 } 4783 4784 read () { 4785 if (this.count === 0) { 4786 this.s = this.reader(this) 4787 if (decoding_hasContent(this)) { 4788 this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented 4789 } else { 4790 this.count = -1 // read the current value forever 4791 } 4792 } 4793 this.count-- 4794 return /** @type {T} */ (this.s) 4795 } 4796} 4797 4798class IntDiffDecoder extends (/* unused pure expression or super */ null && (Decoder)) { 4799 /** 4800 * @param {Uint8Array} uint8Array 4801 * @param {number} start 4802 */ 4803 constructor (uint8Array, start) { 4804 super(uint8Array) 4805 /** 4806 * Current state 4807 * @type {number} 4808 */ 4809 this.s = start 4810 } 4811 4812 /** 4813 * @return {number} 4814 */ 4815 read () { 4816 this.s += readVarInt(this) 4817 return this.s 4818 } 4819} 4820 4821class RleIntDiffDecoder extends (/* unused pure expression or super */ null && (Decoder)) { 4822 /** 4823 * @param {Uint8Array} uint8Array 4824 * @param {number} start 4825 */ 4826 constructor (uint8Array, start) { 4827 super(uint8Array) 4828 /** 4829 * Current state 4830 * @type {number} 4831 */ 4832 this.s = start 4833 this.count = 0 4834 } 4835 4836 /** 4837 * @return {number} 4838 */ 4839 read () { 4840 if (this.count === 0) { 4841 this.s += readVarInt(this) 4842 if (decoding_hasContent(this)) { 4843 this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented 4844 } else { 4845 this.count = -1 // read the current value forever 4846 } 4847 } 4848 this.count-- 4849 return /** @type {number} */ (this.s) 4850 } 4851} 4852 4853class UintOptRleDecoder extends Decoder { 4854 /** 4855 * @param {Uint8Array} uint8Array 4856 */ 4857 constructor (uint8Array) { 4858 super(uint8Array) 4859 /** 4860 * @type {number} 4861 */ 4862 this.s = 0 4863 this.count = 0 4864 } 4865 4866 read () { 4867 if (this.count === 0) { 4868 this.s = readVarInt(this) 4869 // if the sign is negative, we read the count too, otherwise count is 1 4870 const isNegative = isNegativeZero(this.s) 4871 this.count = 1 4872 if (isNegative) { 4873 this.s = -this.s 4874 this.count = readVarUint(this) + 2 4875 } 4876 } 4877 this.count-- 4878 return /** @type {number} */ (this.s) 4879 } 4880} 4881 4882class IncUintOptRleDecoder extends (/* unused pure expression or super */ null && (Decoder)) { 4883 /** 4884 * @param {Uint8Array} uint8Array 4885 */ 4886 constructor (uint8Array) { 4887 super(uint8Array) 4888 /** 4889 * @type {number} 4890 */ 4891 this.s = 0 4892 this.count = 0 4893 } 4894 4895 read () { 4896 if (this.count === 0) { 4897 this.s = readVarInt(this) 4898 // if the sign is negative, we read the count too, otherwise count is 1 4899 const isNegative = math.isNegativeZero(this.s) 4900 this.count = 1 4901 if (isNegative) { 4902 this.s = -this.s 4903 this.count = readVarUint(this) + 2 4904 } 4905 } 4906 this.count-- 4907 return /** @type {number} */ (this.s++) 4908 } 4909} 4910 4911class IntDiffOptRleDecoder extends Decoder { 4912 /** 4913 * @param {Uint8Array} uint8Array 4914 */ 4915 constructor (uint8Array) { 4916 super(uint8Array) 4917 /** 4918 * @type {number} 4919 */ 4920 this.s = 0 4921 this.count = 0 4922 this.diff = 0 4923 } 4924 4925 /** 4926 * @return {number} 4927 */ 4928 read () { 4929 if (this.count === 0) { 4930 const diff = readVarInt(this) 4931 // if the first bit is set, we read more data 4932 const hasCount = diff & 1 4933 this.diff = floor(diff / 2) // shift >> 1 4934 this.count = 1 4935 if (hasCount) { 4936 this.count = readVarUint(this) + 2 4937 } 4938 } 4939 this.s += this.diff 4940 this.count-- 4941 return this.s 4942 } 4943} 4944 4945class StringDecoder { 4946 /** 4947 * @param {Uint8Array} uint8Array 4948 */ 4949 constructor (uint8Array) { 4950 this.decoder = new UintOptRleDecoder(uint8Array) 4951 this.str = readVarString(this.decoder) 4952 /** 4953 * @type {number} 4954 */ 4955 this.spos = 0 4956 } 4957 4958 /** 4959 * @return {string} 4960 */ 4961 read () { 4962 const end = this.spos + this.decoder.read() 4963 const res = this.str.slice(this.spos, end) 4964 this.spos = end 4965 return res 4966 } 4967} 4968 4969;// CONCATENATED MODULE: ./node_modules/lib0/webcrypto.js 4970/* eslint-env browser */ 4971 4972const subtle = crypto.subtle 4973const webcrypto_getRandomValues = crypto.getRandomValues.bind(crypto) 4974 4975;// CONCATENATED MODULE: ./node_modules/lib0/random.js 4976/** 4977 * Isomorphic module for true random numbers / buffers / uuids. 4978 * 4979 * Attention: falls back to Math.random if the browser does not support crypto. 4980 * 4981 * @module random 4982 */ 4983 4984 4985 4986 4987 4988const rand = Math.random 4989 4990const uint32 = () => webcrypto_getRandomValues(new Uint32Array(1))[0] 4991 4992const uint53 = () => { 4993 const arr = getRandomValues(new Uint32Array(8)) 4994 return (arr[0] & binary.BITS21) * (binary.BITS32 + 1) + (arr[1] >>> 0) 4995} 4996 4997/** 4998 * @template T 4999 * @param {Array<T>} arr 5000 * @return {T} 5001 */ 5002const oneOf = arr => arr[math.floor(rand() * arr.length)] 5003 5004// @ts-ignore 5005const uuidv4Template = [1e7] + -1e3 + -4e3 + -8e3 + -1e11 5006 5007/** 5008 * @return {string} 5009 */ 5010const uuidv4 = () => uuidv4Template.replace(/[018]/g, /** @param {number} c */ c => 5011 (c ^ uint32() & 15 >> c / 4).toString(16) 5012) 5013 5014;// CONCATENATED MODULE: ./node_modules/lib0/promise.js 5015/** 5016 * Utility helpers to work with promises. 5017 * 5018 * @module promise 5019 */ 5020 5021 5022 5023/** 5024 * @template T 5025 * @callback PromiseResolve 5026 * @param {T|PromiseLike<T>} [result] 5027 */ 5028 5029/** 5030 * @template T 5031 * @param {function(PromiseResolve<T>,function(Error):void):any} f 5032 * @return {Promise<T>} 5033 */ 5034const promise_create = f => /** @type {Promise<T>} */ (new Promise(f)) 5035 5036/** 5037 * @param {function(function():void,function(Error):void):void} f 5038 * @return {Promise<void>} 5039 */ 5040const createEmpty = f => new Promise(f) 5041 5042/** 5043 * `Promise.all` wait for all promises in the array to resolve and return the result 5044 * @template {unknown[] | []} PS 5045 *
5046 * @param {PS} ps 5047 * @return {Promise<{ -readonly [P in keyof PS]: Awaited<PS[P]> }>} 5048 */ 5049const promise_all = Promise.all.bind(Promise) 5050 5051/** 5052 * @param {Error} [reason] 5053 * @return {Promise<never>} 5054 */ 5055const reject = reason => Promise.reject(reason) 5056 5057/** 5058 * @template T 5059 * @param {T|void} res 5060 * @return {Promise<T|void>} 5061 */ 5062const resolve = res => Promise.resolve(res) 5063 5064/** 5065 * @template T 5066 * @param {T} res 5067 * @return {Promise<T>} 5068 */ 5069const resolveWith = res => Promise.resolve(res) 5070 5071/** 5072 * @todo Next version, reorder parameters: check, [timeout, [intervalResolution]] 5073 * 5074 * @param {number} timeout 5075 * @param {function():boolean} check 5076 * @param {number} [intervalResolution] 5077 * @return {Promise<void>} 5078 */ 5079const until = (timeout, check, intervalResolution = 10) => promise_create((resolve, reject) => { 5080 const startTime = time.getUnixTime() 5081 const hasTimeout = timeout > 0 5082 const untilInterval = () => { 5083 if (check()) { 5084 clearInterval(intervalHandle) 5085 resolve() 5086 } else if (hasTimeout) { 5087 /* c8 ignore else */ 5088 if (time.getUnixTime() - startTime > timeout) { 5089 clearInterval(intervalHandle) 5090 reject(new Error('Timeout')) 5091 } 5092 } 5093 } 5094 const intervalHandle = setInterval(untilInterval, intervalResolution) 5095}) 5096 5097/** 5098 * @param {number} timeout 5099 * @return {Promise<undefined>} 5100 */ 5101const wait = timeout => promise_create((resolve, reject) => setTimeout(resolve, timeout)) 5102 5103/** 5104 * Checks if an object is a promise using ducktyping. 5105 * 5106 * Promises are often polyfilled, so it makes sense to add some additional guarantees if the user of this 5107 * library has some insane environment where global Promise objects are overwritten. 5108 * 5109 * @param {any} p 5110 * @return {boolean} 5111 */ 5112const isPromise = p => p instanceof Promise || (p && p.then && p.catch && p.finally) 5113 5114;// CONCATENATED MODULE: ./node_modules/lib0/pair.js 5115/** 5116 * Working with value pairs. 5117 * 5118 * @module pair 5119 */ 5120 5121/** 5122 * @template L,R 5123 */ 5124class Pair { 5125 /** 5126 * @param {L} left 5127 * @param {R} right 5128 */ 5129 constructor (left, right) { 5130 this.left = left 5131 this.right = right 5132 } 5133} 5134 5135/** 5136 * @template L,R 5137 * @param {L} left 5138 * @param {R} right 5139 * @return {Pair<L,R>} 5140 */ 5141const pair_create = (left, right) => new Pair(left, right) 5142 5143/** 5144 * @template L,R 5145 * @param {R} right 5146 * @param {L} left 5147 * @return {Pair<L,R>} 5148 */ 5149const createReversed = (right, left) => new Pair(left, right) 5150 5151/** 5152 * @template L,R 5153 * @param {Array<Pair<L,R>>} arr 5154 * @param {function(L, R):any} f 5155 */
5156const pair_forEach = (arr, f) => arr.forEach(p => f(p.left, p.right)) 5157 5158/** 5159 * @template L,R,X 5160 * @param {Array<Pair<L,R>>} arr 5161 * @param {function(L, R):X} f 5162 * @return {Array<X>} 5163 */ 5164const pair_map = (arr, f) => arr.map(p => f(p.left, p.right)) 5165 5166;// CONCATENATED MODULE: ./node_modules/lib0/dom.js 5167/* eslint-env browser */ 5168 5169/** 5170 * Utility module to work with the DOM. 5171 * 5172 * @module dom 5173 */ 5174 5175 5176 5177 5178/* c8 ignore start */ 5179/** 5180 * @type {Document} 5181 */ 5182const doc = /** @type {Document} */ (typeof document !== 'undefined' ? document : {}) 5183 5184/** 5185 * @param {string} name 5186 * @return {HTMLElement} 5187 */ 5188const createElement = name => doc.createElement(name) 5189 5190/** 5191 * @return {DocumentFragment} 5192 */ 5193const createDocumentFragment = () => doc.createDocumentFragment() 5194 5195/** 5196 * @param {string} text 5197 * @return {Text} 5198 */ 5199const createTextNode = text => doc.createTextNode(text) 5200 5201const domParser = /** @type {DOMParser} */ (typeof DOMParser !== 'undefined' ? new DOMParser() : null) 5202 5203/** 5204 * @param {HTMLElement} el 5205 * @param {string} name 5206 * @param {Object} opts 5207 */ 5208const emitCustomEvent = (el, name, opts) => el.dispatchEvent(new CustomEvent(name, opts)) 5209 5210/** 5211 * @param {Element} el 5212 * @param {Array<pair.Pair<string,string|boolean>>} attrs Array of key-value pairs 5213 * @return {Element} 5214 */ 5215const setAttributes = (el, attrs) => { 5216 pair.forEach(attrs, (key, value) => { 5217 if (value === false) { 5218 el.removeAttribute(key) 5219 } else if (value === true) { 5220 el.setAttribute(key, '') 5221 } else { 5222 // @ts-ignore 5223 el.setAttribute(key, value) 5224 } 5225 }) 5226 return el 5227} 5228 5229/** 5230 * @param {Element} el 5231 * @param {Map<string, string>} attrs Array of key-value pairs 5232 * @return {Element} 5233 */ 5234const setAttributesMap = (el, attrs) => { 5235 attrs.forEach((value, key) => { el.setAttribute(key, value) }) 5236 return el 5237} 5238 5239/** 5240 * @param {Array<Node>|HTMLCollection} children 5241 * @return {DocumentFragment} 5242 */ 5243const fragment = children => { 5244 const fragment = createDocumentFragment() 5245 for (let i = 0; i < children.length; i++) { 5246 appendChild(fragment, children[i]) 5247 } 5248 return fragment 5249} 5250 5251/** 5252 * @param {Element} parent 5253 * @param {Array<Node>} nodes 5254 * @return {Element} 5255 */ 5256const append = (parent, nodes) => { 5257 appendChild(parent, fragment(nodes)) 5258 return parent 5259} 5260 5261/** 5262 * @param {HTMLElement} el 5263 */ 5264const remove = el => el.remove() 5265 5266/** 5267 * @param {EventTarget} el 5268 * @param {string} name 5269 * @param {EventListener} f 5270 */ 5271const dom_addEventListener = (el, name, f) => el.addEventListener(name, f) 5272 5273/** 5274 * @param {EventTarget} el 5275 * @param {string} name 5276 * @param {EventListener} f 5277 */ 5278const dom_removeEventListener = (el, name, f) => el.removeEventListener(name, f) 5279 5280/** 5281 * @param {Node} node 5282 * @param {Array<pair.Pair<string,EventListener>>} listeners 5283 * @return {Node} 5284 */ 5285const addEventListeners = (node, listeners) => { 5286 pair.forEach(listeners, (name, f) => dom_addEventListener(node, name, f)) 5287 return node 5288} 5289 5290/** 5291 * @param {Node} node 5292 * @param {Array<pair.Pair<string,EventListener>>} listeners 5293 * @return {Node} 5294 */ 5295const removeEventListeners = (node, listeners) => { 5296 pair.forEach(listeners, (name, f) => dom_removeEventListener(node, name, f)) 5297 return node 5298} 5299 5300/** 5301 * @param {string} name 5302 * @param {Array<pair.Pair<string,string>|pair.Pair<string,boolean>>} attrs Array of key-value pairs 5303 * @param {Array<Node>} children 5304 * @return {Element} 5305 */ 5306const dom_element = (name, attrs = [], children = []) => 5307 append(setAttributes(createElement(name), attrs), children) 5308 5309/** 5310 * @param {number} width 5311 * @param {number} height 5312 */ 5313const canvas = (width, height) => { 5314 const c = /** @type {HTMLCanvasElement} */ (createElement('canvas')) 5315 c.height = height 5316 c.width = width 5317 return c 5318} 5319 5320/** 5321 * @param {string} t 5322 * @return {Text} 5323 */ 5324const dom_text = (/* unused pure expression or super */ null && (createTextNode)) 5325 5326/** 5327 * @param {pair.Pair<string,string>} pair 5328 */ 5329const pairToStyleString = pair => `${pair.left}:${pair.right};` 5330 5331/** 5332 * @param {Array<pair.Pair<string,string>>} pairs 5333 * @return {string} 5334 */ 5335const pairsToStyleString = pairs => pairs.map(pairToStyleString).join('') 5336 5337/** 5338 * @param {Map<string,string>} m 5339 * @return {string} 5340 */ 5341const mapToStyleString = m => map_map(m, (value, key) => `${key}:${value};`).join('') 5342 5343/** 5344 * @todo should always query on a dom element 5345 * 5346 * @param {HTMLElement|ShadowRoot} el 5347 * @param {string} query 5348 * @return {HTMLElement | null} 5349 */ 5350const querySelector = (el, query) => el.querySelector(query) 5351 5352/** 5353 * @param {HTMLElement|ShadowRoot} el 5354 * @param {string} query 5355 * @return {NodeListOf<HTMLElement>} 5356 */ 5357const querySelectorAll = (el, query) => el.querySelectorAll(query) 5358 5359/** 5360 * @param {string} id 5361 * @return {HTMLElement} 5362 */ 5363const getElementById = id => /** @type {HTMLElement} */ (doc.getElementById(id)) 5364 5365/** 5366 * @param {string} html 5367 * @return {HTMLElement} 5368 */ 5369const _parse = html => domParser.parseFromString(`<html><body>${html}</body></html>`, 'text/html').body 5370 5371/** 5372 * @param {string} html 5373 * @return {DocumentFragment} 5374 */ 5375const parseFragment = html => fragment(/** @type {any} */ (_parse(html).childNodes)) 5376 5377/** 5378 * @param {string} html 5379 * @return {HTMLElement} 5380 */ 5381const parseElement = html => /** @type HTMLElement */ (_parse(html).firstElementChild) 5382 5383/** 5384 * @param {HTMLElement} oldEl 5385 * @param {HTMLElement|DocumentFragment} newEl 5386 */ 5387const replaceWith = (oldEl, newEl) => oldEl.replaceWith(newEl) 5388 5389/** 5390 * @param {HTMLElement} parent 5391 * @param {HTMLElement} el 5392 * @param {Node|null} ref 5393 * @return {HTMLElement} 5394 */ 5395const insertBefore = (parent, el, ref) => parent.insertBefore(el, ref) 5396 5397/** 5398 * @param {Node} parent 5399 * @param {Node} child 5400 * @return {Node} 5401 */ 5402const appendChild = (parent, child) => parent.appendChild(child) 5403 5404const ELEMENT_NODE = doc.ELEMENT_NODE 5405const TEXT_NODE = doc.TEXT_NODE 5406const CDATA_SECTION_NODE = doc.CDATA_SECTION_NODE 5407const COMMENT_NODE = doc.COMMENT_NODE 5408const DOCUMENT_NODE = doc.DOCUMENT_NODE 5409const DOCUMENT_TYPE_NODE = doc.DOCUMENT_TYPE_NODE 5410const DOCUMENT_FRAGMENT_NODE = doc.DOCUMENT_FRAGMENT_NODE 5411 5412/** 5413 * @param {any} node 5414 * @param {number} type 5415 */ 5416const checkNodeType = (node, type) => node.nodeType === type 5417 5418/** 5419 * @param {Node} parent 5420 * @param {HTMLElement} child 5421 */ 5422const isParentOf = (parent, child) => { 5423 let p = child.parentNode 5424 while (p && p !== parent) { 5425 p = p.parentNode 5426 } 5427 return p === parent 5428} 5429/* c8 ignore stop */ 5430 5431;// CONCATENATED MODULE: ./node_modules/lib0/symbol.js 5432/** 5433 * Utility module to work with EcmaScript Symbols. 5434 * 5435 * @module symbol 5436 */ 5437 5438/** 5439 * Return fresh symbol. 5440 * 5441 * @return {Symbol} 5442 */ 5443const symbol_create = Symbol 5444 5445/** 5446 * @param {any} s 5447 * @return {boolean} 5448 */ 5449const isSymbol = s => typeof s === 'symbol' 5450 5451;// CONCATENATED MODULE: ./node_modules/lib0/time.js 5452/** 5453 * Utility module to work with time. 5454 * 5455 * @module time 5456 */ 5457 5458 5459 5460 5461/** 5462 * Return current time. 5463 * 5464 * @return {Date} 5465 */ 5466const getDate = () => new Date() 5467 5468/** 5469 * Return current unix time. 5470 * 5471 * @return {number} 5472 */ 5473const getUnixTime = Date.now 5474 5475/** 5476 * Transform time (in ms) to a human readable format. E.g. 1100 => 1.1s. 60s => 1min. .001 => 10μs. 5477 * 5478 * @param {number} d duration in milliseconds 5479 * @return {string} humanized approximation of time 5480 */ 5481const humanizeDuration = d => { 5482 if (d < 60000) { 5483 const p = metric.prefix(d, -1) 5484 return math.round(p.n * 100) / 100 + p.prefix + 's' 5485 } 5486 d = math.floor(d / 1000) 5487 const seconds = d % 60 5488 const minutes = math.floor(d / 60) % 60 5489 const hours = math.floor(d / 3600) % 24 5490 const days = math.floor(d / 86400) 5491 if (days > 0) { 5492 return days + 'd' + ((hours > 0 || minutes > 30) ? ' ' + (minutes > 30 ? hours + 1 : hours) + 'h' : '') 5493 } 5494 if (hours > 0) { 5495 /* c8 ignore next */ 5496 return hours + 'h' + ((minutes > 0 || seconds > 30) ? ' ' + (seconds > 30 ? minutes + 1 : minutes) + 'min' : '') 5497 } 5498 return minutes + 'min' + (seconds > 0 ? ' ' + seconds + 's' : '') 5499} 5500 5501;// CONCATENATED MODULE: ./node_modules/lib0/logging.common.js 5502 5503 5504 5505 5506 5507const BOLD = symbol_create() 5508const UNBOLD = symbol_create() 5509const BLUE = symbol_create() 5510const GREY = symbol_create() 5511const GREEN = symbol_create() 5512const RED = symbol_create() 5513const PURPLE = symbol_create() 5514const ORANGE = symbol_create() 5515const UNCOLOR = symbol_create() 5516 5517/* c8 ignore start */ 5518/** 5519 * @param {Array<string|Symbol|Object|number>} args 5520 * @return {Array<string|object|number>} 5521 */
5522const computeNoColorLoggingArgs = args => { 5523 const strBuilder = [] 5524 const logArgs = [] 5525 // try with formatting until we find something unsupported 5526 let i = 0 5527 for (; i < args.length; i++) { 5528 const arg = args[i] 5529 if (arg.constructor === String || arg.constructor === Number) { 5530 strBuilder.push(arg) 5531 } else if (arg.constructor === Object) { 5532 logArgs.push(JSON.stringify(arg)) 5533 } 5534 } 5535 return logArgs 5536} 5537/* c8 ignore stop */ 5538 5539const loggingColors = [GREEN, PURPLE, ORANGE, BLUE] 5540let nextColor = 0 5541let lastLoggingTime = getUnixTime() 5542 5543/* c8 ignore start */ 5544/** 5545 * @param {function(...any):void} _print 5546 * @param {string} moduleName 5547 * @return {function(...any):void} 5548 */ 5549const createModuleLogger = (_print, moduleName) => { 5550 const color = loggingColors[nextColor] 5551 const debugRegexVar = getVariable('log') 5552 const doLogging = debugRegexVar !== null && 5553 (debugRegexVar === '*' || debugRegexVar === 'true' || 5554 new RegExp(debugRegexVar, 'gi').test(moduleName)) 5555 nextColor = (nextColor + 1) % loggingColors.length 5556 moduleName += ': ' 5557 return !doLogging 5558 ? nop 5559 : (...args) => { 5560 const timeNow = getUnixTime() 5561 const timeDiff = timeNow - lastLoggingTime 5562 lastLoggingTime = timeNow 5563 _print( 5564 color, 5565 moduleName, 5566 UNCOLOR, 5567 ...args.map((arg) => 5568 (typeof arg === 'string' || typeof arg === 'symbol') 5569 ? arg 5570 : JSON.stringify(arg) 5571 ), 5572 color, 5573 ' +' + timeDiff + 'ms' 5574 ) 5575 } 5576} 5577/* c8 ignore stop */ 5578 5579;// CONCATENATED MODULE: ./node_modules/lib0/logging.js 5580/** 5581 * Isomorphic logging module with support for colors! 5582 * 5583 * @module logging 5584 */ 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598/** 5599 * @type {Object<Symbol,pair.Pair<string,string>>} 5600 */ 5601const _browserStyleMap = { 5602 [BOLD]: pair_create('font-weight', 'bold'), 5603 [UNBOLD]: pair_create('font-weight', 'normal'), 5604 [BLUE]: pair_create('color', 'blue'), 5605 [GREEN]: pair_create('color', 'green'), 5606 [GREY]: pair_create('color', 'grey'), 5607 [RED]: pair_create('color', 'red'), 5608 [PURPLE]: pair_create('color', 'purple'), 5609 [ORANGE]: pair_create('color', 'orange'), // not well supported in chrome when debugging node with inspector - TODO: deprecate 5610 [UNCOLOR]: pair_create('color', 'black') 5611} 5612 5613/** 5614 * @param {Array<string|Symbol|Object|number>} args 5615 * @return {Array<string|object|number>} 5616 */ 5617/* c8 ignore start */ 5618const computeBrowserLoggingArgs = (args) => { 5619 const strBuilder = [] 5620 const styles = [] 5621 const currentStyle = create() 5622 /** 5623 * @type {Array<string|Object|number>} 5624 */ 5625 let logArgs = [] 5626 // try with formatting until we find something unsupported 5627 let i = 0 5628 for (; i < args.length; i++) { 5629 const arg = args[i] 5630 // @ts-ignore 5631 const style = _browserStyleMap[arg] 5632 if (style !== undefined) { 5633 currentStyle.set(style.left, style.right) 5634 } else { 5635 if (arg.constructor === String || arg.constructor === Number) { 5636 const style = mapToStyleString(currentStyle) 5637 if (i > 0 || style.length > 0) { 5638 strBuilder.push('%c' + arg) 5639 styles.push(style) 5640 } else { 5641 strBuilder.push(arg) 5642 } 5643 } else { 5644 break 5645 } 5646 } 5647 } 5648 if (i > 0) { 5649 // create logArgs with what we have so far 5650 logArgs = styles 5651 logArgs.unshift(strBuilder.join('')) 5652 } 5653 // append the rest 5654 for (; i < args.length; i++) { 5655 const arg = args[i] 5656 if (!(arg instanceof Symbol)) { 5657 logArgs.push(arg) 5658 } 5659 } 5660 return logArgs 5661} 5662/* c8 ignore stop */ 5663 5664/* c8 ignore start */ 5665const computeLoggingArgs = supportsColor 5666 ? computeBrowserLoggingArgs 5667 : computeNoColorLoggingArgs 5668/* c8 ignore stop */ 5669 5670/** 5671 * @param {Array<string|Symbol|Object|number>} args 5672 */ 5673const print = (...args) => { 5674 console.log(...computeLoggingArgs(args)) 5675 /* c8 ignore next */ 5676 vconsoles.forEach((vc) => vc.print(args)) 5677} 5678 5679/* c8 ignore start */ 5680/** 5681 * @param {Array<string|Symbol|Object|number>} args 5682 */ 5683const warn = (...args) => { 5684 console.warn(...computeLoggingArgs(args)) 5685 args.unshift(common.ORANGE) 5686 vconsoles.forEach((vc) => vc.print(args)) 5687} 5688/* c8 ignore stop */ 5689 5690/** 5691 * @param {Error} err 5692 */ 5693/* c8 ignore start */ 5694const printError = (err) => { 5695 console.error(err)
5696 vconsoles.forEach((vc) => vc.printError(err)) 5697} 5698/* c8 ignore stop */ 5699 5700/** 5701 * @param {string} url image location 5702 * @param {number} height height of the image in pixel 5703 */ 5704/* c8 ignore start */ 5705const printImg = (url, height) => { 5706 if (env.isBrowser) { 5707 console.log( 5708 '%c ', 5709 `font-size: ${height}px; background-size: contain; background-repeat: no-repeat; background-image: url(${url})` 5710 ) 5711 // console.log('%c ', `font-size: ${height}x; background: url(${url}) no-repeat;`) 5712 } 5713 vconsoles.forEach((vc) => vc.printImg(url, height)) 5714} 5715/* c8 ignore stop */ 5716 5717/** 5718 * @param {string} base64 5719 * @param {number} height 5720 */ 5721/* c8 ignore next 2 */ 5722const printImgBase64 = (base64, height) => 5723 printImg(`data:image/gif;base64,${base64}`, height) 5724 5725/** 5726 * @param {Array<string|Symbol|Object|number>} args 5727 */ 5728const group = (...args) => { 5729 console.group(...computeLoggingArgs(args)) 5730 /* c8 ignore next */ 5731 vconsoles.forEach((vc) => vc.group(args)) 5732} 5733 5734/** 5735 * @param {Array<string|Symbol|Object|number>} args 5736 */ 5737const groupCollapsed = (...args) => { 5738 console.groupCollapsed(...computeLoggingArgs(args)) 5739 /* c8 ignore next */ 5740 vconsoles.forEach((vc) => vc.groupCollapsed(args)) 5741} 5742 5743const groupEnd = () => { 5744 console.groupEnd() 5745 /* c8 ignore next */ 5746 vconsoles.forEach((vc) => vc.groupEnd()) 5747} 5748 5749/** 5750 * @param {function():Node} createNode 5751 */ 5752/* c8 ignore next 2 */ 5753const printDom = (createNode) => 5754 vconsoles.forEach((vc) => vc.printDom(createNode())) 5755 5756/** 5757 * @param {HTMLCanvasElement} canvas 5758 * @param {number} height 5759 */ 5760/* c8 ignore next 2 */ 5761const printCanvas = (canvas, height) => 5762 printImg(canvas.toDataURL(), height) 5763 5764const vconsoles = set_create() 5765 5766/** 5767 * @param {Array<string|Symbol|Object|number>} args 5768 * @return {Array<Element>} 5769 */ 5770/* c8 ignore start */ 5771const _computeLineSpans = (args) => { 5772 const spans = [] 5773 const currentStyle = new Map() 5774 // try with formatting until we find something unsupported 5775 let i = 0 5776 for (; i < args.length; i++) { 5777 const arg = args[i] 5778 // @ts-ignore 5779 const style = _browserStyleMap[arg] 5780 if (style !== undefined) { 5781 currentStyle.set(style.left, style.right) 5782 } else { 5783 if (arg.constructor === String || arg.constructor === Number) { 5784 // @ts-ignore 5785 const span = dom.element('span', [ 5786 pair.create('style', dom.mapToStyleString(currentStyle)) 5787 ], [dom.text(arg.toString())]) 5788 if (span.innerHTML === '') { 5789 span.innerHTML = ' ' 5790 } 5791 spans.push(span) 5792 } else { 5793 break 5794 } 5795 } 5796 } 5797 // append the rest 5798 for (; i < args.length; i++) {
vendor: 3,843 bytes, lines 5799-5963
5799 let content = args[i] 5800 if (!(content instanceof Symbol)) { 5801 if (content.constructor !== String && content.constructor !== Number) { 5802 content = ' ' + json.stringify(content) + ' ' 5803 } 5804 spans.push( 5805 dom.element('span', [], [dom.text(/** @type {string} */ (content))]) 5806 ) 5807 } 5808 } 5809 return spans 5810} 5811/* c8 ignore stop */ 5812 5813const lineStyle = 5814 'font-family:monospace;border-bottom:1px solid #e2e2e2;padding:2px;' 5815 5816/* c8 ignore start */ 5817class VConsole { 5818 /** 5819 * @param {Element} dom 5820 */ 5821 constructor (dom) { 5822 this.dom = dom 5823 /** 5824 * @type {Element} 5825 */ 5826 this.ccontainer = this.dom 5827 this.depth = 0 5828 vconsoles.add(this) 5829 } 5830 5831 /** 5832 * @param {Array<string|Symbol|Object|number>} args 5833 * @param {boolean} collapsed 5834 */ 5835 group (args, collapsed = false) { 5836 eventloop.enqueue(() => { 5837 const triangleDown = dom.element('span', [ 5838 pair.create('hidden', collapsed), 5839 pair.create('style', 'color:grey;font-size:120%;') 5840 ], [dom.text('â¼')]) 5841 const triangleRight = dom.element('span', [ 5842 pair.create('hidden', !collapsed), 5843 pair.create('style', 'color:grey;font-size:125%;') 5844 ], [dom.text('â¶')]) 5845 const content = dom.element( 5846 'div', 5847 [pair.create( 5848 'style', 5849 `${lineStyle};padding-left:${this.depth * 10}px` 5850 )], 5851 [triangleDown, triangleRight, dom.text(' ')].concat( 5852 _computeLineSpans(args) 5853 ) 5854 ) 5855 const nextContainer = dom.element('div', [ 5856 pair.create('hidden', collapsed) 5857 ]) 5858 const nextLine = dom.element('div', [], [content, nextContainer]) 5859 dom.append(this.ccontainer, [nextLine]) 5860 this.ccontainer = nextContainer 5861 this.depth++ 5862 // when header is clicked, collapse/uncollapse container 5863 dom.addEventListener(content, 'click', (_event) => { 5864 nextContainer.toggleAttribute('hidden') 5865 triangleDown.toggleAttribute('hidden') 5866 triangleRight.toggleAttribute('hidden') 5867 }) 5868 }) 5869 } 5870 5871 /** 5872 * @param {Array<string|Symbol|Object|number>} args 5873 */ 5874 groupCollapsed (args) { 5875 this.group(args, true) 5876 } 5877 5878 groupEnd () { 5879 eventloop.enqueue(() => { 5880 if (this.depth > 0) { 5881 this.depth-- 5882 // @ts-ignore 5883 this.ccontainer = this.ccontainer.parentElement.parentElement 5884 } 5885 }) 5886 } 5887 5888 /** 5889 * @param {Array<string|Symbol|Object|number>} args 5890 */ 5891 print (args) { 5892 eventloop.enqueue(() => { 5893 dom.append(this.ccontainer, [ 5894 dom.element('div', [ 5895 pair.create( 5896 'style', 5897 `${lineStyle};padding-left:${this.depth * 10}px` 5898 ) 5899 ], _computeLineSpans(args)) 5900 ]) 5901 }) 5902 } 5903 5904 /** 5905 * @param {Error} err 5906 */ 5907 printError (err) { 5908 this.print([common.RED, common.BOLD, err.toString()]) 5909 } 5910 5911 /** 5912 * @param {string} url 5913 * @param {number} height 5914 */ 5915 printImg (url, height) { 5916 eventloop.enqueue(() => { 5917 dom.append(this.ccontainer, [ 5918 dom.element('img', [ 5919 pair.create('src', url), 5920 pair.create('height', `${math.round(height * 1.5)}px`) 5921 ]) 5922 ]) 5923 }) 5924 } 5925 5926 /** 5927 * @param {Node} node 5928 */ 5929 printDom (node) { 5930 eventloop.enqueue(() => { 5931 dom.append(this.ccontainer, [node]) 5932 }) 5933 } 5934 5935 destroy () { 5936 eventloop.enqueue(() => { 5937 vconsoles.delete(this) 5938 }) 5939 } 5940} 5941/* c8 ignore stop */ 5942 5943/** 5944 * @param {Element} dom 5945 */ 5946/* c8 ignore next */ 5947const createVConsole = (dom) => new VConsole(dom) 5948 5949/** 5950 * @param {string} moduleName 5951 * @return {function(...any):void} 5952 */ 5953const logging_createModuleLogger = (moduleName) => createModuleLogger(print, moduleName) 5954 5955;// CONCATENATED MODULE: ./node_modules/lib0/iterator.js 5956/** 5957 * Utility module to create and manipulate Iterators. 5958 * 5959 * @module iterator 5960 */ 5961 5962/** 5963 * @template T,R
5964 * @param {Iterator<T>} iterator 5965 * @param {function(T):R} f 5966 * @return {IterableIterator<R>} 5967 */ 5968const mapIterator = (iterator, f) => ({ 5969 [Symbol.iterator] () { 5970 return this 5971 }, 5972 // @ts-ignore 5973 next () { 5974 const r = iterator.next() 5975 return { value: r.done ? undefined : f(r.value), done: r.done } 5976 } 5977}) 5978 5979/** 5980 * @template T 5981 * @param {function():IteratorResult<T>} next 5982 * @return {IterableIterator<T>} 5983 */ 5984const createIterator = next => ({ 5985 /** 5986 * @return {IterableIterator<T>} 5987 */ 5988 [Symbol.iterator] () { 5989 return this 5990 }, 5991 // @ts-ignore 5992 next 5993}) 5994 5995/** 5996 * @template T 5997 * @param {Iterator<T>} iterator 5998 * @param {function(T):boolean} filter 5999 */ 6000const iteratorFilter = (iterator, filter) => createIterator(() => { 6001 let res 6002 do { 6003 res = iterator.next() 6004 } while (!res.done && !filter(res.value)) 6005 return res 6006}) 6007 6008/** 6009 * @template T,M 6010 * @param {Iterator<T>} iterator 6011 * @param {function(T):M} fmap 6012 */ 6013const iteratorMap = (iterator, fmap) => createIterator(() => { 6014 const { done, value } = iterator.next() 6015 return { done, value: done ? undefined : fmap(value) } 6016}) 6017 6018;// CONCATENATED MODULE: ./node_modules/yjs/dist/yjs.mjs 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039/** 6040 * This is an abstract interface that all Connectors should implement to keep them interchangeable. 6041 * 6042 * @note This interface is experimental and it is not advised to actually inherit this class. 6043 * It just serves as typing information. 6044 * 6045 * @extends {Observable<any>} 6046 */ 6047class AbstractConnector extends (/* unused pure expression or super */ null && (Observable)) { 6048 /** 6049 * @param {Doc} ydoc 6050 * @param {any} awareness 6051 */ 6052 constructor (ydoc, awareness) { 6053 super(); 6054 this.doc = ydoc; 6055 this.awareness = awareness; 6056 } 6057} 6058 6059class DeleteItem { 6060 /** 6061 * @param {number} clock 6062 * @param {number} len 6063 */ 6064 constructor (clock, len) { 6065 /** 6066 * @type {number} 6067 */ 6068 this.clock = clock; 6069 /** 6070 * @type {number} 6071 */ 6072 this.len = len; 6073 } 6074} 6075 6076/** 6077 * We no longer maintain a DeleteStore. DeleteSet is a temporary object that is created when needed. 6078 * - When created in a transaction, it must only be accessed after sorting, and merging 6079 * - This DeleteSet is send to other clients 6080 * - We do not create a DeleteSet when we send a sync message. The DeleteSet message is created directly from StructStore 6081 * - We read a DeleteSet as part of a sync/update message. In this case the DeleteSet is already sorted and merged. 6082 */ 6083class DeleteSet { 6084 constructor () { 6085 /** 6086 * @type {Map<number,Array<DeleteItem>>} 6087 */ 6088 this.clients = new Map(); 6089 } 6090} 6091 6092/** 6093 * Iterate over all structs that the DeleteSet gc's. 6094 * 6095 * @param {Transaction} transaction 6096 * @param {DeleteSet} ds 6097 * @param {function(GC|Item):void} f 6098 * 6099 * @function 6100 */ 6101const iterateDeletedStructs = (transaction, ds, f) => 6102 ds.clients.forEach((deletes, clientid) => { 6103 const structs = /** @type {Array<GC|Item>} */ (transaction.doc.store.clients.get(clientid)); 6104 for (let i = 0; i < deletes.length; i++) { 6105 const del = deletes[i]; 6106 iterateStructs(transaction, structs, del.clock, del.len, f); 6107 } 6108 }); 6109 6110/** 6111 * @param {Array<DeleteItem>} dis 6112 * @param {number} clock 6113 * @return {number|null} 6114 * 6115 * @private 6116 * @function 6117 */ 6118const findIndexDS = (dis, clock) => { 6119 let left = 0; 6120 let right = dis.length - 1; 6121 while (left <= right) { 6122 const midindex = floor((left + right) / 2); 6123 const mid = dis[midindex]; 6124 const midclock = mid.clock; 6125 if (midclock <= clock) { 6126 if (clock < midclock + mid.len) { 6127 return midindex 6128 } 6129 left = midindex + 1; 6130 } else { 6131 right = midindex - 1; 6132 } 6133 } 6134 return null 6135}; 6136 6137/** 6138 * @param {DeleteSet} ds 6139 * @param {ID} id 6140 * @return {boolean} 6141 * 6142 * @private 6143 * @function 6144 */ 6145const isDeleted = (ds, id) => { 6146 const dis = ds.clients.get(id.client); 6147 return dis !== undefined && findIndexDS(dis, id.clock) !== null 6148}; 6149 6150/** 6151 * @param {DeleteSet} ds 6152 * 6153 * @private 6154 * @function 6155 */ 6156const sortAndMergeDeleteSet = ds => { 6157 ds.clients.forEach(dels => { 6158 dels.sort((a, b) => a.clock - b.clock); 6159 // merge items without filtering or splicing the array 6160 // i is the current pointer 6161 // j refers to the current insert position for the pointed item 6162 // try to merge dels[i] into dels[j-1] or set dels[j]=dels[i] 6163 let i, j; 6164 for (i = 1, j = 1; i < dels.length; i++) { 6165 const left = dels[j - 1]; 6166 const right = dels[i]; 6167 if (left.clock + left.len >= right.clock) { 6168 left.len = max(left.len, right.clock + right.len - left.clock); 6169 } else { 6170 if (j < i) { 6171 dels[j] = right; 6172 } 6173 j++; 6174 } 6175 } 6176 dels.length = j; 6177 }); 6178}; 6179 6180/** 6181 * @param {Array<DeleteSet>} dss 6182 * @return {DeleteSet} A fresh DeleteSet 6183 */ 6184const mergeDeleteSets = dss => { 6185 const merged = new DeleteSet(); 6186 for (let dssI = 0; dssI < dss.length; dssI++) {
6187 dss[dssI].clients.forEach((delsLeft, client) => { 6188 if (!merged.clients.has(client)) { 6189 // Write all missing keys from current ds and all following. 6190 // If merged already contains `client` current ds has already been added. 6191 /** 6192 * @type {Array<DeleteItem>} 6193 */ 6194 const dels = delsLeft.slice(); 6195 for (let i = dssI + 1; i < dss.length; i++) { 6196 appendTo(dels, dss[i].clients.get(client) || []); 6197 } 6198 merged.clients.set(client, dels); 6199 } 6200 }); 6201 } 6202 sortAndMergeDeleteSet(merged); 6203 return merged 6204}; 6205 6206/** 6207 * @param {DeleteSet} ds 6208 * @param {number} client 6209 * @param {number} clock 6210 * @param {number} length 6211 * 6212 * @private 6213 * @function 6214 */ 6215const addToDeleteSet = (ds, client, clock, length) => { 6216 setIfUndefined(ds.clients, client, () => /** @type {Array<DeleteItem>} */ ([])).push(new DeleteItem(clock, length)); 6217}; 6218 6219const createDeleteSet = () => new DeleteSet(); 6220 6221/** 6222 * @param {StructStore} ss 6223 * @return {DeleteSet} Merged and sorted DeleteSet 6224 * 6225 * @private 6226 * @function 6227 */ 6228const createDeleteSetFromStructStore = ss => { 6229 const ds = createDeleteSet(); 6230 ss.clients.forEach((structs, client) => { 6231 /** 6232 * @type {Array<DeleteItem>} 6233 */ 6234 const dsitems = []; 6235 for (let i = 0; i < structs.length; i++) { 6236 const struct = structs[i]; 6237 if (struct.deleted) { 6238 const clock = struct.id.clock; 6239 let len = struct.length; 6240 if (i + 1 < structs.length) { 6241 for (let next = structs[i + 1]; i + 1 < structs.length && next.deleted; next = structs[++i + 1]) { 6242 len += next.length; 6243 } 6244 } 6245 dsitems.push(new DeleteItem(clock, len)); 6246 } 6247 } 6248 if (dsitems.length > 0) { 6249 ds.clients.set(client, dsitems); 6250 } 6251 }); 6252 return ds 6253}; 6254 6255/** 6256 * @param {DSEncoderV1 | DSEncoderV2} encoder 6257 * @param {DeleteSet} ds 6258 * 6259 * @private 6260 * @function 6261 */ 6262const writeDeleteSet = (encoder, ds) => { 6263 writeVarUint(encoder.restEncoder, ds.clients.size); 6264 6265 // Ensure that the delete set is written in a deterministic order 6266 array_from(ds.clients.entries()) 6267 .sort((a, b) => b[0] - a[0]) 6268 .forEach(([client, dsitems]) => { 6269 encoder.resetDsCurVal(); 6270 writeVarUint(encoder.restEncoder, client); 6271 const len = dsitems.length; 6272 writeVarUint(encoder.restEncoder, len); 6273 for (let i = 0; i < len; i++) { 6274 const item = dsitems[i]; 6275 encoder.writeDsClock(item.clock); 6276 encoder.writeDsLen(item.len); 6277 } 6278 }); 6279}; 6280 6281/** 6282 * @param {DSDecoderV1 | DSDecoderV2} decoder 6283 * @return {DeleteSet} 6284 * 6285 * @private 6286 * @function 6287 */ 6288const readDeleteSet = decoder => { 6289 const ds = new DeleteSet(); 6290 const numClients = readVarUint(decoder.restDecoder); 6291 for (let i = 0; i < numClients; i++) { 6292 decoder.resetDsCurVal(); 6293 const client = readVarUint(decoder.restDecoder); 6294 const numberOfDeletes = readVarUint(decoder.restDecoder); 6295 if (numberOfDeletes > 0) { 6296 const dsField = setIfUndefined(ds.clients, client, () => /** @type {Array<DeleteItem>} */ ([])); 6297 for (let i = 0; i < numberOfDeletes; i++) { 6298 dsField.push(new DeleteItem(decoder.readDsClock(), decoder.readDsLen())); 6299 } 6300 } 6301 } 6302 return ds 6303}; 6304 6305/** 6306 * @todo YDecoder also contains references to String and other Decoders. Would make sense to exchange YDecoder.toUint8Array for YDecoder.DsToUint8Array().. 6307 */ 6308 6309/** 6310 * @param {DSDecoderV1 | DSDecoderV2} decoder 6311 * @param {Transaction} transaction 6312 * @param {StructStore} store 6313 * @return {Uint8Array|null} Returns a v2 update containing all deletes that couldn't be applied yet; or null if all deletes were applied successfully. 6314 * 6315 * @private 6316 * @function 6317 */ 6318const readAndApplyDeleteSet = (decoder, transaction, store) => { 6319 const unappliedDS = new DeleteSet(); 6320 const numClients = readVarUint(decoder.restDecoder); 6321 for (let i = 0; i < numClients; i++) { 6322 decoder.resetDsCurVal(); 6323 const client = readVarUint(decoder.restDecoder); 6324 const numberOfDeletes = readVarUint(decoder.restDecoder); 6325 const structs = store.clients.get(client) || []; 6326 const state = getState(store, client); 6327 for (let i = 0; i < numberOfDeletes; i++) { 6328 const clock = decoder.readDsClock(); 6329 const clockEnd = clock + decoder.readDsLen(); 6330 if (clock < state) { 6331 if (state < clockEnd) { 6332 addToDeleteSet(unappliedDS, client, state, clockEnd - state); 6333 } 6334 let index = findIndexSS(structs, clock); 6335 /** 6336 * We can ignore the case of GC and Delete structs, because we are going to skip them 6337 * @type {Item} 6338 */ 6339 // @ts-ignore 6340 let struct = structs[index]; 6341 // split the first item if necessary
6342 if (!struct.deleted && struct.id.clock < clock) { 6343 structs.splice(index + 1, 0, splitItem(transaction, struct, clock - struct.id.clock)); 6344 index++; // increase we now want to use the next struct 6345 } 6346 while (index < structs.length) { 6347 // @ts-ignore 6348 struct = structs[index++]; 6349 if (struct.id.clock < clockEnd) { 6350 if (!struct.deleted) { 6351 if (clockEnd < struct.id.clock + struct.length) { 6352 structs.splice(index, 0, splitItem(transaction, struct, clockEnd - struct.id.clock)); 6353 } 6354 struct.delete(transaction); 6355 } 6356 } else { 6357 break 6358 } 6359 } 6360 } else { 6361 addToDeleteSet(unappliedDS, client, clock, clockEnd - clock); 6362 } 6363 } 6364 } 6365 if (unappliedDS.clients.size > 0) { 6366 const ds = new UpdateEncoderV2(); 6367 writeVarUint(ds.restEncoder, 0); // encode 0 structs 6368 writeDeleteSet(ds, unappliedDS); 6369 return ds.toUint8Array() 6370 } 6371 return null 6372}; 6373 6374/** 6375 * @param {DeleteSet} ds1 6376 * @param {DeleteSet} ds2 6377 */ 6378const equalDeleteSets = (ds1, ds2) => { 6379 if (ds1.clients.size !== ds2.clients.size) return false 6380 for (const [client, deleteItems1] of ds1.clients.entries()) { 6381 const deleteItems2 = /** @type {Array<import('../internals.js').DeleteItem>} */ (ds2.clients.get(client)); 6382 if (deleteItems2 === undefined || deleteItems1.length !== deleteItems2.length) return false 6383 for (let i = 0; i < deleteItems1.length; i++) { 6384 const di1 = deleteItems1[i]; 6385 const di2 = deleteItems2[i]; 6386 if (di1.clock !== di2.clock || di1.len !== di2.len) { 6387 return false 6388 } 6389 } 6390 } 6391 return true 6392}; 6393 6394/** 6395 * @module Y 6396 */ 6397 6398const generateNewClientId = uint32; 6399 6400/** 6401 * @typedef {Object} DocOpts 6402 * @property {boolean} [DocOpts.gc=true] Disable garbage collection (default: gc=true) 6403 * @property {function(Item):boolean} [DocOpts.gcFilter] Will be called before an Item is garbage collected. Return false to keep the Item. 6404 * @property {string} [DocOpts.guid] Define a globally unique identifier for this document 6405 * @property {string | null} [DocOpts.collectionid] Associate this document with a collection. This only plays a role if your provider has a concept of collection. 6406 * @property {any} [DocOpts.meta] Any kind of meta information you want to associate with this document. If this is a subdocument, remote peers will store the meta information as well. 6407 * @property {boolean} [DocOpts.autoLoad] If a subdocument, automatically load document. If this is a subdocument, remote peers will load the document as well automatically. 6408 * @property {boolean} [DocOpts.shouldLoad] Whether the document should be synced by the provider now. This is toggled to true when you call ydoc.load() 6409 */ 6410
6411/** 6412 * A Yjs instance handles the state of shared data. 6413 * @extends Observable<string> 6414 */ 6415class Doc extends observable_Observable { 6416 /** 6417 * @param {DocOpts} opts configuration 6418 */ 6419 constructor ({ guid = uuidv4(), collectionid = null, gc = true, gcFilter = () => true, meta = null, autoLoad = false, shouldLoad = true } = {}) { 6420 super(); 6421 this.gc = gc; 6422 this.gcFilter = gcFilter; 6423 this.clientID = generateNewClientId(); 6424 this.guid = guid; 6425 this.collectionid = collectionid; 6426 /** 6427 * @type {Map<string, AbstractType<YEvent<any>>>} 6428 */ 6429 this.share = new Map(); 6430 this.store = new StructStore(); 6431 /** 6432 * @type {Transaction | null} 6433 */ 6434 this._transaction = null; 6435 /** 6436 * @type {Array<Transaction>} 6437 */ 6438 this._transactionCleanups = []; 6439 /** 6440 * @type {Set<Doc>} 6441 */ 6442 this.subdocs = new Set(); 6443 /** 6444 * If this document is a subdocument - a document integrated into another document - then _item is defined. 6445 * @type {Item?} 6446 */ 6447 this._item = null; 6448 this.shouldLoad = shouldLoad; 6449 this.autoLoad = autoLoad; 6450 this.meta = meta; 6451 /** 6452 * This is set to true when the persistence provider loaded the document from the database or when the `sync` event fires. 6453 * Note that not all providers implement this feature. Provider authors are encouraged to fire the `load` event when the doc content is loaded from the database. 6454 * 6455 * @type {boolean} 6456 */ 6457 this.isLoaded = false; 6458 /** 6459 * This is set to true when the connection provider has successfully synced with a backend. 6460 * Note that when using peer-to-peer providers this event may not provide very useful. 6461 * Also note that not all providers implement this feature. Provider authors are encouraged to fire 6462 * the `sync` event when the doc has been synced (with `true` as a parameter) or if connection is 6463 * lost (with false as a parameter). 6464 */ 6465 this.isSynced = false; 6466 /** 6467 * Promise that resolves once the document has been loaded from a presistence provider. 6468 */ 6469 this.whenLoaded = promise_create(resolve => { 6470 this.on('load', () => { 6471 this.isLoaded = true; 6472 resolve(this); 6473 }); 6474 }); 6475 const provideSyncedPromise = () => promise_create(resolve => { 6476 /** 6477 * @param {boolean} isSynced 6478 */ 6479 const eventHandler = (isSynced) => { 6480 if (isSynced === undefined || isSynced === true) { 6481 this.off('sync', eventHandler); 6482 resolve(); 6483 } 6484 }; 6485 this.on('sync', eventHandler); 6486 }); 6487 this.on('sync', isSynced => { 6488 if (isSynced === false && this.isSynced) { 6489 this.whenSynced = provideSyncedPromise(); 6490 } 6491 this.isSynced = isSynced === undefined || isSynced === true; 6492 if (!this.isLoaded) { 6493 this.emit('load', []); 6494 } 6495 }); 6496 /** 6497 * Promise that resolves once the document has been synced with a backend. 6498 * This promise is recreated when the connection is lost. 6499 * Note the documentation about the `isSynced` property. 6500 */ 6501 this.whenSynced = provideSyncedPromise(); 6502 } 6503 6504 /** 6505 * Notify the parent document that you request to load data into this subdocument (if it is a subdocument). 6506 * 6507 * `load()` might be used in the future to request any provider to load the most current data. 6508 * 6509 * It is safe to call `load()` multiple times. 6510 */ 6511 load () { 6512 const item = this._item; 6513 if (item !== null && !this.shouldLoad) { 6514 transact(/** @type {any} */ (item.parent).doc, transaction => { 6515 transaction.subdocsLoaded.add(this); 6516 }, null, true); 6517 } 6518 this.shouldLoad = true; 6519 } 6520 6521 getSubdocs () { 6522 return this.subdocs 6523 } 6524 6525 getSubdocGuids () { 6526 return new Set(array_from(this.subdocs).map(doc => doc.guid)) 6527 } 6528 6529 /** 6530 * Changes that happen inside of a transaction are bundled. This means that 6531 * the observer fires _after_ the transaction is finished and that all changes 6532 * that happened inside of the transaction are sent as one message to the 6533 * other peers. 6534 * 6535 * @template T 6536 * @param {function(Transaction):T} f The function that should be executed as a transaction 6537 * @param {any} [origin] Origin of who started the transaction. Will be stored on transaction.origin 6538 * @return T 6539 * 6540 * @public 6541 */ 6542 transact (f, origin = null) { 6543 return transact(this, f, origin) 6544 } 6545 6546 /** 6547 * Define a shared data type. 6548 * 6549 * Multiple calls of `y.get(name, TypeConstructor)` yield the same result 6550 * and do not overwrite each other. I.e. 6551 * `y.define(name, Y.Array) === y.define(name, Y.Array)` 6552 * 6553 * After this method is called, the type is also available on `y.share.get(name)`. 6554 * 6555 * *Best Practices:* 6556 * Define all types right after the Yjs instance is created and store them in a separate object. 6557 * Also use the typed methods `getText(name)`, `getArray(name)`, .. 6558 * 6559 * @example 6560 * const y = new Y(..) 6561 * const appState = { 6562 * document: y.getText('document') 6563 * comments: y.getArray('comments') 6564 * } 6565 * 6566 * @param {string} name 6567 * @param {Function} TypeConstructor The constructor of the type definition. E.g. Y.Text, Y.Array, Y.Map, ... 6568 * @return {AbstractType<any>} The created type. Constructed with TypeConstructor 6569 * 6570 * @public 6571 */ 6572 get (name, TypeConstructor = AbstractType) { 6573 const type = setIfUndefined(this.share, name, () => { 6574 // @ts-ignore 6575 const t = new TypeConstructor(); 6576 t._integrate(this, null); 6577 return t 6578 }); 6579 const Constr = type.constructor; 6580 if (TypeConstructor !== AbstractType && Constr !== TypeConstructor) { 6581 if (Constr === AbstractType) { 6582 // @ts-ignore 6583 const t = new TypeConstructor(); 6584 t._map = type._map;
6585 type._map.forEach(/** @param {Item?} n */ n => { 6586 for (; n !== null; n = n.left) { 6587 // @ts-ignore 6588 n.parent = t; 6589 } 6590 }); 6591 t._start = type._start; 6592 for (let n = t._start; n !== null; n = n.right) { 6593 n.parent = t; 6594 } 6595 t._length = type._length; 6596 this.share.set(name, t); 6597 t._integrate(this, null); 6598 return t 6599 } else { 6600 throw new Error(`Type with the name ${name} has already been defined with a different constructor`) 6601 } 6602 } 6603 return type 6604 } 6605 6606 /** 6607 * @template T 6608 * @param {string} [name] 6609 * @return {YArray<T>} 6610 * 6611 * @public 6612 */ 6613 getArray (name = '') { 6614 // @ts-ignore 6615 return this.get(name, YArray) 6616 } 6617 6618 /** 6619 * @param {string} [name] 6620 * @return {YText} 6621 * 6622 * @public 6623 */ 6624 getText (name = '') { 6625 // @ts-ignore 6626 return this.get(name, YText) 6627 } 6628 6629 /** 6630 * @template T 6631 * @param {string} [name] 6632 * @return {YMap<T>} 6633 * 6634 * @public 6635 */ 6636 getMap (name = '') { 6637 // @ts-ignore 6638 return this.get(name, YMap) 6639 } 6640 6641 /** 6642 * @param {string} [name] 6643 * @return {YXmlFragment} 6644 * 6645 * @public 6646 */ 6647 getXmlFragment (name = '') { 6648 // @ts-ignore 6649 return this.get(name, YXmlFragment) 6650 } 6651 6652 /** 6653 * Converts the entire document into a js object, recursively traversing each yjs type 6654 * Doesn't log types that have not been defined (using ydoc.getType(..)). 6655 * 6656 * @deprecated Do not use this method and rather call toJSON directly on the shared types. 6657 * 6658 * @return {Object<string, any>} 6659 */ 6660 toJSON () { 6661 /** 6662 * @type {Object<string, any>} 6663 */ 6664 const doc = {}; 6665 6666 this.share.forEach((value, key) => { 6667 doc[key] = value.toJSON(); 6668 }); 6669 6670 return doc 6671 } 6672 6673 /** 6674 * Emit `destroy` event and unregister all event handlers. 6675 */ 6676 destroy () { 6677 array_from(this.subdocs).forEach(subdoc => subdoc.destroy()); 6678 const item = this._item; 6679 if (item !== null) { 6680 this._item = null; 6681 const content = /** @type {ContentDoc} */ (item.content); 6682 content.doc = new Doc({ guid: this.guid, ...content.opts, shouldLoad: false }); 6683 content.doc._item = item; 6684 transact(/** @type {any} */ (item).parent.doc, transaction => { 6685 const doc = content.doc; 6686 if (!item.deleted) { 6687 transaction.subdocsAdded.add(doc); 6688 } 6689 transaction.subdocsRemoved.add(this); 6690 }, null, true); 6691 } 6692 this.emit('destroyed', [true]); 6693 this.emit('destroy', [this]); 6694 super.destroy(); 6695 } 6696 6697 /** 6698 * @param {string} eventName 6699 * @param {function(...any):any} f 6700 */ 6701 on (eventName, f) { 6702 super.on(eventName, f); 6703 } 6704 6705 /** 6706 * @param {string} eventName 6707 * @param {function} f 6708 */ 6709 off (eventName, f) { 6710 super.off(eventName, f); 6711 } 6712} 6713 6714class DSDecoderV1 { 6715 /** 6716 * @param {decoding.Decoder} decoder 6717 */ 6718 constructor (decoder) { 6719 this.restDecoder = decoder; 6720 } 6721 6722 resetDsCurVal () { 6723 // nop 6724 } 6725 6726 /** 6727 * @return {number} 6728 */ 6729 readDsClock () { 6730 return readVarUint(this.restDecoder) 6731 } 6732 6733 /** 6734 * @return {number} 6735 */ 6736 readDsLen () { 6737 return readVarUint(this.restDecoder) 6738 } 6739} 6740 6741class UpdateDecoderV1 extends DSDecoderV1 { 6742 /** 6743 * @return {ID} 6744 */ 6745 readLeftID () { 6746 return createID(readVarUint(this.restDecoder), readVarUint(this.restDecoder)) 6747 } 6748 6749 /** 6750 * @return {ID} 6751 */ 6752 readRightID () { 6753 return createID(readVarUint(this.restDecoder), readVarUint(this.restDecoder)) 6754 } 6755 6756 /** 6757 * Read the next client id. 6758 * Use this in favor of readID whenever possible to reduce the number of objects created. 6759 */ 6760 readClient () { 6761 return readVarUint(this.restDecoder) 6762 } 6763 6764 /** 6765 * @return {number} info An unsigned 8-bit integer 6766 */ 6767 readInfo () { 6768 return readUint8(this.restDecoder) 6769 } 6770 6771 /** 6772 * @return {string} 6773 */ 6774 readString () { 6775 return readVarString(this.restDecoder) 6776 } 6777 6778 /** 6779 * @return {boolean} isKey 6780 */ 6781 readParentInfo () { 6782 return readVarUint(this.restDecoder) === 1 6783 } 6784 6785 /** 6786 * @return {number} info An unsigned 8-bit integer 6787 */ 6788 readTypeRef () { 6789 return readVarUint(this.restDecoder) 6790 } 6791 6792 /** 6793 * Write len of a struct - well suited for Opt RLE encoder. 6794 * 6795 * @return {number} len 6796 */ 6797 readLen () { 6798 return readVarUint(this.restDecoder) 6799 } 6800 6801 /** 6802 * @return {any} 6803 */ 6804 readAny () { 6805 return readAny(this.restDecoder) 6806 } 6807 6808 /** 6809 * @return {Uint8Array} 6810 */ 6811 readBuf () { 6812 return copyUint8Array(readVarUint8Array(this.restDecoder)) 6813 } 6814 6815 /** 6816 * Legacy implementation uses JSON parse. We use any-decoding in v2. 6817 * 6818 * @return {any} 6819 */ 6820 readJSON () { 6821 return JSON.parse(readVarString(this.restDecoder)) 6822 } 6823 6824 /** 6825 * @return {string} 6826 */ 6827 readKey () { 6828 return readVarString(this.restDecoder) 6829 } 6830} 6831 6832class DSDecoderV2 { 6833 /** 6834 * @param {decoding.Decoder} decoder 6835 */ 6836 constructor (decoder) { 6837 /** 6838 * @private 6839 */ 6840 this.dsCurrVal = 0; 6841 this.restDecoder = decoder; 6842 } 6843 6844 resetDsCurVal () { 6845 this.dsCurrVal = 0; 6846 } 6847 6848 /** 6849 * @return {number} 6850 */ 6851 readDsClock () { 6852 this.dsCurrVal += readVarUint(this.restDecoder); 6853 return this.dsCurrVal 6854 } 6855 6856 /** 6857 * @return {number} 6858 */ 6859 readDsLen () { 6860 const diff = readVarUint(this.restDecoder) + 1; 6861 this.dsCurrVal += diff; 6862 return diff 6863 } 6864} 6865 6866class UpdateDecoderV2 extends DSDecoderV2 { 6867 /** 6868 * @param {decoding.Decoder} decoder 6869 */ 6870 constructor (decoder) { 6871 super(decoder); 6872 /** 6873 * List of cached keys. If the keys[id] does not exist, we read a new key 6874 * from stringEncoder and push it to keys. 6875 * 6876 * @type {Array<string>} 6877 */ 6878 this.keys = []; 6879 readVarUint(decoder); // read feature flag - currently unused 6880 this.keyClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder)); 6881 this.clientDecoder = new UintOptRleDecoder(readVarUint8Array(decoder)); 6882 this.leftClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder)); 6883 this.rightClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder)); 6884 this.infoDecoder = new RleDecoder(readVarUint8Array(decoder), readUint8); 6885 this.stringDecoder = new StringDecoder(readVarUint8Array(decoder)); 6886 this.parentInfoDecoder = new RleDecoder(readVarUint8Array(decoder), readUint8); 6887 this.typeRefDecoder = new UintOptRleDecoder(readVarUint8Array(decoder)); 6888 this.lenDecoder = new UintOptRleDecoder(readVarUint8Array(decoder)); 6889 } 6890 6891 /** 6892 * @return {ID} 6893 */ 6894 readLeftID () { 6895 return new ID(this.clientDecoder.read(), this.leftClockDecoder.read()) 6896 } 6897 6898 /** 6899 * @return {ID} 6900 */ 6901 readRightID () { 6902 return new ID(this.clientDecoder.read(), this.rightClockDecoder.read()) 6903 } 6904 6905 /** 6906 * Read the next client id. 6907 * Use this in favor of readID whenever possible to reduce the number of objects created. 6908 */ 6909 readClient () { 6910 return this.clientDecoder.read() 6911 } 6912 6913 /** 6914 * @return {number} info An unsigned 8-bit integer 6915 */ 6916 readInfo () { 6917 return /** @type {number} */ (this.infoDecoder.read()) 6918 } 6919 6920 /** 6921 * @return {string} 6922 */ 6923 readString () { 6924 return this.stringDecoder.read() 6925 } 6926 6927 /** 6928 * @return {boolean} 6929 */ 6930 readParentInfo () { 6931 return this.parentInfoDecoder.read() === 1 6932 } 6933 6934 /** 6935 * @return {number} An unsigned 8-bit integer 6936 */ 6937 readTypeRef () { 6938 return this.typeRefDecoder.read() 6939 } 6940 6941 /** 6942 * Write len of a struct - well suited for Opt RLE encoder. 6943 * 6944 * @return {number} 6945 */ 6946 readLen () { 6947 return this.lenDecoder.read() 6948 } 6949 6950 /** 6951 * @return {any} 6952 */ 6953 readAny () { 6954 return readAny(this.restDecoder) 6955 } 6956 6957 /** 6958 * @return {Uint8Array} 6959 */ 6960 readBuf () { 6961 return readVarUint8Array(this.restDecoder) 6962 } 6963 6964 /** 6965 * This is mainly here for legacy purposes. 6966 * 6967 * Initial we incoded objects using JSON. Now we use the much faster lib0/any-encoder. This method mainly exists for legacy purposes for the v1 encoder. 6968 * 6969 * @return {any} 6970 */ 6971 readJSON () { 6972 return readAny(this.restDecoder) 6973 } 6974 6975 /** 6976 * @return {string} 6977 */ 6978 readKey () {
6979 const keyClock = this.keyClockDecoder.read(); 6980 if (keyClock < this.keys.length) { 6981 return this.keys[keyClock] 6982 } else { 6983 const key = this.stringDecoder.read(); 6984 this.keys.push(key); 6985 return key 6986 } 6987 } 6988} 6989 6990class DSEncoderV1 { 6991 constructor () { 6992 this.restEncoder = createEncoder(); 6993 } 6994 6995 toUint8Array () { 6996 return toUint8Array(this.restEncoder) 6997 } 6998 6999 resetDsCurVal () { 7000 // nop 7001 } 7002 7003 /** 7004 * @param {number} clock 7005 */ 7006 writeDsClock (clock) { 7007 writeVarUint(this.restEncoder, clock); 7008 } 7009 7010 /** 7011 * @param {number} len 7012 */ 7013 writeDsLen (len) { 7014 writeVarUint(this.restEncoder, len); 7015 } 7016} 7017 7018class UpdateEncoderV1 extends DSEncoderV1 { 7019 /** 7020 * @param {ID} id 7021 */ 7022 writeLeftID (id) { 7023 writeVarUint(this.restEncoder, id.client); 7024 writeVarUint(this.restEncoder, id.clock); 7025 } 7026 7027 /** 7028 * @param {ID} id 7029 */ 7030 writeRightID (id) { 7031 writeVarUint(this.restEncoder, id.client); 7032 writeVarUint(this.restEncoder, id.clock); 7033 } 7034 7035 /** 7036 * Use writeClient and writeClock instead of writeID if possible. 7037 * @param {number} client 7038 */ 7039 writeClient (client) { 7040 writeVarUint(this.restEncoder, client); 7041 } 7042 7043 /** 7044 * @param {number} info An unsigned 8-bit integer 7045 */ 7046 writeInfo (info) { 7047 writeUint8(this.restEncoder, info); 7048 } 7049 7050 /** 7051 * @param {string} s 7052 */ 7053 writeString (s) { 7054 writeVarString(this.restEncoder, s); 7055 } 7056 7057 /** 7058 * @param {boolean} isYKey 7059 */ 7060 writeParentInfo (isYKey) { 7061 writeVarUint(this.restEncoder, isYKey ? 1 : 0); 7062 } 7063 7064 /** 7065 * @param {number} info An unsigned 8-bit integer 7066 */ 7067 writeTypeRef (info) { 7068 writeVarUint(this.restEncoder, info); 7069 } 7070 7071 /** 7072 * Write len of a struct - well suited for Opt RLE encoder. 7073 * 7074 * @param {number} len 7075 */ 7076 writeLen (len) { 7077 writeVarUint(this.restEncoder, len); 7078 } 7079 7080 /** 7081 * @param {any} any 7082 */ 7083 writeAny (any) { 7084 writeAny(this.restEncoder, any); 7085 } 7086 7087 /** 7088 * @param {Uint8Array} buf 7089 */ 7090 writeBuf (buf) { 7091 writeVarUint8Array(this.restEncoder, buf); 7092 } 7093 7094 /** 7095 * @param {any} embed 7096 */ 7097 writeJSON (embed) { 7098 writeVarString(this.restEncoder, JSON.stringify(embed)); 7099 } 7100 7101 /** 7102 * @param {string} key 7103 */ 7104 writeKey (key) { 7105 writeVarString(this.restEncoder, key); 7106 } 7107} 7108 7109class DSEncoderV2 { 7110 constructor () { 7111 this.restEncoder = createEncoder(); // encodes all the rest / non-optimized 7112 this.dsCurrVal = 0; 7113 } 7114 7115 toUint8Array () { 7116 return toUint8Array(this.restEncoder) 7117 } 7118 7119 resetDsCurVal () { 7120 this.dsCurrVal = 0; 7121 } 7122 7123 /** 7124 * @param {number} clock 7125 */ 7126 writeDsClock (clock) { 7127 const diff = clock - this.dsCurrVal; 7128 this.dsCurrVal = clock; 7129 writeVarUint(this.restEncoder, diff); 7130 } 7131 7132 /** 7133 * @param {number} len 7134 */ 7135 writeDsLen (len) { 7136 if (len === 0) { 7137 unexpectedCase(); 7138 } 7139 writeVarUint(this.restEncoder, len - 1); 7140 this.dsCurrVal += len; 7141 } 7142} 7143 7144class UpdateEncoderV2 extends DSEncoderV2 { 7145 constructor () { 7146 super(); 7147 /** 7148 * @type {Map<string,number>} 7149 */ 7150 this.keyMap = new Map(); 7151 /** 7152 * Refers to the next uniqe key-identifier to me used. 7153 * See writeKey method for more information. 7154 * 7155 * @type {number} 7156 */ 7157 this.keyClock = 0; 7158 this.keyClockEncoder = new IntDiffOptRleEncoder(); 7159 this.clientEncoder = new UintOptRleEncoder(); 7160 this.leftClockEncoder = new IntDiffOptRleEncoder(); 7161 this.rightClockEncoder = new IntDiffOptRleEncoder(); 7162 this.infoEncoder = new RleEncoder(writeUint8); 7163 this.stringEncoder = new StringEncoder(); 7164 this.parentInfoEncoder = new RleEncoder(writeUint8); 7165 this.typeRefEncoder = new UintOptRleEncoder(); 7166 this.lenEncoder = new UintOptRleEncoder(); 7167 } 7168 7169 toUint8Array () { 7170 const encoder = createEncoder(); 7171 writeVarUint(encoder, 0); // this is a feature flag that we might use in the future 7172 writeVarUint8Array(encoder, this.keyClockEncoder.toUint8Array()); 7173 writeVarUint8Array(encoder, this.clientEncoder.toUint8Array()); 7174 writeVarUint8Array(encoder, this.leftClockEncoder.toUint8Array()); 7175 writeVarUint8Array(encoder, this.rightClockEncoder.toUint8Array()); 7176 writeVarUint8Array(encoder, toUint8Array(this.infoEncoder)); 7177 writeVarUint8Array(encoder, this.stringEncoder.toUint8Array()); 7178 writeVarUint8Array(encoder, toUint8Array(this.parentInfoEncoder)); 7179 writeVarUint8Array(encoder, this.typeRefEncoder.toUint8Array()); 7180 writeVarUint8Array(encoder, this.lenEncoder.toUint8Array()); 7181 // @note The rest encoder is appended! (note the missing var) 7182 writeUint8Array(encoder, toUint8Array(this.restEncoder)); 7183 return toUint8Array(encoder) 7184 } 7185 7186 /** 7187 * @param {ID} id 7188 */ 7189 writeLeftID (id) { 7190 this.clientEncoder.write(id.client); 7191 this.leftClockEncoder.write(id.clock); 7192 } 7193 7194 /** 7195 * @param {ID} id 7196 */ 7197 writeRightID (id) { 7198 this.clientEncoder.write(id.client); 7199 this.rightClockEncoder.write(id.clock); 7200 } 7201 7202 /** 7203 * @param {number} client 7204 */ 7205 writeClient (client) { 7206 this.clientEncoder.write(client); 7207 } 7208 7209 /** 7210 * @param {number} info An unsigned 8-bit integer 7211 */ 7212 writeInfo (info) { 7213 this.infoEncoder.write(info); 7214 } 7215 7216 /** 7217 * @param {string} s 7218 */ 7219 writeString (s) { 7220 this.stringEncoder.write(s); 7221 } 7222 7223 /** 7224 * @param {boolean} isYKey 7225 */ 7226 writeParentInfo (isYKey) { 7227 this.parentInfoEncoder.write(isYKey ? 1 : 0); 7228 } 7229 7230 /** 7231 * @param {number} info An unsigned 8-bit integer 7232 */ 7233 writeTypeRef (info) { 7234 this.typeRefEncoder.write(info); 7235 } 7236 7237 /** 7238 * Write len of a struct - well suited for Opt RLE encoder. 7239 * 7240 * @param {number} len 7241 */ 7242 writeLen (len) { 7243 this.lenEncoder.write(len); 7244 } 7245 7246 /** 7247 * @param {any} any 7248 */ 7249 writeAny (any) { 7250 writeAny(this.restEncoder, any); 7251 } 7252 7253 /** 7254 * @param {Uint8Array} buf 7255 */ 7256 writeBuf (buf) { 7257 writeVarUint8Array(this.restEncoder, buf); 7258 } 7259 7260 /** 7261 * This is mainly here for legacy purposes. 7262 * 7263 * Initial we incoded objects using JSON. Now we use the much faster lib0/any-encoder. This method mainly exists for legacy purposes for the v1 encoder. 7264 * 7265 * @param {any} embed 7266 */ 7267 writeJSON (embed) { 7268 writeAny(this.restEncoder, embed); 7269 } 7270 7271 /** 7272 * Property keys are often reused. For example, in y-prosemirror the key `bold` might 7273 * occur very often. For a 3d application, the key `position` might occur very often. 7274 * 7275 * We cache these keys in a Map and refer to them via a unique number. 7276 * 7277 * @param {string} key 7278 */ 7279 writeKey (key) { 7280 const clock = this.keyMap.get(key); 7281 if (clock === undefined) { 7282 /** 7283 * @todo uncomment to introduce this feature finally 7284 *
7285 * Background. The ContentFormat object was always encoded using writeKey, but the decoder used to use readString. 7286 * Furthermore, I forgot to set the keyclock. So everything was working fine. 7287 * 7288 * However, this feature here is basically useless as it is not being used (it actually only consumes extra memory). 7289 * 7290 * I don't know yet how to reintroduce this feature.. 7291 * 7292 * Older clients won't be able to read updates when we reintroduce this feature. So this should probably be done using a flag. 7293 * 7294 */ 7295 // this.keyMap.set(key, this.keyClock) 7296 this.keyClockEncoder.write(this.keyClock++); 7297 this.stringEncoder.write(key); 7298 } else { 7299 this.keyClockEncoder.write(clock); 7300 } 7301 } 7302} 7303 7304/** 7305 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 7306 * @param {Array<GC|Item>} structs All structs by `client` 7307 * @param {number} client 7308 * @param {number} clock write structs starting with `ID(client,clock)` 7309 * 7310 * @function 7311 */ 7312const writeStructs = (encoder, structs, client, clock) => { 7313 // write first id 7314 clock = max(clock, structs[0].id.clock); // make sure the first id exists 7315 const startNewStructs = findIndexSS(structs, clock); 7316 // write # encoded structs 7317 writeVarUint(encoder.restEncoder, structs.length - startNewStructs); 7318 encoder.writeClient(client); 7319 writeVarUint(encoder.restEncoder, clock); 7320 const firstStruct = structs[startNewStructs]; 7321 // write first struct with an offset 7322 firstStruct.write(encoder, clock - firstStruct.id.clock); 7323 for (let i = startNewStructs + 1; i < structs.length; i++) { 7324 structs[i].write(encoder, 0); 7325 } 7326}; 7327 7328/** 7329 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 7330 * @param {StructStore} store 7331 * @param {Map<number,number>} _sm 7332 * 7333 * @private 7334 * @function 7335 */ 7336const writeClientsStructs = (encoder, store, _sm) => { 7337 // we filter all valid _sm entries into sm 7338 const sm = new Map(); 7339 _sm.forEach((clock, client) => { 7340 // only write if new structs are available 7341 if (getState(store, client) > clock) { 7342 sm.set(client, clock); 7343 } 7344 }); 7345 getStateVector(store).forEach((_clock, client) => { 7346 if (!_sm.has(client)) { 7347 sm.set(client, 0); 7348 } 7349 }); 7350 // write # states that were updated 7351 writeVarUint(encoder.restEncoder, sm.size); 7352 // Write items with higher client ids first 7353 // This heavily improves the conflict algorithm. 7354 array_from(sm.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => { 7355 writeStructs(encoder, /** @type {Array<GC|Item>} */ (store.clients.get(client)), client, clock); 7356 }); 7357}; 7358 7359/** 7360 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder The decoder object to read data from. 7361 * @param {Doc} doc 7362 * @return {Map<number, { i: number, refs: Array<Item | GC> }>} 7363 * 7364 * @private 7365 * @function 7366 */ 7367const readClientsStructRefs = (decoder, doc) => { 7368 /** 7369 * @type {Map<number, { i: number, refs: Array<Item | GC> }>} 7370 */ 7371 const clientRefs = create(); 7372 const numOfStateUpdates = readVarUint(decoder.restDecoder); 7373 for (let i = 0; i < numOfStateUpdates; i++) { 7374 const numberOfStructs = readVarUint(decoder.restDecoder); 7375 /** 7376 * @type {Array<GC|Item>} 7377 */ 7378 const refs = new Array(numberOfStructs); 7379 const client = decoder.readClient(); 7380 let clock = readVarUint(decoder.restDecoder); 7381 // const start = performance.now() 7382 clientRefs.set(client, { i: 0, refs }); 7383 for (let i = 0; i < numberOfStructs; i++) { 7384 const info = decoder.readInfo(); 7385 switch (BITS5 & info) { 7386 case 0: { // GC 7387 const len = decoder.readLen(); 7388 refs[i] = new GC(createID(client, clock), len); 7389 clock += len; 7390 break 7391 } 7392 case 10: { // Skip Struct (nothing to apply) 7393 // @todo we could reduce the amount of checks by adding Skip struct to clientRefs so we know that something is missing. 7394 const len = readVarUint(decoder.restDecoder); 7395 refs[i] = new Skip(createID(client, clock), len); 7396 clock += len; 7397 break 7398 } 7399 default: { // Item with content 7400 /** 7401 * The optimized implementation doesn't use any variables because inlining variables is faster. 7402 * Below a non-optimized version is shown that implements the basic algorithm with 7403 * a few comments 7404 */ 7405 const cantCopyParentInfo = (info & (BIT7 | BIT8)) === 0; 7406 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y` 7407 // and we read the next string as parentYKey. 7408 // It indicates how we store/retrieve parent from `y.share` 7409 // @type {string|null} 7410 const struct = new Item( 7411 createID(client, clock), 7412 null, // leftd 7413 (info & BIT8) === BIT8 ? decoder.readLeftID() : null, // origin 7414 null, // right 7415 (info & BIT7) === BIT7 ? decoder.readRightID() : null, // right origin 7416 cantCopyParentInfo ? (decoder.readParentInfo() ? doc.get(decoder.readString()) : decoder.readLeftID()) : null, // parent 7417 cantCopyParentInfo && (info & BIT6) === BIT6 ? decoder.readString() : null, // parentSub 7418 readItemContent(decoder, info) // item content 7419 ); 7420 /* A non-optimized implementation of the above algorithm: 7421 7422 // The item that was originally to the left of this item. 7423 const origin = (info & binary.BIT8) === binary.BIT8 ? decoder.readLeftID() : null 7424 // The item that was originally to the right of this item. 7425 const rightOrigin = (info & binary.BIT7) === binary.BIT7 ? decoder.readRightID() : null 7426 const cantCopyParentInfo = (info & (binary.BIT7 | binary.BIT8)) === 0 7427 const hasParentYKey = cantCopyParentInfo ? decoder.readParentInfo() : false 7428 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y` 7429 // and we read the next string as parentYKey. 7430 // It indicates how we store/retrieve parent from `y.share` 7431 // @type {string|null} 7432 const parentYKey = cantCopyParentInfo && hasParentYKey ? decoder.readString() : null 7433 7434 const struct = new Item( 7435 createID(client, clock), 7436 null, // leftd 7437 origin, // origin 7438 null, // right 7439 rightOrigin, // right origin 7440 cantCopyParentInfo && !hasParentYKey ? decoder.readLeftID() : (parentYKey !== null ? doc.get(parentYKey) : null), // parent 7441 cantCopyParentInfo && (info & binary.BIT6) === binary.BIT6 ? decoder.readString() : null, // parentSub 7442 readItemContent(decoder, info) // item content 7443 ) 7444 */ 7445 refs[i] = struct; 7446 clock += struct.length; 7447 } 7448 } 7449 } 7450 // console.log('time to read: ', performance.now() - start) // @todo remove 7451 } 7452 return clientRefs 7453}; 7454 7455/** 7456 * Resume computing structs generated by struct readers. 7457 * 7458 * While there is something to do, we integrate structs in this order
7459 * 1. top element on stack, if stack is not empty 7460 * 2. next element from current struct reader (if empty, use next struct reader) 7461 * 7462 * If struct causally depends on another struct (ref.missing), we put next reader of 7463 * `ref.id.client` on top of stack. 7464 * 7465 * At some point we find a struct that has no causal dependencies, 7466 * then we start emptying the stack. 7467 * 7468 * It is not possible to have circles: i.e. struct1 (from client1) depends on struct2 (from client2) 7469 * depends on struct3 (from client1). Therefore the max stack size is eqaul to `structReaders.length`. 7470 * 7471 * This method is implemented in a way so that we can resume computation if this update 7472 * causally depends on another update. 7473 * 7474 * @param {Transaction} transaction 7475 * @param {StructStore} store 7476 * @param {Map<number, { i: number, refs: (GC | Item)[] }>} clientsStructRefs 7477 * @return { null | { update: Uint8Array, missing: Map<number,number> } } 7478 * 7479 * @private 7480 * @function 7481 */ 7482const integrateStructs = (transaction, store, clientsStructRefs) => { 7483 /** 7484 * @type {Array<Item | GC>} 7485 */ 7486 const stack = []; 7487 // sort them so that we take the higher id first, in case of conflicts the lower id will probably not conflict with the id from the higher user. 7488 let clientsStructRefsIds = array_from(clientsStructRefs.keys()).sort((a, b) => a - b); 7489 if (clientsStructRefsIds.length === 0) { 7490 return null 7491 } 7492 const getNextStructTarget = () => { 7493 if (clientsStructRefsIds.length === 0) { 7494 return null 7495 } 7496 let nextStructsTarget = /** @type {{i:number,refs:Array<GC|Item>}} */ (clientsStructRefs.get(clientsStructRefsIds[clientsStructRefsIds.length - 1])); 7497 while (nextStructsTarget.refs.length === nextStructsTarget.i) { 7498 clientsStructRefsIds.pop(); 7499 if (clientsStructRefsIds.length > 0) { 7500 nextStructsTarget = /** @type {{i:number,refs:Array<GC|Item>}} */ (clientsStructRefs.get(clientsStructRefsIds[clientsStructRefsIds.length - 1])); 7501 } else { 7502 return null 7503 } 7504 } 7505 return nextStructsTarget 7506 }; 7507 let curStructsTarget = getNextStructTarget(); 7508 if (curStructsTarget === null && stack.length === 0) { 7509 return null 7510 } 7511 7512 /** 7513 * @type {StructStore} 7514 */ 7515 const restStructs = new StructStore(); 7516 const missingSV = new Map(); 7517 /** 7518 * @param {number} client 7519 * @param {number} clock 7520 */ 7521 const updateMissingSv = (client, clock) => { 7522 const mclock = missingSV.get(client); 7523 if (mclock == null || mclock > clock) { 7524 missingSV.set(client, clock); 7525 } 7526 }; 7527 /** 7528 * @type {GC|Item} 7529 */ 7530 let stackHead = /** @type {any} */ (curStructsTarget).refs[/** @type {any} */ (curStructsTarget).i++]; 7531 // caching the state because it is used very often 7532 const state = new Map(); 7533 7534 const addStackToRestSS = () => { 7535 for (const item of stack) { 7536 const client = item.id.client; 7537 const unapplicableItems = clientsStructRefs.get(client); 7538 if (unapplicableItems) { 7539 // decrement because we weren't able to apply previous operation 7540 unapplicableItems.i--; 7541 restStructs.clients.set(client, unapplicableItems.refs.slice(unapplicableItems.i)); 7542 clientsStructRefs.delete(client); 7543 unapplicableItems.i = 0; 7544 unapplicableItems.refs = []; 7545 } else { 7546 // item was the last item on clientsStructRefs and the field was already cleared. Add item to restStructs and continue 7547 restStructs.clients.set(client, [item]); 7548 } 7549 // remove client from clientsStructRefsIds to prevent users from applying the same update again 7550 clientsStructRefsIds = clientsStructRefsIds.filter(c => c !== client); 7551 } 7552 stack.length = 0; 7553 }; 7554 7555 // iterate over all struct readers until we are done 7556 while (true) { 7557 if (stackHead.constructor !== Skip) { 7558 const localClock = setIfUndefined(state, stackHead.id.client, () => getState(store, stackHead.id.client)); 7559 const offset = localClock - stackHead.id.clock; 7560 if (offset < 0) { 7561 // update from the same client is missing 7562 stack.push(stackHead); 7563 updateMissingSv(stackHead.id.client, stackHead.id.clock - 1); 7564 // hid a dead wall, add all items from stack to restSS 7565 addStackToRestSS(); 7566 } else { 7567 const missing = stackHead.getMissing(transaction, store); 7568 if (missing !== null) { 7569 stack.push(stackHead); 7570 // get the struct reader that has the missing struct 7571 /** 7572 * @type {{ refs: Array<GC|Item>, i: number }} 7573 */ 7574 const structRefs = clientsStructRefs.get(/** @type {number} */ (missing)) || { refs: [], i: 0 }; 7575 if (structRefs.refs.length === structRefs.i) { 7576 // This update message causally depends on another update message that doesn't exist yet 7577 updateMissingSv(/** @type {number} */ (missing), getState(store, missing)); 7578 addStackToRestSS(); 7579 } else { 7580 stackHead = structRefs.refs[structRefs.i++]; 7581 continue 7582 } 7583 } else if (offset === 0 || offset < stackHead.length) { 7584 // all fine, apply the stackhead 7585 stackHead.integrate(transaction, offset); 7586 state.set(stackHead.id.client, stackHead.id.clock + stackHead.length); 7587 } 7588 } 7589 } 7590 // iterate to next stackHead 7591 if (stack.length > 0) { 7592 stackHead = /** @type {GC|Item} */ (stack.pop()); 7593 } else if (curStructsTarget !== null && curStructsTarget.i < curStructsTarget.refs.length) { 7594 stackHead = /** @type {GC|Item} */ (curStructsTarget.refs[curStructsTarget.i++]); 7595 } else { 7596 curStructsTarget = getNextStructTarget(); 7597 if (curStructsTarget === null) { 7598 // we are done! 7599 break 7600 } else { 7601 stackHead = /** @type {GC|Item} */ (curStructsTarget.refs[curStructsTarget.i++]); 7602 } 7603 } 7604 } 7605 if (restStructs.clients.size > 0) { 7606 const encoder = new UpdateEncoderV2(); 7607 writeClientsStructs(encoder, restStructs, new Map()); 7608 // write empty deleteset 7609 // writeDeleteSet(encoder, new DeleteSet()) 7610 writeVarUint(encoder.restEncoder, 0); // => no need for an extra function call, just write 0 deletes 7611 return { missing: missingSV, update: encoder.toUint8Array() } 7612 } 7613 return null 7614}; 7615 7616/** 7617 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 7618 * @param {Transaction} transaction 7619 * 7620 * @private 7621 * @function 7622 */ 7623const writeStructsFromTransaction = (encoder, transaction) => writeClientsStructs(encoder, transaction.doc.store, transaction.beforeState); 7624 7625/** 7626 * Read and apply a document update. 7627 * 7628 * This function has the same effect as `applyUpdate` but accepts an decoder. 7629 * 7630 * @param {decoding.Decoder} decoder 7631 * @param {Doc} ydoc 7632 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))` 7633 * @param {UpdateDecoderV1 | UpdateDecoderV2} [structDecoder] 7634 * 7635 * @function 7636 */ 7637const readUpdateV2 = (decoder, ydoc, transactionOrigin, structDecoder = new UpdateDecoderV2(decoder)) => 7638 transact(ydoc, transaction => { 7639 // force that transaction.local is set to non-local 7640 transaction.local = false;
7641 let retry = false; 7642 const doc = transaction.doc; 7643 const store = doc.store; 7644 // let start = performance.now() 7645 const ss = readClientsStructRefs(structDecoder, doc); 7646 // console.log('time to read structs: ', performance.now() - start) // @todo remove 7647 // start = performance.now() 7648 // console.log('time to merge: ', performance.now() - start) // @todo remove 7649 // start = performance.now() 7650 const restStructs = integrateStructs(transaction, store, ss); 7651 const pending = store.pendingStructs; 7652 if (pending) { 7653 // check if we can apply something 7654 for (const [client, clock] of pending.missing) { 7655 if (clock < getState(store, client)) { 7656 retry = true; 7657 break 7658 } 7659 } 7660 if (restStructs) { 7661 // merge restStructs into store.pending 7662 for (const [client, clock] of restStructs.missing) { 7663 const mclock = pending.missing.get(client); 7664 if (mclock == null || mclock > clock) { 7665 pending.missing.set(client, clock); 7666 } 7667 } 7668 pending.update = mergeUpdatesV2([pending.update, restStructs.update]); 7669 } 7670 } else { 7671 store.pendingStructs = restStructs; 7672 } 7673 // console.log('time to integrate: ', performance.now() - start) // @todo remove 7674 // start = performance.now() 7675 const dsRest = readAndApplyDeleteSet(structDecoder, transaction, store); 7676 if (store.pendingDs) { 7677 // @todo we could make a lower-bound state-vector check as we do above 7678 const pendingDSUpdate = new UpdateDecoderV2(createDecoder(store.pendingDs)); 7679 readVarUint(pendingDSUpdate.restDecoder); // read 0 structs, because we only encode deletes in pendingdsupdate 7680 const dsRest2 = readAndApplyDeleteSet(pendingDSUpdate, transaction, store); 7681 if (dsRest && dsRest2) { 7682 // case 1: ds1 != null && ds2 != null 7683 store.pendingDs = mergeUpdatesV2([dsRest, dsRest2]); 7684 } else { 7685 // case 2: ds1 != null 7686 // case 3: ds2 != null 7687 // case 4: ds1 == null && ds2 == null 7688 store.pendingDs = dsRest || dsRest2; 7689 } 7690 } else { 7691 // Either dsRest == null && pendingDs == null OR dsRest != null 7692 store.pendingDs = dsRest; 7693 } 7694 // console.log('time to cleanup: ', performance.now() - start) // @todo remove 7695 // start = performance.now() 7696 7697 // console.log('time to resume delete readers: ', performance.now() - start) // @todo remove 7698 // start = performance.now() 7699 if (retry) { 7700 const update = /** @type {{update: Uint8Array}} */ (store.pendingStructs).update; 7701 store.pendingStructs = null; 7702 applyUpdateV2(transaction.doc, update); 7703 } 7704 }, transactionOrigin, false); 7705 7706/** 7707 * Read and apply a document update. 7708 * 7709 * This function has the same effect as `applyUpdate` but accepts an decoder. 7710 * 7711 * @param {decoding.Decoder} decoder 7712 * @param {Doc} ydoc 7713 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))` 7714 * 7715 * @function 7716 */ 7717const readUpdate = (decoder, ydoc, transactionOrigin) =>
7717 readUpdateV2(decoder, ydoc, transactionOrigin, new UpdateDecoderV1(decoder)); 7718 7719/** 7720 * Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`. 7721 * 7722 * This function has the same effect as `readUpdate` but accepts an Uint8Array instead of a Decoder. 7723 * 7724 * @param {Doc} ydoc 7725 * @param {Uint8Array} update 7726 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))` 7727 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder] 7728 * 7729 * @function 7730 */ 7731const applyUpdateV2 = (ydoc, update, transactionOrigin, YDecoder = UpdateDecoderV2) => { 7732 const decoder = createDecoder(update); 7733 readUpdateV2(decoder, ydoc, transactionOrigin, new YDecoder(decoder)); 7734}; 7735 7736/** 7737 * Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`. 7738 * 7739 * This function has the same effect as `readUpdate` but accepts an Uint8Array instead of a Decoder. 7740 * 7741 * @param {Doc} ydoc 7742 * @param {Uint8Array} update 7743 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))` 7744 * 7745 * @function 7746 */ 7747const applyUpdate = (ydoc, update, transactionOrigin) => applyUpdateV2(ydoc, update, transactionOrigin, UpdateDecoderV1); 7748 7749/** 7750 * Write all the document as a single update message. If you specify the state of the remote client (`targetStateVector`) it will 7751 * only write the operations that are missing. 7752 * 7753 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 7754 * @param {Doc} doc 7755 * @param {Map<number,number>} [targetStateVector] The state of the target that receives the update. Leave empty to write all known structs 7756 * 7757 * @function 7758 */ 7759const writeStateAsUpdate = (encoder, doc, targetStateVector = new Map()) => { 7760 writeClientsStructs(encoder, doc.store, targetStateVector); 7761 writeDeleteSet(encoder, createDeleteSetFromStructStore(doc.store)); 7762}; 7763 7764/** 7765 * Write all the document as a single update message that can be applied on the remote document. If you specify the state of the remote client (`targetState`) it will 7766 * only write the operations that are missing. 7767 * 7768 * Use `writeStateAsUpdate` instead if you are working with lib0/encoding.js#Encoder 7769 * 7770 * @param {Doc} doc 7771 * @param {Uint8Array} [encodedTargetStateVector] The state of the target that receives the update. Leave empty to write all known structs 7772 * @param {UpdateEncoderV1 | UpdateEncoderV2} [encoder] 7773 * @return {Uint8Array} 7774 * 7775 * @function 7776 */ 7777const encodeStateAsUpdateV2 = (doc, encodedTargetStateVector = new Uint8Array([0]), encoder = new UpdateEncoderV2()) => { 7778 const targetStateVector = decodeStateVector(encodedTargetStateVector); 7779 writeStateAsUpdate(encoder, doc, targetStateVector); 7780 const updates = [encoder.toUint8Array()]; 7781 // also add the pending updates (if there are any) 7782 if (doc.store.pendingDs) { 7783 updates.push(doc.store.pendingDs); 7784 } 7785 if (doc.store.pendingStructs) { 7786 updates.push(diffUpdateV2(doc.store.pendingStructs.update, encodedTargetStateVector)); 7787 } 7788 if (updates.length > 1) { 7789 if (encoder.constructor === UpdateEncoderV1) { 7790 return mergeUpdates(updates.map((update, i) => i === 0 ? update : convertUpdateFormatV2ToV1(update))) 7791 } else if (encoder.constructor === UpdateEncoderV2) { 7792 return mergeUpdatesV2(updates) 7793 } 7794 } 7795 return updates[0] 7796}; 7797 7798/** 7799 * Write all the document as a single update message that can be applied on the remote document. If you specify the state of the remote client (`targetState`) it will 7800 * only write the operations that are missing. 7801 * 7802 * Use `writeStateAsUpdate` instead if you are working with lib0/encoding.js#Encoder 7803 * 7804 * @param {Doc} doc 7805 * @param {Uint8Array} [encodedTargetStateVector] The state of the target that receives the update. Leave empty to write all known structs 7806 * @return {Uint8Array} 7807 * 7808 * @function 7809 */ 7810const encodeStateAsUpdate = (doc, encodedTargetStateVector) => encodeStateAsUpdateV2(doc, encodedTargetStateVector, new UpdateEncoderV1()); 7811 7812/** 7813 * Read state vector from Decoder and return as Map 7814 * 7815 * @param {DSDecoderV1 | DSDecoderV2} decoder 7816 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client. 7817 * 7818 * @function 7819 */ 7820const readStateVector = decoder => { 7821 const ss = new Map(); 7822 const ssLength = readVarUint(decoder.restDecoder); 7823 for (let i = 0; i < ssLength; i++) { 7824 const client = readVarUint(decoder.restDecoder); 7825 const clock = readVarUint(decoder.restDecoder); 7826 ss.set(client, clock); 7827 } 7828 return ss 7829}; 7830 7831/** 7832 * Read decodedState and return State as Map. 7833 * 7834 * @param {Uint8Array} decodedState 7835 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client. 7836 * 7837 * @function 7838 */
7839// export const decodeStateVectorV2 = decodedState => readStateVector(new DSDecoderV2(decoding.createDecoder(decodedState))) 7840 7841/** 7842 * Read decodedState and return State as Map. 7843 * 7844 * @param {Uint8Array} decodedState 7845 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client. 7846 * 7847 * @function 7848 */ 7849const decodeStateVector = decodedState => readStateVector(new DSDecoderV1(createDecoder(decodedState))); 7850 7851/** 7852 * @param {DSEncoderV1 | DSEncoderV2} encoder 7853 * @param {Map<number,number>} sv 7854 * @function 7855 */ 7856const writeStateVector = (encoder, sv) => { 7857 writeVarUint(encoder.restEncoder, sv.size); 7858 array_from(sv.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => { 7859 writeVarUint(encoder.restEncoder, client); // @todo use a special client decoder that is based on mapping 7860 writeVarUint(encoder.restEncoder, clock); 7861 }); 7862 return encoder 7863}; 7864 7865/** 7866 * @param {DSEncoderV1 | DSEncoderV2} encoder 7867 * @param {Doc} doc 7868 * 7869 * @function 7870 */ 7871const writeDocumentStateVector = (encoder, doc) => writeStateVector(encoder, getStateVector(doc.store)); 7872 7873/** 7874 * Encode State as Uint8Array. 7875 * 7876 * @param {Doc|Map<number,number>} doc 7877 * @param {DSEncoderV1 | DSEncoderV2} [encoder] 7878 * @return {Uint8Array} 7879 * 7880 * @function 7881 */ 7882const encodeStateVectorV2 = (doc, encoder = new DSEncoderV2()) => { 7883 if (doc instanceof Map) { 7884 writeStateVector(encoder, doc); 7885 } else { 7886 writeDocumentStateVector(encoder, doc); 7887 } 7888 return encoder.toUint8Array() 7889}; 7890 7891/** 7892 * Encode State as Uint8Array. 7893 * 7894 * @param {Doc|Map<number,number>} doc 7895 * @return {Uint8Array} 7896 * 7897 * @function 7898 */ 7899const encodeStateVector = doc => encodeStateVectorV2(doc, new DSEncoderV1()); 7900 7901/** 7902 * General event handler implementation. 7903 * 7904 * @template ARG0, ARG1 7905 * 7906 * @private 7907 */ 7908class EventHandler { 7909 constructor () { 7910 /** 7911 * @type {Array<function(ARG0, ARG1):void>} 7912 */ 7913 this.l = []; 7914 } 7915} 7916 7917/** 7918 * @template ARG0,ARG1 7919 * @returns {EventHandler<ARG0,ARG1>} 7920 * 7921 * @private 7922 * @function 7923 */ 7924const createEventHandler = () => new EventHandler(); 7925 7926/** 7927 * Adds an event listener that is called when 7928 * {@link EventHandler#callEventListeners} is called. 7929 * 7930 * @template ARG0,ARG1 7931 * @param {EventHandler<ARG0,ARG1>} eventHandler 7932 * @param {function(ARG0,ARG1):void} f The event handler. 7933 * 7934 * @private 7935 * @function 7936 */ 7937const addEventHandlerListener = (eventHandler, f) => 7938 eventHandler.l.push(f); 7939 7940/** 7941 * Removes an event listener. 7942 * 7943 * @template ARG0,ARG1 7944 * @param {EventHandler<ARG0,ARG1>} eventHandler 7945 * @param {function(ARG0,ARG1):void} f The event handler that was added with 7946 * {@link EventHandler#addEventListener} 7947 * 7948 * @private 7949 * @function 7950 */ 7951const removeEventHandlerListener = (eventHandler, f) => { 7952 const l = eventHandler.l; 7953 const len = l.length; 7954 eventHandler.l = l.filter(g => f !== g); 7955 if (len === eventHandler.l.length) { 7956 console.error('[yjs] Tried to remove event handler that doesn\'t exist.'); 7957 } 7958}; 7959 7960/** 7961 * Call all event listeners that were added via 7962 * {@link EventHandler#addEventListener}. 7963 * 7964 * @template ARG0,ARG1 7965 * @param {EventHandler<ARG0,ARG1>} eventHandler 7966 * @param {ARG0} arg0 7967 * @param {ARG1} arg1 7968 * 7969 * @private 7970 * @function 7971 */ 7972const callEventHandlerListeners = (eventHandler, arg0, arg1) => 7973 callAll(eventHandler.l, [arg0, arg1]); 7974 7975class ID { 7976 /** 7977 * @param {number} client client id 7978 * @param {number} clock unique per client id, continuous number 7979 */ 7980 constructor (client, clock) { 7981 /** 7982 * Client id 7983 * @type {number} 7984 */ 7985 this.client = client; 7986 /** 7987 * unique per client id, continuous number 7988 * @type {number} 7989 */ 7990 this.clock = clock; 7991 } 7992} 7993 7994/** 7995 * @param {ID | null} a 7996 * @param {ID | null} b 7997 * @return {boolean} 7998 * 7999 * @function 8000 */ 8001const compareIDs = (a, b) => a === b || (a !== null && b !== null && a.client === b.client && a.clock === b.clock); 8002 8003/** 8004 * @param {number} client 8005 * @param {number} clock 8006 * 8007 * @private 8008 * @function 8009 */ 8010const createID = (client, clock) => new ID(client, clock); 8011 8012/** 8013 * @param {encoding.Encoder} encoder 8014 * @param {ID} id 8015 * 8016 * @private 8017 * @function 8018 */ 8019const writeID = (encoder, id) => { 8020 encoding.writeVarUint(encoder, id.client); 8021 encoding.writeVarUint(encoder, id.clock); 8022}; 8023 8024/** 8025 * Read ID. 8026 * * If first varUint read is 0xFFFFFF a RootID is returned. 8027 * * Otherwise an ID is returned 8028 * 8029 * @param {decoding.Decoder} decoder 8030 * @return {ID} 8031 * 8032 * @private 8033 * @function 8034 */ 8035const readID = decoder => 8036 createID(decoding.readVarUint(decoder), decoding.readVarUint(decoder)); 8037 8038/** 8039 * The top types are mapped from y.share.get(keyname) => type. 8040 * `type` does not store any information about the `keyname`. 8041 * This function finds the correct `keyname` for `type` and throws otherwise. 8042 * 8043 * @param {AbstractType<any>} type 8044 * @return {string} 8045 * 8046 * @private 8047 * @function 8048 */ 8049const findRootTypeKey = type => { 8050 // @ts-ignore _y must be defined, otherwise unexpected case 8051 for (const [key, value] of type.doc.share.entries()) { 8052 if (value === type) { 8053 return key 8054 } 8055 } 8056 throw unexpectedCase() 8057}; 8058 8059/** 8060 * Check if `parent` is a parent of `child`. 8061 * 8062 * @param {AbstractType<any>} parent 8063 * @param {Item|null} child 8064 * @return {Boolean} Whether `parent` is a parent of `child`. 8065 * 8066 * @private 8067 * @function 8068 */ 8069const yjs_isParentOf = (parent, child) => { 8070 while (child !== null) { 8071 if (child.parent === parent) { 8072 return true 8073 } 8074 child = /** @type {AbstractType<any>} */ (child.parent)._item; 8075 } 8076 return false 8077}; 8078 8079/** 8080 * Convenient helper to log type information. 8081 * 8082 * Do not use in productive systems as the output can be immense! 8083 * 8084 * @param {AbstractType<any>} type 8085 */ 8086const logType = type => { 8087 const res = []; 8088 let n = type._start; 8089 while (n) { 8090 res.push(n); 8091 n = n.right; 8092 } 8093 console.log('Children: ', res); 8094 console.log('Children content: ', res.filter(m => !m.deleted).map(m => m.content)); 8095}; 8096 8097class PermanentUserData { 8098 /** 8099 * @param {Doc} doc 8100 * @param {YMap<any>} [storeType] 8101 */ 8102 constructor (doc, storeType = doc.getMap('users')) { 8103 /** 8104 * @type {Map<string,DeleteSet>} 8105 */ 8106 const dss = new Map(); 8107 this.yusers = storeType; 8108 this.doc = doc; 8109 /** 8110 * Maps from clientid to userDescription 8111 * 8112 * @type {Map<number,string>} 8113 */ 8114 this.clients = new Map(); 8115 this.dss = dss; 8116 /** 8117 * @param {YMap<any>} user 8118 * @param {string} userDescription 8119 */ 8120 const initUser = (user, userDescription) => { 8121 /** 8122 * @type {YArray<Uint8Array>} 8123 */ 8124 const ds = user.get('ds'); 8125 const ids = user.get('ids'); 8126 const addClientId = /** @param {number} clientid */ clientid => this.clients.set(clientid, userDescription); 8127 ds.observe(/** @param {YArrayEvent<any>} event */ event => { 8128 event.changes.added.forEach(item => {
8129 item.content.getContent().forEach(encodedDs => { 8130 if (encodedDs instanceof Uint8Array) { 8131 this.dss.set(userDescription, mergeDeleteSets([this.dss.get(userDescription) || createDeleteSet(), readDeleteSet(new DSDecoderV1(decoding.createDecoder(encodedDs)))])); 8132 } 8133 }); 8134 }); 8135 }); 8136 this.dss.set(userDescription, mergeDeleteSets(ds.map(encodedDs => readDeleteSet(new DSDecoderV1(decoding.createDecoder(encodedDs)))))); 8137 ids.observe(/** @param {YArrayEvent<any>} event */ event => 8138 event.changes.added.forEach(item => item.content.getContent().forEach(addClientId)) 8139 ); 8140 ids.forEach(addClientId); 8141 }; 8142 // observe users 8143 storeType.observe(event => { 8144 event.keysChanged.forEach(userDescription => 8145 initUser(storeType.get(userDescription), userDescription) 8146 ); 8147 }); 8148 // add intial data 8149 storeType.forEach(initUser); 8150 } 8151 8152 /** 8153 * @param {Doc} doc 8154 * @param {number} clientid 8155 * @param {string} userDescription 8156 * @param {Object} conf 8157 * @param {function(Transaction, DeleteSet):boolean} [conf.filter] 8158 */ 8159 setUserMapping (doc, clientid, userDescription, { filter = () => true } = {}) { 8160 const users = this.yusers; 8161 let user = users.get(userDescription); 8162 if (!user) { 8163 user = new YMap(); 8164 user.set('ids', new YArray()); 8165 user.set('ds', new YArray()); 8166 users.set(userDescription, user); 8167 } 8168 user.get('ids').push([clientid]); 8169 users.observe(_event => { 8170 setTimeout(() => { 8171 const userOverwrite = users.get(userDescription); 8172 if (userOverwrite !== user) { 8173 // user was overwritten, port all data over to the next user object 8174 // @todo Experiment with Y.Sets here 8175 user = userOverwrite; 8176 // @todo iterate over old type 8177 this.clients.forEach((_userDescription, clientid) => { 8178 if (userDescription === _userDescription) { 8179 user.get('ids').push([clientid]); 8180 } 8181 }); 8182 const encoder = new DSEncoderV1(); 8183 const ds = this.dss.get(userDescription); 8184 if (ds) { 8185 writeDeleteSet(encoder, ds); 8186 user.get('ds').push([encoder.toUint8Array()]); 8187 } 8188 } 8189 }, 0); 8190 }); 8191 doc.on('afterTransaction', /** @param {Transaction} transaction */ transaction => { 8192 setTimeout(() => { 8193 const yds = user.get('ds'); 8194 const ds = transaction.deleteSet; 8195 if (transaction.local && ds.clients.size > 0 && filter(transaction, ds)) { 8196 const encoder = new DSEncoderV1(); 8197 writeDeleteSet(encoder, ds); 8198 yds.push([encoder.toUint8Array()]); 8199 } 8200 }); 8201 }); 8202 } 8203 8204 /** 8205 * @param {number} clientid 8206 * @return {any} 8207 */ 8208 getUserByClientId (clientid) { 8209 return this.clients.get(clientid) || null 8210 } 8211 8212 /** 8213 * @param {ID} id 8214 * @return {string | null} 8215 */ 8216 getUserByDeletedId (id) { 8217 for (const [userDescription, ds] of this.dss.entries()) { 8218 if (isDeleted(ds, id)) { 8219 return userDescription 8220 } 8221 } 8222 return null 8223 } 8224} 8225 8226/** 8227 * A relative position is based on the Yjs model and is not affected by document changes. 8228 * E.g. If you place a relative position before a certain character, it will always point to this character. 8229 * If you place a relative position at the end of a type, it will always point to the end of the type. 8230 * 8231 * A numeric position is often unsuited for user selections, because it does not change when content is inserted 8232 * before or after. 8233 * 8234 * ```Insert(0, 'x')('a|bc') = 'xa|bc'``` Where | is the relative position. 8235 * 8236 * One of the properties must be defined. 8237 * 8238 * @example 8239 * // Current cursor position is at position 10 8240 * const relativePosition = createRelativePositionFromIndex(yText, 10) 8241 * // modify yText 8242 * yText.insert(0, 'abc') 8243 * yText.delete(3, 10) 8244 * // Compute the cursor position 8245 * const absolutePosition = createAbsolutePositionFromRelativePosition(y, relativePosition) 8246 * absolutePosition.type === yText // => true 8247 * console.log('cursor location is ' + absolutePosition.index) // => cursor location is 3 8248 * 8249 */ 8250class RelativePosition { 8251 /** 8252 * @param {ID|null} type 8253 * @param {string|null} tname 8254 * @param {ID|null} item 8255 * @param {number} assoc 8256 */ 8257 constructor (type, tname, item, assoc = 0) { 8258 /** 8259 * @type {ID|null} 8260 */ 8261 this.type = type; 8262 /** 8263 * @type {string|null} 8264 */ 8265 this.tname = tname; 8266 /** 8267 * @type {ID | null} 8268 */ 8269 this.item = item; 8270 /** 8271 * A relative position is associated to a specific character. By default 8272 * assoc >= 0, the relative position is associated to the character 8273 * after the meant position. 8274 * I.e. position 1 in 'ab' is associated to character 'b'. 8275 * 8276 * If assoc < 0, then the relative position is associated to the caharacter 8277 * before the meant position. 8278 * 8279 * @type {number} 8280 */ 8281 this.assoc = assoc; 8282 } 8283} 8284 8285/** 8286 * @param {RelativePosition} rpos 8287 * @return {any} 8288 */ 8289const relativePositionToJSON = rpos => { 8290 const json = {}; 8291 if (rpos.type) { 8292 json.type = rpos.type; 8293 } 8294 if (rpos.tname) { 8295 json.tname = rpos.tname; 8296 } 8297 if (rpos.item) { 8298 json.item = rpos.item; 8299 } 8300 if (rpos.assoc != null) { 8301 json.assoc = rpos.assoc; 8302 } 8303 return json 8304}; 8305 8306/** 8307 * @param {any} json 8308 * @return {RelativePosition} 8309 * 8310 * @function 8311 */ 8312const createRelativePositionFromJSON = json => new RelativePosition(json.type == null ? null : createID(json.type.client, json.type.clock), json.tname || null, json.item == null ? null : createID(json.item.client, json.item.clock), json.assoc == null ? 0 : json.assoc); 8313 8314class AbsolutePosition { 8315 /** 8316 * @param {AbstractType<any>} type 8317 * @param {number} index 8318 * @param {number} [assoc] 8319 */ 8320 constructor (type, index, assoc = 0) { 8321 /** 8322 * @type {AbstractType<any>} 8323 */ 8324 this.type = type; 8325 /** 8326 * @type {number} 8327 */ 8328 this.index = index; 8329 this.assoc = assoc; 8330 } 8331} 8332 8333/** 8334 * @param {AbstractType<any>} type 8335 * @param {number} index 8336 * @param {number} [assoc] 8337 * 8338 * @function 8339 */ 8340const createAbsolutePosition = (type, index, assoc = 0) => new AbsolutePosition(type, index, assoc); 8341 8342/** 8343 * @param {AbstractType<any>} type 8344 * @param {ID|null} item 8345 * @param {number} [assoc] 8346 * 8347 * @function 8348 */ 8349const createRelativePosition = (type, item, assoc) => { 8350 let typeid = null; 8351 let tname = null; 8352 if (type._item === null) { 8353 tname = findRootTypeKey(type); 8354 } else { 8355 typeid = createID(type._item.id.client, type._item.id.clock); 8356 } 8357 return new RelativePosition(typeid, tname, item, assoc) 8358}; 8359 8360/** 8361 * Create a relativePosition based on a absolute position. 8362 * 8363 * @param {AbstractType<any>} type The base type (e.g. YText or YArray). 8364 * @param {number} index The absolute position. 8365 * @param {number} [assoc] 8366 * @return {RelativePosition} 8367 * 8368 * @function 8369 */ 8370const createRelativePositionFromTypeIndex = (type, index, assoc = 0) => { 8371 let t = type._start; 8372 if (assoc < 0) { 8373 // associated to the left character or the beginning of a type, increment index if possible. 8374 if (index === 0) { 8375 return createRelativePosition(type, null, assoc) 8376 } 8377 index--; 8378 } 8379 while (t !== null) { 8380 if (!t.deleted && t.countable) { 8381 if (t.length > index) { 8382 // case 1: found position somewhere in the linked list 8383 return createRelativePosition(type, createID(t.id.client, t.id.clock + index), assoc) 8384 } 8385 index -= t.length; 8386 } 8387 if (t.right === null && assoc < 0) { 8388 // left-associated position, return last available id 8389 return createRelativePosition(type, t.lastId, assoc) 8390 } 8391 t = t.right; 8392 } 8393 return createRelativePosition(type, null, assoc) 8394}; 8395 8396/** 8397 * @param {encoding.Encoder} encoder 8398 * @param {RelativePosition} rpos 8399 * 8400 * @function 8401 */ 8402const writeRelativePosition = (encoder, rpos) => { 8403 const { type, tname, item, assoc } = rpos; 8404 if (item !== null) { 8405 encoding.writeVarUint(encoder, 0); 8406 writeID(encoder, item); 8407 } else if (tname !== null) { 8408 // case 2: found position at the end of the list and type is stored in y.share 8409 encoding.writeUint8(encoder, 1); 8410 encoding.writeVarString(encoder, tname); 8411 } else if (type !== null) { 8412 // case 3: found position at the end of the list and type is attached to an item 8413 encoding.writeUint8(encoder, 2); 8414 writeID(encoder, type); 8415 } else { 8416 throw error.unexpectedCase() 8417 } 8418 encoding.writeVarInt(encoder, assoc); 8419 return encoder 8420}; 8421 8422/** 8423 * @param {RelativePosition} rpos 8424 * @return {Uint8Array} 8425 */ 8426const encodeRelativePosition = rpos => { 8427 const encoder = encoding.createEncoder(); 8428 writeRelativePosition(encoder, rpos); 8429 return encoding.toUint8Array(encoder) 8430}; 8431 8432/** 8433 * @param {decoding.Decoder} decoder 8434 * @return {RelativePosition} 8435 * 8436 * @function 8437 */ 8438const readRelativePosition = decoder => { 8439 let type = null; 8440 let tname = null; 8441 let itemID = null; 8442 switch (decoding.readVarUint(decoder)) { 8443 case 0: 8444 // case 1: found position somewhere in the linked list 8445 itemID = readID(decoder); 8446 break 8447 case 1: 8448 // case 2: found position at the end of the list and type is stored in y.share 8449 tname = decoding.readVarString(decoder); 8450 break 8451 case 2: { 8452 // case 3: found position at the end of the list and type is attached to an item 8453 type = readID(decoder); 8454 } 8455 } 8456 const assoc = decoding.hasContent(decoder) ? decoding.readVarInt(decoder) : 0; 8457 return new RelativePosition(type, tname, itemID, assoc) 8458}; 8459 8460/** 8461 * @param {Uint8Array} uint8Array 8462 * @return {RelativePosition} 8463 */ 8464const decodeRelativePosition = uint8Array => readRelativePosition(decoding.createDecoder(uint8Array)); 8465 8466/** 8467 * @param {RelativePosition} rpos 8468 * @param {Doc} doc 8469 * @return {AbsolutePosition|null} 8470 * 8471 * @function 8472 */ 8473const createAbsolutePositionFromRelativePosition = (rpos, doc) => { 8474 const store = doc.store; 8475 const rightID = rpos.item; 8476 const typeID = rpos.type; 8477 const tname = rpos.tname; 8478 const assoc = rpos.assoc; 8479 let type = null; 8480 let index = 0; 8481 if (rightID !== null) { 8482 if (getState(store, rightID.client) <= rightID.clock) { 8483 return null 8484 } 8485 const res = followRedone(store, rightID); 8486 const right = res.item; 8487 if (!(right instanceof Item)) { 8488 return null 8489 } 8490 type = /** @type {AbstractType<any>} */ (right.parent); 8491 if (type._item === null || !type._item.deleted) { 8492 index = (right.deleted || !right.countable) ? 0 : (res.diff + (assoc >= 0 ? 0 : 1)); // adjust position based on left association if necessary 8493 let n = right.left; 8494 while (n !== null) { 8495 if (!n.deleted && n.countable) { 8496 index += n.length; 8497 } 8498 n = n.left; 8499 } 8500 } 8501 } else { 8502 if (tname !== null) { 8503 type = doc.get(tname); 8504 } else if (typeID !== null) { 8505 if (getState(store, typeID.client) <= typeID.clock) { 8506 // type does not exist yet 8507 return null 8508 } 8509 const { item } = followRedone(store, typeID); 8510 if (item instanceof Item && item.content instanceof ContentType) { 8511 type = item.content.type; 8512 } else { 8513 // struct is garbage collected 8514 return null 8515 } 8516 } else { 8517 throw error.unexpectedCase() 8518 } 8519 if (assoc >= 0) { 8520 index = type._length; 8521 } else { 8522 index = 0; 8523 } 8524 } 8525 return createAbsolutePosition(type, index, rpos.assoc) 8526}; 8527 8528/** 8529 * @param {RelativePosition|null} a 8530 * @param {RelativePosition|null} b 8531 * @return {boolean} 8532 * 8533 * @function 8534 */ 8535const compareRelativePositions = (a, b) => a === b || ( 8536 a !== null && b !== null && a.tname === b.tname && compareIDs(a.item, b.item) && compareIDs(a.type, b.type) && a.assoc === b.assoc 8537); 8538 8539class Snapshot { 8540 /** 8541 * @param {DeleteSet} ds 8542 * @param {Map<number,number>} sv state map 8543 */ 8544 constructor (ds, sv) { 8545 /** 8546 * @type {DeleteSet} 8547 */ 8548 this.ds = ds; 8549 /** 8550 * State Map 8551 * @type {Map<number,number>} 8552 */ 8553 this.sv = sv; 8554 } 8555} 8556 8557/** 8558 * @param {Snapshot} snap1 8559 * @param {Snapshot} snap2 8560 * @return {boolean} 8561 */ 8562const equalSnapshots = (snap1, snap2) => { 8563 const ds1 = snap1.ds.clients; 8564 const ds2 = snap2.ds.clients; 8565 const sv1 = snap1.sv; 8566 const sv2 = snap2.sv; 8567 if (sv1.size !== sv2.size || ds1.size !== ds2.size) { 8568 return false 8569 } 8570 for (const [key, value] of sv1.entries()) { 8571 if (sv2.get(key) !== value) { 8572 return false 8573 } 8574 } 8575 for (const [client, dsitems1] of ds1.entries()) { 8576 const dsitems2 = ds2.get(client) || []; 8577 if (dsitems1.length !== dsitems2.length) { 8578 return false 8579 } 8580 for (let i = 0; i < dsitems1.length; i++) { 8581 const dsitem1 = dsitems1[i]; 8582 const dsitem2 = dsitems2[i]; 8583 if (dsitem1.clock !== dsitem2.clock || dsitem1.len !== dsitem2.len) { 8584 return false 8585 } 8586 } 8587 } 8588 return true 8589}; 8590 8591/** 8592 * @param {Snapshot} snapshot 8593 * @param {DSEncoderV1 | DSEncoderV2} [encoder] 8594 * @return {Uint8Array} 8595 */
8596const encodeSnapshotV2 = (snapshot, encoder = new DSEncoderV2()) => { 8597 writeDeleteSet(encoder, snapshot.ds); 8598 writeStateVector(encoder, snapshot.sv); 8599 return encoder.toUint8Array() 8600}; 8601 8602/** 8603 * @param {Snapshot} snapshot 8604 * @return {Uint8Array} 8605 */ 8606const encodeSnapshot = snapshot => encodeSnapshotV2(snapshot, new DSEncoderV1()); 8607 8608/** 8609 * @param {Uint8Array} buf 8610 * @param {DSDecoderV1 | DSDecoderV2} [decoder] 8611 * @return {Snapshot} 8612 */ 8613const decodeSnapshotV2 = (buf, decoder = new DSDecoderV2(decoding.createDecoder(buf))) => { 8614 return new Snapshot(readDeleteSet(decoder), readStateVector(decoder)) 8615}; 8616 8617/** 8618 * @param {Uint8Array} buf 8619 * @return {Snapshot} 8620 */ 8621const decodeSnapshot = buf => decodeSnapshotV2(buf, new DSDecoderV1(decoding.createDecoder(buf))); 8622 8623/** 8624 * @param {DeleteSet} ds 8625 * @param {Map<number,number>} sm 8626 * @return {Snapshot} 8627 */ 8628const createSnapshot = (ds, sm) => new Snapshot(ds, sm); 8629 8630const emptySnapshot = createSnapshot(createDeleteSet(), new Map()); 8631 8632/** 8633 * @param {Doc} doc 8634 * @return {Snapshot} 8635 */ 8636const snapshot = doc => createSnapshot(createDeleteSetFromStructStore(doc.store), getStateVector(doc.store)); 8637 8638/** 8639 * @param {Item} item 8640 * @param {Snapshot|undefined} snapshot 8641 * 8642 * @protected 8643 * @function 8644 */ 8645const isVisible = (item, snapshot) => snapshot === undefined 8646 ? !item.deleted 8647 : snapshot.sv.has(item.id.client) && (snapshot.sv.get(item.id.client) || 0) > item.id.clock && !isDeleted(snapshot.ds, item.id); 8648 8649/** 8650 * @param {Transaction} transaction 8651 * @param {Snapshot} snapshot 8652 */ 8653const splitSnapshotAffectedStructs = (transaction, snapshot) => { 8654 const meta = setIfUndefined(transaction.meta, splitSnapshotAffectedStructs, set_create); 8655 const store = transaction.doc.store; 8656 // check if we already split for this snapshot 8657 if (!meta.has(snapshot)) { 8658 snapshot.sv.forEach((clock, client) => { 8659 if (clock < getState(store, client)) { 8660 getItemCleanStart(transaction, createID(client, clock)); 8661 } 8662 }); 8663 iterateDeletedStructs(transaction, snapshot.ds, _item => {}); 8664 meta.add(snapshot); 8665 } 8666}; 8667 8668/** 8669 * @example 8670 * const ydoc = new Y.Doc({ gc: false }) 8671 * ydoc.getText().insert(0, 'world!') 8672 * const snapshot = Y.snapshot(ydoc) 8673 * ydoc.getText().insert(0, 'hello ') 8674 * const restored = Y.createDocFromSnapshot(ydoc, snapshot) 8675 * assert(restored.getText().toString() === 'world!') 8676 * 8677 * @param {Doc} originDoc 8678 * @param {Snapshot} snapshot 8679 * @param {Doc} [newDoc] Optionally, you may define the Yjs document that receives the data from originDoc 8680 * @return {Doc} 8681 */ 8682const createDocFromSnapshot = (originDoc, snapshot, newDoc = new Doc()) => { 8683 if (originDoc.gc) { 8684 // we should not try to restore a GC-ed document, because some of the restored items might have their content deleted 8685 throw new Error('Garbage-collection must be disabled in `originDoc`!') 8686 } 8687 const { sv, ds } = snapshot; 8688 8689 const encoder = new UpdateEncoderV2(); 8690 originDoc.transact(transaction => { 8691 let size = 0; 8692 sv.forEach(clock => { 8693 if (clock > 0) { 8694 size++; 8695 } 8696 }); 8697 encoding.writeVarUint(encoder.restEncoder, size); 8698 // splitting the structs before writing them to the encoder 8699 for (const [client, clock] of sv) { 8700 if (clock === 0) { 8701 continue 8702 } 8703 if (clock < getState(originDoc.store, client)) { 8704 getItemCleanStart(transaction, createID(client, clock)); 8705 } 8706 const structs = originDoc.store.clients.get(client) || []; 8707 const lastStructIndex = findIndexSS(structs, clock - 1); 8708 // write # encoded structs 8709 encoding.writeVarUint(encoder.restEncoder, lastStructIndex + 1); 8710 encoder.writeClient(client); 8711 // first clock written is 0 8712 encoding.writeVarUint(encoder.restEncoder, 0); 8713 for (let i = 0; i <= lastStructIndex; i++) { 8714 structs[i].write(encoder, 0); 8715 } 8716 } 8717 writeDeleteSet(encoder, ds); 8718 }); 8719 8720 applyUpdateV2(newDoc, encoder.toUint8Array(), 'snapshot'); 8721 return newDoc 8722}; 8723 8724/** 8725 * @param {Snapshot} snapshot 8726 * @param {Uint8Array} update 8727 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder] 8728 */
8729const snapshotContainsUpdateV2 = (snapshot, update, YDecoder = UpdateDecoderV2) => { 8730 const updateDecoder = new YDecoder(decoding.createDecoder(update)); 8731 const lazyDecoder = new LazyStructReader(updateDecoder, false); 8732 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) { 8733 if ((snapshot.sv.get(curr.id.client) || 0) < curr.id.clock + curr.length) { 8734 return false 8735 } 8736 } 8737 const mergedDS = mergeDeleteSets([snapshot.ds, readDeleteSet(updateDecoder)]); 8738 return equalDeleteSets(snapshot.ds, mergedDS) 8739}; 8740 8741/** 8742 * @param {Snapshot} snapshot 8743 * @param {Uint8Array} update 8744 */ 8745const snapshotContainsUpdate = (snapshot, update) => snapshotContainsUpdateV2(snapshot, update, UpdateDecoderV1); 8746 8747class StructStore { 8748 constructor () { 8749 /** 8750 * @type {Map<number,Array<GC|Item>>} 8751 */ 8752 this.clients = new Map(); 8753 /** 8754 * @type {null | { missing: Map<number, number>, update: Uint8Array }} 8755 */ 8756 this.pendingStructs = null; 8757 /** 8758 * @type {null | Uint8Array} 8759 */ 8760 this.pendingDs = null; 8761 } 8762} 8763 8764/** 8765 * Return the states as a Map<client,clock>. 8766 * Note that clock refers to the next expected clock id. 8767 * 8768 * @param {StructStore} store 8769 * @return {Map<number,number>} 8770 * 8771 * @public 8772 * @function 8773 */ 8774const getStateVector = store => { 8775 const sm = new Map(); 8776 store.clients.forEach((structs, client) => { 8777 const struct = structs[structs.length - 1]; 8778 sm.set(client, struct.id.clock + struct.length); 8779 }); 8780 return sm 8781}; 8782 8783/** 8784 * @param {StructStore} store 8785 * @param {number} client 8786 * @return {number} 8787 * 8788 * @public 8789 * @function 8790 */ 8791const getState = (store, client) => { 8792 const structs = store.clients.get(client); 8793 if (structs === undefined) { 8794 return 0 8795 } 8796 const lastStruct = structs[structs.length - 1]; 8797 return lastStruct.id.clock + lastStruct.length 8798}; 8799 8800/** 8801 * @param {StructStore} store 8802 * @param {GC|Item} struct 8803 * 8804 * @private 8805 * @function 8806 */ 8807const addStruct = (store, struct) => { 8808 let structs = store.clients.get(struct.id.client); 8809 if (structs === undefined) { 8810 structs = []; 8811 store.clients.set(struct.id.client, structs); 8812 } else { 8813 const lastStruct = structs[structs.length - 1]; 8814 if (lastStruct.id.clock + lastStruct.length !== struct.id.clock) { 8815 throw unexpectedCase() 8816 } 8817 } 8818 structs.push(struct); 8819}; 8820 8821/** 8822 * Perform a binary search on a sorted array 8823 * @param {Array<Item|GC>} structs 8824 * @param {number} clock 8825 * @return {number} 8826 * 8827 * @private 8828 * @function 8829 */ 8830const findIndexSS = (structs, clock) => { 8831 let left = 0; 8832 let right = structs.length - 1; 8833 let mid = structs[right]; 8834 let midclock = mid.id.clock; 8835 if (midclock === clock) { 8836 return right 8837 } 8838 // @todo does it even make sense to pivot the search? 8839 // If a good split misses, it might actually increase the time to find the correct item. 8840 // Currently, the only advantage is that search with pivoting might find the item on the first try. 8841 let midindex = floor((clock / (midclock + mid.length - 1)) * right); // pivoting the search 8842 while (left <= right) { 8843 mid = structs[midindex]; 8844 midclock = mid.id.clock; 8845 if (midclock <= clock) { 8846 if (clock < midclock + mid.length) { 8847 return midindex 8848 } 8849 left = midindex + 1; 8850 } else { 8851 right = midindex - 1; 8852 } 8853 midindex = floor((left + right) / 2); 8854 } 8855 // Always check state before looking for a struct in StructStore 8856 // Therefore the case of not finding a struct is unexpected 8857 throw unexpectedCase() 8858}; 8859 8860/** 8861 * Expects that id is actually in store. This function throws or is an infinite loop otherwise. 8862 * 8863 * @param {StructStore} store 8864 * @param {ID} id 8865 * @return {GC|Item} 8866 * 8867 * @private 8868 * @function 8869 */ 8870const find = (store, id) => { 8871 /** 8872 * @type {Array<GC|Item>} 8873 */ 8874 // @ts-ignore 8875 const structs = store.clients.get(id.client); 8876 return structs[findIndexSS(structs, id.clock)] 8877}; 8878 8879/** 8880 * Expects that id is actually in store. This function throws or is an infinite loop otherwise. 8881 * @private 8882 * @function 8883 */ 8884const getItem = /** @type {function(StructStore,ID):Item} */ (find); 8885 8886/** 8887 * @param {Transaction} transaction 8888 * @param {Array<Item|GC>} structs 8889 * @param {number} clock 8890 */ 8891const findIndexCleanStart = (transaction, structs, clock) => { 8892 const index = findIndexSS(structs, clock); 8893 const struct = structs[index]; 8894 if (struct.id.clock < clock && struct instanceof Item) { 8895 structs.splice(index + 1, 0, splitItem(transaction, struct, clock - struct.id.clock)); 8896 return index + 1 8897 } 8898 return index 8899}; 8900 8901/** 8902 * Expects that id is actually in store. This function throws or is an infinite loop otherwise. 8903 * 8904 * @param {Transaction} transaction 8905 * @param {ID} id 8906 * @return {Item} 8907 * 8908 * @private 8909 * @function 8910 */ 8911const getItemCleanStart = (transaction, id) => { 8912 const structs = /** @type {Array<Item>} */ (transaction.doc.store.clients.get(id.client)); 8913 return structs[findIndexCleanStart(transaction, structs, id.clock)] 8914}; 8915 8916/** 8917 * Expects that id is actually in store. This function throws or is an infinite loop otherwise. 8918 * 8919 * @param {Transaction} transaction 8920 * @param {StructStore} store 8921 * @param {ID} id 8922 * @return {Item} 8923 * 8924 * @private 8925 * @function 8926 */ 8927const getItemCleanEnd = (transaction, store, id) => { 8928 /** 8929 * @type {Array<Item>} 8930 */ 8931 // @ts-ignore 8932 const structs = store.clients.get(id.client); 8933 const index = findIndexSS(structs, id.clock); 8934 const struct = structs[index]; 8935 if (id.clock !== struct.id.clock + struct.length - 1 && struct.constructor !== GC) { 8936 structs.splice(index + 1, 0, splitItem(transaction, struct, id.clock - struct.id.clock + 1)); 8937 } 8938 return struct 8939}; 8940 8941/** 8942 * Replace `item` with `newitem` in store 8943 * @param {StructStore} store 8944 * @param {GC|Item} struct 8945 * @param {GC|Item} newStruct 8946 * 8947 * @private 8948 * @function 8949 */ 8950const replaceStruct = (store, struct, newStruct) => { 8951 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(struct.id.client)); 8952 structs[findIndexSS(structs, struct.id.clock)] = newStruct; 8953}; 8954 8955/** 8956 * Iterate over a range of structs 8957 * 8958 * @param {Transaction} transaction 8959 * @param {Array<Item|GC>} structs 8960 * @param {number} clockStart Inclusive start 8961 * @param {number} len 8962 * @param {function(GC|Item):void} f 8963 * 8964 * @function 8965 */ 8966const iterateStructs = (transaction, structs, clockStart, len, f) => { 8967 if (len === 0) { 8968 return 8969 } 8970 const clockEnd = clockStart + len; 8971 let index = findIndexCleanStart(transaction, structs, clockStart); 8972 let struct; 8973 do { 8974 struct = structs[index++]; 8975 if (clockEnd < struct.id.clock + struct.length) { 8976 findIndexCleanStart(transaction, structs, clockEnd); 8977 } 8978 f(struct); 8979 } while (index < structs.length && structs[index].id.clock < clockEnd) 8980}; 8981 8982/** 8983 * A transaction is created for every change on the Yjs model. It is possible 8984 * to bundle changes on the Yjs model in a single transaction to 8985 * minimize the number on messages sent and the number of observer calls. 8986 * If possible the user of this library should bundle as many changes as 8987 * possible. Here is an example to illustrate the advantages of bundling: 8988 * 8989 * @example 8990 * const map = y.define('map', YMap)
8991 * // Log content when change is triggered 8992 * map.observe(() => { 8993 * console.log('change triggered') 8994 * }) 8995 * // Each change on the map type triggers a log message: 8996 * map.set('a', 0) // => "change triggered" 8997 * map.set('b', 0) // => "change triggered" 8998 * // When put in a transaction, it will trigger the log after the transaction: 8999 * y.transact(() => { 9000 * map.set('a', 1) 9001 * map.set('b', 1) 9002 * }) // => "change triggered" 9003 * 9004 * @public 9005 */ 9006class Transaction { 9007 /** 9008 * @param {Doc} doc 9009 * @param {any} origin 9010 * @param {boolean} local 9011 */ 9012 constructor (doc, origin, local) { 9013 /** 9014 * The Yjs instance. 9015 * @type {Doc} 9016 */ 9017 this.doc = doc; 9018 /** 9019 * Describes the set of deleted items by ids 9020 * @type {DeleteSet} 9021 */ 9022 this.deleteSet = new DeleteSet(); 9023 /** 9024 * Holds the state before the transaction started. 9025 * @type {Map<Number,Number>} 9026 */ 9027 this.beforeState = getStateVector(doc.store); 9028 /** 9029 * Holds the state after the transaction. 9030 * @type {Map<Number,Number>} 9031 */ 9032 this.afterState = new Map(); 9033 /** 9034 * All types that were directly modified (property added or child 9035 * inserted/deleted). New types are not included in this Set. 9036 * Maps from type to parentSubs (`item.parentSub = null` for YArray) 9037 * @type {Map<AbstractType<YEvent<any>>,Set<String|null>>} 9038 */ 9039 this.changed = new Map(); 9040 /** 9041 * Stores the events for the types that observe also child elements. 9042 * It is mainly used by `observeDeep`. 9043 * @type {Map<AbstractType<YEvent<any>>,Array<YEvent<any>>>} 9044 */ 9045 this.changedParentTypes = new Map(); 9046 /** 9047 * @type {Array<AbstractStruct>} 9048 */ 9049 this._mergeStructs = []; 9050 /** 9051 * @type {any} 9052 */ 9053 this.origin = origin; 9054 /** 9055 * Stores meta information on the transaction 9056 * @type {Map<any,any>} 9057 */ 9058 this.meta = new Map(); 9059 /** 9060 * Whether this change originates from this doc. 9061 * @type {boolean} 9062 */ 9063 this.local = local; 9064 /** 9065 * @type {Set<Doc>} 9066 */ 9067 this.subdocsAdded = new Set(); 9068 /** 9069 * @type {Set<Doc>} 9070 */ 9071 this.subdocsRemoved = new Set(); 9072 /** 9073 * @type {Set<Doc>} 9074 */ 9075 this.subdocsLoaded = new Set(); 9076 /** 9077 * @type {boolean} 9078 */ 9079 this._needFormattingCleanup = false; 9080 } 9081} 9082 9083/** 9084 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 9085 * @param {Transaction} transaction 9086 * @return {boolean} Whether data was written. 9087 */ 9088const writeUpdateMessageFromTransaction = (encoder, transaction) => { 9089 if (transaction.deleteSet.clients.size === 0 && !any(transaction.afterState, (clock, client) => transaction.beforeState.get(client) !== clock)) { 9090 return false 9091 } 9092 sortAndMergeDeleteSet(transaction.deleteSet); 9093 writeStructsFromTransaction(encoder, transaction); 9094 writeDeleteSet(encoder, transaction.deleteSet); 9095 return true 9096}; 9097 9098/** 9099 * If `type.parent` was added in current transaction, `type` technically 9100 * did not change, it was just added and we should not fire events for `type`. 9101 * 9102 * @param {Transaction} transaction 9103 * @param {AbstractType<YEvent<any>>} type 9104 * @param {string|null} parentSub 9105 */ 9106const addChangedTypeToTransaction = (transaction, type, parentSub) => { 9107 const item = type._item; 9108 if (item === null || (item.id.clock < (transaction.beforeState.get(item.id.client) || 0) && !item.deleted)) { 9109 setIfUndefined(transaction.changed, type, set_create).add(parentSub); 9110 } 9111}; 9112 9113/** 9114 * @param {Array<AbstractStruct>} structs 9115 * @param {number} pos 9116 * @return {number} # of merged structs 9117 */ 9118const tryToMergeWithLefts = (structs, pos) => { 9119 let right = structs[pos]; 9120 let left = structs[pos - 1]; 9121 let i = pos; 9122 for (; i > 0; right = left, left = structs[--i - 1]) { 9123 if (left.deleted === right.deleted && left.constructor === right.constructor) { 9124 if (left.mergeWith(right)) { 9125 if (right instanceof Item && right.parentSub !== null && /** @type {AbstractType<any>} */ (right.parent)._map.get(right.parentSub) === right) { 9126 /** @type {AbstractType<any>} */ (right.parent)._map.set(right.parentSub, /** @type {Item} */ (left)); 9127 } 9128 continue 9129 } 9130 } 9131 break 9132 } 9133 const merged = pos - i; 9134 if (merged) { 9135 // remove all merged structs from the array 9136 structs.splice(pos + 1 - merged, merged); 9137 } 9138 return merged 9139}; 9140 9141/** 9142 * @param {DeleteSet} ds 9143 * @param {StructStore} store 9144 * @param {function(Item):boolean} gcFilter 9145 */ 9146const tryGcDeleteSet = (ds, store, gcFilter) => { 9147 for (const [client, deleteItems] of ds.clients.entries()) { 9148 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client)); 9149 for (let di = deleteItems.length - 1; di >= 0; di--) { 9150 const deleteItem = deleteItems[di]; 9151 const endDeleteItemClock = deleteItem.clock + deleteItem.len; 9152 for ( 9153 let si = findIndexSS(structs, deleteItem.clock), struct = structs[si]; 9154 si < structs.length && struct.id.clock < endDeleteItemClock; 9155 struct = structs[++si] 9156 ) { 9157 const struct = structs[si]; 9158 if (deleteItem.clock + deleteItem.len <= struct.id.clock) { 9159 break 9160 } 9161 if (struct instanceof Item && struct.deleted && !struct.keep && gcFilter(struct)) { 9162 struct.gc(store, false); 9163 } 9164 } 9165 } 9166 } 9167}; 9168 9169/** 9170 * @param {DeleteSet} ds 9171 * @param {StructStore} store 9172 */ 9173const tryMergeDeleteSet = (ds, store) => { 9174 // try to merge deleted / gc'd items 9175 // merge from right to left for better efficiecy and so we don't miss any merge targets
9176 ds.clients.forEach((deleteItems, client) => { 9177 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client)); 9178 for (let di = deleteItems.length - 1; di >= 0; di--) { 9179 const deleteItem = deleteItems[di]; 9180 // start with merging the item next to the last deleted item 9181 const mostRightIndexToCheck = min(structs.length - 1, 1 + findIndexSS(structs, deleteItem.clock + deleteItem.len - 1)); 9182 for ( 9183 let si = mostRightIndexToCheck, struct = structs[si]; 9184 si > 0 && struct.id.clock >= deleteItem.clock; 9185 struct = structs[si] 9186 ) { 9187 si -= 1 + tryToMergeWithLefts(structs, si); 9188 } 9189 } 9190 }); 9191}; 9192 9193/** 9194 * @param {DeleteSet} ds 9195 * @param {StructStore} store 9196 * @param {function(Item):boolean} gcFilter 9197 */ 9198const tryGc = (ds, store, gcFilter) => { 9199 tryGcDeleteSet(ds, store, gcFilter); 9200 tryMergeDeleteSet(ds, store); 9201}; 9202 9203/** 9204 * @param {Array<Transaction>} transactionCleanups 9205 * @param {number} i 9206 */ 9207const cleanupTransactions = (transactionCleanups, i) => { 9208 if (i < transactionCleanups.length) { 9209 const transaction = transactionCleanups[i]; 9210 const doc = transaction.doc; 9211 const store = doc.store; 9212 const ds = transaction.deleteSet; 9213 const mergeStructs = transaction._mergeStructs; 9214 try { 9215 sortAndMergeDeleteSet(ds); 9216 transaction.afterState = getStateVector(transaction.doc.store); 9217 doc.emit('beforeObserverCalls', [transaction, doc]); 9218 /** 9219 * An array of event callbacks. 9220 * 9221 * Each callback is called even if the other ones throw errors. 9222 * 9223 * @type {Array<function():void>} 9224 */ 9225 const fs = []; 9226 // observe events on changed types 9227 transaction.changed.forEach((subs, itemtype) => 9228 fs.push(() => { 9229 if (itemtype._item === null || !itemtype._item.deleted) { 9230 itemtype._callObserver(transaction, subs); 9231 } 9232 }) 9233 ); 9234 fs.push(() => { 9235 // deep observe events 9236 transaction.changedParentTypes.forEach((events, type) => { 9237 // We need to think about the possibility that the user transforms the 9238 // Y.Doc in the event. 9239 if (type._dEH.l.length > 0 && (type._item === null || !type._item.deleted)) { 9240 events = events 9241 .filter(event => 9242 event.target._item === null || !event.target._item.deleted 9243 ); 9244 events 9245 .forEach(event => { 9246 event.currentTarget = type; 9247 // path is relative to the current target 9248 event._path = null; 9249 }); 9250 // sort events by path length so that top-level events are fired first. 9251 events 9252 .sort((event1, event2) => event1.path.length - event2.path.length); 9253 // We don't need to check for events.length 9254 // because we know it has at least one element 9255 callEventHandlerListeners(type._dEH, events, transaction); 9256 } 9257 }); 9258 }); 9259 fs.push(() => doc.emit('afterTransaction', [transaction, doc])); 9260 callAll(fs, []); 9261 if (transaction._needFormattingCleanup) { 9262 cleanupYTextAfterTransaction(transaction); 9263 } 9264 } finally { 9265 // Replace deleted items with ItemDeleted / GC. 9266 // This is where content is actually remove from the Yjs Doc. 9267 if (doc.gc) { 9268 tryGcDeleteSet(ds, store, doc.gcFilter); 9269 } 9270 tryMergeDeleteSet(ds, store); 9271 9272 // on all affected store.clients props, try to merge 9273 transaction.afterState.forEach((clock, client) => { 9274 const beforeClock = transaction.beforeState.get(client) || 0; 9275 if (beforeClock !== clock) { 9276 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client)); 9277 // we iterate from right to left so we can safely remove entries 9278 const firstChangePos = max(findIndexSS(structs, beforeClock), 1); 9279 for (let i = structs.length - 1; i >= firstChangePos;) { 9280 i -= 1 + tryToMergeWithLefts(structs, i); 9281 } 9282 } 9283 }); 9284 // try to merge mergeStructs 9285 // @todo: it makes more sense to transform mergeStructs to a DS, sort it, and merge from right to left 9286 // but at the moment DS does not handle duplicates 9287 for (let i = mergeStructs.length - 1; i >= 0; i--) { 9288 const { client, clock } = mergeStructs[i].id; 9289 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client)); 9290 const replacedStructPos = findIndexSS(structs, clock); 9291 if (replacedStructPos + 1 < structs.length) { 9292 if (tryToMergeWithLefts(structs, replacedStructPos + 1) > 1) { 9293 continue // no need to perform next check, both are already merged 9294 } 9295 } 9296 if (replacedStructPos > 0) { 9297 tryToMergeWithLefts(structs, replacedStructPos); 9298 } 9299 } 9300 if (!transaction.local && transaction.afterState.get(doc.clientID) !== transaction.beforeState.get(doc.clientID)) { 9301 print(ORANGE, BOLD, '[yjs] ', UNBOLD, RED, 'Changed the client-id because another client seems to be using it.'); 9302 doc.clientID = generateNewClientId(); 9303 } 9304 // @todo Merge all the transactions into one and provide send the data as a single update message 9305 doc.emit('afterTransactionCleanup', [transaction, doc]); 9306 if (doc._observers.has('update')) { 9307 const encoder = new UpdateEncoderV1(); 9308 const hasContent = writeUpdateMessageFromTransaction(encoder, transaction); 9309 if (hasContent) { 9310 doc.emit('update', [encoder.toUint8Array(), transaction.origin, doc, transaction]); 9311 } 9312 } 9313 if (doc._observers.has('updateV2')) { 9314 const encoder = new UpdateEncoderV2(); 9315 const hasContent = writeUpdateMessageFromTransaction(encoder, transaction); 9316 if (hasContent) { 9317 doc.emit('updateV2', [encoder.toUint8Array(), transaction.origin, doc, transaction]); 9318 } 9319 } 9320 const { subdocsAdded, subdocsLoaded, subdocsRemoved } = transaction; 9321 if (subdocsAdded.size > 0 || subdocsRemoved.size > 0 || subdocsLoaded.size > 0) { 9322 subdocsAdded.forEach(subdoc => { 9323 subdoc.clientID = doc.clientID; 9324 if (subdoc.collectionid == null) { 9325 subdoc.collectionid = doc.collectionid; 9326 } 9327 doc.subdocs.add(subdoc); 9328 }); 9329 subdocsRemoved.forEach(subdoc => doc.subdocs.delete(subdoc)); 9330 doc.emit('subdocs', [{ loaded: subdocsLoaded, added: subdocsAdded, removed: subdocsRemoved }, doc, transaction]); 9331 subdocsRemoved.forEach(subdoc => subdoc.destroy()); 9332 } 9333 9334 if (transactionCleanups.length <= i + 1) { 9335 doc._transactionCleanups = []; 9336 doc.emit('afterAllTransactions', [doc, transactionCleanups]); 9337 } else { 9338 cleanupTransactions(transactionCleanups, i + 1); 9339 } 9340 } 9341 } 9342}; 9343 9344/** 9345 * Implements the functionality of `y.transact(()=>{..})` 9346 * 9347 * @template T 9348 * @param {Doc} doc 9349 * @param {function(Transaction):T} f 9350 * @param {any} [origin=true] 9351 * @return {T} 9352 * 9353 * @function 9354 */ 9355const transact = (doc, f, origin = null, local = true) => { 9356 const transactionCleanups = doc._transactionCleanups; 9357 let initialCall = false;
9358 /** 9359 * @type {any} 9360 */ 9361 let result = null; 9362 if (doc._transaction === null) { 9363 initialCall = true; 9364 doc._transaction = new Transaction(doc, origin, local); 9365 transactionCleanups.push(doc._transaction); 9366 if (transactionCleanups.length === 1) { 9367 doc.emit('beforeAllTransactions', [doc]); 9368 } 9369 doc.emit('beforeTransaction', [doc._transaction, doc]); 9370 } 9371 try { 9372 result = f(doc._transaction); 9373 } finally { 9374 if (initialCall) { 9375 const finishCleanup = doc._transaction === transactionCleanups[0]; 9376 doc._transaction = null; 9377 if (finishCleanup) { 9378 // The first transaction ended, now process observer calls. 9379 // Observer call may create new transactions for which we need to call the observers and do cleanup. 9380 // We don't want to nest these calls, so we execute these calls one after 9381 // another. 9382 // Also we need to ensure that all cleanups are called, even if the 9383 // observes throw errors. 9384 // This file is full of hacky try {} finally {} blocks to ensure that an 9385 // event can throw errors and also that the cleanup is called. 9386 cleanupTransactions(transactionCleanups, 0); 9387 } 9388 } 9389 } 9390 return result 9391}; 9392 9393class StackItem { 9394 /** 9395 * @param {DeleteSet} deletions 9396 * @param {DeleteSet} insertions 9397 */ 9398 constructor (deletions, insertions) { 9399 this.insertions = insertions; 9400 this.deletions = deletions; 9401 /** 9402 * Use this to save and restore metadata like selection range 9403 */ 9404 this.meta = new Map(); 9405 } 9406} 9407/** 9408 * @param {Transaction} tr 9409 * @param {UndoManager} um 9410 * @param {StackItem} stackItem 9411 */ 9412const clearUndoManagerStackItem = (tr, um, stackItem) => { 9413 iterateDeletedStructs(tr, stackItem.deletions, item => { 9414 if (item instanceof Item && um.scope.some(type => yjs_isParentOf(type, item))) { 9415 keepItem(item, false); 9416 } 9417 }); 9418}; 9419 9420/** 9421 * @param {UndoManager} undoManager 9422 * @param {Array<StackItem>} stack 9423 * @param {string} eventType 9424 * @return {StackItem?} 9425 */ 9426const popStackItem = (undoManager, stack, eventType) => { 9427 /** 9428 * Whether a change happened 9429 * @type {StackItem?} 9430 */ 9431 let result = null; 9432 /** 9433 * Keep a reference to the transaction so we can fire the event with the changedParentTypes 9434 * @type {any} 9435 */ 9436 let _tr = null; 9437 const doc = undoManager.doc;
9438 const scope = undoManager.scope; 9439 transact(doc, transaction => { 9440 while (stack.length > 0 && result === null) { 9441 const store = doc.store; 9442 const stackItem = /** @type {StackItem} */ (stack.pop()); 9443 /** 9444 * @type {Set<Item>} 9445 */ 9446 const itemsToRedo = new Set(); 9447 /** 9448 * @type {Array<Item>} 9449 */ 9450 const itemsToDelete = []; 9451 let performedChange = false; 9452 iterateDeletedStructs(transaction, stackItem.insertions, struct => { 9453 if (struct instanceof Item) { 9454 if (struct.redone !== null) { 9455 let { item, diff } = followRedone(store, struct.id); 9456 if (diff > 0) { 9457 item = getItemCleanStart(transaction, createID(item.id.client, item.id.clock + diff)); 9458 } 9459 struct = item; 9460 } 9461 if (!struct.deleted && scope.some(type => yjs_isParentOf(type, /** @type {Item} */ (struct)))) { 9462 itemsToDelete.push(struct); 9463 } 9464 } 9465 }); 9466 iterateDeletedStructs(transaction, stackItem.deletions, struct => { 9467 if ( 9468 struct instanceof Item && 9469 scope.some(type => yjs_isParentOf(type, struct)) && 9470 // Never redo structs in stackItem.insertions because they were created and deleted in the same capture interval. 9471 !isDeleted(stackItem.insertions, struct.id) 9472 ) { 9473 itemsToRedo.add(struct); 9474 } 9475 }); 9476 itemsToRedo.forEach(struct => { 9477 performedChange = redoItem(transaction, struct, itemsToRedo, stackItem.insertions, undoManager.ignoreRemoteMapChanges, undoManager) !== null || performedChange; 9478 }); 9479 // We want to delete in reverse order so that children are deleted before 9480 // parents, so we have more information available when items are filtered. 9481 for (let i = itemsToDelete.length - 1; i >= 0; i--) { 9482 const item = itemsToDelete[i]; 9483 if (undoManager.deleteFilter(item)) { 9484 item.delete(transaction); 9485 performedChange = true; 9486 } 9487 } 9488 result = performedChange ? stackItem : null; 9489 } 9490 transaction.changed.forEach((subProps, type) => { 9491 // destroy search marker if necessary 9492 if (subProps.has(null) && type._searchMarker) { 9493 type._searchMarker.length = 0; 9494 } 9495 }); 9496 _tr = transaction; 9497 }, undoManager); 9498 if (result != null) { 9499 const changedParentTypes = _tr.changedParentTypes; 9500 undoManager.emit('stack-item-popped', [{ stackItem: result, type: eventType, changedParentTypes }, undoManager]); 9501 } 9502 return result 9503}; 9504 9505/** 9506 * @typedef {Object} UndoManagerOptions 9507 * @property {number} [UndoManagerOptions.captureTimeout=500] 9508 * @property {function(Transaction):boolean} [UndoManagerOptions.captureTransaction] Do not capture changes of a Transaction if result false. 9509 * @property {function(Item):boolean} [UndoManagerOptions.deleteFilter=()=>true] Sometimes 9510 * it is necessary to filter what an Undo/Redo operation can delete. If this 9511 * filter returns false, the type/item won't be deleted even it is in the 9512 * undo/redo scope. 9513 * @property {Set<any>} [UndoManagerOptions.trackedOrigins=new Set([null])] 9514 * @property {boolean} [ignoreRemoteMapChanges] Experimental. By default, the UndoManager will never overwrite remote changes. Enable this property to enable overwriting remote changes on key-value changes (Y.Map, properties on Y.Xml, etc..). 9515 * @property {Doc} [doc] The document that this UndoManager operates on. Only needed if typeScope is empty. 9516 */ 9517 9518/** 9519 * Fires 'stack-item-added' event when a stack item was added to either the undo- or 9520 * the redo-stack. You may store additional stack information via the 9521 * metadata property on `event.stackItem.meta` (it is a `Map` of metadata properties). 9522 * Fires 'stack-item-popped' event when a stack item was popped from either the 9523 * undo- or the redo-stack. You may restore the saved stack information from `event.stackItem.meta`. 9524 * 9525 * @extends {Observable<'stack-item-added'|'stack-item-popped'|'stack-cleared'|'stack-item-updated'>} 9526 */ 9527class UndoManager extends (/* unused pure expression or super */ null && (Observable)) { 9528 /** 9529 * @param {AbstractType<any>|Array<AbstractType<any>>} typeScope Accepts either a single type, or an array of types 9530 * @param {UndoManagerOptions} options 9531 */ 9532 constructor (typeScope, { 9533 captureTimeout = 500, 9534 captureTransaction = _tr => true, 9535 deleteFilter = () => true, 9536 trackedOrigins = new Set([null]), 9537 ignoreRemoteMapChanges = false, 9538 doc = /** @type {Doc} */ (array.isArray(typeScope) ? typeScope[0].doc : typeScope.doc) 9539 } = {}) { 9540 super(); 9541 /** 9542 * @type {Array<AbstractType<any>>} 9543 */ 9544 this.scope = []; 9545 this.addToScope(typeScope); 9546 this.deleteFilter = deleteFilter; 9547 trackedOrigins.add(this); 9548 this.trackedOrigins = trackedOrigins; 9549 this.captureTransaction = captureTransaction; 9550 /** 9551 * @type {Array<StackItem>} 9552 */ 9553 this.undoStack = []; 9554 /** 9555 * @type {Array<StackItem>} 9556 */ 9557 this.redoStack = []; 9558 /** 9559 * Whether the client is currently undoing (calling UndoManager.undo) 9560 * 9561 * @type {boolean} 9562 */ 9563 this.undoing = false;
9564 this.redoing = false; 9565 this.doc = doc; 9566 this.lastChange = 0; 9567 this.ignoreRemoteMapChanges = ignoreRemoteMapChanges; 9568 this.captureTimeout = captureTimeout; 9569 /** 9570 * @param {Transaction} transaction 9571 */ 9572 this.afterTransactionHandler = transaction => { 9573 // Only track certain transactions 9574 if ( 9575 !this.captureTransaction(transaction) || 9576 !this.scope.some(type => transaction.changedParentTypes.has(type)) || 9577 (!this.trackedOrigins.has(transaction.origin) && (!transaction.origin || !this.trackedOrigins.has(transaction.origin.constructor))) 9578 ) { 9579 return 9580 } 9581 const undoing = this.undoing; 9582 const redoing = this.redoing; 9583 const stack = undoing ? this.redoStack : this.undoStack; 9584 if (undoing) { 9585 this.stopCapturing(); // next undo should not be appended to last stack item 9586 } else if (!redoing) { 9587 // neither undoing nor redoing: delete redoStack 9588 this.clear(false, true); 9589 } 9590 const insertions = new DeleteSet(); 9591 transaction.afterState.forEach((endClock, client) => { 9592 const startClock = transaction.beforeState.get(client) || 0; 9593 const len = endClock - startClock; 9594 if (len > 0) { 9595 addToDeleteSet(insertions, client, startClock, len); 9596 } 9597 }); 9598 const now = time.getUnixTime(); 9599 let didAdd = false; 9600 if (this.lastChange > 0 && now - this.lastChange < this.captureTimeout && stack.length > 0 && !undoing && !redoing) { 9601 // append change to last stack op 9602 const lastOp = stack[stack.length - 1]; 9603 lastOp.deletions = mergeDeleteSets([lastOp.deletions, transaction.deleteSet]); 9604 lastOp.insertions = mergeDeleteSets([lastOp.insertions, insertions]); 9605 } else { 9606 // create a new stack op 9607 stack.push(new StackItem(transaction.deleteSet, insertions)); 9608 didAdd = true; 9609 } 9610 if (!undoing && !redoing) { 9611 this.lastChange = now; 9612 } 9613 // make sure that deleted structs are not gc'd 9614 iterateDeletedStructs(transaction, transaction.deleteSet, /** @param {Item|GC} item */ item => { 9615 if (item instanceof Item && this.scope.some(type => yjs_isParentOf(type, item))) { 9616 keepItem(item, true); 9617 } 9618 }); 9619 const changeEvent = [{ stackItem: stack[stack.length - 1], origin: transaction.origin, type: undoing ? 'redo' : 'undo', changedParentTypes: transaction.changedParentTypes }, this]; 9620 if (didAdd) { 9621 this.emit('stack-item-added', changeEvent); 9622 } else { 9623 this.emit('stack-item-updated', changeEvent); 9624 } 9625 }; 9626 this.doc.on('afterTransaction', this.afterTransactionHandler); 9627 this.doc.on('destroy', () => { 9628 this.destroy(); 9629 }); 9630 } 9631 9632 /** 9633 * @param {Array<AbstractType<any>> | AbstractType<any>} ytypes 9634 */ 9635 addToScope (ytypes) { 9636 ytypes = array.isArray(ytypes) ? ytypes : [ytypes]; 9637 ytypes.forEach(ytype => { 9638 if (this.scope.every(yt => yt !== ytype)) { 9639 this.scope.push(ytype); 9640 } 9641 }); 9642 } 9643 9644 /** 9645 * @param {any} origin 9646 */ 9647 addTrackedOrigin (origin) { 9648 this.trackedOrigins.add(origin); 9649 } 9650 9651 /** 9652 * @param {any} origin 9653 */ 9654 removeTrackedOrigin (origin) { 9655 this.trackedOrigins.delete(origin); 9656 } 9657 9658 clear (clearUndoStack = true, clearRedoStack = true) { 9659 if ((clearUndoStack && this.canUndo()) || (clearRedoStack && this.canRedo())) { 9660 this.doc.transact(tr => { 9661 if (clearUndoStack) { 9662 this.undoStack.forEach(item => clearUndoManagerStackItem(tr, this, item)); 9663 this.undoStack = []; 9664 } 9665 if (clearRedoStack) { 9666 this.redoStack.forEach(item => clearUndoManagerStackItem(tr, this, item)); 9667 this.redoStack = []; 9668 } 9669 this.emit('stack-cleared', [{ undoStackCleared: clearUndoStack, redoStackCleared: clearRedoStack }]); 9670 }); 9671 } 9672 } 9673 9674 /** 9675 * UndoManager merges Undo-StackItem if they are created within time-gap 9676 * smaller than `options.captureTimeout`. Call `um.stopCapturing()` so that the next 9677 * StackItem won't be merged. 9678 * 9679 * 9680 * @example 9681 * // without stopCapturing 9682 * ytext.insert(0, 'a') 9683 * ytext.insert(1, 'b') 9684 * um.undo() 9685 * ytext.toString() // => '' (note that 'ab' was removed) 9686 * // with stopCapturing 9687 * ytext.insert(0, 'a') 9688 * um.stopCapturing() 9689 * ytext.insert(0, 'b') 9690 * um.undo() 9691 * ytext.toString() // => 'a' (note that only 'b' was removed) 9692 * 9693 */ 9694 stopCapturing () { 9695 this.lastChange = 0; 9696 } 9697 9698 /** 9699 * Undo last changes on type. 9700 * 9701 * @return {StackItem?} Returns StackItem if a change was applied 9702 */ 9703 undo () { 9704 this.undoing = true; 9705 let res; 9706 try { 9707 res = popStackItem(this, this.undoStack, 'undo'); 9708 } finally { 9709 this.undoing = false;
9710 } 9711 return res 9712 } 9713 9714 /** 9715 * Redo last undo operation. 9716 * 9717 * @return {StackItem?} Returns StackItem if a change was applied 9718 */ 9719 redo () { 9720 this.redoing = true; 9721 let res; 9722 try { 9723 res = popStackItem(this, this.redoStack, 'redo'); 9724 } finally { 9725 this.redoing = false; 9726 } 9727 return res 9728 } 9729 9730 /** 9731 * Are undo steps available? 9732 * 9733 * @return {boolean} `true` if undo is possible 9734 */ 9735 canUndo () { 9736 return this.undoStack.length > 0 9737 } 9738 9739 /** 9740 * Are redo steps available? 9741 * 9742 * @return {boolean} `true` if redo is possible 9743 */ 9744 canRedo () { 9745 return this.redoStack.length > 0 9746 } 9747 9748 destroy () { 9749 this.trackedOrigins.delete(this); 9750 this.doc.off('afterTransaction', this.afterTransactionHandler); 9751 super.destroy(); 9752 } 9753} 9754 9755/** 9756 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 9757 */ 9758function * lazyStructReaderGenerator (decoder) { 9759 const numOfStateUpdates = readVarUint(decoder.restDecoder); 9760 for (let i = 0; i < numOfStateUpdates; i++) { 9761 const numberOfStructs = readVarUint(decoder.restDecoder); 9762 const client = decoder.readClient(); 9763 let clock = readVarUint(decoder.restDecoder); 9764 for (let i = 0; i < numberOfStructs; i++) { 9765 const info = decoder.readInfo(); 9766 // @todo use switch instead of ifs 9767 if (info === 10) { 9768 const len = readVarUint(decoder.restDecoder); 9769 yield new Skip(createID(client, clock), len); 9770 clock += len; 9771 } else if ((BITS5 & info) !== 0) { 9772 const cantCopyParentInfo = (info & (BIT7 | BIT8)) === 0; 9773 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y` 9774 // and we read the next string as parentYKey. 9775 // It indicates how we store/retrieve parent from `y.share` 9776 // @type {string|null} 9777 const struct = new Item( 9778 createID(client, clock), 9779 null, // left 9780 (info & BIT8) === BIT8 ? decoder.readLeftID() : null, // origin 9781 null, // right 9782 (info & BIT7) === BIT7 ? decoder.readRightID() : null, // right origin 9783 // @ts-ignore Force writing a string here. 9784 cantCopyParentInfo ? (decoder.readParentInfo() ? decoder.readString() : decoder.readLeftID()) : null, // parent 9785 cantCopyParentInfo && (info & BIT6) === BIT6 ? decoder.readString() : null, // parentSub 9786 readItemContent(decoder, info) // item content 9787 ); 9788 yield struct; 9789 clock += struct.length; 9790 } else { 9791 const len = decoder.readLen(); 9792 yield new GC(createID(client, clock), len); 9793 clock += len; 9794 } 9795 } 9796 } 9797} 9798 9799class LazyStructReader { 9800 /** 9801 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 9802 * @param {boolean} filterSkips 9803 */ 9804 constructor (decoder, filterSkips) { 9805 this.gen = lazyStructReaderGenerator(decoder); 9806 /** 9807 * @type {null | Item | Skip | GC} 9808 */ 9809 this.curr = null; 9810 this.done = false; 9811 this.filterSkips = filterSkips; 9812 this.next(); 9813 } 9814 9815 /** 9816 * @return {Item | GC | Skip |null} 9817 */ 9818 next () { 9819 // ignore "Skip" structs 9820 do { 9821 this.curr = this.gen.next().value || null; 9822 } while (this.filterSkips && this.curr !== null && this.curr.constructor === Skip) 9823 return this.curr 9824 } 9825} 9826 9827/** 9828 * @param {Uint8Array} update 9829 * 9830 */ 9831const logUpdate = update => logUpdateV2(update, UpdateDecoderV1); 9832 9833/** 9834 * @param {Uint8Array} update 9835 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder] 9836 * 9837 */ 9838const logUpdateV2 = (update, YDecoder = UpdateDecoderV2) => { 9839 const structs = []; 9840 const updateDecoder = new YDecoder(decoding.createDecoder(update)); 9841 const lazyDecoder = new LazyStructReader(updateDecoder, false); 9842 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) { 9843 structs.push(curr); 9844 } 9845 logging.print('Structs: ', structs); 9846 const ds = readDeleteSet(updateDecoder); 9847 logging.print('DeleteSet: ', ds); 9848}; 9849 9850/** 9851 * @param {Uint8Array} update 9852 * 9853 */ 9854const decodeUpdate = (update) => decodeUpdateV2(update, UpdateDecoderV1); 9855 9856/** 9857 * @param {Uint8Array} update 9858 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder] 9859 * 9860 */ 9861const decodeUpdateV2 = (update, YDecoder = UpdateDecoderV2) => { 9862 const structs = []; 9863 const updateDecoder = new YDecoder(decoding.createDecoder(update)); 9864 const lazyDecoder = new LazyStructReader(updateDecoder, false);
9865 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) { 9866 structs.push(curr); 9867 } 9868 return { 9869 structs, 9870 ds: readDeleteSet(updateDecoder) 9871 } 9872}; 9873 9874class LazyStructWriter { 9875 /** 9876 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 9877 */ 9878 constructor (encoder) { 9879 this.currClient = 0; 9880 this.startClock = 0; 9881 this.written = 0; 9882 this.encoder = encoder; 9883 /** 9884 * We want to write operations lazily, but also we need to know beforehand how many operations we want to write for each client. 9885 * 9886 * This kind of meta-information (#clients, #structs-per-client-written) is written to the restEncoder. 9887 * 9888 * We fragment the restEncoder and store a slice of it per-client until we know how many clients there are. 9889 * When we flush (toUint8Array) we write the restEncoder using the fragments and the meta-information. 9890 * 9891 * @type {Array<{ written: number, restEncoder: Uint8Array }>} 9892 */ 9893 this.clientStructs = []; 9894 } 9895} 9896 9897/** 9898 * @param {Array<Uint8Array>} updates 9899 * @return {Uint8Array} 9900 */ 9901const mergeUpdates = updates => mergeUpdatesV2(updates, UpdateDecoderV1, UpdateEncoderV1); 9902 9903/** 9904 * @param {Uint8Array} update 9905 * @param {typeof DSEncoderV1 | typeof DSEncoderV2} YEncoder 9906 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} YDecoder 9907 * @return {Uint8Array} 9908 */ 9909const encodeStateVectorFromUpdateV2 = (update, YEncoder = DSEncoderV2, YDecoder = UpdateDecoderV2) => { 9910 const encoder = new YEncoder(); 9911 const updateDecoder = new LazyStructReader(new YDecoder(decoding.createDecoder(update)), false); 9912 let curr = updateDecoder.curr; 9913 if (curr !== null) { 9914 let size = 0; 9915 let currClient = curr.id.client; 9916 let stopCounting = curr.id.clock !== 0; // must start at 0 9917 let currClock = stopCounting ? 0 : curr.id.clock + curr.length; 9918 for (; curr !== null; curr = updateDecoder.next()) { 9919 if (currClient !== curr.id.client) { 9920 if (currClock !== 0) { 9921 size++; 9922 // We found a new client 9923 // write what we have to the encoder 9924 encoding.writeVarUint(encoder.restEncoder, currClient); 9925 encoding.writeVarUint(encoder.restEncoder, currClock); 9926 } 9927 currClient = curr.id.client; 9928 currClock = 0; 9929 stopCounting = curr.id.clock !== 0; 9930 } 9931 // we ignore skips 9932 if (curr.constructor === Skip) { 9933 stopCounting = true; 9934 } 9935 if (!stopCounting) { 9936 currClock = curr.id.clock + curr.length; 9937 } 9938 } 9939 // write what we have 9940 if (currClock !== 0) { 9941 size++; 9942 encoding.writeVarUint(encoder.restEncoder, currClient); 9943 encoding.writeVarUint(encoder.restEncoder, currClock); 9944 } 9945 // prepend the size of the state vector 9946 const enc = encoding.createEncoder(); 9947 encoding.writeVarUint(enc, size); 9948 encoding.writeBinaryEncoder(enc, encoder.restEncoder); 9949 encoder.restEncoder = enc; 9950 return encoder.toUint8Array() 9951 } else { 9952 encoding.writeVarUint(encoder.restEncoder, 0); 9953 return encoder.toUint8Array() 9954 } 9955}; 9956 9957/** 9958 * @param {Uint8Array} update 9959 * @return {Uint8Array} 9960 */ 9961const encodeStateVectorFromUpdate = update => encodeStateVectorFromUpdateV2(update, DSEncoderV1, UpdateDecoderV1); 9962 9963/** 9964 * @param {Uint8Array} update 9965 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} YDecoder 9966 * @return {{ from: Map<number,number>, to: Map<number,number> }} 9967 */ 9968const parseUpdateMetaV2 = (update, YDecoder = UpdateDecoderV2) => { 9969 /** 9970 * @type {Map<number, number>} 9971 */ 9972 const from = new Map(); 9973 /** 9974 * @type {Map<number, number>} 9975 */ 9976 const to = new Map(); 9977 const updateDecoder = new LazyStructReader(new YDecoder(decoding.createDecoder(update)), false); 9978 let curr = updateDecoder.curr; 9979 if (curr !== null) { 9980 let currClient = curr.id.client;
9981 let currClock = curr.id.clock; 9982 // write the beginning to `from` 9983 from.set(currClient, currClock); 9984 for (; curr !== null; curr = updateDecoder.next()) { 9985 if (currClient !== curr.id.client) { 9986 // We found a new client 9987 // write the end to `to` 9988 to.set(currClient, currClock); 9989 // write the beginning to `from` 9990 from.set(curr.id.client, curr.id.clock); 9991 // update currClient 9992 currClient = curr.id.client; 9993 } 9994 currClock = curr.id.clock + curr.length; 9995 } 9996 // write the end to `to` 9997 to.set(currClient, currClock); 9998 } 9999 return { from, to } 10000}; 10001 10002/** 10003 * @param {Uint8Array} update 10004 * @return {{ from: Map<number,number>, to: Map<number,number> }} 10005 */ 10006const parseUpdateMeta = update => parseUpdateMetaV2(update, UpdateDecoderV1); 10007 10008/** 10009 * This method is intended to slice any kind of struct and retrieve the right part. 10010 * It does not handle side-effects, so it should only be used by the lazy-encoder. 10011 * 10012 * @param {Item | GC | Skip} left 10013 * @param {number} diff 10014 * @return {Item | GC} 10015 */ 10016const sliceStruct = (left, diff) => { 10017 if (left.constructor === GC) { 10018 const { client, clock } = left.id; 10019 return new GC(createID(client, clock + diff), left.length - diff) 10020 } else if (left.constructor === Skip) { 10021 const { client, clock } = left.id; 10022 return new Skip(createID(client, clock + diff), left.length - diff) 10023 } else { 10024 const leftItem = /** @type {Item} */ (left); 10025 const { client, clock } = leftItem.id; 10026 return new Item( 10027 createID(client, clock + diff), 10028 null, 10029 createID(client, clock + diff - 1), 10030 null, 10031 leftItem.rightOrigin, 10032 leftItem.parent, 10033 leftItem.parentSub, 10034 leftItem.content.splice(diff) 10035 ) 10036 } 10037}; 10038 10039/** 10040 * 10041 * This function works similarly to `readUpdateV2`. 10042 * 10043 * @param {Array<Uint8Array>} updates 10044 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder] 10045 * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder] 10046 * @return {Uint8Array} 10047 */ 10048const mergeUpdatesV2 = (updates, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => { 10049 if (updates.length === 1) { 10050 return updates[0] 10051 } 10052 const updateDecoders = updates.map(update => new YDecoder(createDecoder(update))); 10053 let lazyStructDecoders = updateDecoders.map(decoder => new LazyStructReader(decoder, true)); 10054 10055 /** 10056 * @todo we don't need offset because we always slice before 10057 * @type {null | { struct: Item | GC | Skip, offset: number }} 10058 */ 10059 let currWrite = null; 10060 10061 const updateEncoder = new YEncoder(); 10062 // write structs lazily 10063 const lazyStructEncoder = new LazyStructWriter(updateEncoder); 10064 10065 // Note: We need to ensure that all lazyStructDecoders are fully consumed 10066 // Note: Should merge document updates whenever possible - even from different updates 10067 // Note: Should handle that some operations cannot be applied yet () 10068 10069 while (true) { 10070 // Write higher clients first â sort by clientID & clock and remove decoders without content 10071 lazyStructDecoders = lazyStructDecoders.filter(dec => dec.curr !== null); 10072 lazyStructDecoders.sort( 10073 /** @type {function(any,any):number} */ (dec1, dec2) => { 10074 if (dec1.curr.id.client === dec2.curr.id.client) { 10075 const clockDiff = dec1.curr.id.clock - dec2.curr.id.clock; 10076 if (clockDiff === 0) { 10077 // @todo remove references to skip since the structDecoders must filter Skips. 10078 return dec1.curr.constructor === dec2.curr.constructor 10079 ? 0 10080 : dec1.curr.constructor === Skip ? 1 : -1 // we are filtering skips anyway. 10081 } else { 10082 return clockDiff 10083 } 10084 } else { 10085 return dec2.curr.id.client - dec1.curr.id.client 10086 } 10087 } 10088 ); 10089 if (lazyStructDecoders.length === 0) { 10090 break 10091 } 10092 const currDecoder = lazyStructDecoders[0]; 10093 // write from currDecoder until the next operation is from another client or if filler-struct 10094 // then we need to reorder the decoders and find the next operation to write 10095 const firstClient = /** @type {Item | GC} */ (currDecoder.curr).id.client; 10096 10097 if (currWrite !== null) { 10098 let curr = /** @type {Item | GC | null} */ (currDecoder.curr); 10099 let iterated = false;
10100 10101 // iterate until we find something that we haven't written already 10102 // remember: first the high client-ids are written 10103 while (curr !== null && curr.id.clock + curr.length <= currWrite.struct.id.clock + currWrite.struct.length && curr.id.client >= currWrite.struct.id.client) { 10104 curr = currDecoder.next(); 10105 iterated = true; 10106 } 10107 if ( 10108 curr === null || // current decoder is empty 10109 curr.id.client !== firstClient || // check whether there is another decoder that has has updates from `firstClient` 10110 (iterated && curr.id.clock > currWrite.struct.id.clock + currWrite.struct.length) // the above while loop was used and we are potentially missing updates 10111 ) { 10112 continue 10113 } 10114 10115 if (firstClient !== currWrite.struct.id.client) { 10116 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset); 10117 currWrite = { struct: curr, offset: 0 }; 10118 currDecoder.next(); 10119 } else { 10120 if (currWrite.struct.id.clock + currWrite.struct.length < curr.id.clock) { 10121 // @todo write currStruct & set currStruct = Skip(clock = currStruct.id.clock + currStruct.length, length = curr.id.clock - self.clock) 10122 if (currWrite.struct.constructor === Skip) { 10123 // extend existing skip 10124 currWrite.struct.length = curr.id.clock + curr.length - currWrite.struct.id.clock; 10125 } else { 10126 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset); 10127 const diff = curr.id.clock - currWrite.struct.id.clock - currWrite.struct.length; 10128 /** 10129 * @type {Skip} 10130 */ 10131 const struct = new Skip(createID(firstClient, currWrite.struct.id.clock + currWrite.struct.length), diff); 10132 currWrite = { struct, offset: 0 }; 10133 } 10134 } else { // if (currWrite.struct.id.clock + currWrite.struct.length >= curr.id.clock) { 10135 const diff = currWrite.struct.id.clock + currWrite.struct.length - curr.id.clock; 10136 if (diff > 0) { 10137 if (currWrite.struct.constructor === Skip) { 10138 // prefer to slice Skip because the other struct might contain more information 10139 currWrite.struct.length -= diff; 10140 } else { 10141 curr = sliceStruct(curr, diff); 10142 } 10143 } 10144 if (!currWrite.struct.mergeWith(/** @type {any} */ (curr))) { 10145 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset); 10146 currWrite = { struct: curr, offset: 0 }; 10147 currDecoder.next(); 10148 } 10149 } 10150 } 10151 } else { 10152 currWrite = { struct: /** @type {Item | GC} */ (currDecoder.curr), offset: 0 }; 10153 currDecoder.next(); 10154 } 10155 for ( 10156 let next = currDecoder.curr; 10157 next !== null && next.id.client === firstClient && next.id.clock === currWrite.struct.id.clock + currWrite.struct.length && next.constructor !== Skip; 10158 next = currDecoder.next() 10159 ) { 10160 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset); 10161 currWrite = { struct: next, offset: 0 }; 10162 } 10163 } 10164 if (currWrite !== null) { 10165 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset); 10166 currWrite = null; 10167 } 10168 finishLazyStructWriting(lazyStructEncoder); 10169 10170 const dss = updateDecoders.map(decoder => readDeleteSet(decoder)); 10171 const ds = mergeDeleteSets(dss); 10172 writeDeleteSet(updateEncoder, ds); 10173 return updateEncoder.toUint8Array() 10174}; 10175 10176/** 10177 * @param {Uint8Array} update 10178 * @param {Uint8Array} sv 10179 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder] 10180 * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder] 10181 */ 10182const diffUpdateV2 = (update, sv, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => { 10183 const state = decodeStateVector(sv); 10184 const encoder = new YEncoder(); 10185 const lazyStructWriter = new LazyStructWriter(encoder); 10186 const decoder = new YDecoder(createDecoder(update)); 10187 const reader = new LazyStructReader(decoder, false); 10188 while (reader.curr) { 10189 const curr = reader.curr; 10190 const currClient = curr.id.client; 10191 const svClock = state.get(currClient) || 0; 10192 if (reader.curr.constructor === Skip) { 10193 // the first written struct shouldn't be a skip 10194 reader.next(); 10195 continue 10196 } 10197 if (curr.id.clock + curr.length > svClock) { 10198 writeStructToLazyStructWriter(lazyStructWriter, curr, max(svClock - curr.id.clock, 0)); 10199 reader.next(); 10200 while (reader.curr && reader.curr.id.client === currClient) { 10201 writeStructToLazyStructWriter(lazyStructWriter, reader.curr, 0); 10202 reader.next(); 10203 } 10204 } else { 10205 // read until something new comes up 10206 while (reader.curr && reader.curr.id.client === currClient && reader.curr.id.clock + reader.curr.length <= svClock) { 10207 reader.next(); 10208 } 10209 } 10210 } 10211 finishLazyStructWriting(lazyStructWriter); 10212 // write ds 10213 const ds = readDeleteSet(decoder); 10214 writeDeleteSet(encoder, ds); 10215 return encoder.toUint8Array() 10216}; 10217 10218/** 10219 * @param {Uint8Array} update 10220 * @param {Uint8Array} sv 10221 */
10222const diffUpdate = (update, sv) => diffUpdateV2(update, sv, UpdateDecoderV1, UpdateEncoderV1); 10223 10224/** 10225 * @param {LazyStructWriter} lazyWriter 10226 */ 10227const flushLazyStructWriter = lazyWriter => { 10228 if (lazyWriter.written > 0) { 10229 lazyWriter.clientStructs.push({ written: lazyWriter.written, restEncoder: toUint8Array(lazyWriter.encoder.restEncoder) }); 10230 lazyWriter.encoder.restEncoder = createEncoder(); 10231 lazyWriter.written = 0; 10232 } 10233}; 10234 10235/** 10236 * @param {LazyStructWriter} lazyWriter 10237 * @param {Item | GC} struct 10238 * @param {number} offset 10239 */ 10240const writeStructToLazyStructWriter = (lazyWriter, struct, offset) => { 10241 // flush curr if we start another client 10242 if (lazyWriter.written > 0 && lazyWriter.currClient !== struct.id.client) { 10243 flushLazyStructWriter(lazyWriter); 10244 } 10245 if (lazyWriter.written === 0) { 10246 lazyWriter.currClient = struct.id.client; 10247 // write next client 10248 lazyWriter.encoder.writeClient(struct.id.client); 10249 // write startClock 10250 writeVarUint(lazyWriter.encoder.restEncoder, struct.id.clock + offset); 10251 } 10252 struct.write(lazyWriter.encoder, offset); 10253 lazyWriter.written++; 10254}; 10255/** 10256 * Call this function when we collected all parts and want to 10257 * put all the parts together. After calling this method, 10258 * you can continue using the UpdateEncoder. 10259 * 10260 * @param {LazyStructWriter} lazyWriter 10261 */ 10262const finishLazyStructWriting = (lazyWriter) => { 10263 flushLazyStructWriter(lazyWriter); 10264 10265 // this is a fresh encoder because we called flushCurr 10266 const restEncoder = lazyWriter.encoder.restEncoder; 10267 10268 /** 10269 * Now we put all the fragments together. 10270 * This works similarly to `writeClientsStructs` 10271 */ 10272 10273 // write # states that were updated - i.e. the clients 10274 writeVarUint(restEncoder, lazyWriter.clientStructs.length); 10275 10276 for (let i = 0; i < lazyWriter.clientStructs.length; i++) { 10277 const partStructs = lazyWriter.clientStructs[i]; 10278 /** 10279 * Works similarly to `writeStructs` 10280 */ 10281 // write # encoded structs 10282 writeVarUint(restEncoder, partStructs.written); 10283 // write the rest of the fragment 10284 writeUint8Array(restEncoder, partStructs.restEncoder); 10285 } 10286}; 10287 10288/** 10289 * @param {Uint8Array} update 10290 * @param {function(Item|GC|Skip):Item|GC|Skip} blockTransformer 10291 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} YDecoder 10292 * @param {typeof UpdateEncoderV2 | typeof UpdateEncoderV1 } YEncoder 10293 */ 10294const convertUpdateFormat = (update, blockTransformer, YDecoder, YEncoder) => { 10295 const updateDecoder = new YDecoder(createDecoder(update)); 10296 const lazyDecoder = new LazyStructReader(updateDecoder, false); 10297 const updateEncoder = new YEncoder(); 10298 const lazyWriter = new LazyStructWriter(updateEncoder); 10299 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) { 10300 writeStructToLazyStructWriter(lazyWriter, blockTransformer(curr), 0); 10301 } 10302 finishLazyStructWriting(lazyWriter); 10303 const ds = readDeleteSet(updateDecoder); 10304 writeDeleteSet(updateEncoder, ds); 10305 return updateEncoder.toUint8Array() 10306}; 10307 10308/** 10309 * @typedef {Object} ObfuscatorOptions 10310 * @property {boolean} [ObfuscatorOptions.formatting=true] 10311 * @property {boolean} [ObfuscatorOptions.subdocs=true] 10312 * @property {boolean} [ObfuscatorOptions.yxml=true] Whether to obfuscate nodeName / hookName 10313 */ 10314 10315/** 10316 * @param {ObfuscatorOptions} obfuscator 10317 */ 10318const createObfuscator = ({ formatting = true, subdocs = true, yxml = true } = {}) => { 10319 let i = 0; 10320 const mapKeyCache = map.create(); 10321 const nodeNameCache = map.create(); 10322 const formattingKeyCache = map.create(); 10323 const formattingValueCache = map.create(); 10324 formattingValueCache.set(null, null); // end of a formatting range should always be the end of a formatting range 10325 /** 10326 * @param {Item|GC|Skip} block 10327 * @return {Item|GC|Skip} 10328 */ 10329 return block => { 10330 switch (block.constructor) { 10331 case GC: 10332 case Skip: 10333 return block 10334 case Item: { 10335 const item = /** @type {Item} */ (block); 10336 const content = item.content; 10337 switch (content.constructor) { 10338 case ContentDeleted: 10339 break 10340 case ContentType: { 10341 if (yxml) { 10342 const type = /** @type {ContentType} */ (content).type; 10343 if (type instanceof YXmlElement) { 10344 type.nodeName = map.setIfUndefined(nodeNameCache, t
10344ype.nodeName, () => 'node-' + i); 10345 } 10346 if (type instanceof YXmlHook) { 10347 type.hookName = map.setIfUndefined(nodeNameCache, type.hookName, () => 'hook-' + i); 10348 } 10349 } 10350 break 10351 } 10352 case ContentAny: { 10353 const c = /** @type {ContentAny} */ (content); 10354 c.arr = c.arr.map(() => i); 10355 break 10356 } 10357 case ContentBinary: { 10358 const c = /** @type {ContentBinary} */ (content); 10359 c.content = new Uint8Array([i]); 10360 break 10361 } 10362 case ContentDoc: { 10363 const c = /** @type {ContentDoc} */ (content); 10364 if (subdocs) { 10365 c.opts = {}; 10366 c.doc.guid = i + ''; 10367 } 10368 break 10369 } 10370 case ContentEmbed: { 10371 const c = /** @type {ContentEmbed} */ (content); 10372 c.embed = {}; 10373 break 10374 } 10375 case ContentFormat: { 10376 const c = /** @type {ContentFormat} */ (content); 10377 if (formatting) { 10378 c.key = map.setIfUndefined(formattingKeyCache, c.key, () => i + ''); 10379 c.value = map.setIfUndefined(formattingValueCache, c.value, () => ({ i })); 10380 } 10381 break 10382 } 10383 case ContentJSON: { 10384 const c = /** @type {ContentJSON} */ (content); 10385 c.arr = c.arr.map(() => i); 10386 break 10387 } 10388 case ContentString: { 10389 const c = /** @type {ContentString} */ (content); 10390 c.str = string.repeat((i % 10) + '', c.str.length); 10391 break 10392 } 10393 default: 10394 // unknown content type 10395 error.unexpectedCase(); 10396 } 10397 if (item.parentSub) { 10398 item.parentSub = map.setIfUndefined(mapKeyCache, item.parentSub, () => i + ''); 10399 } 10400 i++; 10401 return block 10402 } 10403 default: 10404 // unknown block-type 10405 error.unexpectedCase(); 10406 } 10407 } 10408}; 10409 10410/** 10411 * This function obfuscates the content of a Yjs update. This is useful to share 10412 * buggy Yjs documents while significantly limiting the possibility that a 10413 * developer can on the user. Note that it might still be possible to deduce 10414 * some information by analyzing the "structure" of the document or by analyzing 10415 * the typing behavior using the CRDT-related metadata that is still kept fully 10416 * intact. 10417 * 10418 * @param {Uint8Array} update 10419 * @param {ObfuscatorOptions} [opts] 10420 */ 10421const obfuscateUpdate = (update, opts) => convertUpdateFormat(update, createObfuscator(opts), UpdateDecoderV1, UpdateEncoderV1); 10422 10423/** 10424 * @param {Uint8Array} update 10425 * @param {ObfuscatorOptions} [opts] 10426 */ 10427const obfuscateUpdateV2 = (update, opts) => convertUpdateFormat(update, createObfuscator(opts), UpdateDecoderV2, UpdateEncoderV2); 10428 10429/** 10430 * @param {Uint8Array} update 10431 */ 10432const convertUpdateFormatV1ToV2 = update => convertUpdateFormat(update, f.id, UpdateDecoderV1, UpdateEncoderV2); 10433 10434/** 10435 * @param {Uint8Array} update 10436 */ 10437const convertUpdateFormatV2ToV1 = update => convertUpdateFormat(update, id, UpdateDecoderV2, UpdateEncoderV1); 10438 10439const errorComputeChanges = 'You must not compute changes after the event-handler fired.'; 10440 10441/** 10442 * @template {AbstractType<any>} T 10443 * YEvent describes the changes on a YType. 10444 */ 10445class YEvent { 10446 /** 10447 * @param {T} target The changed type. 10448 * @param {Transaction} transaction 10449 */ 10450 constructor (target, transaction) { 10451 /** 10452 * The type on which this event was created on. 10453 * @type {T} 10454 */ 10455 this.target = target; 10456 /** 10457 * The current target on which the observe callback is called. 10458 * @type {AbstractType<any>} 10459 */ 10460 this.currentTarget = target; 10461 /** 10462 * The transaction that triggered this event. 10463 * @type {Transaction} 10464 */ 10465 this.transaction = transaction; 10466 /** 10467 * @type {Object|null} 10468 */ 10469 this._changes = null; 10470 /** 10471 * @type {null | Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>} 10472 */ 10473 this._keys = null; 10474 /** 10475 * @type {null | Array<{ insert?: string | Array<any> | object | AbstractType<any>, retain?: number, delete?: number, attributes?: Object<string, any> }>} 10476 */ 10477 this._delta = null; 10478 /** 10479 * @type {Array<string|number>|null} 10480 */ 10481 this._path = null; 10482 } 10483 10484 /** 10485 * Computes the path from `y` to the changed type. 10486 * 10487 * @todo v14 should standardize on path: Array<{parent, index}> because that is easier to work with. 10488 * 10489 * The following property holds: 10490 * @example 10491 * let type = y 10492 * event.path.forEach(dir => { 10493 * type = type.get(dir) 10494 * }) 10495 * type === event.target // => true 10496 */ 10497 get path () { 10498 return this._path || (this._path = getPathTo(this.currentTarget, this.target)) 10499 } 10500 10501 /** 10502 * Check if a struct is deleted by this event. 10503 * 10504 * In contrast to change.deleted, this method also returns true if the struct was added and then deleted. 10505 * 10506 * @param {AbstractStruct} struct 10507 * @return {boolean} 10508 */ 10509 deletes (struct) { 10510 return isDeleted(this.transaction.deleteSet, struct.id) 10511 } 10512 10513 /** 10514 * @type {Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>} 10515 */ 10516 get keys () { 10517 if (this._keys === null) { 10518 if (this.transaction.doc._transactionCleanups.length === 0) { 10519 throw error_create(errorComputeChanges) 10520 }
10521 const keys = new Map(); 10522 const target = this.target; 10523 const changed = /** @type Set<string|null> */ (this.transaction.changed.get(target)); 10524 changed.forEach(key => { 10525 if (key !== null) { 10526 const item = /** @type {Item} */ (target._map.get(key)); 10527 /** 10528 * @type {'delete' | 'add' | 'update'} 10529 */ 10530 let action; 10531 let oldValue; 10532 if (this.adds(item)) { 10533 let prev = item.left; 10534 while (prev !== null && this.adds(prev)) { 10535 prev = prev.left; 10536 } 10537 if (this.deletes(item)) { 10538 if (prev !== null && this.deletes(prev)) { 10539 action = 'delete'; 10540 oldValue = last(prev.content.getContent()); 10541 } else { 10542 return 10543 } 10544 } else { 10545 if (prev !== null && this.deletes(prev)) { 10546 action = 'update'; 10547 oldValue = last(prev.content.getContent()); 10548 } else { 10549 action = 'add'; 10550 oldValue = undefined; 10551 } 10552 } 10553 } else { 10554 if (this.deletes(item)) { 10555 action = 'delete'; 10556 oldValue = last(/** @type {Item} */ item.content.getContent()); 10557 } else { 10558 return // nop 10559 } 10560 } 10561 keys.set(key, { action, oldValue }); 10562 } 10563 }); 10564 this._keys = keys; 10565 } 10566 return this._keys 10567 } 10568 10569 /** 10570 * This is a computed property. Note that this can only be safely computed during the 10571 * event call. Computing this property after other changes happened might result in 10572 * unexpected behavior (incorrect computation of deltas). A safe way to collect changes 10573 * is to store the `changes` or the `delta` object. Avoid storing the `transaction` object. 10574 * 10575 * @type {Array<{insert?: string | Array<any> | object | AbstractType<any>, retain?: number, delete?: number, attributes?: Object<string, any>}>} 10576 */ 10577 get delta () { 10578 return this.changes.delta 10579 } 10580 10581 /** 10582 * Check if a struct is added by this event. 10583 * 10584 * In contrast to change.deleted, this method also returns true if the struct was added and then deleted. 10585 * 10586 * @param {AbstractStruct} struct 10587 * @return {boolean} 10588 */ 10589 adds (struct) { 10590 return struct.id.clock >= (this.transaction.beforeState.get(struct.id.client) || 0) 10591 } 10592 10593 /** 10594 * This is a computed property. Note that this can only be safely computed during the 10595 * event call. Computing this property after other changes happened might result in 10596 * unexpected behavior (incorrect computation of deltas). A safe way to collect changes 10597 * is to store the `changes` or the `delta` object. Avoid storing the `transaction` object. 10598 * 10599 * @type {{added:Set<Item>,deleted:Set<Item>,keys:Map<string,{action:'add'|'update'|'delete',oldValue:any}>,delta:Array<{insert?:Array<any>|string, delete?:number, retain?:number}>}} 10600 */ 10601 get changes () {
10602 let changes = this._changes; 10603 if (changes === null) { 10604 if (this.transaction.doc._transactionCleanups.length === 0) { 10605 throw error_create(errorComputeChanges) 10606 } 10607 const target = this.target; 10608 const added = set_create(); 10609 const deleted = set_create(); 10610 /** 10611 * @type {Array<{insert:Array<any>}|{delete:number}|{retain:number}>} 10612 */ 10613 const delta = []; 10614 changes = { 10615 added, 10616 deleted, 10617 delta, 10618 keys: this.keys 10619 }; 10620 const changed = /** @type Set<string|null> */ (this.transaction.changed.get(target)); 10621 if (changed.has(null)) { 10622 /** 10623 * @type {any} 10624 */ 10625 let lastOp = null; 10626 const packOp = () => { 10627 if (lastOp) { 10628 delta.push(lastOp); 10629 } 10630 }; 10631 for (let item = target._start; item !== null; item = item.right) { 10632 if (item.deleted) { 10633 if (this.deletes(item) && !this.adds(item)) { 10634 if (lastOp === null || lastOp.delete === undefined) { 10635 packOp(); 10636 lastOp = { delete: 0 }; 10637 } 10638 lastOp.delete += item.length; 10639 deleted.add(item); 10640 } // else nop 10641 } else { 10642 if (this.adds(item)) { 10643 if (lastOp === null || lastOp.insert === undefined) { 10644 packOp(); 10645 lastOp = { insert: [] }; 10646 } 10647 lastOp.insert = lastOp.insert.concat(item.content.getContent()); 10648 added.add(item); 10649 } else { 10650 if (lastOp === null || lastOp.retain === undefined) { 10651 packOp(); 10652 lastOp = { retain: 0 }; 10653 } 10654 lastOp.retain += item.length; 10655 } 10656 } 10657 } 10658 if (lastOp !== null && lastOp.retain === undefined) { 10659 packOp(); 10660 } 10661 } 10662 this._changes = changes; 10663 } 10664 return /** @type {any} */ (changes) 10665 } 10666} 10667 10668/** 10669 * Compute the path from this type to the specified target. 10670 * 10671 * @example 10672 * // `child` should be accessible via `type.get(path[0]).get(path[1])..` 10673 * const path = type.getPathTo(child) 10674 * // assuming `type instanceof YArray` 10675 * console.log(path) // might look like => [2, 'key1'] 10676 * child === type.get(path[0]).get(path[1]) 10677 * 10678 * @param {AbstractType<any>} parent 10679 * @param {AbstractType<any>} child target 10680 * @return {Array<string|number>} Path to the target 10681 * 10682 * @private 10683 * @function 10684 */ 10685const getPathTo = (parent, child) => { 10686 const path = []; 10687 while (child._item !== null && child !== parent) { 10688 if (child._item.parentSub !== null) { 10689 // parent is map-ish 10690 path.unshift(child._item.parentSub); 10691 } else { 10692 // parent is array-ish 10693 let i = 0; 10694 let c = /** @type {AbstractType<any>} */ (child._item.parent)._start; 10695 while (c !== child._item && c !== null) { 10696 if (!c.deleted) { 10697 i++; 10698 } 10699 c = c.right; 10700 } 10701 path.unshift(i); 10702 } 10703 child = /** @type {AbstractType<any>} */ (child._item.parent); 10704 } 10705 return path 10706}; 10707 10708const maxSearchMarker = 80; 10709 10710/** 10711 * A unique timestamp that identifies each marker. 10712 * 10713 * Time is relative,.. this is more like an ever-increasing clock. 10714 * 10715 * @type {number} 10716 */ 10717let globalSearchMarkerTimestamp = 0; 10718 10719class ArraySearchMarker { 10720 /** 10721 * @param {Item} p 10722 * @param {number} index 10723 */ 10724 constructor (p, index) { 10725 p.marker = true; 10726 this.p = p; 10727 this.index = index; 10728 this.timestamp = globalSearchMarkerTimestamp++; 10729 } 10730} 10731 10732/** 10733 * @param {ArraySearchMarker} marker 10734 */ 10735const refreshMarkerTimestamp = marker => { marker.timestamp = globalSearchMarkerTimestamp++; }; 10736 10737/** 10738 * This is rather complex so this function is the only thing that should overwrite a marker 10739 * 10740 * @param {ArraySearchMarker} marker 10741 * @param {Item} p 10742 * @param {number} index 10743 */ 10744const overwriteMarker = (marker, p, index) => { 10745 marker.p.marker = false;
10746 marker.p = p; 10747 p.marker = true; 10748 marker.index = index; 10749 marker.timestamp = globalSearchMarkerTimestamp++; 10750}; 10751 10752/** 10753 * @param {Array<ArraySearchMarker>} searchMarker 10754 * @param {Item} p 10755 * @param {number} index 10756 */ 10757const markPosition = (searchMarker, p, index) => { 10758 if (searchMarker.length >= maxSearchMarker) { 10759 // override oldest marker (we don't want to create more objects) 10760 const marker = searchMarker.reduce((a, b) => a.timestamp < b.timestamp ? a : b); 10761 overwriteMarker(marker, p, index); 10762 return marker 10763 } else { 10764 // create new marker 10765 const pm = new ArraySearchMarker(p, index); 10766 searchMarker.push(pm); 10767 return pm 10768 } 10769}; 10770 10771/** 10772 * Search marker help us to find positions in the associative array faster. 10773 * 10774 * They speed up the process of finding a position without much bookkeeping. 10775 * 10776 * A maximum of `maxSearchMarker` objects are created. 10777 * 10778 * This function always returns a refreshed marker (updated timestamp) 10779 * 10780 * @param {AbstractType<any>} yarray 10781 * @param {number} index 10782 */ 10783const findMarker = (yarray, index) => { 10784 if (yarray._start === null || index === 0 || yarray._searchMarker === null) { 10785 return null 10786 } 10787 const marker = yarray._searchMarker.length === 0 ? null : yarray._searchMarker.reduce((a, b) => abs(index - a.index) < abs(index - b.index) ? a : b); 10788 let p = yarray._start; 10789 let pindex = 0; 10790 if (marker !== null) { 10791 p = marker.p; 10792 pindex = marker.index; 10793 refreshMarkerTimestamp(marker); // we used it, we might need to use it again 10794 } 10795 // iterate to right if possible 10796 while (p.right !== null && pindex < index) { 10797 if (!p.deleted && p.countable) { 10798 if (index < pindex + p.length) { 10799 break 10800 } 10801 pindex += p.length; 10802 } 10803 p = p.right; 10804 } 10805 // iterate to left if necessary (might be that pindex > index) 10806 while (p.left !== null && pindex > index) { 10807 p = p.left; 10808 if (!p.deleted && p.countable) { 10809 pindex -= p.length; 10810 } 10811 } 10812 // we want to make sure that p can't be merged with left, because that would screw up everything 10813 // in that cas just return what we have (it is most likely the best marker anyway) 10814 // iterate to left until p can't be merged with left 10815 while (p.left !== null && p.left.id.client === p.id.client && p.left.id.clock + p.left.length === p.id.clock) { 10816 p = p.left; 10817 if (!p.deleted && p.countable) { 10818 pindex -= p.length; 10819 } 10820 } 10821 10822 // @todo remove! 10823 // assure position 10824 // { 10825 // let start = yarray._start 10826 // let pos = 0 10827 // while (start !== p) { 10828 // if (!start.deleted && start.countable) { 10829 // pos += start.length 10830 // } 10831 // start = /** @type {Item} */ (start.right) 10832 // } 10833 // if (pos !== pindex) { 10834 // debugger 10835 // throw new Error('Gotcha position fail!') 10836 // } 10837 // } 10838 // if (marker) { 10839 // if (window.lengthes == null) { 10840 // window.lengthes = [] 10841 // window.getLengthes = () => window.lengthes.sort((a, b) => a - b) 10842 // } 10843 // window.lengthes.push(marker.index - pindex) 10844 // console.log('distance', marker.index - pindex, 'len', p && p.parent.length) 10845 // } 10846 if (marker !== null && abs(marker.index - pindex) < /** @type {YText|YArray<any>} */ (p.parent).length / maxSearchMarker) { 10847 // adjust existing marker 10848 overwriteMarker(marker, p, pindex); 10849 return marker 10850 } else { 10851 // create new marker 10852 return markPosition(yarray._searchMarker, p, pindex) 10853 } 10854}; 10855 10856/** 10857 * Update markers when a change happened.
10858 * 10859 * This should be called before doing a deletion! 10860 * 10861 * @param {Array<ArraySearchMarker>} searchMarker 10862 * @param {number} index 10863 * @param {number} len If insertion, len is positive. If deletion, len is negative. 10864 */ 10865const updateMarkerChanges = (searchMarker, index, len) => { 10866 for (let i = searchMarker.length - 1; i >= 0; i--) { 10867 const m = searchMarker[i]; 10868 if (len > 0) { 10869 /** 10870 * @type {Item|null} 10871 */ 10872 let p = m.p; 10873 p.marker = false; 10874 // Ideally we just want to do a simple position comparison, but this will only work if 10875 // search markers don't point to deleted items for formats. 10876 // Iterate marker to prev undeleted countable position so we know what to do when updating a position 10877 while (p && (p.deleted || !p.countable)) { 10878 p = p.left; 10879 if (p && !p.deleted && p.countable) { 10880 // adjust position. the loop should break now 10881 m.index -= p.length; 10882 } 10883 } 10884 if (p === null || p.marker === true) { 10885 // remove search marker if updated position is null or if position is already marked 10886 searchMarker.splice(i, 1); 10887 continue 10888 } 10889 m.p = p; 10890 p.marker = true; 10891 } 10892 if (index < m.index || (len > 0 && index === m.index)) { // a simple index <= m.index check would actually suffice 10893 m.index = max(index, m.index + len); 10894 } 10895 } 10896}; 10897 10898/** 10899 * Accumulate all (list) children of a type and return them as an Array. 10900 * 10901 * @param {AbstractType<any>} t 10902 * @return {Array<Item>} 10903 */ 10904const getTypeChildren = t => { 10905 let s = t._start; 10906 const arr = []; 10907 while (s) { 10908 arr.push(s); 10909 s = s.right; 10910 } 10911 return arr 10912}; 10913 10914/** 10915 * Call event listeners with an event. This will also add an event to all 10916 * parents (for `.observeDeep` handlers). 10917 * 10918 * @template EventType 10919 * @param {AbstractType<EventType>} type 10920 * @param {Transaction} transaction 10921 * @param {EventType} event 10922 */ 10923const callTypeObservers = (type, transaction, event) => { 10924 const changedType = type; 10925 const changedParentTypes = transaction.changedParentTypes; 10926 while (true) { 10927 // @ts-ignore 10928 setIfUndefined(changedParentTypes, type, () => []).push(event); 10929 if (type._item === null) { 10930 break 10931 } 10932 type = /** @type {AbstractType<any>} */ (type._item.parent); 10933 } 10934 callEventHandlerListeners(changedType._eH, event, transaction); 10935}; 10936 10937/** 10938 * @template EventType 10939 * Abstract Yjs Type class 10940 */ 10941class AbstractType { 10942 constructor () { 10943 /** 10944 * @type {Item|null} 10945 */ 10946 this._item = null; 10947 /** 10948 * @type {Map<string,Item>} 10949 */ 10950 this._map = new Map(); 10951 /** 10952 * @type {Item|null} 10953 */ 10954 this._start = null; 10955 /** 10956 * @type {Doc|null} 10957 */ 10958 this.doc = null; 10959 this._length = 0; 10960 /** 10961 * Event handlers 10962 * @type {EventHandler<EventType,Transaction>} 10963 */ 10964 this._eH = createEventHandler(); 10965 /** 10966 * Deep event handlers 10967 * @type {EventHandler<Array<YEvent<any>>,Transaction>} 10968 */ 10969 this._dEH = createEventHandler(); 10970 /** 10971 * @type {null | Array<ArraySearchMarker>} 10972 */ 10973 this._searchMarker = null; 10974 } 10975 10976 /** 10977 * @return {AbstractType<any>|null} 10978 */ 10979 get parent () { 10980 return this._item ? /** @type {AbstractType<any>} */ (this._item.parent) : null 10981 } 10982 10983 /** 10984 * Integrate this type into the Yjs instance. 10985 * 10986 * * Save this struct in the os 10987 * * This type is sent to other client 10988 * * Observer functions are fired 10989 * 10990 * @param {Doc} y The Yjs instance 10991 * @param {Item|null} item 10992 */ 10993 _integrate (y, item) { 10994 this.doc = y; 10995 this._item = item; 10996 } 10997 10998 /** 10999 * @return {AbstractType<EventType>} 11000 */ 11001 _copy () { 11002 throw methodUnimplemented() 11003 } 11004 11005 /** 11006 * @return {AbstractType<EventType>} 11007 */ 11008 clone () { 11009 throw methodUnimplemented() 11010 } 11011 11012 /** 11013 * @param {UpdateEncoderV1 | UpdateEncoderV2} _encoder 11014 */ 11015 _write (_encoder) { } 11016 11017 /** 11018 * The first non-deleted item 11019 */ 11020 get _first () { 11021 let n = this._start; 11022 while (n !== null && n.deleted) { 11023 n = n.right; 11024 } 11025 return n 11026 } 11027 11028 /** 11029 * Creates YEvent and calls all type observers. 11030 * Must be implemented by each type. 11031 * 11032 * @param {Transaction} transaction 11033 * @param {Set<null|string>} _parentSubs Keys changed on this type. `null` if list was modified. 11034 */ 11035 _callObserver (transaction, _parentSubs) { 11036 if (!transaction.local && this._searchMarker) { 11037 this._searchMarker.length = 0; 11038 } 11039 } 11040 11041 /** 11042 * Observe all events that are created on this type. 11043 * 11044 * @param {function(EventType, Transaction):void} f Observer function 11045 */ 11046 observe (f) { 11047 addEventHandlerListener(this._eH, f); 11048 } 11049 11050 /** 11051 * Observe all events that are created by this type and its children. 11052 * 11053 * @param {function(Array<YEvent<any>>,Transaction):void} f Observer function 11054 */ 11055 observeDeep (f) { 11056 addEventHandlerListener(this._dEH, f); 11057 } 11058 11059 /** 11060 * Unregister an observer function. 11061 * 11062 * @param {function(EventType,Transaction):void} f Observer function 11063 */ 11064 unobserve (f) { 11065 removeEventHandlerListener(this._eH, f); 11066 } 11067 11068 /** 11069 * Unregister an observer function. 11070 * 11071 * @param {function(Array<YEvent<any>>,Transaction):void} f Observer function 11072 */ 11073 unobserveDeep (f) { 11074 removeEventHandlerListener(this._dEH, f); 11075 } 11076 11077 /** 11078 * @abstract 11079 * @return {any} 11080 */ 11081 toJSON () {} 11082} 11083 11084/** 11085 * @param {AbstractType<any>} type 11086 * @param {number} start 11087 * @param {number} end 11088 * @return {Array<any>} 11089 * 11090 * @private 11091 * @function 11092 */ 11093const typeListSlice = (type, start, end) => { 11094 if (start < 0) { 11095 start = type._length + start; 11096 } 11097 if (end < 0) { 11098 end = type._length + end; 11099 } 11100 let len = end - start; 11101 const cs = []; 11102 let n = type._start; 11103 while (n !== null && len > 0) { 11104 if (n.countable && !n.deleted) { 11105 const c = n.content.getContent(); 11106 if (c.length <= start) { 11107 start -= c.length; 11108 } else { 11109 for (let i = start; i < c.length && len > 0; i++) { 11110 cs.push(c[i]); 11111 len--; 11112 } 11113 start = 0; 11114 } 11115 } 11116 n = n.right; 11117 } 11118 return cs 11119}; 11120 11121/** 11122 * @param {AbstractType<any>} type 11123 * @return {Array<any>} 11124 * 11125 * @private 11126 * @function 11127 */ 11128const typeListToArray = type => { 11129 const cs = []; 11130 let n = type._start; 11131 while (n !== null) { 11132 if (n.countable && !n.deleted) { 11133 const c = n.content.getContent(); 11134 for (let i = 0; i < c.length; i++) { 11135 cs.push(c[i]); 11136 } 11137 } 11138 n = n.right; 11139 } 11140 return cs 11141}; 11142 11143/** 11144 * @param {AbstractType<any>} type 11145 * @param {Snapshot} snapshot 11146 * @return {Array<any>} 11147 * 11148 * @private 11149 * @function 11150 */ 11151const typeListToArraySnapshot = (type, snapshot) => { 11152 const cs = []; 11153 let n = type._start; 11154 while (n !== null) { 11155 if (n.countable && isVisible(n, snapshot)) { 11156 const c = n.content.getContent(); 11157 for (let i = 0; i < c.length; i++) { 11158 cs.push(c[i]); 11159 } 11160 } 11161 n = n.right; 11162 } 11163 return cs 11164}; 11165 11166/** 11167 * Executes a provided function on once on overy element of this YArray. 11168 * 11169 * @param {AbstractType<any>} type 11170 * @param {function(any,number,any):void} f A function to execute on every element of this YArray. 11171 * 11172 * @private 11173 * @function 11174 */ 11175const typeListForEach = (type, f) => { 11176 let index = 0; 11177 let n = type._start; 11178 while (n !== null) { 11179 if (n.countable && !n.deleted) { 11180 const c = n.content.getContent(); 11181 for (let i = 0; i < c.length; i++) { 11182 f(c[i], index++, type); 11183 } 11184 } 11185 n = n.right; 11186 } 11187}; 11188 11189/** 11190 * @template C,R 11191 * @param {AbstractType<any>} type 11192 * @param {function(C,number,AbstractType<any>):R} f 11193 * @return {Array<R>} 11194 * 11195 * @private 11196 * @function 11197 */ 11198const typeListMap = (type, f) => { 11199 /** 11200 * @type {Array<any>} 11201 */ 11202 const result = []; 11203 typeListForEach(type, (c, i) => { 11204 result.push(f(c, i, type)); 11205 }); 11206 return result 11207}; 11208 11209/** 11210 * @param {AbstractType<any>} type
11211 * @return {IterableIterator<any>} 11212 * 11213 * @private 11214 * @function 11215 */ 11216const typeListCreateIterator = type => { 11217 let n = type._start; 11218 /** 11219 * @type {Array<any>|null} 11220 */ 11221 let currentContent = null; 11222 let currentContentIndex = 0; 11223 return { 11224 [Symbol.iterator] () { 11225 return this 11226 }, 11227 next: () => { 11228 // find some content 11229 if (currentContent === null) { 11230 while (n !== null && n.deleted) { 11231 n = n.right; 11232 } 11233 // check if we reached the end, no need to check currentContent, because it does not exist 11234 if (n === null) { 11235 return { 11236 done: true, 11237 value: undefined 11238 } 11239 } 11240 // we found n, so we can set currentContent 11241 currentContent = n.content.getContent(); 11242 currentContentIndex = 0; 11243 n = n.right; // we used the content of n, now iterate to next 11244 } 11245 const value = currentContent[currentContentIndex++]; 11246 // check if we need to empty currentContent 11247 if (currentContent.length <= currentContentIndex) { 11248 currentContent = null; 11249 } 11250 return { 11251 done: false, 11252 value 11253 } 11254 } 11255 } 11256}; 11257 11258/** 11259 * @param {AbstractType<any>} type 11260 * @param {number} index 11261 * @return {any} 11262 * 11263 * @private 11264 * @function 11265 */ 11266const typeListGet = (type, index) => { 11267 const marker = findMarker(type, index); 11268 let n = type._start; 11269 if (marker !== null) { 11270 n = marker.p; 11271 index -= marker.index; 11272 } 11273 for (; n !== null; n = n.right) { 11274 if (!n.deleted && n.countable) { 11275 if (index < n.length) { 11276 return n.content.getContent()[index] 11277 } 11278 index -= n.length; 11279 } 11280 } 11281}; 11282 11283/** 11284 * @param {Transaction} transaction 11285 * @param {AbstractType<any>} parent 11286 * @param {Item?} referenceItem 11287 * @param {Array<Object<string,any>|Array<any>|boolean|number|null|string|Uint8Array>} content 11288 * 11289 * @private 11290 * @function 11291 */ 11292const typeListInsertGenericsAfter = (transaction, parent, referenceItem, content) => { 11293 let left = referenceItem; 11294 const doc = transaction.doc; 11295 const ownClientId = doc.clientID; 11296 const store = doc.store; 11297 const right = referenceItem === null ? parent._start : referenceItem.right; 11298 /** 11299 * @type {Array<Object|Array<any>|number|null>} 11300 */ 11301 let jsonContent = []; 11302 const packJsonContent = () => { 11303 if (jsonContent.length > 0) { 11304 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentAny(jsonContent)); 11305 left.integrate(transaction, 0); 11306 jsonContent = []; 11307 } 11308 }; 11309 content.forEach(c => { 11310 if (c === null) { 11311 jsonContent.push(c); 11312 } else { 11313 switch (c.constructor) { 11314 case Number: 11315 case Object: 11316 case Boolean: 11317 case Array: 11318 case String: 11319 jsonContent.push(c); 11320 break 11321 default: 11322 packJsonContent(); 11323 switch (c.constructor) { 11324 case Uint8Array: 11325 case ArrayBuffer: 11326 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentBinary(new Uint8Array(/** @type {Uint8Array} */ (c)))); 11327 left.integrate(transaction, 0); 11328 break 11329 case Doc: 11330 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentDoc(/** @type {Doc} */ (c))); 11331 left.integrate(transaction, 0); 11332 break 11333 default: 11334 if (c instanceof AbstractType) { 11335 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentType(c)); 11336 left.integrate(transaction, 0); 11337 } else { 11338 throw new Error('Unexpected content type in insert operation') 11339 } 11340 } 11341 } 11342 } 11343 }); 11344 packJsonContent(); 11345}; 11346 11347const lengthExceeded = error_create('Length exceeded!'); 11348 11349/** 11350 * @param {Transaction} transaction 11351 * @param {AbstractType<any>} parent 11352 * @param {number} index 11353 * @param {Array<Object<string,any>|Array<any>|number|null|string|Uint8Array>} content 11354 * 11355 * @private 11356 * @function 11357 */ 11358const typeListInsertGenerics = (transaction, parent, index, content) => { 11359 if (index > parent._length) { 11360 throw lengthExceeded 11361 } 11362 if (index === 0) { 11363 if (parent._searchMarker) { 11364 updateMarkerChanges(parent._searchMarker, index, content.length); 11365 } 11366 return typeListInsertGenericsAfter(transaction, parent, null, content) 11367 } 11368 const startIndex = index; 11369 const marker = findMarker(parent, index); 11370 let n = parent._start; 11371 if (marker !== null) { 11372 n = marker.p; 11373 index -= marker.index; 11374 // we need to iterate one to the left so that the algorithm works 11375 if (index === 0) { 11376 // @todo refactor this as it actually doesn't consider formats 11377 n = n.prev; // important! get the left undeleted item so that we can actually decrease index 11378 index += (n && n.countable && !n.deleted) ? n.length : 0; 11379 } 11380 } 11381 for (; n !== null; n = n.right) { 11382 if (!n.deleted && n.countable) { 11383 if (index <= n.length) { 11384 if (index < n.length) { 11385 // insert in-between 11386 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + index)); 11387 } 11388 break 11389 } 11390 index -= n.length; 11391 } 11392 } 11393 if (parent._searchMarker) { 11394 updateMarkerChanges(parent._searchMarker, startIndex, content.length); 11395 } 11396 return typeListInsertGenericsAfter(transaction, parent, n, content) 11397}; 11398 11399/** 11400 * Pushing content is special as we generally want to push after the last item. So we don't have to update 11401 * the serach marker. 11402 * 11403 * @param {Transaction} transaction 11404 * @param {AbstractType<any>} parent 11405 * @param {Array<Object<string,any>|Array<any>|number|null|string|Uint8Array>} content 11406 * 11407 * @private 11408 * @function 11409 */ 11410const typeListPushGenerics = (transaction, parent, content) => { 11411 // Use the marker with the highest index and iterate to the right. 11412 const marker = (parent._searchMarker || []).reduce((maxMarker, currMarker) => currMarker.index > maxMarker.index ? currMarker : maxMarker, { index: 0, p: parent._start }); 11413 let n = marker.p; 11414 if (n) { 11415 while (n.right) { 11416 n = n.right; 11417 } 11418 } 11419 return typeListInsertGenericsAfter(transaction, parent, n, content) 11420}; 11421 11422/** 11423 * @param {Transaction} transaction 11424 * @param {AbstractType<any>} parent 11425 * @param {number} index 11426 * @param {number} length 11427 * 11428 * @private 11429 * @function 11430 */ 11431const typeListDelete = (transaction, parent, index, length) => { 11432 if (length === 0) { return } 11433 const startIndex = index; 11434 const startLength = length; 11435 const marker = findMarker(parent, index); 11436 let n = parent._start; 11437 if (marker !== null) { 11438 n = marker.p; 11439 index -= marker.index; 11440 } 11441 // compute the first item to be deleted 11442 for (; n !== null && index > 0; n = n.right) { 11443 if (!n.deleted && n.countable) { 11444 if (index < n.length) { 11445 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + index)); 11446 } 11447 index -= n.length; 11448 } 11449 } 11450 // delete all items until done 11451 while (length > 0 && n !== null) { 11452 if (!n.deleted) { 11453 if (length < n.length) { 11454 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + length)); 11455 } 11456 n.delete(transaction); 11457 length -= n.length; 11458 } 11459 n = n.right; 11460 } 11461 if (length > 0) { 11462 throw lengthExceeded 11463 } 11464 if (parent._searchMarker) { 11465 updateMarkerChanges(parent._searchMarker, startIndex, -startLength + length /* in case we remove the above exception */); 11466 } 11467}; 11468 11469/** 11470 * @param {Transaction} transaction 11471 * @param {AbstractType<any>} parent 11472 * @param {string} key 11473 * 11474 * @private 11475 * @function 11476 */ 11477const typeMapDelete = (transaction, parent, key) => { 11478 const c = parent._map.get(key); 11479 if (c !== undefined) { 11480 c.delete(transaction); 11481 } 11482}; 11483 11484/** 11485 * @param {Transaction} transaction 11486 * @param {AbstractType<any>} parent 11487 * @param {string} key 11488 * @param {Object|number|null|Array<any>|string|Uint8Array|AbstractType<any>} value 11489 * 11490 * @private 11491 * @function 11492 */ 11493const typeMapSet = (transaction, parent, key, value) => { 11494 const left = parent._map.get(key) || null; 11495 const doc = transaction.doc; 11496 const ownClientId = doc.clientID; 11497 let content; 11498 if (value == null) { 11499 content = new ContentAny([value]); 11500 } else { 11501 switch (value.constructor) { 11502 case Number: 11503 case Object: 11504 case Boolean: 11505 case Array: 11506 case String: 11507 content = new ContentAny([value]); 11508 break 11509 case Uint8Array: 11510 content = new ContentBinary(/** @type {Uint8Array} */ (value)); 11511 break 11512 case Doc: 11513 content = new ContentDoc(/** @type {Doc} */ (value)); 11514 break 11515 default: 11516 if (value instanceof AbstractType) { 11517 content = new ContentType(value); 11518 } else { 11519 throw new Error('Unexpected content type') 11520 } 11521 } 11522 } 11523 new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, null, null, parent, key, content).integrate(transaction, 0); 11524}; 11525 11526/** 11527 * @param {AbstractType<any>} parent 11528 * @param {string} key 11529 * @return {Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined} 11530 * 11531 * @private 11532 * @function 11533 */ 11534const typeMapGet = (parent, key) => { 11535 const val = parent._map.get(key); 11536 return val !== undefined && !val.deleted ? val.content.getContent()[val.length - 1] : undefined 11537}; 11538 11539/** 11540 * @param {AbstractType<any>} parent 11541 * @return {Object<string,Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined>} 11542 * 11543 * @private 11544 * @function 11545 */ 11546const typeMapGetAll = (parent) => { 11547 /** 11548 * @type {Object<string,any>} 11549 */ 11550 const res = {};
11551 parent._map.forEach((value, key) => { 11552 if (!value.deleted) { 11553 res[key] = value.content.getContent()[value.length - 1]; 11554 } 11555 }); 11556 return res 11557}; 11558 11559/** 11560 * @param {AbstractType<any>} parent 11561 * @param {string} key 11562 * @return {boolean} 11563 * 11564 * @private 11565 * @function 11566 */ 11567const typeMapHas = (parent, key) => { 11568 const val = parent._map.get(key); 11569 return val !== undefined && !val.deleted 11570}; 11571 11572/** 11573 * @param {AbstractType<any>} parent 11574 * @param {string} key 11575 * @param {Snapshot} snapshot 11576 * @return {Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined} 11577 * 11578 * @private 11579 * @function 11580 */ 11581const typeMapGetSnapshot = (parent, key, snapshot) => { 11582 let v = parent._map.get(key) || null; 11583 while (v !== null && (!snapshot.sv.has(v.id.client) || v.id.clock >= (snapshot.sv.get(v.id.client) || 0))) { 11584 v = v.left; 11585 } 11586 return v !== null && isVisible(v, snapshot) ? v.content.getContent()[v.length - 1] : undefined 11587}; 11588 11589/** 11590 * @param {Map<string,Item>} map 11591 * @return {IterableIterator<Array<any>>} 11592 * 11593 * @private 11594 * @function 11595 */ 11596const createMapIterator = map => iteratorFilter(map.entries(), /** @param {any} entry */ entry => !entry[1].deleted); 11597 11598/** 11599 * @module YArray 11600 */ 11601 11602/** 11603 * Event that describes the changes on a YArray 11604 * @template T 11605 * @extends YEvent<YArray<T>> 11606 */ 11607class YArrayEvent extends YEvent { 11608 /** 11609 * @param {YArray<T>} yarray The changed type 11610 * @param {Transaction} transaction The transaction object 11611 */ 11612 constructor (yarray, transaction) { 11613 super(yarray, transaction); 11614 this._transaction = transaction; 11615 } 11616} 11617 11618/** 11619 * A shared Array implementation. 11620 * @template T 11621 * @extends AbstractType<YArrayEvent<T>> 11622 * @implements {Iterable<T>} 11623 */ 11624class YArray extends AbstractType { 11625 constructor () { 11626 super(); 11627 /** 11628 * @type {Array<any>?} 11629 * @private 11630 */ 11631 this._prelimContent = []; 11632 /** 11633 * @type {Array<ArraySearchMarker>} 11634 */ 11635 this._searchMarker = []; 11636 } 11637 11638 /** 11639 * Construct a new YArray containing the specified items. 11640 * @template {Object<string,any>|Array<any>|number|null|string|Uint8Array} T 11641 * @param {Array<T>} items 11642 * @return {YArray<T>} 11643 */ 11644 static from (items) { 11645 /** 11646 * @type {YArray<T>} 11647 */ 11648 const a = new YArray(); 11649 a.push(items); 11650 return a 11651 } 11652 11653 /** 11654 * Integrate this type into the Yjs instance. 11655 * 11656 * * Save this struct in the os 11657 * * This type is sent to other client 11658 * * Observer functions are fired 11659 * 11660 * @param {Doc} y The Yjs instance 11661 * @param {Item} item 11662 */ 11663 _integrate (y, item) { 11664 super._integrate(y, item); 11665 this.insert(0, /** @type {Array<any>} */ (this._prelimContent)); 11666 this._prelimContent = null; 11667 } 11668 11669 /** 11670 * @return {YArray<T>} 11671 */ 11672 _copy () { 11673 return new YArray() 11674 } 11675 11676 /** 11677 * @return {YArray<T>} 11678 */ 11679 clone () { 11680 /** 11681 * @type {YArray<T>} 11682 */ 11683 const arr = new YArray(); 11684 arr.insert(0, this.toArray().map(el => 11685 el instanceof AbstractType ? /** @type {typeof el} */ (el.clone()) : el 11686 )); 11687 return arr 11688 } 11689 11690 get length () { 11691 return this._prelimContent === null ? this._length : this._prelimContent.length 11692 } 11693 11694 /** 11695 * Creates YArrayEvent and calls observers. 11696 * 11697 * @param {Transaction} transaction 11698 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified. 11699 */ 11700 _callObserver (transaction, parentSubs) { 11701 super._callObserver(transaction, parentSubs); 11702 callTypeObservers(this, transaction, new YArrayEvent(this, transaction)); 11703 } 11704 11705 /** 11706 * Inserts new content at an index. 11707 * 11708 * Important: This function expects an array of content. Not just a content 11709 * object. The reason for this "weirdness" is that inserting several elements 11710 * is very efficient when it is done as a single operation. 11711 * 11712 * @example 11713 * // Insert character 'a' at position 0 11714 * yarray.insert(0, ['a']) 11715 * // Insert numbers 1, 2 at position 1 11716 * yarray.insert(1, [1, 2]) 11717 * 11718 * @param {number} index The index to insert content at. 11719 * @param {Array<T>} content The array of content 11720 */ 11721 insert (index, content) { 11722 if (this.doc !== null) { 11723 transact(this.doc, transaction => { 11724 typeListInsertGenerics(transaction, this, index, /** @type {any} */ (content)); 11725 }); 11726 } else { 11727 /** @type {Array<any>} */ (this._prelimContent).splice(index, 0, ...content); 11728 } 11729 } 11730 11731 /** 11732 * Appends content to this YArray. 11733 * 11734 * @param {Array<T>} content Array of content to append. 11735 * 11736 * @todo Use the following implementation in all types. 11737 */ 11738 push (content) { 11739 if (this.doc !== null) { 11740 transact(this.doc, transaction => { 11741 typeListPushGenerics(transaction, this, /** @type {any} */ (content)); 11742 }); 11743 } else { 11744 /** @type {Array<any>} */ (this._prelimContent).push(...content); 11745 } 11746 } 11747 11748 /** 11749 * Preppends content to this YArray. 11750 * 11751 * @param {Array<T>} content Array of content to preppend. 11752 */ 11753 unshift (content) { 11754 this.insert(0, content); 11755 } 11756 11757 /** 11758 * Deletes elements starting from an index. 11759 * 11760 * @param {number} index Index at which to start deleting elements 11761 * @param {number} length The number of elements to remove. Defaults to 1. 11762 */ 11763 delete (index, length = 1) { 11764 if (this.doc !== null) { 11765 transact(this.doc, transaction => { 11766 typeListDelete(transaction, this, index, length); 11767 }); 11768 } else { 11769 /** @type {Array<any>} */ (this._prelimContent).splice(index, length); 11770 } 11771 } 11772 11773 /** 11774 * Returns the i-th element from a YArray. 11775 * 11776 * @param {number} index The index of the element to return from the YArray 11777 * @return {T} 11778 */ 11779 get (index) { 11780 return typeListGet(this, index) 11781 } 11782 11783 /** 11784 * Transforms this YArray to a JavaScript Array. 11785 * 11786 * @return {Array<T>} 11787 */ 11788 toArray () { 11789 return typeListToArray(this) 11790 } 11791 11792 /** 11793 * Transforms this YArray to a JavaScript Array. 11794 * 11795 * @param {number} [start] 11796 * @param {number} [end] 11797 * @return {Array<T>} 11798 */ 11799 slice (start = 0, end = this.length) { 11800 return typeListSlice(this, start, end) 11801 } 11802 11803 /** 11804 * Transforms this Shared Type to a JSON object. 11805 * 11806 * @return {Array<any>} 11807 */ 11808 toJSON () { 11809 return this.map(c => c instanceof AbstractType ? c.toJSON() : c) 11810 } 11811 11812 /** 11813 * Returns an Array with the result of calling a provided function on every 11814 * element of this YArray. 11815 * 11816 * @template M 11817 * @param {function(T,number,YArray<T>):M} f Function that produces an element of the new Array 11818 * @return {Array<M>} A new array with each element being the result of the 11819 * callback function 11820 */ 11821 map (f) { 11822 return typeListMap(this, /** @type {any} */ (f)) 11823 } 11824 11825 /** 11826 * Executes a provided function once on overy element of this YArray. 11827 * 11828 * @param {function(T,number,YArray<T>):void} f A function to execute on every element of this YArray. 11829 */ 11830 forEach (f) { 11831 typeListForEach(this, f); 11832 } 11833 11834 /**
11835 * @return {IterableIterator<T>} 11836 */ 11837 [Symbol.iterator] () { 11838 return typeListCreateIterator(this) 11839 } 11840 11841 /** 11842 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 11843 */ 11844 _write (encoder) { 11845 encoder.writeTypeRef(YArrayRefID); 11846 } 11847} 11848 11849/** 11850 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder 11851 * 11852 * @private 11853 * @function 11854 */ 11855const readYArray = _decoder => new YArray(); 11856 11857/** 11858 * @template T 11859 * @extends YEvent<YMap<T>> 11860 * Event that describes the changes on a YMap. 11861 */ 11862class YMapEvent extends YEvent { 11863 /** 11864 * @param {YMap<T>} ymap The YArray that changed. 11865 * @param {Transaction} transaction 11866 * @param {Set<any>} subs The keys that changed. 11867 */ 11868 constructor (ymap, transaction, subs) { 11869 super(ymap, transaction); 11870 this.keysChanged = subs; 11871 } 11872} 11873 11874/** 11875 * @template MapType 11876 * A shared Map implementation. 11877 * 11878 * @extends AbstractType<YMapEvent<MapType>> 11879 * @implements {Iterable<MapType>} 11880 */ 11881class YMap extends AbstractType { 11882 /** 11883 * 11884 * @param {Iterable<readonly [string, any]>=} entries - an optional iterable to initialize the YMap 11885 */ 11886 constructor (entries) { 11887 super(); 11888 /** 11889 * @type {Map<string,any>?} 11890 * @private 11891 */ 11892 this._prelimContent = null; 11893 11894 if (entries === undefined) { 11895 this._prelimContent = new Map(); 11896 } else { 11897 this._prelimContent = new Map(entries); 11898 } 11899 } 11900 11901 /** 11902 * Integrate this type into the Yjs instance. 11903 * 11904 * * Save this struct in the os 11905 * * This type is sent to other client 11906 * * Observer functions are fired 11907 * 11908 * @param {Doc} y The Yjs instance 11909 * @param {Item} item 11910 */ 11911 _integrate (y, item) { 11912 super._integrate(y, item) 11913 ;/** @type {Map<string, any>} */ (this._prelimContent).forEach((value, key) => { 11914 this.set(key, value); 11915 }); 11916 this._prelimContent = null; 11917 } 11918 11919 /** 11920 * @return {YMap<MapType>} 11921 */ 11922 _copy () { 11923 return new YMap() 11924 } 11925 11926 /** 11927 * @return {YMap<MapType>} 11928 */ 11929 clone () { 11930 /** 11931 * @type {YMap<MapType>} 11932 */ 11933 const map = new YMap(); 11934 this.forEach((value, key) => { 11935 map.set(key, value instanceof AbstractType ? /** @type {typeof value} */ (value.clone()) : value); 11936 }); 11937 return map 11938 } 11939 11940 /** 11941 * Creates YMapEvent and calls observers. 11942 * 11943 * @param {Transaction} transaction 11944 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified. 11945 */ 11946 _callObserver (transaction, parentSubs) { 11947 callTypeObservers(this, transaction, new YMapEvent(this, transaction, parentSubs)); 11948 } 11949 11950 /** 11951 * Transforms this Shared Type to a JSON object. 11952 * 11953 * @return {Object<string,any>} 11954 */ 11955 toJSON () { 11956 /** 11957 * @type {Object<string,MapType>} 11958 */ 11959 const map = {}; 11960 this._map.forEach((item, key) => { 11961 if (!item.deleted) { 11962 const v = item.content.getContent()[item.length - 1]; 11963 map[key] = v instanceof AbstractType ? v.toJSON() : v; 11964 } 11965 }); 11966 return map 11967 } 11968 11969 /** 11970 * Returns the size of the YMap (count of key/value pairs) 11971 * 11972 * @return {number} 11973 */ 11974 get size () { 11975 return [...createMapIterator(this._map)].length 11976 } 11977 11978 /** 11979 * Returns the keys for each element in the YMap Type. 11980 * 11981 * @return {IterableIterator<string>} 11982 */ 11983 keys () { 11984 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => v[0]) 11985 } 11986 11987 /** 11988 * Returns the values for each element in the YMap Type. 11989 * 11990 * @return {IterableIterator<any>} 11991 */ 11992 values () { 11993 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => v[1].content.getContent()[v[1].length - 1]) 11994 } 11995 11996 /** 11997 * Returns an Iterator of [key, value] pairs 11998 * 11999 * @return {IterableIterator<any>} 12000 */ 12001 entries () { 12002 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => [v[0], v[1].content.getContent()[v[1].length - 1]]) 12003 } 12004 12005 /** 12006 * Executes a provided function on once on every key-value pair. 12007 * 12008 * @param {function(MapType,string,YMap<MapType>):void} f A function to execute on every element of this YArray. 12009 */ 12010 forEach (f) { 12011 this._map.forEach((item, key) => { 12012 if (!item.deleted) { 12013 f(item.content.getContent()[item.length - 1], key, this); 12014 } 12015 }); 12016 } 12017 12018 /** 12019 * Returns an Iterator of [key, value] pairs 12020 *
12021 * @return {IterableIterator<any>} 12022 */ 12023 [Symbol.iterator] () { 12024 return this.entries() 12025 } 12026 12027 /** 12028 * Remove a specified element from this YMap. 12029 * 12030 * @param {string} key The key of the element to remove. 12031 */ 12032 delete (key) { 12033 if (this.doc !== null) { 12034 transact(this.doc, transaction => { 12035 typeMapDelete(transaction, this, key); 12036 }); 12037 } else { 12038 /** @type {Map<string, any>} */ (this._prelimContent).delete(key); 12039 } 12040 } 12041 12042 /** 12043 * Adds or updates an element with a specified key and value. 12044 * @template {MapType} VAL 12045 * 12046 * @param {string} key The key of the element to add to this YMap 12047 * @param {VAL} value The value of the element to add 12048 * @return {VAL} 12049 */ 12050 set (key, value) { 12051 if (this.doc !== null) { 12052 transact(this.doc, transaction => { 12053 typeMapSet(transaction, this, key, /** @type {any} */ (value)); 12054 }); 12055 } else { 12056 /** @type {Map<string, any>} */ (this._prelimContent).set(key, value); 12057 } 12058 return value 12059 } 12060 12061 /** 12062 * Returns a specified element from this YMap. 12063 * 12064 * @param {string} key 12065 * @return {MapType|undefined} 12066 */ 12067 get (key) { 12068 return /** @type {any} */ (typeMapGet(this, key)) 12069 } 12070 12071 /** 12072 * Returns a boolean indicating whether the specified key exists or not. 12073 * 12074 * @param {string} key The key to test. 12075 * @return {boolean} 12076 */ 12077 has (key) { 12078 return typeMapHas(this, key) 12079 } 12080 12081 /** 12082 * Removes all elements from this YMap. 12083 */ 12084 clear () { 12085 if (this.doc !== null) { 12086 transact(this.doc, transaction => { 12087 this.forEach(function (_value, key, map) { 12088 typeMapDelete(transaction, map, key); 12089 }); 12090 }); 12091 } else { 12092 /** @type {Map<string, any>} */ (this._prelimContent).clear(); 12093 } 12094 } 12095 12096 /** 12097 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 12098 */ 12099 _write (encoder) { 12100 encoder.writeTypeRef(YMapRefID); 12101 } 12102} 12103 12104/** 12105 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder 12106 * 12107 * @private 12108 * @function 12109 */ 12110const readYMap = _decoder => new YMap(); 12111 12112/** 12113 * @param {any} a 12114 * @param {any} b 12115 * @return {boolean} 12116 */ 12117const equalAttrs = (a, b) => a === b || (typeof a === 'object' && typeof b === 'object' && a && b && object_equalFlat(a, b)); 12118 12119class ItemTextListPosition { 12120 /** 12121 * @param {Item|null} left 12122 * @param {Item|null} right 12123 * @param {number} index 12124 * @param {Map<string,any>} currentAttributes 12125 */ 12126 constructor (left, right, index, currentAttributes) { 12127 this.left = left; 12128 this.right = right; 12129 this.index = index; 12130 this.currentAttributes = currentAttributes; 12131 } 12132 12133 /** 12134 * Only call this if you know that this.right is defined 12135 */ 12136 forward () { 12137 if (this.right === null) { 12138 unexpectedCase(); 12139 } 12140 switch (this.right.content.constructor) { 12141 case ContentFormat: 12142 if (!this.right.deleted) { 12143 updateCurrentAttributes(this.currentAttributes, /** @type {ContentFormat} */ (this.right.content)); 12144 } 12145 break 12146 default: 12147 if (!this.right.deleted) { 12148 this.index += this.right.length; 12149 } 12150 break 12151 } 12152 this.left = this.right; 12153 this.right = this.right.right; 12154 } 12155} 12156 12157/** 12158 * @param {Transaction} transaction 12159 * @param {ItemTextListPosition} pos 12160 * @param {number} count steps to move forward 12161 * @return {ItemTextListPosition} 12162 * 12163 * @private 12164 * @function 12165 */ 12166const findNextPosition = (transaction, pos, count) => { 12167 while (pos.right !== null && count > 0) { 12168 switch (pos.right.content.constructor) { 12169 case ContentFormat: 12170 if (!pos.right.deleted) { 12171 updateCurrentAttributes(pos.currentAttributes, /** @type {ContentFormat} */ (pos.right.content)); 12172 } 12173 break 12174 default: 12175 if (!pos.right.deleted) { 12176 if (count < pos.right.length) { 12177 // split right 12178 getItemCleanStart(transaction, createID(pos.right.id.client, pos.right.id.clock + count)); 12179 } 12180 pos.index += pos.right.length; 12181 count -= pos.right.length; 12182 } 12183 break 12184 } 12185 pos.left = pos.right; 12186 pos.right = pos.right.right; 12187 // pos.forward() - we don't forward because that would halve the performance because we already do the checks above 12188 } 12189 return pos 12190}; 12191 12192/** 12193 * @param {Transaction} transaction 12194 * @param {AbstractType<any>} parent 12195 * @param {number} index 12196 * @return {ItemTextListPosition} 12197 * 12198 * @private 12199 * @function 12200 */ 12201const findPosition = (transaction, parent, index) => { 12202 const currentAttributes = new Map(); 12203 const marker = findMarker(parent, index); 12204 if (marker) { 12205 const pos = new ItemTextListPosition(marker.p.left, marker.p, marker.index, currentAttributes); 12206 return findNextPosition(transaction, pos, index - marker.index) 12207 } else { 12208 const pos = new ItemTextListPosition(null, parent._start, 0, currentAttributes); 12209 return findNextPosition(transaction, pos, index) 12210 } 12211}; 12212 12213/** 12214 * Negate applied formats 12215 * 12216 * @param {Transaction} transaction 12217 * @param {AbstractType<any>} parent 12218 * @param {ItemTextListPosition} currPos 12219 * @param {Map<string,any>} negatedAttributes 12220 * 12221 * @private 12222 * @function 12223 */ 12224const insertNegatedAttributes = (transaction, parent, currPos, negatedAttributes) => { 12225 // check if we really need to remove attributes 12226 while ( 12227 currPos.right !== null && ( 12228 currPos.right.deleted === true || ( 12229 currPos.right.content.constructor === ContentFormat && 12230 equalAttrs(negatedAttributes.get(/** @type {ContentFormat} */ (currPos.right.content).key), /** @type {ContentFormat} */ (currPos.right.content).value) 12231 ) 12232 ) 12233 ) { 12234 if (!currPos.right.deleted) { 12235 negatedAttributes.delete(/** @type {ContentFormat} */ (currPos.right.content).key); 12236 } 12237 currPos.forward(); 12238 } 12239 const doc = transaction.doc; 12240 const ownClientId = doc.clientID;
12241 negatedAttributes.forEach((val, key) => { 12242 const left = currPos.left; 12243 const right = currPos.right; 12244 const nextFormat = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentFormat(key, val)); 12245 nextFormat.integrate(transaction, 0); 12246 currPos.right = nextFormat; 12247 currPos.forward(); 12248 }); 12249}; 12250 12251/** 12252 * @param {Map<string,any>} currentAttributes 12253 * @param {ContentFormat} format 12254 * 12255 * @private 12256 * @function 12257 */ 12258const updateCurrentAttributes = (currentAttributes, format) => { 12259 const { key, value } = format; 12260 if (value === null) { 12261 currentAttributes.delete(key); 12262 } else { 12263 currentAttributes.set(key, value); 12264 } 12265}; 12266 12267/** 12268 * @param {ItemTextListPosition} currPos 12269 * @param {Object<string,any>} attributes 12270 * 12271 * @private 12272 * @function 12273 */ 12274const minimizeAttributeChanges = (currPos, attributes) => { 12275 // go right while attributes[right.key] === right.value (or right is deleted) 12276 while (true) { 12277 if (currPos.right === null) { 12278 break 12279 } else if (currPos.right.deleted || (currPos.right.content.constructor === ContentFormat && equalAttrs(attributes[(/** @type {ContentFormat} */ (currPos.right.content)).key] || null, /** @type {ContentFormat} */ (currPos.right.content).value))) ; else { 12280 break 12281 } 12282 currPos.forward(); 12283 } 12284}; 12285 12286/** 12287 * @param {Transaction} transaction 12288 * @param {AbstractType<any>} parent 12289 * @param {ItemTextListPosition} currPos 12290 * @param {Object<string,any>} attributes 12291 * @return {Map<string,any>} 12292 * 12293 * @private 12294 * @function 12295 **/ 12296const insertAttributes = (transaction, parent, currPos, attributes) => { 12297 const doc = transaction.doc; 12298 const ownClientId = doc.clientID; 12299 const negatedAttributes = new Map(); 12300 // insert format-start items 12301 for (const key in attributes) { 12302 const val = attributes[key]; 12303 const currentVal = currPos.currentAttributes.get(key) || null; 12304 if (!equalAttrs(currentVal, val)) { 12305 // save negated attribute (set null if currentVal undefined) 12306 negatedAttributes.set(key, currentVal); 12307 const { left, right } = currPos; 12308 currPos.right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentFormat(key, val)); 12309 currPos.right.integrate(transaction, 0); 12310 currPos.forward(); 12311 } 12312 } 12313 return negatedAttributes 12314}; 12315 12316/** 12317 * @param {Transaction} transaction 12318 * @param {AbstractType<any>} parent 12319 * @param {ItemTextListPosition} currPos 12320 * @param {string|object|AbstractType<any>} text 12321 * @param {Object<string,any>} attributes 12322 * 12323 * @private 12324 * @function 12325 **/ 12326const insertText = (transaction, parent, currPos, text, attributes) => { 12327 currPos.currentAttributes.forEach((_val, key) => { 12328 if (attributes[key] === undefined) { 12329 attributes[key] = null; 12330 } 12331 }); 12332 const doc = transaction.doc; 12333 const ownClientId = doc.clientID; 12334 minimizeAttributeChanges(currPos, attributes); 12335 const negatedAttributes = insertAttributes(transaction, parent, currPos, attributes); 12336 // insert content 12337 const content = text.constructor === String ? new ContentString(/** @type {string} */ (text)) : (text instanceof AbstractType ? new ContentType(text) : new ContentEmbed(text)); 12338 let { left, right, index } = currPos; 12339 if (parent._searchMarker) { 12340 updateMarkerChanges(parent._searchMarker, currPos.index, content.getLength()); 12341 } 12342 right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, content); 12343 right.integrate(transaction, 0); 12344 currPos.right = right; 12345 currPos.index = index; 12346 currPos.forward(); 12347 insertNegatedAttributes(transaction, parent, currPos, negatedAttributes); 12348}; 12349 12350/** 12351 * @param {Transaction} transaction 12352 * @param {AbstractType<any>} parent 12353 * @param {ItemTextListPosition} currPos 12354 * @param {number} length 12355 * @param {Object<string,any>} attributes 12356 * 12357 * @private 12358 * @function 12359 */ 12360const formatText = (transaction, parent, currPos, length, attributes) => { 12361 const doc = transaction.doc; 12362 const ownClientId = doc.clientID; 12363 minimizeAttributeChanges(currPos, attributes); 12364 const negatedAttributes = insertAttributes(transaction, parent, currPos, attributes); 12365 // iterate until first non-format or null is found 12366 // delete all formats with attributes[format.key] != null 12367 // also check the attributes after the first non-format as we do not want to insert redundant negated attributes there 12368 // eslint-disable-next-line no-labels 12369 iterationLoop: while ( 12370 currPos.right !== null && 12371 (length > 0 || 12372 ( 12373 negatedAttributes.size > 0 && 12374 (currPos.right.deleted || currPos.right.content.constructor === ContentFormat) 12375 ) 12376 ) 12377 ) { 12378 if (!currPos.right.deleted) { 12379 switch (currPos.right.content.constructor) { 12380 case ContentFormat: { 12381 const { key, value } = /** @type {ContentFormat} */ (currPos.right.content); 12382 const attr = attributes[key]; 12383 if (attr !== undefined) { 12384 if (equalAttrs(attr, value)) { 12385 negatedAttributes.delete(key); 12386 } else { 12387 if (length === 0) { 12388 // no need to further extend negatedAttributes 12389 // eslint-disable-next-line no-labels 12390 break iterationLoop 12391 } 12392 negatedAttributes.set(key, value); 12393 } 12394 currPos.right.delete(transaction); 12395 } else { 12396 currPos.currentAttributes.set(key, value); 12397 } 12398 break 12399 } 12400 default: 12401 if (length < currPos.right.length) { 12402 getItemCleanStart(transaction, createID(currPos.right.id.client, currPos.right.id.clock + length)); 12403 } 12404 length -= currPos.right.length; 12405 break 12406 } 12407 } 12408 currPos.forward(); 12409 } 12410 // Quill just assumes that the editor starts with a newline and that it al
12410ways 12411 // ends with a newline. We only insert that newline when a new newline is 12412 // inserted - i.e when length is bigger than type.length 12413 if (length > 0) { 12414 let newlines = ''; 12415 for (; length > 0; length--) { 12416 newlines += '\n'; 12417 } 12418 currPos.right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), currPos.left, currPos.left && currPos.left.lastId, currPos.right, currPos.right && currPos.right.id, parent, null, new ContentString(newlines)); 12419 currPos.right.integrate(transaction, 0); 12420 currPos.forward(); 12421 } 12422 insertNegatedAttributes(transaction, parent, currPos, negatedAttributes); 12423}; 12424 12425/** 12426 * Call this function after string content has been deleted in order to 12427 * clean up formatting Items. 12428 * 12429 * @param {Transaction} transaction 12430 * @param {Item} start 12431 * @param {Item|null} curr exclusive end, automatically iterates to the next Content Item 12432 * @param {Map<string,any>} startAttributes 12433 * @param {Map<string,any>} currAttributes 12434 * @return {number} The amount of formatting Items deleted. 12435 * 12436 * @function 12437 */ 12438const cleanupFormattingGap = (transaction, start, curr, startAttributes, currAttributes) => { 12439 /** 12440 * @type {Item|null} 12441 */ 12442 let end = start; 12443 /** 12444 * @type {Map<string,ContentFormat>} 12445 */ 12446 const endFormats = create(); 12447 while (end && (!end.countable || end.deleted)) { 12448 if (!end.deleted && end.content.constructor === ContentFormat) { 12449 const cf = /** @type {ContentFormat} */ (end.content); 12450 endFormats.set(cf.key, cf); 12451 } 12452 end = end.right; 12453 } 12454 let cleanups = 0; 12455 let reachedCurr = false;
12456 while (start !== end) { 12457 if (curr === start) { 12458 reachedCurr = true; 12459 } 12460 if (!start.deleted) { 12461 const content = start.content; 12462 switch (content.constructor) { 12463 case ContentFormat: { 12464 const { key, value } = /** @type {ContentFormat} */ (content); 12465 const startAttrValue = startAttributes.get(key) || null; 12466 if (endFormats.get(key) !== content || startAttrValue === value) { 12467 // Either this format is overwritten or it is not necessary because the attribute already existed. 12468 start.delete(transaction); 12469 cleanups++; 12470 if (!reachedCurr && (currAttributes.get(key) || null) === value && startAttrValue !== value) { 12471 if (startAttrValue === null) { 12472 currAttributes.delete(key); 12473 } else { 12474 currAttributes.set(key, startAttrValue); 12475 } 12476 } 12477 } 12478 if (!reachedCurr && !start.deleted) { 12479 updateCurrentAttributes(currAttributes, /** @type {ContentFormat} */ (content)); 12480 } 12481 break 12482 } 12483 } 12484 } 12485 start = /** @type {Item} */ (start.right); 12486 } 12487 return cleanups 12488}; 12489 12490/** 12491 * @param {Transaction} transaction 12492 * @param {Item | null} item 12493 */ 12494const cleanupContextlessFormattingGap = (transaction, item) => { 12495 // iterate until item.right is null or content 12496 while (item && item.right && (item.right.deleted || !item.right.countable)) { 12497 item = item.right; 12498 } 12499 const attrs = new Set(); 12500 // iterate back until a content item is found 12501 while (item && (item.deleted || !item.countable)) { 12502 if (!item.deleted && item.content.constructor === ContentFormat) { 12503 const key = /** @type {ContentFormat} */ (item.content).key; 12504 if (attrs.has(key)) { 12505 item.delete(transaction); 12506 } else { 12507 attrs.add(key); 12508 } 12509 } 12510 item = item.left; 12511 } 12512}; 12513 12514/** 12515 * This function is experimental and subject to change / be removed. 12516 * 12517 * Ideally, we don't need this function at all. Formatting attributes should be cleaned up 12518 * automatically after each change. This function iterates twice over the complete YText type 12519 * and removes unnecessary formatting attributes. This is also helpful for testing. 12520 * 12521 * This function won't be exported anymore as soon as there is confidence that the YText type works as intended. 12522 * 12523 * @param {YText} type 12524 * @return {number} How many formatting attributes have been cleaned up. 12525 */ 12526const cleanupYTextFormatting = type => { 12527 let res = 0; 12528 transact(/** @type {Doc} */ (type.doc), transaction => { 12529 let start = /** @type {Item} */ (type._start); 12530 let end = type._start; 12531 let startAttributes = create(); 12532 const currentAttributes = copy(startAttributes); 12533 while (end) { 12534 if (end.deleted === false) { 12535 switch (end.content.constructor) { 12536 case ContentFormat: 12537 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (end.content)); 12538 break 12539 default: 12540 res += cleanupFormattingGap(transaction, start, end, startAttributes, currentAttributes); 12541 startAttributes = copy(currentAttributes); 12542 start = end; 12543 break 12544 } 12545 } 12546 end = end.right; 12547 } 12548 }); 12549 return res 12550}; 12551 12552/** 12553 * This will be called by the transction once the event handlers are called to potentially cleanup 12554 * formatting attributes. 12555 * 12556 * @param {Transaction} transaction 12557 */ 12558const cleanupYTextAfterTransaction = transaction => { 12559 /** 12560 * @type {Set<YText>} 12561 */ 12562 const needFullCleanup = new Set(); 12563 // check if another formatting item was inserted 12564 const doc = transaction.doc; 12565 for (const [client, afterClock] of transaction.afterState.entries()) { 12566 const clock = transaction.beforeState.get(client) || 0; 12567 if (afterClock === clock) { 12568 continue 12569 } 12570 iterateStructs(transaction, /** @type {Array<Item|GC>} */ (doc.store.clients.get(client)), clock, afterClock, item => { 12571 if ( 12572 !item.deleted && /** @type {Item} */ (item).content.constructor === ContentFormat && item.constructor !== GC 12573 ) { 12574 needFullCleanup.add(/** @type {any} */ (item).parent); 12575 } 12576 }); 12577 } 12578 // cleanup in a new transaction 12579 transact(doc, (t) => { 12580 iterateDeletedStructs(transaction, transaction.deleteSet, item => { 12581 if (item instanceof GC || !(/** @type {YText} */ (item.parent)._hasFormatting) || needFullCleanup.has(/** @type {YText} */ (item.parent))) { 12582 return 12583 } 12584 const parent = /** @type {YText} */ (item.parent); 12585 if (item.content.constructor === ContentFormat) { 12586 needFullCleanup.add(parent); 12587 } else { 12588 // If no formatting attribute was inserted or deleted, we can make due with contextless 12589 // formatting cleanups. 12590 // Contextless: it is not necessary to compute currentAttributes for the affected position. 12591 cleanupContextlessFormattingGap(t, item); 12592 } 12593 }); 12594 // If a formatting item was inserted, we simply clean the whole type. 12595 // We need to compute currentAttributes for the current position anyway. 12596 for (const yText of needFullCleanup) { 12597 cleanupYTextFormatting(yText); 12598 } 12599 }); 12600}; 12601 12602/** 12603 * @param {Transaction} transaction 12604 * @param {ItemTextListPosition} currPos 12605 * @param {number} length 12606 * @return {ItemTextListPosition} 12607 * 12608 * @private 12609 * @function 12610 */ 12611const deleteText = (transaction, currPos, length) => { 12612 const startLength = length; 12613 const startAttrs = copy(currPos.currentAttributes); 12614 const start = currPos.right; 12615 while (length > 0 && currPos.right !== null) { 12616 if (currPos.right.deleted === false) { 12617 switch (currPos.right.content.constructor) { 12618 case ContentType: 12619 case ContentEmbed: 12620 case ContentString: 12621 if (length < currPos.right.length) { 12622 getItemCleanStart(transaction, createID(currPos.right.id.client, currPos.right.id.clock + length)); 12623 } 12624 length -= currPos.right.length; 12625 currPos.right.delete(transaction); 12626 break 12627 } 12628 } 12629 currPos.forward(); 12630 } 12631 if (start) { 12632 cleanupFormattingGap(transaction, start, currPos.right, startAttrs, currPos.currentAttributes); 12633 } 12634 const parent = /** @type {AbstractType<any>} */ (/** @type {Item} */ (currPos.left || currPos.right).parent); 12635 if (parent._searchMarker) { 12636 updateMarkerChanges(parent._searchMarker, currPos.index, -startLength + length); 12637 } 12638 return currPos 12639}; 12640 12641/** 12642 * The Quill Delta format represents changes on a text document with 12643 * formatting information. For mor information visit {@link https://quilljs.com/docs/delta/|Quill Delta} 12644 * 12645 * @example 12646 * { 12647 * ops: [ 12648 * { insert: 'Gandalf', attributes: { bold: true } }, 12649 * { insert: ' the ' }, 12650 * { insert: 'Grey', attributes: { color: '#cccccc' } } 12651 * ] 12652 * } 12653 * 12654 */ 12655 12656/** 12657 * Attributes that can be assigned to a selection of text. 12658 * 12659 * @example 12660 * { 12661 * bold: true, 12662 * font-size: '40px' 12663 * } 12664 * 12665 * @typedef {Object} TextAttributes 12666 */ 12667 12668/** 12669 * @extends YEvent<YText> 12670 * Event that describes the changes on a YText type. 12671 */ 12672class YTextEvent extends YEvent { 12673 /** 12674 * @param {YText} ytext 12675 * @param {Transaction} transaction 12676 * @param {Set<any>} subs The keys that changed 12677 */ 12678 constructor (ytext, transaction, subs) { 12679 super(ytext, transaction); 12680 /** 12681 * Whether the children changed. 12682 * @type {Boolean} 12683 * @private 12684 */ 12685 this.childListChanged = false;
12686 /** 12687 * Set of all changed attributes. 12688 * @type {Set<string>} 12689 */ 12690 this.keysChanged = new Set(); 12691 subs.forEach((sub) => { 12692 if (sub === null) { 12693 this.childListChanged = true; 12694 } else { 12695 this.keysChanged.add(sub); 12696 } 12697 }); 12698 } 12699 12700 /** 12701 * @type {{added:Set<Item>,deleted:Set<Item>,keys:Map<string,{action:'add'|'update'|'delete',oldValue:any}>,delta:Array<{insert?:Array<any>|string, delete?:number, retain?:number}>}} 12702 */ 12703 get changes () { 12704 if (this._changes === null) { 12705 /** 12706 * @type {{added:Set<Item>,deleted:Set<Item>,keys:Map<string,{action:'add'|'update'|'delete',oldValue:any}>,delta:Array<{insert?:Array<any>|string|AbstractType<any>|object, delete?:number, retain?:number}>}} 12707 */ 12708 const changes = { 12709 keys: this.keys, 12710 delta: this.delta, 12711 added: new Set(), 12712 deleted: new Set() 12713 }; 12714 this._changes = changes; 12715 } 12716 return /** @type {any} */ (this._changes) 12717 } 12718 12719 /** 12720 * Compute the changes in the delta format. 12721 * A {@link https://quilljs.com/docs/delta/|Quill Delta}) that represents the changes on the document. 12722 * 12723 * @type {Array<{insert?:string|object|AbstractType<any>, delete?:number, retain?:number, attributes?: Object<string,any>}>} 12724 * 12725 * @public 12726 */ 12727 get delta () { 12728 if (this._delta === null) { 12729 const y = /** @type {Doc} */ (this.target.doc); 12730 /** 12731 * @type {Array<{insert?:string|object|AbstractType<any>, delete?:number, retain?:number, attributes?: Object<string,any>}>} 12732 */ 12733 const delta = []; 12734 transact(y, transaction => { 12735 const currentAttributes = new Map(); // saves all current attributes for insert 12736 const oldAttributes = new Map(); 12737 let item = this.target._start; 12738 /** 12739 * @type {string?} 12740 */ 12741 let action = null; 12742 /** 12743 * @type {Object<string,any>} 12744 */ 12745 const attributes = {}; // counts added or removed new attributes for retain 12746 /** 12747 * @type {string|object} 12748 */ 12749 let insert = ''; 12750 let retain = 0; 12751 let deleteLen = 0; 12752 const addOp = () => { 12753 if (action !== null) { 12754 /** 12755 * @type {any} 12756 */ 12757 let op = null; 12758 switch (action) { 12759 case 'delete': 12760 if (deleteLen > 0) { 12761 op = { delete: deleteLen }; 12762 } 12763 deleteLen = 0; 12764 break 12765 case 'insert': 12766 if (typeof insert === 'object' || insert.length > 0) { 12767 op = { insert }; 12768 if (currentAttributes.size > 0) { 12769 op.attributes = {}; 12770 currentAttributes.forEach((value, key) => { 12771 if (value !== null) { 12772 op.attributes[key] = value; 12773 } 12774 }); 12775 } 12776 } 12777 insert = ''; 12778 break 12779 case 'retain': 12780 if (retain > 0) { 12781 op = { retain }; 12782 if (!isEmpty(attributes)) { 12783 op.attributes = object_assign({}, attributes); 12784 } 12785 } 12786 retain = 0; 12787 break 12788 } 12789 if (op) delta.push(op); 12790 action = null; 12791 } 12792 }; 12793 while (item !== null) { 12794 switch (item.content.constructor) { 12795 case ContentType: 12796 case ContentEmbed: 12797 if (this.adds(item)) { 12798 if (!this.deletes(item)) { 12799 addOp(); 12800 action = 'insert'; 12801 insert = item.content.getContent()[0]; 12802 addOp(); 12803 } 12804 } else if (this.deletes(item)) { 12805 if (action !== 'delete') { 12806 addOp(); 12807 action = 'delete'; 12808 } 12809 deleteLen += 1; 12810 } else if (!item.deleted) { 12811 if (action !== 'retain') { 12812 addOp(); 12813 action = 'retain'; 12814 } 12815 retain += 1; 12816 } 12817 break 12818 case ContentString: 12819 if (this.adds(item)) { 12820 if (!this.deletes(item)) { 12821 if (action !== 'insert') { 12822 addOp(); 12823 action = 'insert'; 12824 } 12825 insert += /** @type {ContentString} */ (item.content).str; 12826 } 12827 } else if (this.deletes(item)) { 12828 if (action !== 'delete') { 12829 addOp(); 12830 action = 'delete'; 12831 } 12832 deleteLen += item.length; 12833 } else if (!item.deleted) { 12834 if (action !== 'retain') { 12835 addOp(); 12836 action = 'retain'; 12837 } 12838 retain += item.length; 12839 } 12840 break 12841 case ContentFormat: { 12842 const { key, value } = /** @type {ContentFormat} */ (item.content); 12843 if (this.adds(item)) { 12844 if (!this.deletes(item)) { 12845 const curVal = currentAttributes.get(key) || null; 12846 if (!equalAttrs(curVal, value)) { 12847 if (action === 'retain') { 12848 addOp(); 12849 } 12850 if (equalAttrs(value, (oldAttributes.get(key) || null))) { 12851 delete attributes[key]; 12852 } else { 12853 attributes[key] = value; 12854 } 12855 } else if (value !== null) { 12856 item.delete(transaction); 12857 } 12858 } 12859 } else if (this.deletes(item)) { 12860 oldAttributes.set(key, value); 12861 const curVal = currentAttributes.get(key) || null; 12862 if (!equalAttrs(curVal, value)) { 12863 if (action === 'retain') { 12864 addOp(); 12865 } 12866 attributes[key] = curVal; 12867 } 12868 } else if (!item.deleted) { 12869 oldAttributes.set(key, value); 12870 const attr = attributes[key]; 12871 if (attr !== undefined) { 12872 if (!equalAttrs(attr, value)) { 12873 if (action === 'retain') { 12874 addOp(); 12875 } 12876 if (value === null) { 12877 delete attributes[key]; 12878 } else { 12879 attributes[key] = value; 12880 } 12881 } else if (attr !== null) { // this will be cleaned up automatically by the contextless cleanup function 12882 item.delete(transaction); 12883 } 12884 } 12885 } 12886 if (!item.deleted) {
12887 if (action === 'insert') { 12888 addOp(); 12889 } 12890 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (item.content)); 12891 } 12892 break 12893 } 12894 } 12895 item = item.right; 12896 } 12897 addOp(); 12898 while (delta.length > 0) { 12899 const lastOp = delta[delta.length - 1]; 12900 if (lastOp.retain !== undefined && lastOp.attributes === undefined) { 12901 // retain delta's if they don't assign attributes 12902 delta.pop(); 12903 } else { 12904 break 12905 } 12906 } 12907 }); 12908 this._delta = delta; 12909 } 12910 return /** @type {any} */ (this._delta) 12911 } 12912} 12913 12914/** 12915 * Type that represents text with formatting information. 12916 * 12917 * This type replaces y-richtext as this implementation is able to handle 12918 * block formats (format information on a paragraph), embeds (complex elements 12919 * like pictures and videos), and text formats (**bold**, *italic*). 12920 * 12921 * @extends AbstractType<YTextEvent> 12922 */ 12923class YText extends AbstractType { 12924 /** 12925 * @param {String} [string] The initial value of the YText. 12926 */ 12927 constructor (string) { 12928 super(); 12929 /** 12930 * Array of pending operations on this type 12931 * @type {Array<function():void>?} 12932 */ 12933 this._pending = string !== undefined ? [() => this.insert(0, string)] : []; 12934 /** 12935 * @type {Array<ArraySearchMarker>|null} 12936 */ 12937 this._searchMarker = []; 12938 /** 12939 * Whether this YText contains formatting attributes. 12940 * This flag is updated when a formatting item is integrated (see ContentFormat.integrate) 12941 */ 12942 this._hasFormatting = false; 12943 } 12944 12945 /** 12946 * Number of characters of this text type. 12947 * 12948 * @type {number} 12949 */ 12950 get length () { 12951 return this._length 12952 } 12953 12954 /** 12955 * @param {Doc} y 12956 * @param {Item} item 12957 */ 12958 _integrate (y, item) { 12959 super._integrate(y, item); 12960 try { 12961 /** @type {Array<function>} */ (this._pending).forEach(f => f()); 12962 } catch (e) { 12963 console.error(e); 12964 } 12965 this._pending = null; 12966 } 12967 12968 _copy () { 12969 return new YText() 12970 } 12971 12972 /** 12973 * @return {YText} 12974 */ 12975 clone () { 12976 const text = new YText(); 12977 text.applyDelta(this.toDelta()); 12978 return text 12979 } 12980 12981 /** 12982 * Creates YTextEvent and calls observers. 12983 * 12984 * @param {Transaction} transaction 12985 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified. 12986 */ 12987 _callObserver (transaction, parentSubs) { 12988 super._callObserver(transaction, parentSubs); 12989 const event = new YTextEvent(this, transaction, parentSubs); 12990 callTypeObservers(this, transaction, event); 12991 // If a remote change happened, we try to cleanup potential formatting duplicates. 12992 if (!transaction.local && this._hasFormatting) { 12993 transaction._needFormattingCleanup = true; 12994 } 12995 } 12996 12997 /** 12998 * Returns the unformatted string representation of this YText type. 12999 * 13000 * @public 13001 */ 13002 toString () { 13003 let str = ''; 13004 /** 13005 * @type {Item|null} 13006 */ 13007 let n = this._start; 13008 while (n !== null) { 13009 if (!n.deleted && n.countable && n.content.constructor === ContentString) { 13010 str += /** @type {ContentString} */ (n.content).str; 13011 } 13012 n = n.right; 13013 } 13014 return str 13015 } 13016 13017 /** 13018 * Returns the unformatted string representation of this YText type. 13019 * 13020 * @return {string} 13021 * @public 13022 */ 13023 toJSON () { 13024 return this.toString() 13025 } 13026 13027 /** 13028 * Apply a {@link Delta} on this shared YText type. 13029 * 13030 * @param {any} delta The changes to apply on this element. 13031 * @param {object} opts 13032 * @param {boolean} [opts.sanitize] Sanitize input delta. Removes ending newlines if set to true. 13033 * 13034 * 13035 * @public 13036 */ 13037 applyDelta (delta, { sanitize = true } = {}) { 13038 if (this.doc !== null) { 13039 transact(this.doc, transaction => { 13040 const currPos = new ItemTextListPosition(null, this._start, 0, new Map()); 13041 for (let i = 0; i < delta.length; i++) { 13042 const op = delta[i]; 13043 if (op.insert !== undefined) { 13044 // Quill assumes that the content starts with an empty paragraph. 13045 // Yjs/Y.Text assumes that it starts empty. We always hide that 13046 // there is a newline at the end of the content. 13047 // If we omit this step, clients will see a different number of 13048 // paragraphs, but nothing bad will happen. 13049 const ins = (!sanitize && typeof op.insert === 'string' && i === delta.length - 1 && currPos.right === null && op.insert.slice(-1) === '\n') ? op.insert.slice(0, -1) : op.insert; 13050 if (typeof ins !== 'string' || ins.length > 0) { 13051 insertText(transaction, this, currPos, ins, op.attributes || {}); 13052 } 13053 } else if (op.retain !== undefined) { 13054 formatText(transaction, this, currPos, op.retain, op.attributes || {}); 13055 } else if (op.delete !== undefined) { 13056 deleteText(transaction, currPos, op.delete); 13057 } 13058 } 13059 }); 13060 } else { 13061 /** @type {Array<function>}
13061 */ (this._pending).push(() => this.applyDelta(delta)); 13062 } 13063 } 13064 13065 /** 13066 * Returns the Delta representation of this YText type. 13067 * 13068 * @param {Snapshot} [snapshot] 13069 * @param {Snapshot} [prevSnapshot] 13070 * @param {function('removed' | 'added', ID):any} [computeYChange] 13071 * @return {any} The Delta representation of this type. 13072 * 13073 * @public 13074 */ 13075 toDelta (snapshot, prevSnapshot, computeYChange) { 13076 /** 13077 * @type{Array<any>} 13078 */ 13079 const ops = []; 13080 const currentAttributes = new Map(); 13081 const doc = /** @type {Doc} */ (this.doc); 13082 let str = ''; 13083 let n = this._start; 13084 function packStr () { 13085 if (str.length > 0) { 13086 // pack str with attributes to ops 13087 /** 13088 * @type {Object<string,any>} 13089 */ 13090 const attributes = {}; 13091 let addAttributes = false; 13092 currentAttributes.forEach((value, key) => { 13093 addAttributes = true; 13094 attributes[key] = value; 13095 }); 13096 /** 13097 * @type {Object<string,any>} 13098 */ 13099 const op = { insert: str }; 13100 if (addAttributes) { 13101 op.attributes = attributes; 13102 } 13103 ops.push(op); 13104 str = ''; 13105 } 13106 } 13107 const computeDelta = () => { 13108 while (n !== null) { 13109 if (isVisible(n, snapshot) || (prevSnapshot !== undefined && isVisible(n, prevSnapshot))) { 13110 switch (n.content.constructor) { 13111 case ContentString: { 13112 const cur = currentAttributes.get('ychange'); 13113 if (snapshot !== undefined && !isVisible(n, snapshot)) { 13114 if (cur === undefined || cur.user !== n.id.client || cur.type !== 'removed') { 13115 packStr(); 13116 currentAttributes.set('ychange', computeYChange ? computeYChange('removed', n.id) : { type: 'removed' }); 13117 } 13118 } else if (prevSnapshot !== undefined && !isVisible(n, prevSnapshot)) { 13119 if (cur === undefined || cur.user !== n.id.client || cur.type !== 'added') { 13120 packStr(); 13121 currentAttributes.set('ychange', computeYChange ? computeYChange('added', n.id) : { type: 'added' }); 13122 } 13123 } else if (cur !== undefined) { 13124 packStr(); 13125 currentAttributes.delete('ychange'); 13126 } 13127 str += /** @type {ContentString} */ (n.content).str; 13128 break 13129 } 13130 case ContentType: 13131 case ContentEmbed: { 13132 packStr(); 13133 /** 13134 * @type {Object<string,any>} 13135 */ 13136 const op = { 13137 insert: n.content.getContent()[0] 13138 }; 13139 if (currentAttributes.size > 0) { 13140 const attrs = /** @type {Object<string,any>} */ ({}); 13141 op.attributes = attrs; 13142 currentAttributes.forEach((value, key) => { 13143 attrs[key] = value; 13144 }); 13145 } 13146 ops.push(op); 13147 break 13148 } 13149 case ContentFormat: 13150 if (isVisible(n, snapshot)) { 13151 packStr(); 13152 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (n.content)); 13153 } 13154 break 13155 } 13156 } 13157 n = n.right; 13158 } 13159 packStr(); 13160 }; 13161 if (snapshot || prevSnapshot) { 13162 // snapshots are merged again after the transaction, so we need to keep the 13163 // transaction alive until we are done 13164 transact(doc, transaction => { 13165 if (snapshot) { 13166 splitSnapshotAffectedStructs(transaction, snapshot); 13167 } 13168 if (prevSnapshot) { 13169 splitSnapshotAffectedStructs(transaction, prevSnapshot); 13170 } 13171 computeDelta(); 13172 }, 'cleanup'); 13173 } else { 13174 computeDelta(); 13175 } 13176 return ops 13177 } 13178 13179 /** 13180 * Insert text at a given index. 13181 * 13182 * @param {number} index The index at which to start inserting. 13183 * @param {String} text The text to insert at the specified position. 13184 * @param {TextAttributes} [attributes] Optionally define some formatting 13185 * information to apply on the inserted 13186 * Text. 13187 * @public 13188 */ 13189 insert (index, text, attributes) { 13190 if (text.length <= 0) { 13191 return 13192 } 13193 const y = this.doc; 13194 if (y !== null) { 13195 transact(y, transaction => { 13196 const pos = findPosition(transaction, this, index); 13197 if (!attributes) { 13198 attributes = {}; 13199 // @ts-ignore
13200 pos.currentAttributes.forEach((v, k) => { attributes[k] = v; }); 13201 } 13202 insertText(transaction, this, pos, text, attributes); 13203 }); 13204 } else { 13205 /** @type {Array<function>} */ (this._pending).push(() => this.insert(index, text, attributes)); 13206 } 13207 } 13208 13209 /** 13210 * Inserts an embed at a index. 13211 * 13212 * @param {number} index The index to insert the embed at. 13213 * @param {Object | AbstractType<any>} embed The Object that represents the embed. 13214 * @param {TextAttributes} attributes Attribute information to apply on the 13215 * embed 13216 * 13217 * @public 13218 */ 13219 insertEmbed (index, embed, attributes = {}) { 13220 const y = this.doc; 13221 if (y !== null) { 13222 transact(y, transaction => { 13223 const pos = findPosition(transaction, this, index); 13224 insertText(transaction, this, pos, embed, attributes); 13225 }); 13226 } else { 13227 /** @type {Array<function>} */ (this._pending).push(() => this.insertEmbed(index, embed, attributes)); 13228 } 13229 } 13230 13231 /** 13232 * Deletes text starting from an index. 13233 * 13234 * @param {number} index Index at which to start deleting. 13235 * @param {number} length The number of characters to remove. Defaults to 1. 13236 * 13237 * @public 13238 */ 13239 delete (index, length) { 13240 if (length === 0) { 13241 return 13242 } 13243 const y = this.doc; 13244 if (y !== null) { 13245 transact(y, transaction => { 13246 deleteText(transaction, findPosition(transaction, this, index), length); 13247 }); 13248 } else { 13249 /** @type {Array<function>} */ (this._pending).push(() => this.delete(index, length)); 13250 } 13251 } 13252 13253 /** 13254 * Assigns properties to a range of text. 13255 * 13256 * @param {number} index The position where to start formatting. 13257 * @param {number} length The amount of characters to assign properties to. 13258 * @param {TextAttributes} attributes Attribute information to apply on the 13259 * text. 13260 * 13261 * @public 13262 */ 13263 format (index, length, attributes) { 13264 if (length === 0) { 13265 return 13266 } 13267 const y = this.doc; 13268 if (y !== null) { 13269 transact(y, transaction => { 13270 const pos = findPosition(transaction, this, index); 13271 if (pos.right === null) { 13272 return 13273 } 13274 formatText(transaction, this, pos, length, attributes); 13275 }); 13276 } else { 13277 /** @type {Array<function>} */ (this._pending).push(() => this.format(index, length, attributes)); 13278 } 13279 } 13280 13281 /** 13282 * Removes an attribute. 13283 * 13284 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks. 13285 * 13286 * @param {String} attributeName The attribute name that is to be removed. 13287 * 13288 * @public 13289 */ 13290 removeAttribute (attributeName) { 13291 if (this.doc !== null) { 13292 transact(this.doc, transaction => { 13293 typeMapDelete(transaction, this, attributeName); 13294 }); 13295 } else { 13296 /** @type {Array<function>} */ (this._pending).push(() => this.removeAttribute(attributeName)); 13297 } 13298 } 13299 13300 /** 13301 * Sets or updates an attribute. 13302 * 13303 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks. 13304 * 13305 * @param {String} attributeName The attribute name that is to be set. 13306 * @param {any} attributeValue The attribute value that is to be set. 13307 * 13308 * @public 13309 */ 13310 setAttribute (attributeName, attributeValue) { 13311 if (this.doc !== null) { 13312 transact(this.doc, transaction => { 13313 typeMapSet(transaction, this, attributeName, attributeValue); 13314 }); 13315 } else { 13316 /** @type {Array<function>} */ (this._pending).push(() => this.setAttribute(attributeName, attributeValue)); 13317 } 13318 } 13319 13320 /** 13321 * Returns an attribute value that belongs to the attribute name. 13322 * 13323 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks. 13324 * 13325 * @param {String} attributeName The attribute name that identifies the 13326 * queried value. 13327 * @return {any} The queried attribute value. 13328 * 13329 * @public 13330 */ 13331 getAttribute (attributeName) { 13332 return /** @type {any} */ (typeMapGet(this, attributeName)) 13333 } 13334 13335 /** 13336 * Returns all attribute name/value pairs in a JSON Object. 13337 * 13338 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks. 13339 * 13340 * @return {Object<string, any>} A JSON Object that describes the attributes. 13341 * 13342 * @public 13343 */ 13344 getAttributes () { 13345 return typeMapGetAll(this) 13346 } 13347 13348 /** 13349 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 13350 */ 13351 _write (encoder) { 13352 encoder.writeTypeRef(YTextRefID); 13353 } 13354} 13355 13356/** 13357 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder 13358 * @return {YText} 13359 * 13360 * @private 13361 * @function 13362 */ 13363const readYText = _decoder => new YText(); 13364 13365/** 13366 * @module YXml 13367 */ 13368 13369/** 13370 * Define the elements to which a set of CSS queries apply. 13371 * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors} 13372 * 13373 * @example 13374 * query = '.classSelector' 13375 * query = 'nodeSelector' 13376 * query = '#idSelector' 13377 * 13378 * @typedef {string} CSS_Selector 13379 */ 13380 13381/** 13382 * Dom filter function. 13383 * 13384 * @callback domFilter 13385 * @param {string}
13385 nodeName The nodeName of the element 13386 * @param {Map} attributes The map of attributes. 13387 * @return {boolean} Whether to include the Dom node in the YXmlElement. 13388 */ 13389 13390/** 13391 * Represents a subset of the nodes of a YXmlElement / YXmlFragment and a 13392 * position within them. 13393 * 13394 * Can be created with {@link YXmlFragment#createTreeWalker} 13395 * 13396 * @public 13397 * @implements {Iterable<YXmlElement|YXmlText|YXmlElement|YXmlHook>} 13398 */ 13399class YXmlTreeWalker { 13400 /** 13401 * @param {YXmlFragment | YXmlElement} root 13402 * @param {function(AbstractType<any>):boolean} [f] 13403 */ 13404 constructor (root, f = () => true) { 13405 this._filter = f; 13406 this._root = root; 13407 /** 13408 * @type {Item} 13409 */ 13410 this._currentNode = /** @type {Item} */ (root._start); 13411 this._firstCall = true; 13412 } 13413 13414 [Symbol.iterator] () { 13415 return this 13416 } 13417 13418 /** 13419 * Get the next node. 13420 * 13421 * @return {IteratorResult<YXmlElement|YXmlText|YXmlHook>} The next node. 13422 * 13423 * @public 13424 */ 13425 next () { 13426 /** 13427 * @type {Item|null} 13428 */ 13429 let n = this._currentNode; 13430 let type = n && n.content && /** @type {any} */ (n.content).type; 13431 if (n !== null && (!this._firstCall || n.deleted || !this._filter(type))) { // if first call, we check if we can use the first item 13432 do { 13433 type = /** @type {any} */ (n.content).type; 13434 if (!n.deleted && (type.constructor === YXmlElement || type.constructor === YXmlFragment) && type._start !== null) { 13435 // walk down in the tree 13436 n = type._start; 13437 } else { 13438 // walk right or up in the tree 13439 while (n !== null) { 13440 if (n.right !== null) { 13441 n = n.right; 13442 break 13443 } else if (n.parent === this._root) { 13444 n = null; 13445 } else { 13446 n = /** @type {AbstractType<any>} */ (n.parent)._item; 13447 } 13448 } 13449 } 13450 } while (n !== null && (n.deleted || !this._filter(/** @type {ContentType} */ (n.content).type))) 13451 } 13452 this._firstCall = false; 13453 if (n === null) { 13454 // @ts-ignore 13455 return { value: undefined, done: true } 13456 } 13457 this._currentNode = n; 13458 return { value: /** @type {any} */ (n.content).type, done: false } 13459 } 13460} 13461 13462/** 13463 * Represents a list of {@link YXmlElement}.and {@link YXmlText} types. 13464 * A YxmlFragment is similar to a {@link YXmlElement}, but it does not have a 13465 * nodeName and it does not have attributes. Though it can be bound to a DOM 13466 * element - in this case the attributes and the nodeName are not shared. 13467 * 13468 * @public 13469 * @extends AbstractType<YXmlEvent> 13470 */ 13471class YXmlFragment extends AbstractType { 13472 constructor () { 13473 super(); 13474 /** 13475 * @type {Array<any>|null} 13476 */ 13477 this._prelimContent = []; 13478 } 13479 13480 /** 13481 * @type {YXmlElement|YXmlText|null} 13482 */ 13483 get firstChild () { 13484 const first = this._first; 13485 return first ? first.content.getContent()[0] : null 13486 } 13487 13488 /** 13489 * Integrate this type into the Yjs instance. 13490 * 13491 * * Save this struct in the os 13492 * * This type is sent to other client 13493 * * Observer functions are fired 13494 * 13495 * @param {Doc} y The Yjs instance 13496 * @param {Item} item 13497 */ 13498 _integrate (y, item) { 13499 super._integrate(y, item); 13500 this.insert(0, /** @type {Array<any>} */ (this._prelimContent)); 13501 this._prelimContent = null; 13502 } 13503 13504 _copy () { 13505 return new YXmlFragment() 13506 } 13507 13508 /** 13509 * @return {YXmlFragment} 13510 */ 13511 clone () { 13512 const el = new YXmlFragment(); 13513 // @ts-ignore 13514 el.insert(0, this.toArray().map(item => item instanceof AbstractType ? item.clone() : item)); 13515 return el 13516 } 13517 13518 get length () { 13519 return this._prelimContent === null ? this._length : this._prelimContent.length 13520 } 13521 13522 /** 13523 * Create a subtree of childNodes. 13524 * 13525 * @example 13526 * const walker = elem.createTreeWalker(dom => dom.nodeName === 'div') 13527 * for (let node in walker) { 13528 * // `node` is a div node 13529 * nop(node) 13530 * } 13531 * 13532 * @param {function(AbstractType<any>):boolean} filter Function that is called on each child element and 13533 * returns a Boolean indicating whether the child 13534 * is to be included in the subtree. 13535 * @return {YXmlTreeWalker} A subtree and a position within it. 13536 * 13537 * @public 13538 */ 13539 createTreeWalker (filter) { 13540 return new YXmlTreeWalker(this, filter) 13541 } 13542 13543 /** 13544 * Returns the first YXmlElement that matches the query. 13545 * Similar to DOM's {@link querySelector}. 13546 * 13547 * Query support: 13548 * - tagname 13549 * TODO: 13550 * - id 13551 * - attribute 13552 * 13553 * @param {CSS_Selector} query The query on the children. 13554 * @return {YXmlElement|YXmlText|YXmlHook|null} The first element that matches the query or null. 13555 * 13556 * @public 13557 */ 13558 querySelector (query) { 13559 query = query.toUpperCase(); 13560 // @ts-ignore 13561 const iterator = new YXmlTreeWalker(this, element => element.nodeName && element.nodeName.toUpperCase() === query); 13562 const next = iterator.next(); 13563 if (next.done) { 13564 return null 13565 } else { 13566 return next.value 13567 } 13568 } 13569 13570 /** 13571 * Returns all YXmlElements that match the query. 13572 * Similar to Dom's {@link querySelectorAll}. 13573 * 13574 * @todo Does not yet support all queries. Currently only query by tagName. 13575 * 13576 * @param {CSS_Selector} query The query on the children 13577 * @return {Array<YXmlElement|YXmlText|YXmlHook|null>} The elements that match this query. 13578 * 13579 * @public 13580 */ 13581 querySelectorAll (query) { 13582 query = query.toUpperCase(); 13583 // @ts-ignore 13584 return array_from(new YXmlTreeWalker(this, element => element.nodeName && element.nodeName.toUpperCase() === query)) 13585 } 13586 13587 /** 13588 * Creates YXmlEvent and calls observers. 13589 * 13590 * @param {Transaction} transaction 13591 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified. 13592 */ 13593 _callObserver (transaction, parentSubs) { 13594 callTypeObservers(this, transaction, new YXmlEvent(this, parentSubs, transaction)); 13595 } 13596 13597 /** 13598 * Get the string representation of all the children of this YXmlFragment. 13599 * 13600 * @return {string} The string representation of all children. 13601 */ 13602 toString () { 13603 return typeListMap(this, xml => xml.toString()).join('') 13604 } 13605 13606 /** 13607 * @return {string} 13608 */ 13609 toJSON () { 13610 return this.toString() 13611 } 13612 13613 /** 13614 * Creates a Dom Element that mirrors this YXmlElement. 13615 * 13616 * @param {Document} [_document=document] The document object (you must define 13617 * this when calling this method in 13618 * nodejs) 13619 * @param {Object<string, any>} [hooks={}] Optional property to customize how hooks 13620 * are presented in the DOM 13621 * @param {any} [binding] You should not set this property. This is 13622 * used if DomBinding wants to create a 13623 * association to the created DOM type. 13624 * @return {Node} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element} 13625 * 13626 * @public 13627 */ 13628 toDOM (_document = document, hooks = {}, binding) { 13629 const fragment = _document.createDocumentFragment(); 13630 if (binding !== undefined) { 13631 binding._createAssociation(fragment, this); 13632 } 13633 typeListForEach(this, xmlType => { 13634 fragment.insertBefore(xmlType.toDOM(_document, hooks, binding), null); 13635 }); 13636 return fragment 13637 } 13638 13639 /** 13640 * Inserts new content at an index. 13641 * 13642 * @example 13643 * // Insert character 'a' at position 0 13644 * xml.insert(0, [new Y.XmlText('text')]) 13645 * 13646 * @param {number} index The index to insert content at 13647 * @param {Array<YXmlElement|YXmlText>} content The array of content 13648 */ 13649 insert (index, content) { 13650 if (this.doc !== null) { 13651 transact(this.doc, transaction => { 13652 typeListInsertGenerics(transaction, this, index, content); 13653 }); 13654 } else { 13655 // @ts-ignore _prelimContent is defined because this is not yet integrated 13656 this._prelimContent.splice(index, 0, ...content); 13657 } 13658 } 13659 13660 /** 13661 * Inserts new content at an index. 13662 * 13663 * @example 13664 * // Insert character 'a' at position 0 13665 * xml.insert(0, [new Y.XmlText('text')]) 13666 * 13667 * @param {null|Item|YXmlElement|YXmlText} ref The index to insert content at 13668 * @param {Array<YXmlElement|YXmlText>} content The array of content 13669 */ 13670 insertAfter (ref, content) { 13671 if (this.doc !== null) { 13672 transact(this.doc, transaction => { 13673 const refItem = (ref && ref instanceof AbstractType) ? ref._item : ref; 13674 typeListInsertGenericsAfter(transaction, this, refItem, content); 13675 }); 13676 } else { 13677 const pc = /** @type {Array<any>} */ (this._prelimContent); 13678 const index = ref === null ? 0 : pc.findIndex(el => el === ref) + 1; 13679 if (index === 0 && ref !== null) { 13680 throw error_create('Reference item not found') 13681 } 13682 pc.splice(index, 0, ...content); 13683 } 13684 } 13685 13686 /** 13687 * Deletes elements starting from an index. 13688 * 13689 * @param {number} index Index at which to start deleting elements 13690 * @param {number} [length=1] The number of elements to remove. Defaults to 1. 13691 */ 13692 delete (index, length = 1) { 13693 if (this.doc !== null) { 13694 transact(this.doc, transaction => { 13695 typeListDelete(transaction, this, index, length); 13696 }); 13697 } else { 13698 // @ts-ignore _prelimContent is defined because this is not yet integrated 13699 this._prelimContent.splice(index, length); 13700 } 13701 } 13702 13703 /** 13704 * Transforms this YArray to a JavaScript Array. 13705 * 13706 * @return {Array<YXmlElement|YXmlText|YXmlHook>} 13707 */ 13708 toArray () { 13709 return typeListToArray(this) 13710 } 13711 13712 /** 13713 * Appends content to this YArray. 13714 * 13715 * @param {Array<YXmlElement|YXmlText>} content Array of content to append. 13716 */ 13717 push (content) { 13718 this.insert(this.length, content); 13719 } 13720 13721 /** 13722 * Preppends content to this YArray. 13723 * 13724 * @param {Array<YXmlElement|YXmlText>} content Array of content to preppend. 13725 */ 13726 unshift (content) { 13727 this.insert(0, content); 13728 } 13729 13730 /** 13731 * Returns the i-th element from a YArray. 13732 * 13733 * @param {number} index The index of the element to return from the YArray 13734 * @return {YXmlElement|YXmlText} 13735 */ 13736 get (index) { 13737 return typeListGet(this, index) 13738 } 13739 13740 /** 13741 * Transforms this YArray to a JavaScript Array. 13742 * 13743 * @param {number} [start] 13744 * @param {number} [end] 13745 * @return {Array<YXmlElement|YXmlText>} 13746 */ 13747 slice (start = 0, end = this.length) { 13748 return typeListSlice(this, start, end) 13749 } 13750 13751 /** 13752 * Executes a provided function on once on overy child element. 13753 * 13754 * @param {function(YXmlElement|YXmlText,number, typeof self):void} f A function to execute on every element of this YArray. 13755 */ 13756 forEach (f) { 13757 typeListForEach(this, f); 13758 } 13759 13760 /** 13761 * Transform the properties of this type to binary and write it to an 13762 * BinaryEncoder. 13763 * 13764 * This is called when this Item is sent to a remote peer. 13765 * 13766 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to. 13767 */ 13768 _write (encoder) { 13769 encoder.writeTypeRef(YXmlFragmentRefID); 13770 } 13771} 13772 13773/** 13774 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder 13775 * @return {YXmlFragment} 13776 * 13777 * @private 13778 * @function 13779 */ 13780const readYXmlFragment = _decoder => new YXmlFragment(); 13781 13782/** 13783 * @typedef {Object|number|null|Array<any>|string|Uint8Array|AbstractType<any>} ValueTypes 13784 */ 13785
13786/** 13787 * An YXmlElement imitates the behavior of a 13788 * {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}. 13789 * 13790 * * An YXmlElement has attributes (key value pairs) 13791 * * An YXmlElement has childElements that must inherit from YXmlElement 13792 * 13793 * @template {{ [key: string]: ValueTypes }} [KV={ [key: string]: string }] 13794 */ 13795class YXmlElement extends YXmlFragment { 13796 constructor (nodeName = 'UNDEFINED') { 13797 super(); 13798 this.nodeName = nodeName; 13799 /** 13800 * @type {Map<string, any>|null} 13801 */ 13802 this._prelimAttrs = new Map(); 13803 } 13804 13805 /** 13806 * @type {YXmlElement|YXmlText|null} 13807 */ 13808 get nextSibling () { 13809 const n = this._item ? this._item.next : null; 13810 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null 13811 } 13812 13813 /** 13814 * @type {YXmlElement|YXmlText|null} 13815 */ 13816 get prevSibling () { 13817 const n = this._item ? this._item.prev : null; 13818 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null 13819 } 13820 13821 /** 13822 * Integrate this type into the Yjs instance. 13823 * 13824 * * Save this struct in the os 13825 * * This type is sent to other client 13826 * * Observer functions are fired 13827 * 13828 * @param {Doc} y The Yjs instance 13829 * @param {Item} item 13830 */ 13831 _integrate (y, item) { 13832 super._integrate(y, item) 13833 ;(/** @type {Map<string, any>} */ (this._prelimAttrs)).forEach((value, key) => { 13834 this.setAttribute(key, value); 13835 }); 13836 this._prelimAttrs = null; 13837 } 13838 13839 /** 13840 * Creates an Item with the same effect as this Item (without position effect) 13841 * 13842 * @return {YXmlElement} 13843 */ 13844 _copy () { 13845 return new YXmlElement(this.nodeName) 13846 } 13847 13848 /** 13849 * @return {YXmlElement<KV>} 13850 */ 13851 clone () { 13852 /** 13853 * @type {YXmlElement<KV>} 13854 */ 13855 const el = new YXmlElement(this.nodeName); 13856 const attrs = this.getAttributes(); 13857 forEach(attrs, (value, key) => { 13858 if (typeof value === 'string') { 13859 el.setAttribute(key, value); 13860 } 13861 }); 13862 // @ts-ignore 13863 el.insert(0, this.toArray().map(item => item instanceof AbstractType ? item.clone() : item)); 13864 return el 13865 } 13866 13867 /** 13868 * Returns the XML serialization of this YXmlElement. 13869 * The attributes are ordered by attribute-name, so you can easily use this 13870 * method to compare YXmlElements 13871 * 13872 * @return {string} The string representation of this type. 13873 * 13874 * @public 13875 */ 13876 toString () { 13877 const attrs = this.getAttributes(); 13878 const stringBuilder = []; 13879 const keys = []; 13880 for (const key in attrs) { 13881 keys.push(key); 13882 } 13883 keys.sort(); 13884 const keysLen = keys.length; 13885 for (let i = 0; i < keysLen; i++) { 13886 const key = keys[i]; 13887 stringBuilder.push(key + '="' + attrs[key] + '"'); 13888 } 13889 const nodeName = this.nodeName.toLocaleLowerCase(); 13890 const attrsString = stringBuilder.length > 0 ? ' ' + stringBuilder.join(' ') : ''; 13891 return `<${nodeName}${attrsString}>${super.toString()}</${nodeName}>` 13892 } 13893 13894 /** 13895 * Removes an attribute from this YXmlElement. 13896 * 13897 * @param {string} attributeName The attribute name that is to be removed. 13898 * 13899 * @public 13900 */ 13901 removeAttribute (attributeName) { 13902 if (this.doc !== null) { 13903 transact(this.doc, transaction => { 13904 typeMapDelete(transaction, this, attributeName); 13905 }); 13906 } else { 13907 /** @type {Map<string,any>} */ (this._prelimAttrs).delete(attributeName); 13908 } 13909 } 13910 13911 /** 13912 * Sets or updates an attribute. 13913 * 13914 * @template {keyof KV & string} KEY 13915 * 13916 * @param {KEY} attributeName The attribute name that is to be set. 13917 * @param {KV[KEY]} attributeValue The attribute value that is to be set. 13918 * 13919 * @public 13920 */ 13921 setAttribute (attributeName, attributeValue) { 13922 if (this.doc !== null) { 13923 transact(this.doc, transaction => { 13924 typeMapSet(transaction, this, attributeName, attributeValue); 13925 }); 13926 } else { 13927 /** @type {Map<string, any>} */ (this._prelimAttrs).set(attributeName, attributeValue); 13928 } 13929 } 13930 13931 /** 13932 * Returns an attribute value that belongs to the attribute name. 13933 * 13934 * @template {keyof KV & string} KEY 13935 * 13936 * @param {KEY} attributeName The attribute name that identifies the 13937 * queried value. 13938 * @return {KV[KEY]|undefined} The queried attribute value. 13939 * 13940 * @public 13941 */ 13942 getAttribute (attributeName) { 13943 return /** @type {any} */ (typeMapGet(this, attributeName)) 13944 } 13945 13946 /** 13947 * Returns whether an attribute exists 13948 * 13949 * @param {string} attributeName The attribute name to check for existence. 13950 * @return {boolean} whether the attribute exists. 13951 * 13952 * @public 13953 */ 13954 hasAttribute (attributeName) { 13955 return /** @type {any} */ (typeMapHas(this, attributeName)) 13956 } 13957 13958 /** 13959 * Returns all attribute name/value pairs in a JSON Object. 13960 * 13961 * @return {{ [Key in Extract<keyof KV,string>]?: KV[Key]}} A JSON Object that describes the attributes. 13962 * 13963 * @public 13964 */ 13965 getAttributes () { 13966 return /** @type {any} */ (typeMapGetAll(this)) 13967 } 13968 13969 /** 13970 * Creates a Dom Element that mirrors this YXmlElement. 13971 * 13972 * @param {Document} [_document=document] The document object (you must define 13973 * this when calling this method in 13974 * nodejs) 13975 * @param {Object<string, any>} [hooks={}] Optional property to customize how hooks 13976 * are presented in the DOM 13977 * @param {any} [binding] You should not set this property. This is 13978 * used if DomBinding wants to create a 13979 * association to the created DOM type. 13980 * @return {Node} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element} 13981 * 13982 * @public 13983 */ 13984 toDOM (_document = document, hooks = {}, binding) { 13985 const dom = _document.createElement(this.nodeName); 13986 const attrs = this.getAttributes(); 13987 for (const key in attrs) { 13988 const value = attrs[key]; 13989 if (typeof value === 'string') { 13990 dom.setAttribute(key, value); 13991 } 13992 } 13993 typeListForEach(this, yxml => { 13994 dom.appendChild(yxml.toDOM(_document, hooks, binding)); 13995 }); 13996 if (binding !== undefined) { 13997 binding._createAssociation(dom, this); 13998 } 13999 return dom 14000 } 14001 14002 /** 14003 * Transform the properties of this type to binary and write it to an 14004 * BinaryEncoder. 14005 * 14006 * This is called when this Item is sent to a remote peer. 14007 * 14008 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to. 14009 */ 14010 _write (encoder) { 14011 encoder.writeTypeRef(YXmlElementRefID); 14012 encoder.writeKey(this.nodeName); 14013 } 14014} 14015 14016/** 14017 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 14018 * @return {YXmlElement} 14019 * 14020 * @function 14021 */ 14022const readYXmlElement = decoder => new YXmlElement(decoder.readKey()); 14023 14024/** 14025 * @extends YEvent<YXmlElement|YXmlText|YXmlFragment> 14026 * An Event that describes changes on a YXml Element or Yxml Fragment 14027 */ 14028class YXmlEvent extends YEvent { 14029 /** 14030 * @param {YXmlElement|YXmlText|YXmlFragment} target The target on which the event is created. 14031 * @param {Set<string|null>} subs The set of changed attributes. `null` is included if the 14032 * child list changed. 14033 * @param {Transaction} transaction The transaction instance with wich the 14034 * change was created. 14035 */ 14036 constructor (target, subs, transaction) { 14037 super(target, transaction); 14038 /** 14039 * Whether the children changed. 14040 * @type {Boolean} 14041 * @private 14042 */ 14043 this.childListChanged = false;
14044 /** 14045 * Set of all changed attributes. 14046 * @type {Set<string>} 14047 */ 14048 this.attributesChanged = new Set(); 14049 subs.forEach((sub) => { 14050 if (sub === null) { 14051 this.childListChanged = true; 14052 } else { 14053 this.attributesChanged.add(sub); 14054 } 14055 }); 14056 } 14057} 14058 14059/** 14060 * You can manage binding to a custom type with YXmlHook. 14061 * 14062 * @extends {YMap<any>} 14063 */ 14064class YXmlHook extends YMap { 14065 /** 14066 * @param {string} hookName nodeName of the Dom Node. 14067 */ 14068 constructor (hookName) { 14069 super(); 14070 /** 14071 * @type {string} 14072 */ 14073 this.hookName = hookName; 14074 } 14075 14076 /** 14077 * Creates an Item with the same effect as this Item (without position effect) 14078 */ 14079 _copy () { 14080 return new YXmlHook(this.hookName) 14081 } 14082 14083 /** 14084 * @return {YXmlHook} 14085 */ 14086 clone () { 14087 const el = new YXmlHook(this.hookName); 14088 this.forEach((value, key) => { 14089 el.set(key, value); 14090 }); 14091 return el 14092 } 14093 14094 /** 14095 * Creates a Dom Element that mirrors this YXmlElement. 14096 * 14097 * @param {Document} [_document=document] The document object (you must define 14098 * this when calling this method in 14099 * nodejs) 14100 * @param {Object.<string, any>} [hooks] Optional property to customize how hooks 14101 * are presented in the DOM 14102 * @param {any} [binding] You should not set this property. This is 14103 * used if DomBinding wants to create a 14104 * association to the created DOM type 14105 * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element} 14106 * 14107 * @public 14108 */ 14109 toDOM (_document = document, hooks = {}, binding) { 14110 const hook = hooks[this.hookName]; 14111 let dom; 14112 if (hook !== undefined) { 14113 dom = hook.createDom(this); 14114 } else { 14115 dom = document.createElement(this.hookName); 14116 } 14117 dom.setAttribute('data-yjs-hook', this.hookName); 14118 if (binding !== undefined) { 14119 binding._createAssociation(dom, this); 14120 } 14121 return dom 14122 } 14123 14124 /** 14125 * Transform the properties of this type to binary and write it to an 14126 * BinaryEncoder. 14127 * 14128 * This is called when this Item is sent to a remote peer. 14129 * 14130 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to. 14131 */ 14132 _write (encoder) { 14133 encoder.writeTypeRef(YXmlHookRefID); 14134 encoder.writeKey(this.hookName); 14135 } 14136} 14137 14138/** 14139 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 14140 * @return {YXmlHook} 14141 * 14142 * @private 14143 * @function 14144 */ 14145const readYXmlHook = decoder => 14146 new YXmlHook(decoder.readKey()); 14147 14148/** 14149 * Represents text in a Dom Element. In the future this type will also handle 14150 * simple formatting information like bold and italic. 14151 */ 14152class YXmlText extends YText { 14153 /** 14154 * @type {YXmlElement|YXmlText|null} 14155 */ 14156 get nextSibling () { 14157 const n = this._item ? this._item.next : null; 14158 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null 14159 } 14160 14161 /** 14162 * @type {YXmlElement|YXmlText|null} 14163 */ 14164 get prevSibling () { 14165 const n = this._item ? this._item.prev : null; 14166 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null 14167 } 14168 14169 _copy () { 14170 return new YXmlText() 14171 } 14172 14173 /** 14174 * @return {YXmlText} 14175 */ 14176 clone () { 14177 const text = new YXmlText(); 14178 text.applyDelta(this.toDelta()); 14179 return text 14180 } 14181 14182 /** 14183 * Creates a Dom Element that mirrors this YXmlText. 14184 * 14185 * @param {Document} [_document=document] The document object (you must define 14186 * this when calling this method in 14187 * nodejs) 14188 * @param {Object<string, any>} [hooks] Optional property to customize how hooks 14189 * are presented in the DOM 14190 * @param {any} [binding] You should not set this property. This is 14191 * used if DomBinding wants to create a 14192 * association to the created DOM type. 14193 * @return {Text} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element} 14194 * 14195 * @public 14196 */ 14197 toDOM (_document = document, hooks, binding) { 14198 const dom = _document.createTextNode(this.toString()); 14199 if (binding !== undefined) { 14200 binding._createAssociation(dom, this); 14201 } 14202 return dom 14203 } 14204 14205 toString () { 14206 // @ts-ignore 14207 return this.toDelta().map(delta => { 14208 const nestedNodes = []; 14209 for (const nodeName in delta.attributes) { 14210 const attrs = []; 14211 for (const key in delta.attributes[nodeName]) { 14212 attrs.push({ key, value: delta.attributes[nodeName][key] }); 14213 } 14214 // sort attributes to get a unique order 14215 attrs.sort((a, b) => a.key < b.key ? -1 : 1); 14216 nestedNodes.push({ nodeName, attrs }); 14217 } 14218 // sort node order to get a unique order 14219 nestedNodes.sort((a, b) => a.nodeName < b.nodeName ? -1 : 1); 14220 // now convert to dom string 14221 let str = ''; 14222 for (let i = 0; i < nestedNodes.length; i++) { 14223 const node = nestedNodes[i]; 14224 str += `<${node.nodeName}`; 14225 for (let j = 0; j < node.attrs.length; j++) { 14226 const attr = node.attrs[j]; 14227 str += ` ${attr.key}="${attr.value}"`; 14228 } 14229 str += '>'; 14230 } 14231 str += delta.insert; 14232 for (let i = nestedNodes.length - 1; i >= 0; i--) { 14233 str += `</${nestedNodes[i].nodeName}>`; 14234 } 14235 return str 14236 }).join('') 14237 } 14238 14239 /** 14240 * @return {string} 14241 */ 14242 toJSON () { 14243 return this.toString() 14244 } 14245 14246 /** 14247 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 14248 */ 14249 _write (encoder) { 14250 encoder.writeTypeRef(YXmlTextRefID); 14251 } 14252} 14253 14254/** 14255 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 14256 * @return {YXmlText} 14257 * 14258 * @private 14259 * @function 14260 */ 14261const readYXmlText = decoder => new YXmlText(); 14262 14263class AbstractStruct { 14264 /** 14265 * @param {ID} id 14266 * @param {number} length 14267 */ 14268 constructor (id, length) { 14269 this.id = id; 14270 this.length = length; 14271 } 14272 14273 /** 14274 * @type {boolean} 14275 */ 14276 get deleted () { 14277 throw methodUnimplemented() 14278 } 14279 14280 /** 14281 * Merge this struct with the item to the right. 14282 * This method is already assuming that `this.id.clock + this.length === this.id.clock`. 14283 * Also this method does *not* remove right from StructStore! 14284 * @param {AbstractStruct} right 14285 * @return {boolean} wether this merged with right 14286 */ 14287 mergeWith (right) { 14288 return false 14289 } 14290 14291 /** 14292 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to. 14293 * @param {number} offset 14294 * @param {number} encodingRef 14295 */ 14296 write (encoder, offset, encodingRef) { 14297 throw methodUnimplemented() 14298 } 14299 14300 /** 14301 * @param {Transaction} transaction 14302 * @param {number} offset 14303 */ 14304 integrate (transaction, offset) { 14305 throw methodUnimplemented() 14306 } 14307} 14308 14309const structGCRefNumber = 0; 14310 14311/** 14312 * @private 14313 */ 14314class GC extends AbstractStruct { 14315 get deleted () { 14316 return true 14317 } 14318 14319 delete () {} 14320 14321 /** 14322 * @param {GC} right 14323 * @return {boolean} 14324 */ 14325 mergeWith (right) { 14326 if (this.constructor !== right.constructor) { 14327 return false 14328 } 14329 this.length += right.length; 14330 return true 14331 } 14332 14333 /** 14334 * @param {Transaction} transaction 14335 * @param {number} offset 14336 */ 14337 integrate (transaction, offset) { 14338 if (offset > 0) { 14339 this.id.clock += offset; 14340 this.length -= offset; 14341 } 14342 addStruct(transaction.doc.store, this); 14343 } 14344 14345 /** 14346 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 14347 * @param {number} offset 14348 */ 14349 write (encoder, offset) { 14350 encoder.writeInfo(structGCRefNumber); 14351 encoder.writeLen(this.length - offset); 14352 } 14353 14354 /** 14355 * @param {Transaction} transaction 14356 * @param {StructStore} store 14357 * @return {null | number} 14358 */ 14359 getMissing (transaction, store) { 14360 return null 14361 } 14362} 14363 14364class ContentBinary { 14365 /** 14366 * @param {Uint8Array} content 14367 */ 14368 constructor (content) { 14369 this.content = content; 14370 } 14371 14372 /** 14373 * @return {number} 14374 */ 14375 getLength () { 14376 return 1 14377 } 14378 14379 /** 14380 * @return {Array<any>} 14381 */ 14382 getContent () { 14383 return [this.content] 14384 } 14385 14386 /** 14387 * @return {boolean} 14388 */ 14389 isCountable () { 14390 return true 14391 } 14392 14393 /** 14394 * @return {ContentBinary} 14395 */ 14396 copy () { 14397 return new ContentBinary(this.content) 14398 } 14399 14400 /** 14401 * @param {number} offset 14402 * @return {ContentBinary} 14403 */ 14404 splice (offset) { 14405 throw methodUnimplemented() 14406 } 14407 14408 /** 14409 * @param {ContentBinary} right 14410 * @return {boolean} 14411 */ 14412 mergeWith (right) { 14413 return false 14414 } 14415 14416 /** 14417 * @param {Transaction} transaction 14418 * @param {Item} item 14419 */ 14420 integrate (transaction, item) {} 14421 /** 14422 * @param {Transaction} transaction 14423 */ 14424 delete (transaction) {} 14425 /** 14426 * @param {StructStore} store 14427 */ 14428 gc (store) {} 14429 /** 14430 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 14431 * @param {number} offset 14432 */ 14433 write (encoder, offset) { 14434 encoder.writeBuf(this.content); 14435 } 14436 14437 /** 14438 * @return {number} 14439 */ 14440 getRef () { 14441 return 3 14442 } 14443} 14444 14445/** 14446 * @param {UpdateDecoderV1 | UpdateDecoderV2 } decoder 14447 * @return {ContentBinary} 14448 */ 14449const readContentBinary = decoder => new ContentBinary(decoder.readBuf()); 14450 14451class ContentDeleted { 14452 /** 14453 * @param {number} len 14454 */ 14455 constructor (len) { 14456 this.len = len; 14457 } 14458 14459 /** 14460 * @return {number} 14461 */ 14462 getLength () { 14463 return this.len 14464 } 14465 14466 /** 14467 * @return {Array<any>} 14468 */ 14469 getContent () { 14470 return [] 14471 } 14472 14473 /** 14474 * @return {boolean} 14475 */ 14476 isCountable () { 14477 return false 14478 } 14479 14480 /** 14481 * @return {ContentDeleted} 14482 */ 14483 copy () { 14484 return new ContentDeleted(this.len) 14485 } 14486 14487 /** 14488 * @param {number} offset 14489 * @return {ContentDeleted} 14490 */ 14491 splice (offset) { 14492 const right = new ContentDeleted(this.len - offset); 14493 this.len = offset; 14494 return right 14495 } 14496 14497 /** 14498 * @param {ContentDeleted} right 14499 * @return {boolean} 14500 */ 14501 mergeWith (right) { 14502 this.len += right.len; 14503 return true 14504 } 14505 14506 /** 14507 * @param {Transaction} transaction 14508 * @param {Item} item 14509 */ 14510 integrate (transaction, item) { 14511 addToDeleteSet(transaction.deleteSet, item.id.client, item.id.clock, this.len); 14512 item.markDeleted(); 14513 } 14514 14515 /** 14516 * @param {Transaction} transaction 14517 */ 14518 delete (transaction) {} 14519 /** 14520 * @param {StructStore} store 14521 */ 14522 gc (store) {} 14523 /** 14524 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 14525 * @param {number} offset 14526 */ 14527 write (encoder, offset) { 14528 encoder.writeLen(this.len - offset); 14529 } 14530 14531 /** 14532 * @return {number} 14533 */ 14534 getRef () { 14535 return 1 14536 } 14537} 14538 14539/** 14540 * @private 14541 * 14542 * @param {UpdateDecoderV1 | UpdateDecoderV2 } decoder 14543 * @return {ContentDeleted} 14544 */ 14545const readContentDeleted = decoder => new ContentDeleted(decoder.readLen()); 14546 14547/** 14548 * @param {string} guid 14549 * @param {Object<string, any>} opts 14550 */ 14551const createDocFromOpts = (guid, opts) => new Doc({ guid, ...opts, shouldLoad: opts.shouldLoad || opts.autoLoad || false }); 14552 14553/** 14554 * @private 14555 */ 14556class ContentDoc { 14557 /** 14558 * @param {Doc} doc 14559 */ 14560 constructor (doc) { 14561 if (doc._item) { 14562 console.error('This document was already integrated as a sub-document. You should create a second instance instead with the same guid.'); 14563 } 14564 /** 14565 * @type {Doc} 14566 */ 14567 this.doc = doc; 14568 /** 14569 * @type {any} 14570 */ 14571 const opts = {}; 14572 this.opts = opts; 14573 if (!doc.gc) { 14574 opts.gc = false;
14575 } 14576 if (doc.autoLoad) { 14577 opts.autoLoad = true; 14578 } 14579 if (doc.meta !== null) { 14580 opts.meta = doc.meta; 14581 } 14582 } 14583 14584 /** 14585 * @return {number} 14586 */ 14587 getLength () { 14588 return 1 14589 } 14590 14591 /** 14592 * @return {Array<any>} 14593 */ 14594 getContent () { 14595 return [this.doc] 14596 } 14597 14598 /** 14599 * @return {boolean} 14600 */ 14601 isCountable () { 14602 return true 14603 } 14604 14605 /** 14606 * @return {ContentDoc} 14607 */ 14608 copy () { 14609 return new ContentDoc(createDocFromOpts(this.doc.guid, this.opts)) 14610 } 14611 14612 /** 14613 * @param {number} offset 14614 * @return {ContentDoc} 14615 */ 14616 splice (offset) { 14617 throw methodUnimplemented() 14618 } 14619 14620 /** 14621 * @param {ContentDoc} right 14622 * @return {boolean} 14623 */ 14624 mergeWith (right) { 14625 return false 14626 } 14627 14628 /** 14629 * @param {Transaction} transaction 14630 * @param {Item} item 14631 */ 14632 integrate (transaction, item) { 14633 // this needs to be reflected in doc.destroy as well 14634 this.doc._item = item; 14635 transaction.subdocsAdded.add(this.doc); 14636 if (this.doc.shouldLoad) { 14637 transaction.subdocsLoaded.add(this.doc); 14638 } 14639 } 14640 14641 /** 14642 * @param {Transaction} transaction 14643 */ 14644 delete (transaction) { 14645 if (transaction.subdocsAdded.has(this.doc)) { 14646 transaction.subdocsAdded.delete(this.doc); 14647 } else { 14648 transaction.subdocsRemoved.add(this.doc); 14649 } 14650 } 14651 14652 /** 14653 * @param {StructStore} store 14654 */ 14655 gc (store) { } 14656 14657 /** 14658 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 14659 * @param {number} offset 14660 */ 14661 write (encoder, offset) { 14662 encoder.writeString(this.doc.guid); 14663 encoder.writeAny(this.opts); 14664 } 14665 14666 /** 14667 * @return {number} 14668 */ 14669 getRef () { 14670 return 9 14671 } 14672} 14673 14674/** 14675 * @private 14676 * 14677 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 14678 * @return {ContentDoc} 14679 */ 14680const readContentDoc = decoder => new ContentDoc(createDocFromOpts(decoder.readString(), decoder.readAny())); 14681 14682/** 14683 * @private 14684 */ 14685class ContentEmbed { 14686 /** 14687 * @param {Object} embed 14688 */ 14689 constructor (embed) { 14690 this.embed = embed; 14691 } 14692 14693 /** 14694 * @return {number} 14695 */ 14696 getLength () { 14697 return 1 14698 } 14699 14700 /** 14701 * @return {Array<any>} 14702 */ 14703 getContent () { 14704 return [this.embed] 14705 } 14706 14707 /** 14708 * @return {boolean} 14709 */ 14710 isCountable () { 14711 return true 14712 } 14713 14714 /** 14715 * @return {ContentEmbed} 14716 */ 14717 copy () { 14718 return new ContentEmbed(this.embed) 14719 } 14720 14721 /** 14722 * @param {number} offset 14723 * @return {ContentEmbed} 14724 */ 14725 splice (offset) { 14726 throw methodUnimplemented() 14727 } 14728 14729 /** 14730 * @param {ContentEmbed} right 14731 * @return {boolean} 14732 */ 14733 mergeWith (right) { 14734 return false 14735 } 14736 14737 /** 14738 * @param {Transaction} transaction 14739 * @param {Item} item 14740 */ 14741 integrate (transaction, item) {} 14742 /** 14743 * @param {Transaction} transaction 14744 */ 14745 delete (transaction) {} 14746 /** 14747 * @param {StructStore} store 14748 */ 14749 gc (store) {} 14750 /** 14751 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 14752 * @param {number} offset 14753 */ 14754 write (encoder, offset) { 14755 encoder.writeJSON(this.embed); 14756 } 14757 14758 /** 14759 * @return {number} 14760 */ 14761 getRef () { 14762 return 5 14763 } 14764} 14765 14766/** 14767 * @private 14768 * 14769 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 14770 * @return {ContentEmbed} 14771 */ 14772const readContentEmbed = decoder => new ContentEmbed(decoder.readJSON()); 14773 14774/** 14775 * @private 14776 */ 14777class ContentFormat { 14778 /** 14779 * @param {string} key 14780 * @param {Object} value 14781 */ 14782 constructor (key, value) { 14783 this.key = key; 14784 this.value = value; 14785 } 14786 14787 /** 14788 * @return {number} 14789 */ 14790 getLength () { 14791 return 1 14792 } 14793 14794 /** 14795 * @return {Array<any>} 14796 */ 14797 getContent () { 14798 return [] 14799 } 14800 14801 /** 14802 * @return {boolean} 14803 */ 14804 isCountable () { 14805 return false 14806 } 14807 14808 /** 14809 * @return {ContentFormat} 14810 */ 14811 copy () { 14812 return new ContentFormat(this.key, this.value) 14813 } 14814 14815 /** 14816 * @param {number} _offset 14817 * @return {ContentFormat} 14818 */ 14819 splice (_offset) { 14820 throw methodUnimplemented() 14821 } 14822 14823 /** 14824 * @param {ContentFormat} _right 14825 * @return {boolean} 14826 */ 14827 mergeWith (_right) { 14828 return false 14829 } 14830 14831 /** 14832 * @param {Transaction} _transaction 14833 * @param {Item} item 14834 */ 14835 integrate (_transaction, item) { 14836 // @todo searchmarker are currently unsupported for rich text documents 14837 const p = /** @type {YText} */ (item.parent); 14838 p._searchMarker = null; 14839 p._hasFormatting = true; 14840 } 14841 14842 /** 14843 * @param {Transaction} transaction 14844 */ 14845 delete (transaction) {} 14846 /** 14847 * @param {StructStore} store 14848 */ 14849 gc (store) {} 14850 /** 14851 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 14852 * @param {number} offset 14853 */ 14854 write (encoder, offset) { 14855 encoder.writeKey(this.key); 14856 encoder.writeJSON(this.value); 14857 } 14858 14859 /** 14860 * @return {number} 14861 */ 14862 getRef () { 14863 return 6 14864 } 14865} 14866 14867/** 14868 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 14869 * @return {ContentFormat} 14870 */ 14871const readContentFormat = decoder => new ContentFormat(decoder.readKey(), decoder.readJSON()); 14872 14873/** 14874 * @private 14875 */ 14876class ContentJSON { 14877 /** 14878 * @param {Array<any>} arr 14879 */ 14880 constructor (arr) { 14881 /** 14882 * @type {Array<any>} 14883 */ 14884 this.arr = arr; 14885 } 14886 14887 /** 14888 * @return {number} 14889 */ 14890 getLength () { 14891 return this.arr.length 14892 } 14893 14894 /** 14895 * @return {Array<any>} 14896 */ 14897 getContent () { 14898 return this.arr 14899 } 14900 14901 /** 14902 * @return {boolean} 14903 */ 14904 isCountable () { 14905 return true 14906 } 14907 14908 /** 14909 * @return {ContentJSON} 14910 */ 14911 copy () { 14912 return new ContentJSON(this.arr) 14913 } 14914 14915 /** 14916 * @param {number} offset 14917 * @return {ContentJSON} 14918 */ 14919 splice (offset) { 14920 const right = new ContentJSON(this.arr.slice(offset)); 14921 this.arr = this.arr.slice(0, offset); 14922 return right 14923 } 14924 14925 /** 14926 * @param {ContentJSON} right 14927 * @return {boolean} 14928 */ 14929 mergeWith (right) { 14930 this.arr = this.arr.concat(right.arr); 14931 return true 14932 } 14933 14934 /** 14935 * @param {Transaction} transaction 14936 * @param {Item} item 14937 */ 14938 integrate (transaction, item) {} 14939 /** 14940 * @param {Transaction} transaction 14941 */ 14942 delete (transaction) {} 14943 /** 14944 * @param {StructStore} store 14945 */ 14946 gc (store) {} 14947 /** 14948 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 14949 * @param {number} offset 14950 */ 14951 write (encoder, offset) { 14952 const len = this.arr.length; 14953 encoder.writeLen(len - offset); 14954 for (let i = offset; i < len; i++) { 14955 const c = this.arr[i]; 14956 encoder.writeString(c === undefined ? 'undefined' : JSON.stringify(c)); 14957 } 14958 } 14959 14960 /** 14961 * @return {number} 14962 */ 14963 getRef () { 14964 return 2 14965 } 14966} 14967 14968/** 14969 * @private 14970 * 14971 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 14972 * @return {ContentJSON} 14973 */ 14974const readContentJSON = decoder => { 14975 const len = decoder.readLen(); 14976 const cs = []; 14977 for (let i = 0; i < len; i++) { 14978 const c = decoder.readString(); 14979 if (c === 'undefined') { 14980 cs.push(undefined); 14981 } else { 14982 cs.push(JSON.parse(c)); 14983 } 14984 } 14985 return new ContentJSON(cs) 14986}; 14987 14988class ContentAny { 14989 /** 14990 * @param {Array<any>} arr 14991 */ 14992 constructor (arr) { 14993 /** 14994 * @type {Array<any>} 14995 */ 14996 this.arr = arr; 14997 } 14998 14999 /** 15000 * @return {number} 15001 */ 15002 getLength () { 15003 return this.arr.length 15004 } 15005 15006 /** 15007 * @return {Array<any>} 15008 */ 15009 getContent () { 15010 return this.arr 15011 } 15012 15013 /** 15014 * @return {boolean} 15015 */ 15016 isCountable () { 15017 return true 15018 } 15019 15020 /** 15021 * @return {ContentAny} 15022 */ 15023 copy () { 15024 return new ContentAny(this.arr) 15025 } 15026 15027 /** 15028 * @param {number} offset 15029 * @return {ContentAny} 15030 */ 15031 splice (offset) { 15032 const right = new ContentAny(this.arr.slice(offset)); 15033 this.arr = this.arr.slice(0, offset); 15034 return right 15035 } 15036 15037 /** 15038 * @param {ContentAny} right 15039 * @return {boolean} 15040 */ 15041 mergeWith (right) { 15042 this.arr = this.arr.concat(right.arr); 15043 return true 15044 } 15045 15046 /** 15047 * @param {Transaction} transaction 15048 * @param {Item} item 15049 */ 15050 integrate (transaction, item) {} 15051 /** 15052 * @param {Transaction} transaction 15053 */ 15054 delete (transaction) {} 15055 /** 15056 * @param {StructStore} store 15057 */ 15058 gc (store) {} 15059 /** 15060 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 15061 * @param {number} offset 15062 */ 15063 write (encoder, offset) { 15064 const len = this.arr.length; 15065 encoder.writeLen(len - offset); 15066 for (let i = offset; i < len; i++) { 15067 const c = this.arr[i]; 15068 encoder.writeAny(c); 15069 } 15070 } 15071 15072 /** 15073 * @return {number} 15074 */ 15075 getRef () { 15076 return 8 15077 } 15078} 15079 15080/** 15081 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 15082 * @return {ContentAny} 15083 */ 15084const readContentAny = decoder => { 15085 const len = decoder.readLen(); 15086 const cs = []; 15087 for (let i = 0; i < len; i++) { 15088 cs.push(decoder.readAny()); 15089 } 15090 return new ContentAny(cs) 15091}; 15092 15093/** 15094 * @private 15095 */ 15096class ContentString { 15097 /** 15098 * @param {string} str 15099 */ 15100 constructor (str) { 15101 /** 15102 * @type {string} 15103 */ 15104 this.str = str; 15105 } 15106 15107 /** 15108 * @return {number} 15109 */ 15110 getLength () { 15111 return this.str.length 15112 } 15113 15114 /** 15115 * @return {Array<any>} 15116 */ 15117 getContent () { 15118 return this.str.split('') 15119 } 15120 15121 /** 15122 * @return {boolean} 15123 */ 15124 isCountable () { 15125 return true 15126 } 15127 15128 /** 15129 * @return {ContentString} 15130 */ 15131 copy () { 15132 return new ContentString(this.str) 15133 } 15134 15135 /** 15136 * @param {number} offset 15137 * @return {ContentString} 15138 */ 15139 splice (offset) { 15140 const right = new ContentString(this.str.slice(offset)); 15141 this.str = this.str.slice(0, offset); 15142 15143 // Prevent encoding invalid documents because of splitting of surrogate pairs: https://github.com/yjs/yjs/issues/248
15144 const firstCharCode = this.str.charCodeAt(offset - 1); 15145 if (firstCharCode >= 0xD800 && firstCharCode <= 0xDBFF) { 15146 // Last character of the left split is the start of a surrogate utf16/ucs2 pair. 15147 // We don't support splitting of surrogate pairs because this may lead to invalid documents. 15148 // Replace the invalid character with a unicode replacement character (� / U+FFFD) 15149 this.str = this.str.slice(0, offset - 1) + '�'; 15150 // replace right as well 15151 right.str = '�' + right.str.slice(1); 15152 } 15153 return right 15154 } 15155 15156 /** 15157 * @param {ContentString} right 15158 * @return {boolean} 15159 */ 15160 mergeWith (right) { 15161 this.str += right.str; 15162 return true 15163 } 15164 15165 /** 15166 * @param {Transaction} transaction 15167 * @param {Item} item 15168 */ 15169 integrate (transaction, item) {} 15170 /** 15171 * @param {Transaction} transaction 15172 */ 15173 delete (transaction) {} 15174 /** 15175 * @param {StructStore} store 15176 */ 15177 gc (store) {} 15178 /** 15179 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 15180 * @param {number} offset 15181 */ 15182 write (encoder, offset) { 15183 encoder.writeString(offset === 0 ? this.str : this.str.slice(offset)); 15184 } 15185 15186 /** 15187 * @return {number} 15188 */ 15189 getRef () { 15190 return 4 15191 } 15192} 15193 15194/** 15195 * @private 15196 * 15197 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 15198 * @return {ContentString} 15199 */ 15200const readContentString = decoder => new ContentString(decoder.readString()); 15201 15202/** 15203 * @type {Array<function(UpdateDecoderV1 | UpdateDecoderV2):AbstractType<any>>} 15204 * @private 15205 */ 15206const typeRefs = [ 15207 readYArray, 15208 readYMap, 15209 readYText, 15210 readYXmlElement, 15211 readYXmlFragment, 15212 readYXmlHook, 15213 readYXmlText 15214]; 15215 15216const YArrayRefID = 0; 15217const YMapRefID = 1; 15218const YTextRefID = 2; 15219const YXmlElementRefID = 3; 15220const YXmlFragmentRefID = 4; 15221const YXmlHookRefID = 5; 15222const YXmlTextRefID = 6; 15223 15224/** 15225 * @private 15226 */ 15227class ContentType { 15228 /** 15229 * @param {AbstractType<any>} type 15230 */ 15231 constructor (type) { 15232 /** 15233 * @type {AbstractType<any>} 15234 */ 15235 this.type = type; 15236 } 15237 15238 /** 15239 * @return {number} 15240 */ 15241 getLength () { 15242 return 1 15243 } 15244 15245 /** 15246 * @return {Array<any>} 15247 */ 15248 getContent () { 15249 return [this.type] 15250 } 15251 15252 /** 15253 * @return {boolean} 15254 */ 15255 isCountable () { 15256 return true 15257 } 15258 15259 /** 15260 * @return {ContentType} 15261 */ 15262 copy () { 15263 return new ContentType(this.type._copy()) 15264 } 15265 15266 /** 15267 * @param {number} offset 15268 * @return {ContentType} 15269 */ 15270 splice (offset) { 15271 throw methodUnimplemented() 15272 } 15273 15274 /** 15275 * @param {ContentType} right 15276 * @return {boolean} 15277 */ 15278 mergeWith (right) { 15279 return false 15280 } 15281 15282 /** 15283 * @param {Transaction} transaction 15284 * @param {Item} item 15285 */ 15286 integrate (transaction, item) { 15287 this.type._integrate(transaction.doc, item); 15288 } 15289 15290 /** 15291 * @param {Transaction} transaction 15292 */ 15293 delete (transaction) { 15294 let item = this.type._start; 15295 while (item !== null) { 15296 if (!item.deleted) { 15297 item.delete(transaction); 15298 } else if (item.id.clock < (transaction.beforeState.get(item.id.client) || 0)) { 15299 // This will be gc'd later and we want to merge it if possible 15300 // We try to merge all deleted items after each transaction, 15301 // but we have no knowledge about that this needs to be merged 15302 // since it is not in transaction.ds. Hence we add it to transaction._mergeStructs 15303 transaction._mergeStructs.push(item); 15304 } 15305 item = item.right; 15306 } 15307 this.type._map.forEach(item => { 15308 if (!item.deleted) { 15309 item.delete(transaction); 15310 } else if (item.id.clock < (transaction.beforeState.get(item.id.client) || 0)) { 15311 // same as above 15312 transaction._mergeStructs.push(item); 15313 } 15314 }); 15315 transaction.changed.delete(this.type); 15316 } 15317 15318 /** 15319 * @param {StructStore} store 15320 */ 15321 gc (store) { 15322 let item = this.type._start; 15323 while (item !== null) { 15324 item.gc(store, true); 15325 item = item.right; 15326 } 15327 this.type._start = null; 15328 this.type._map.forEach(/** @param {Item | null} item */ (item) => { 15329 while (item !== null) { 15330 item.gc(store, true); 15331 item = item.left; 15332 } 15333 }); 15334 this.type._map = new Map(); 15335 } 15336 15337 /** 15338 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 15339 * @param {number} offset 15340 */ 15341 write (encoder, offset) { 15342 this.type._write(encoder); 15343 } 15344 15345 /** 15346 * @return {number} 15347 */ 15348 getRef () { 15349 return 7 15350 } 15351} 15352 15353/** 15354 * @private 15355 * 15356 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 15357 * @return {ContentType} 15358 */ 15359const readContentType = decoder => new ContentType(typeRefs[decoder.readTypeRef()](decoder)); 15360 15361/** 15362 * @todo This should return several items 15363 * 15364 * @param {StructStore} store 15365 * @param {ID} id 15366 * @return {{item:Item, diff:number}} 15367 */ 15368const followRedone = (store, id) => { 15369 /** 15370 * @type {ID|null} 15371 */ 15372 let nextID = id; 15373 let diff = 0; 15374 let item; 15375 do { 15376 if (diff > 0) { 15377 nextID = createID(nextID.client, nextID.clock + diff); 15378 } 15379 item = getItem(store, nextID); 15380 diff = nextID.clock - item.id.clock; 15381 nextID = item.redone; 15382 } while (nextID !== null && item instanceof Item) 15383 return { 15384 item, diff 15385 } 15386}; 15387 15388/** 15389 * Make sure that neither item nor any of its parents is ever deleted. 15390 * 15391 * This property does not persist when storing it into a database or when 15392 * sending it to other peers 15393 * 15394 * @param {Item|null} item 15395 * @param {boolean} keep 15396 */ 15397const keepItem = (item, keep) => { 15398 while (item !== null && item.keep !== keep) { 15399 item.keep = keep; 15400 item = /** @type {AbstractType<any>} */ (item.parent)._item; 15401 } 15402}; 15403 15404/** 15405 * Split leftItem into two items 15406 * @param {Transaction} transaction 15407 * @param {Item} leftItem 15408 * @param {number} diff 15409 * @return {Item} 15410 * 15411 * @function 15412 * @private 15413 */ 15414const splitItem = (transaction, leftItem, diff) => { 15415 // create rightItem 15416 const { client, clock } = leftItem.id; 15417 const rightItem = new Item( 15418 createID(client, clock + diff), 15419 leftItem, 15420 createID(client, clock + diff - 1), 15421 leftItem.right, 15422 leftItem.rightOrigin, 15423 leftItem.parent, 15424 leftItem.parentSub, 15425 leftItem.content.splice(diff) 15426 ); 15427 if (leftItem.deleted) { 15428 rightItem.markDeleted(); 15429 } 15430 if (leftItem.keep) { 15431 rightItem.keep = true; 15432 } 15433 if (leftItem.redone !== null) { 15434 rightItem.redone = createID(leftItem.redone.client, leftItem.redone.clock + diff); 15435 } 15436 // update left (do not set leftItem.rightOrigin as it will lead to problems when syncing) 15437 leftItem.right = rightItem; 15438 // update right 15439 if (rightItem.right !== null) { 15440 rightItem.right.left = rightItem; 15441 } 15442 // right is more specific. 15443 transaction._mergeStructs.push(rightItem); 15444 // update parent._map 15445 if (rightItem.parentSub !== null && rightItem.right === null) { 15446 /** @type {AbstractType<any>} */ (rightItem.parent)._map.set(rightItem.parentSub, rightItem); 15447 } 15448 leftItem.length = diff; 15449 return rightItem 15450}; 15451 15452/** 15453 * @param {Array<StackItem>} stack 15454 * @param {ID} id 15455 */ 15456const isDeletedByUndoStack = (stack, id) => array.some(stack, /** @param {StackItem} s */ s => isDeleted(s.deletions, id)); 15457 15458/** 15459 * Redoes the effect of this operation. 15460 * 15461 * @param {Transaction} transaction The Yjs instance. 15462 * @param {Item} item 15463 * @param {Set<Item>} redoitems 15464 * @param {DeleteSet} itemsToDelete 15465 * @param {boolean} ignoreRemoteMapChanges 15466 * @param {import('../utils/UndoManager.js').UndoManager} um 15467 * 15468 * @return {Item|null} 15469 * 15470 * @private 15471 */ 15472const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) => { 15473 const doc = transaction.doc; 15474 const store = doc.store; 15475 const ownClientID = doc.clientID; 15476 const redone = item.redone; 15477 if (redone !== null) { 15478 return getItemCleanStart(transaction, redone) 15479 } 15480 let parentItem = /** @type {AbstractType<any>} */ (item.parent)._item; 15481 /** 15482 * @type {Item|null} 15483 */ 15484 let left = null; 15485 /** 15486 * @type {Item|null} 15487 */ 15488 let right; 15489 // make sure that parent is redone 15490 if (parentItem !== null && parentItem.deleted === true) { 15491 // try to undo parent if it will be undone anyway 15492 if (parentItem.redone === null && (!redoitems.has(parentItem) || redoItem(transaction, parentItem, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) === null)) { 15493 return null 15494 } 15495 while (parentItem.redone !== null) { 15496 parentItem = getItemCleanStart(transaction, parentItem.redone); 15497 } 15498 } 15499 const parentType = parentItem === null ? /** @type {AbstractType<any>} */ (item.parent) : /** @type {ContentType} */ (parentItem.content).type; 15500 15501 if (item.parentSub === null) { 15502 // Is an array item. Insert at the old position 15503 left = item.left; 15504 right = item; 15505 // find next cloned_redo items 15506 while (left !== null) { 15507 /** 15508 * @type {Item|null} 15509 */ 15510 let leftTrace = left; 15511 // trace redone until parent matches 15512 while (leftTrace !== null && /** @type {AbstractType<any>} */ (leftTrace.parent)._item !== parentItem) { 15513 leftTrace = leftTrace.redone === null ? null : getItemCleanStart(transaction, leftTrace.redone); 15514 } 15515 if (leftTrace !== null && /** @type {AbstractType<any>} */ (leftTrace.parent)._item === parentItem) { 15516 left = leftTrace; 15517 break 15518 } 15519 left = left.left; 15520 } 15521 while (right !== null) { 15522 /** 15523 * @type {Item|null} 15524 */ 15525 let rightTrace = right; 15526 // trace redone until parent matches 15527 while (rightTrace !== null && /** @type {AbstractType<any>} */ (rightTrace.parent)._item !== parentItem) { 15528 rightTrace = rightTrace.redone === null ? null : getItemCleanStart(transaction, rightTrace.redone); 15529 } 15530 if (rightTrace !== null && /** @type {AbstractType<any>} */ (rightTrace.parent)._item === parentItem) { 15531 right = rightTrace; 15532 break 15533 } 15534 right = right.right; 15535 } 15536 } else { 15537 right = null; 15538 if (item.right && !ignoreRemoteMapChanges) { 15539 left = item; 15540 // Iterate right while right is in itemsToDelete 15541 // If it is intended to delete right while item is redone, we can expect that item should replace right. 15542 while (left !== null && left.right !== null && (left.right.redone || isDeleted(itemsToDelete, left.right.id) || isDeletedByUndoStack(um.undoStack, left.right.id) || isDeletedByUndoStack(um.redoStack, left.right.id))) { 15543 left = left.right; 15544 // follow redone 15545 while (left.redone) left = getItemCleanStart(transaction, left.redone); 15546 } 15547 if (left && left.right !== null) {
15548 // It is not possible to redo this item because it conflicts with a 15549 // change from another client 15550 return null 15551 } 15552 } else { 15553 left = parentType._map.get(item.parentSub) || null; 15554 } 15555 } 15556 const nextClock = getState(store, ownClientID); 15557 const nextId = createID(ownClientID, nextClock); 15558 const redoneItem = new Item( 15559 nextId, 15560 left, left && left.lastId, 15561 right, right && right.id, 15562 parentType, 15563 item.parentSub, 15564 item.content.copy() 15565 ); 15566 item.redone = nextId; 15567 keepItem(redoneItem, true); 15568 redoneItem.integrate(transaction, 0); 15569 return redoneItem 15570}; 15571 15572/** 15573 * Abstract class that represents any content. 15574 */ 15575class Item extends AbstractStruct { 15576 /** 15577 * @param {ID} id 15578 * @param {Item | null} left 15579 * @param {ID | null} origin 15580 * @param {Item | null} right 15581 * @param {ID | null} rightOrigin 15582 * @param {AbstractType<any>|ID|null} parent Is a type if integrated, is null if it is possible to copy parent from left or right, is ID before integration to search for it. 15583 * @param {string | null} parentSub 15584 * @param {AbstractContent} content 15585 */ 15586 constructor (id, left, origin, right, rightOrigin, parent, parentSub, content) { 15587 super(id, content.getLength()); 15588 /** 15589 * The item that was originally to the left of this item. 15590 * @type {ID | null} 15591 */ 15592 this.origin = origin; 15593 /** 15594 * The item that is currently to the left of this item. 15595 * @type {Item | null} 15596 */ 15597 this.left = left; 15598 /** 15599 * The item that is currently to the right of this item. 15600 * @type {Item | null} 15601 */ 15602 this.right = right; 15603 /** 15604 * The item that was originally to the right of this item. 15605 * @type {ID | null} 15606 */ 15607 this.rightOrigin = rightOrigin; 15608 /** 15609 * @type {AbstractType<any>|ID|null} 15610 */ 15611 this.parent = parent; 15612 /** 15613 * If the parent refers to this item with some kind of key (e.g. YMap, the 15614 * key is specified here. The key is then used to refer to the list in which 15615 * to insert this item. If `parentSub = null` type._start is the list in 15616 * which to insert to. Otherwise it is `parent._map`. 15617 * @type {String | null} 15618 */ 15619 this.parentSub = parentSub; 15620 /** 15621 * If this type's effect is redone this type refers to the type that undid 15622 * this operation. 15623 * @type {ID | null} 15624 */ 15625 this.redone = null; 15626 /** 15627 * @type {AbstractContent} 15628 */ 15629 this.content = content; 15630 /** 15631 * bit1: keep 15632 * bit2: countable 15633 * bit3: deleted 15634 * bit4: mark - mark node as fast-search-marker 15635 * @type {number} byte 15636 */ 15637 this.info = this.content.isCountable() ? BIT2 : 0; 15638 } 15639 15640 /** 15641 * This is used to mark the item as an indexed fast-search marker 15642 * 15643 * @type {boolean} 15644 */ 15645 set marker (isMarked) { 15646 if (((this.info & BIT4) > 0) !== isMarked) { 15647 this.info ^= BIT4; 15648 } 15649 } 15650 15651 get marker () { 15652 return (this.info & BIT4) > 0 15653 } 15654 15655 /** 15656 * If true, do not garbage collect this Item. 15657 */ 15658 get keep () { 15659 return (this.info & BIT1) > 0 15660 } 15661 15662 set keep (doKeep) { 15663 if (this.keep !== doKeep) { 15664 this.info ^= BIT1; 15665 } 15666 } 15667 15668 get countable () { 15669 return (this.info & BIT2) > 0 15670 } 15671 15672 /** 15673 * Whether this item was deleted or not. 15674 * @type {Boolean} 15675 */ 15676 get deleted () { 15677 return (this.info & BIT3) > 0 15678 } 15679 15680 set deleted (doDelete) { 15681 if (this.deleted !== doDelete) { 15682 this.info ^= BIT3; 15683 } 15684 } 15685 15686 markDeleted () { 15687 this.info |= BIT3; 15688 } 15689 15690 /** 15691 * Return the creator clientID of the missing op or define missing items and return null. 15692 * 15693 * @param {Transaction} transaction 15694 * @param {StructStore} store 15695 * @return {null | number} 15696 */ 15697 getMissing (transaction, store) { 15698 if (this.origin && this.origin.client !== this.id.client && this.origin.clock >= getState(store, this.origin.client)) { 15699 return this.origin.client 15700 } 15701 if (this.rightOrigin && this.rightOrigin.client !== this.id.client && this.rightOrigin.clock >= getState(store, this.rightOrigin.client)) { 15702 return this.rightOrigin.client 15703 } 15704 if (this.parent && this.parent.constructor === ID && this.id.client !== this.parent.client && this.parent.clock >= getState(store, this.parent.client)) { 15705 return this.parent.client 15706 } 15707 15708 // We have all missing ids, now find the items 15709 15710 if (this.origin) { 15711 this.left = getItemCleanEnd(transaction, store, this.origin); 15712 this.origin = this.left.lastId; 15713 } 15714 if (this.rightOrigin) { 15715 this.right = getItemCleanStart(transaction, this.rightOrigin); 15716 this.rightOrigin = this.right.id; 15717 } 15718 if ((this.left && this.left.constructor === GC) || (this.right && this.right.constructor === GC)) { 15719 this.parent = null; 15720 } 15721 // only set parent if this shouldn't be garbage collected 15722 if (!this.parent) { 15723 if (this.left && this.left.constructor === Item) { 15724 this.parent = this.left.parent; 15725 this.parentSub = this.left.parentSub; 15726 } 15727 if (this.right && this.right.constructor === Item) { 15728 this.parent = this.right.parent; 15729 this.parentSub = this.right.parentSub; 15730 } 15731 } else if (this.parent.constructor === ID) { 15732 const parentItem = getItem(store, this.parent); 15733 if (parentItem.constructor === GC) { 15734 this.parent = null; 15735 } else { 15736 this.parent = /** @type {ContentType} */ (parentItem.content).type; 15737 } 15738 } 15739 return null 15740 } 15741 15742 /** 15743 * @param {Transaction} transaction 15744 * @param {number} offset 15745 */ 15746 integrate (transaction, offset) { 15747 if (offset > 0) { 15748 this.id.clock += offset; 15749 this.left = getItemCleanEnd(transaction, transaction.doc.store, createID(this.id.client, this.id.clock - 1)); 15750 this.origin = this.left.lastId; 15751 this.content = this.content.splice(offset); 15752 this.length -= offset; 15753 } 15754 15755 if (this.parent) { 15756 if ((!this.left && (!this.right || this.right.left !== null)) || (this.left && this.left.right !== this.right)) { 15757 /** 15758 * @type {Item|null} 15759 */ 15760 let left = this.left; 15761 15762 /** 15763 * @type {Item|null} 15764 */ 15765 let o; 15766 // set o to the first conflicting item 15767 if (left !== null) { 15768 o = left.right; 15769 } else if (this.parentSub !== null) { 15770 o = /** @type {AbstractType<any>} */ (this.parent)._map.get(this.parentSub) || null; 15771 while (o !== null && o.left !== null) { 15772 o = o.left; 15773 } 15774 } else { 15775 o = /** @type {AbstractType<any>} */ (this.parent)._start; 15776 } 15777 // TODO: use something like DeleteSet here (a tree implementation would be best) 15778 // @todo use global set definitions 15779 /** 15780 * @type {Set<Item>} 15781 */ 15782 const conflictingItems = new Set(); 15783 /** 15784 * @type {Set<Item>} 15785 */ 15786 const itemsBeforeOrigin = new Set(); 15787 // Let c in conflictingItems, b in itemsBeforeOrigin 15788 // ***{origin}bbbb{this}{c,b}{c,b}{o}*** 15789 // Note that conflictingItems is a subset of itemsBeforeOrigin 15790 while (o !== null && o !== this.right) { 15791 itemsBeforeOrigin.add(o); 15792 conflictingItems.add(o); 15793 if (compareIDs(this.origin, o.origin)) { 15794 // case 1 15795 if (o.id.client < this.id.client) { 15796 left = o; 15797 conflictingItems.clear(); 15798 } else if (compareIDs(this.rightOrigin, o.rightOrigin)) { 15799 // this and o are conflicting and point to the same integration points. The id decides which item comes first. 15800 // Since this is to the left of o, we can break here 15801 break 15802 } // else, o might be integrated before an item that this conflicts with. If so, we will find it in the next iterations 15803 } else if (o.origin !== null && itemsBeforeOrigin.has(getItem(transaction.doc.store, o.origin))) { // use getItem instead of getItemCleanEnd because we don't want / need to split items. 15804 // case 2 15805 if (!conflictingItems.has(getItem(transaction.doc.store, o.origin))) { 15806 left = o; 15807 conflictingItems.clear(); 15808 } 15809 } else { 15810 break 15811 } 15812 o = o.right; 15813 } 15814 this.left = left; 15815 } 15816 // reconnect left/right + update parent map/start if necessary 15817 if (this.left !== null) { 15818 const right = this.left.right; 15819 this.right = right; 15820 this.left.right = this; 15821 } else { 15822 let r; 15823 if (this.parentSub !== null) { 15824 r = /** @type {AbstractType<any>} */ (this.parent)._map.get(this.parentSub) || null; 15825 while (r !== null && r.left !== null) { 15826 r = r.left; 15827 } 15828 } else { 15829 r = /** @type {AbstractType<any>} */ (this.parent)._start 15830 ;/** @type {AbstractType<any>} */ (this.parent)._start = this; 15831 } 15832 this.right = r; 15833 } 15834 if (this.right !== null) { 15835 this.right.left = this; 15836 } else if (this.parentSub !== null) { 15837 // set as current parent value if right === null and this is parentSub 15838 /** @type {AbstractType<any>} */ (this.parent)._map.set(this.parentSub, this); 15839 if (this.left !== null) { 15840 // this is the current attribute value of parent. delete right 15841 this.left.delete(transaction); 15842 } 15843 } 15844 // adjust length of parent 15845 if (this.parentSub === null && this.countable && !this.deleted) { 15846 /** @type {AbstractType<any>} */ (this.parent)._length += this.length; 15847 } 15848 addStruct(transaction.doc.store, this); 15849 this.content.integrate(transaction, this); 15850 // add parent to transaction.changed 15851 addChangedTypeToTransaction(transaction, /** @type {AbstractType<any>} */ (this.parent), this.parentSub); 15852 if ((/** @type {AbstractType<any>} */ (this.parent)._item !== null && /** @type {AbstractType<any>} */ (this.parent)._item.deleted) || (this.parentSub !== null && this.right !== null)) { 15853 // delete if parent is deleted or if this is not the current attribute value of parent 15854 this.delete(transaction); 15855 } 15856 } else { 15857 // parent is not defined. Integrate GC struct instead 15858 new GC(this.id, this.length).integrate(transaction, 0); 15859 } 15860 } 15861 15862 /** 15863 * Returns the next non-deleted item 15864 */ 15865 get next () { 15866 let n = this.right; 15867 while (n !== null && n.deleted) { 15868 n = n.right; 15869 } 15870 return n 15871 } 15872 15873 /** 15874 * Returns the previous non-deleted item 15875 */ 15876 get prev () { 15877 let n = this.left; 15878 while (n !== null && n.deleted) { 15879 n = n.left; 15880 } 15881 return n 15882 } 15883 15884 /** 15885 * Computes the last content address of this Item. 15886 */ 15887 get lastId () { 15888 // allocating ids is pretty costly because of the amount of ids created, so we try to reuse whenever possible 15889 return this.length === 1 ? this.id : createID(this.id.client, this.id.clock + this.length - 1) 15890 } 15891 15892 /** 15893 * Try to merge two items 15894 * 15895 * @param {Item} right 15896 * @return {boolean} 15897 */ 15898 mergeWith (right) { 15899 if ( 15900 this.constructor === right.constructor && 15901 compareIDs(right.origin, this.lastId) && 15902 this.right === right && 15903 compareIDs(this.rightOrigin, right.rightOrigin) && 15904 this.id.client === right.id.client && 15905 this.id.clock + this.length === right.id.clock && 15906 this.deleted === right.deleted && 15907 this.redone === null && 15908 right.redone === null && 15909 this.content.constructor === right.content.constructor && 15910 this.content.mergeWith(right.content) 15911 ) { 15912 const searchMarker = /** @type {AbstractType<any>} */ (this.parent)._searchMarker; 15913 if (searchMarker) { 15914 searchMarker.forEach(marker => { 15915 if (marker.p === right) { 15916 // right is going to be "forgotten" so we need to update the marker 15917 marker.p = this; 15918 // adjust marker index 15919 if (!this.deleted && this.countable) { 15920 marker.index -= this.length; 15921 } 15922 } 15923 }); 15924 } 15925 if (right.keep) { 15926 this.keep = true; 15927 } 15928 this.right = right.right; 15929 if (this.right !== null) { 15930 this.right.left = this; 15931 } 15932 this.length += right.length; 15933 return true 15934 } 15935 return false 15936 } 15937 15938 /** 15939 * Mark this Item as deleted. 15940 * 15941 * @param {Transaction} transaction 15942 */ 15943 delete (transaction) { 15944 if (!this.deleted) { 15945 const parent = /** @type {AbstractType<any>} */ (this.parent); 15946 // adjust the length of parent 15947 if (this.countable && this.parentSub === null) { 15948 parent._length -= this.length; 15949 } 15950 this.markDeleted(); 15951 addToDeleteSet(transaction.deleteSet, this.id.client, this.id.clock, this.length); 15952 addChangedTypeToTransaction(transaction, parent, this.parentSub); 15953 this.content.delete(transaction); 15954 } 15955 } 15956 15957 /** 15958 * @param {StructStore} store 15959 * @param {boolean} parentGCd 15960 */ 15961 gc (store, parentGCd) { 15962 if (!this.deleted) { 15963 throw unexpectedCase() 15964 } 15965 this.content.gc(store); 15966 if (parentGCd) { 15967 replaceStruct(store, this, new GC(this.id, this.length)); 15968 } else { 15969 this.content = new ContentDeleted(this.length); 15970 } 15971 } 15972 15973 /** 15974 * Transform the properties of this type to binary and write it to an 15975 * BinaryEncoder. 15976 * 15977 * This is called when this Item is sent to a remote peer. 15978 * 15979 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to. 15980 * @param {number} offset 15981 */ 15982 write (encoder, offset) { 15983 const origin = offset > 0 ? createID(this.id.client, this.id.clock + offset - 1) : this.origin; 15984 const rightOrigin = this.rightOrigin; 15985 const parentSub = this.parentSub; 15986 const info = (this.content.getRef() & BITS5) | 15987 (origin === null ? 0 : BIT8) | // origin is defined
15988 (rightOrigin === null ? 0 : BIT7) | // right origin is defined 15989 (parentSub === null ? 0 : BIT6); // parentSub is non-null 15990 encoder.writeInfo(info); 15991 if (origin !== null) { 15992 encoder.writeLeftID(origin); 15993 } 15994 if (rightOrigin !== null) { 15995 encoder.writeRightID(rightOrigin); 15996 } 15997 if (origin === null && rightOrigin === null) { 15998 const parent = /** @type {AbstractType<any>} */ (this.parent); 15999 if (parent._item !== undefined) { 16000 const parentItem = parent._item; 16001 if (parentItem === null) { 16002 // parent type on y._map 16003 // find the correct key 16004 const ykey = findRootTypeKey(parent); 16005 encoder.writeParentInfo(true); // write parentYKey 16006 encoder.writeString(ykey); 16007 } else { 16008 encoder.writeParentInfo(false); // write parent id 16009 encoder.writeLeftID(parentItem.id); 16010 } 16011 } else if (parent.constructor === String) { // this edge case was added by differential updates 16012 encoder.writeParentInfo(true); // write parentYKey 16013 encoder.writeString(parent); 16014 } else if (parent.constructor === ID) { 16015 encoder.writeParentInfo(false); // write parent id 16016 encoder.writeLeftID(parent); 16017 } else { 16018 unexpectedCase(); 16019 } 16020 if (parentSub !== null) { 16021 encoder.writeString(parentSub); 16022 } 16023 } 16024 this.content.write(encoder, offset); 16025 } 16026} 16027 16028/** 16029 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder 16030 * @param {number} info 16031 */ 16032const readItemContent = (decoder, info) => contentRefs[info & BITS5](decoder); 16033 16034/** 16035 * A lookup map for reading Item content. 16036 * 16037 * @type {Array<function(UpdateDecoderV1 | UpdateDecoderV2):AbstractContent>} 16038 */ 16039const contentRefs = [ 16040 () => { unexpectedCase(); }, // GC is not ItemContent 16041 readContentDeleted, // 1 16042 readContentJSON, // 2 16043 readContentBinary, // 3 16044 readContentString, // 4 16045 readContentEmbed, // 5 16046 readContentFormat, // 6 16047 readContentType, // 7 16048 readContentAny, // 8 16049 readContentDoc, // 9 16050 () => { unexpectedCase(); } // 10 - Skip is not ItemContent 16051]; 16052 16053const structSkipRefNumber = 10; 16054 16055/** 16056 * @private 16057 */ 16058class Skip extends AbstractStruct { 16059 get deleted () { 16060 return true 16061 } 16062 16063 delete () {} 16064 16065 /** 16066 * @param {Skip} right 16067 * @return {boolean} 16068 */ 16069 mergeWith (right) { 16070 if (this.constructor !== right.constructor) { 16071 return false 16072 } 16073 this.length += right.length; 16074 return true 16075 } 16076 16077 /** 16078 * @param {Transaction} transaction 16079 * @param {number} offset 16080 */ 16081 integrate (transaction, offset) { 16082 // skip structs cannot be integrated 16083 unexpectedCase(); 16084 } 16085 16086 /** 16087 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder 16088 * @param {number} offset 16089 */ 16090 write (encoder, offset) { 16091 encoder.writeInfo(structSkipRefNumber); 16092 // write as VarUint because Skips can't make use of predictable length-encoding 16093 writeVarUint(encoder.restEncoder, this.length - offset); 16094 } 16095 16096 /** 16097 * @param {Transaction} transaction 16098 * @param {StructStore} store 16099 * @return {null | number} 16100 */ 16101 getMissing (transaction, store) { 16102 return null 16103 } 16104} 16105 16106/** eslint-env browser */ 16107 16108const glo = /** @type {any} */ (typeof globalThis !== 'undefined' 16109 ? globalThis 16110 : typeof window !== 'undefined' 16111 ? window 16112 // @ts-ignore 16113 : typeof global !== 'undefined' ? global : {}); 16114 16115const importIdentifier = '__ $YJS$ __'; 16116 16117if (glo[importIdentifier] === true) { 16118 /** 16119 * Dear reader of this message. Please take this seriously. 16120 * 16121 * If you see this message, make sure that you only import one version of Yjs. In many cases, 16122 * your package manager installs two versions of Yjs that are used by different packages within your project. 16123 * Another reason for this message is that some parts of your project use the commonjs version of Yjs 16124 * and others use the EcmaScript version of Yjs. 16125 * 16126 * This often leads to issues that are hard to debug. We often need to perform constructor checks, 16127 * e.g. `struct instanceof GC`. If you imported different versions of Yjs, it is impossible for us to 16128 * do the constructor checks anymore - which might break the CRDT algorithm. 16129 * 16130 * https://github.com/yjs/yjs/issues/438 16131 */ 16132 console.error('Yjs was already imported. This breaks constructor checks and will lead to issues! - https://github.com/yjs/yjs/issues/438'); 16133} 16134glo[importIdentifier] = true; 16135 16136 16137//# sourceMappingURL=yjs.mjs.map 16138 16139;// CONCATENATED MODULE: ./packages/sync/build-module/provider.js 16140/** 16141 * External dependencies 16142 */ 16143// @ts-ignore 16144 16145 16146/** @typedef {import('./types').ObjectType} ObjectType */ 16147/** @typedef {import('./types').ObjectID} ObjectID */ 16148/** @typedef {import('./types').ObjectConfig} ObjectConfig */ 16149/** @typedef {import('./types').CRDTDoc} CRDTDoc */ 16150/** @typedef {import('./types').ConnectDoc} ConnectDoc */ 16151/** @typedef {import('./types').SyncProvider} SyncProvider */ 16152 16153/** 16154 * Create a sync provider. 16155 * 16156 * @param {ConnectDoc} connectLocal Connect the document to a local database. 16157 * @param {ConnectDoc} connectRemote Connect the document to a remote sync connection. 16158 * @return {SyncProvider} Sync provider. 16159 */ 16160const createSyncProvider = (connectLocal, connectRemote) => { 16161 /** 16162 * @type {Record<string,ObjectConfig>} 16163 */ 16164 const config = {}; 16165 16166 /** 16167 * @type {Record<string,Record<string,()=>void>>} 16168 */ 16169 const listeners = {}; 16170 16171 /** 16172 * @type {Record<string,Record<string,CRDTDoc>>} 16173 */ 16174 const docs = {}; 16175 16176 /** 16177 * Registeres an object type. 16178 * 16179 * @param {ObjectType}
16179 objectType Object type to register. 16180 * @param {ObjectConfig} objectConfig Object config. 16181 */ 16182 function register(objectType, objectConfig) { 16183 config[objectType] = objectConfig; 16184 } 16185 16186 /** 16187 * Fetch data from local database or remote source. 16188 * 16189 * @param {ObjectType} objectType Object type to load. 16190 * @param {ObjectID} objectId Object ID to load. 16191 * @param {Function} handleChanges Callback to call when data changes. 16192 */ 16193 async function bootstrap(objectType, objectId, handleChanges) { 16194 const doc = new Doc(); 16195 docs[objectType] = docs[objectType] || {}; 16196 docs[objectType][objectId] = doc; 16197 const updateHandler = () => { 16198 const data = config[objectType].fromCRDTDoc(doc); 16199 handleChanges(data); 16200 }; 16201 doc.on('update', updateHandler); 16202 16203 // connect to locally saved database. 16204 const destroyLocalConnection = await connectLocal(objectId, objectType, doc); 16205 16206 // Once the database syncing is done, start the remote syncing 16207 if (connectRemote) { 16208 await connectRemote(objectId, objectType, doc); 16209 } 16210 const loadRemotely = config[objectType].fetch; 16211 if (loadRemotely) { 16212 loadRemotely(objectId).then(data => { 16213 doc.transact(() => { 16214 config[objectType].applyChangesToDoc(doc, data); 16215 }); 16216 }); 16217 } 16218 listeners[objectType] = listeners[objectType] || {}; 16219 listeners[objectType][objectId] = () => { 16220 destroyLocalConnection(); 16221 doc.off('update', updateHandler); 16222 }; 16223 } 16224 16225 /** 16226 * Fetch data from local database or remote source. 16227 * 16228 * @param {ObjectType} objectType Object type to load. 16229 * @param {ObjectID} objectId Object ID to load. 16230 * @param {any} data Updates to make. 16231 */ 16232 async function update(objectType, objectId, data) { 16233 const doc = docs[objectType][objectId]; 16234 if (!doc) { 16235 throw 'Error doc ' + objectType + ' ' + objectId + ' not found'; 16236 } 16237 doc.transact(() => { 16238 config[objectType].applyChangesToDoc(doc, data); 16239 }); 16240 } 16241 16242 /** 16243 * Stop updating a document and discard it. 16244 * 16245 * @param {ObjectType} objectType Object type to load. 16246 * @param {ObjectID} objectId Object ID to load. 16247 */ 16248 async function discard(objectType, objectId) { 16249 if (listeners?.[objectType]?.[objectId]) { 16250 listeners[objectType][objectId](); 16251 } 16252 } 16253 return { 16254 register, 16255 bootstrap, 16256 update, 16257 discard 16258 }; 16259}; 16260 16261;// CONCATENATED MODULE: ./node_modules/lib0/indexeddb.js 16262/* eslint-env browser */ 16263 16264/** 16265 * Helpers to work with IndexedDB. 16266 * 16267 * @module indexeddb 16268 */ 16269 16270 16271 16272 16273/* c8 ignore start */ 16274 16275/** 16276 * IDB Request to Promise transformer 16277 * 16278 * @param {IDBRequest} request 16279 * @return {Promise<any>} 16280 */ 16281const rtop = request => promise_create((resolve, reject) => { 16282 // @ts-ignore 16283 request.onerror = event => reject(new Error(event.target.error)) 16284 // @ts-ignore 16285 request.onsuccess = event => resolve(event.target.result) 16286}) 16287 16288/** 16289 * @param {string} name 16290 * @param {function(IDBDatabase):any} initDB Called when the database is first created 16291 * @return {Promise<IDBDatabase>} 16292 */ 16293const openDB = (name, initDB) => promise_create((resolve, reject) => { 16294 const request = indexedDB.open(name) 16295 /** 16296 * @param {any} event 16297 */ 16298 request.onupgradeneeded = event => initDB(event.target.result) 16299 /** 16300 * @param {any} event 16301 */ 16302 request.onerror = event => reject(error_create(event.target.error)) 16303 /** 16304 * @param {any} event 16305 */ 16306 request.onsuccess = event => { 16307 /** 16308 * @type {IDBDatabase} 16309 */ 16310 const db = event.target.result 16311 db.onversionchange = () => { db.close() } 16312 if (typeof addEventListener !== 'undefined') { 16313 addEventListener('unload', () => db.close()) 16314 } 16315 resolve(db) 16316 } 16317}) 16318 16319/** 16320 * @param {string} name 16321 */ 16322const deleteDB = name => rtop(indexedDB.deleteDatabase(name)) 16323 16324/** 16325 * @param {IDBDatabase} db 16326 * @param {Array<Array<string>|Array<string|IDBObjectStoreParameters|undefined>>} definitions 16327 */ 16328const createStores = (db, definitions) => definitions.forEach(d => 16329 // @ts-ignore 16330 db.createObjectStore.apply(db, d) 16331) 16332 16333/** 16334 * @param {IDBDatabase} db 16335 * @param {Array<string>} stores 16336 * @param {"readwrite"|"readonly"} [access] 16337 * @return {Array<IDBObjectStore>} 16338 */ 16339const indexeddb_transact = (db, stores, access = 'readwrite') => { 16340 const transaction = db.transaction(stores, access) 16341 return stores.map(store => getStore(transaction, store)) 16342} 16343 16344/** 16345 * @param {IDBObjectStore} store 16346 * @param {IDBKeyRange} [range] 16347 * @return {Promise<number>} 16348 */ 16349const count = (store, range) => 16350 rtop(store.count(range)) 16351 16352/** 16353 * @param {IDBObjectStore} store 16354 * @param {String | number | ArrayBuffer | Date | Array<any> } key 16355 * @return {Promise<String | number | ArrayBuffer | Date | Array<any>>} 16356 */ 16357const get = (store, key) => 16358 rtop(store.get(key)) 16359 16360/** 16361 * @param {IDBObjectStore} store 16362 * @param {String | number | ArrayBuffer | Date | IDBKeyRange | Array<any> } key 16363 */ 16364const del = (store, key) => 16365 rtop(store.delete(key)) 16366 16367/** 16368 * @param {IDBObjectStore} store 16369 * @param {String | number | ArrayBuffer | Date | boolean} item 16370 * @param {String | number | ArrayBuffer | Date | Array<any>} [key] 16371 */ 16372const put = (store, item, key) => 16373 rtop(store.put(item, key)) 16374 16375/** 16376 * @param {IDBObjectStore} store 16377 * @param {String | number | ArrayBuffer | Date | boolean} item 16378 * @param {String | number | ArrayBuffer | Date | Array<any>} key 16379 * @return {Promise<any>} 16380 */ 16381const indexeddb_add = (store, item, key) => 16382 rtop(store.add(item, key)) 16383 16384/** 16385 * @param {IDBObjectStore} store 16386 * @param {String | number | ArrayBuffer | Date} item 16387 * @return {Promise<number>} Returns the generated key 16388 */ 16389const addAutoKey = (store, item) => 16390 rtop(store.add(item)) 16391 16392/** 16393 * @param {IDBObjectStore} store 16394 * @param {IDBKeyRange} [range] 16395 * @param {number} [limit] 16396 * @return {Promise<Array<any>>} 16397 */ 16398const getAll = (store, range, limit) => 16399 rtop(store.getAll(range, limit)) 16400 16401/** 16402 * @param {IDBObjectStore} store 16403 * @param {IDBKeyRange} [range] 16404 * @param {number} [limit] 16405 * @return {Promise<Array<any>>} 16406 */ 16407const getAllKeys = (store, range, limit) => 16408 rtop(store.getAllKeys(range, limit)) 16409 16410/** 16411 * @param {IDBObjectStore} store 16412 * @param {IDBKeyRange|null} query 16413 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction 16414 * @return {Promise<any>} 16415 */ 16416const queryFirst = (store, query, direction) => { 16417 /** 16418 * @type {any} 16419 */ 16420 let first = null 16421 return iterateKeys(store, query, key => { 16422 first = key 16423 return false 16424 }, direction).then(() => first) 16425} 16426 16427/** 16428 * @param {IDBObjectStore} store 16429 * @param {IDBKeyRange?} [range] 16430 * @return {Promise<any>} 16431 */ 16432const getLastKey = (store, range = null) => queryFirst(store, range, 'prev') 16433 16434/** 16435 * @param {IDBObjectStore} store 16436 * @param {IDBKeyRange?} [range] 16437 * @return {Promise<any>} 16438 */ 16439const getFirstKey = (store, range = null) => queryFirst(store, range, 'next') 16440 16441/** 16442 * @typedef KeyValuePair 16443 * @type {Object} 16444 * @property {any} k key 16445 * @property {any}
16445 v Value 16446 */ 16447 16448/** 16449 * @param {IDBObjectStore} store 16450 * @param {IDBKeyRange} [range] 16451 * @param {number} [limit] 16452 * @return {Promise<Array<KeyValuePair>>} 16453 */ 16454const getAllKeysValues = (store, range, limit) => 16455 // @ts-ignore 16456 promise.all([getAllKeys(store, range, limit), getAll(store, range, limit)]).then(([ks, vs]) => ks.map((k, i) => ({ k, v: vs[i] }))) 16457 16458/** 16459 * @param {any} request 16460 * @param {function(IDBCursorWithValue):void|boolean|Promise<void|boolean>} f 16461 * @return {Promise<void>} 16462 */ 16463const iterateOnRequest = (request, f) => promise_create((resolve, reject) => { 16464 request.onerror = reject 16465 /** 16466 * @param {any} event 16467 */ 16468 request.onsuccess = async event => { 16469 const cursor = event.target.result 16470 if (cursor === null || (await f(cursor)) === false) { 16471 return resolve() 16472 } 16473 cursor.continue() 16474 } 16475}) 16476 16477/** 16478 * Iterate on keys and values 16479 * @param {IDBObjectStore} store 16480 * @param {IDBKeyRange|null} keyrange 16481 * @param {function(any,any):void|boolean|Promise<void|boolean>} f Callback that receives (value, key) 16482 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction 16483 */ 16484const iterate = (store, keyrange, f, direction = 'next') => 16485 iterateOnRequest(store.openCursor(keyrange, direction), cursor => f(cursor.value, cursor.key)) 16486 16487/** 16488 * Iterate on the keys (no values) 16489 * 16490 * @param {IDBObjectStore} store 16491 * @param {IDBKeyRange|null} keyrange 16492 * @param {function(any):void|boolean|Promise<void|boolean>} f callback that receives the key 16493 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction 16494 */ 16495const iterateKeys = (store, keyrange, f, direction = 'next') => 16496 iterateOnRequest(store.openKeyCursor(keyrange, direction), cursor => f(cursor.key)) 16497 16498/** 16499 * Open store from transaction 16500 * @param {IDBTransaction} t 16501 * @param {String} store 16502 * @returns {IDBObjectStore} 16503 */ 16504const getStore = (t, store) => t.objectStore(store) 16505 16506/** 16507 * @param {any} lower 16508 * @param {any} upper 16509 * @param {boolean} lowerOpen 16510 * @param {boolean} upperOpen 16511 */ 16512const createIDBKeyRangeBound = (lower, upper, lowerOpen, upperOpen) => IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen) 16513 16514/** 16515 * @param {any} upper 16516 * @param {boolean} upperOpen 16517 */ 16518const createIDBKeyRangeUpperBound = (upper, upperOpen) => IDBKeyRange.upperBound(upper, upperOpen) 16519 16520/** 16521 * @param {any} lower 16522 * @param {boolean} lowerOpen 16523 */ 16524const createIDBKeyRangeLowerBound = (lower, lowerOpen) => IDBKeyRange.lowerBound(lower, lowerOpen) 16525 16526/* c8 ignore stop */ 16527 16528;// CONCATENATED MODULE: ./node_modules/y-indexeddb/src/y-indexeddb.js 16529 16530 16531 16532 16533 16534const customStoreName = 'custom' 16535const updatesStoreName = 'updates' 16536 16537const PREFERRED_TRIM_SIZE = 500 16538 16539/** 16540 * @param {IndexeddbPersistence} idbPersistence 16541 * @param {function(IDBObjectStore):void} [beforeApplyUpdatesCallback] 16542 * @param {function(IDBObjectStore):void} [afterApplyUpdatesCallback] 16543 */ 16544const fetchUpdates = (idbPersistence, beforeApplyUpdatesCallback = () => {}, afterApplyUpdatesCallback = () => {}) => { 16545 const [updatesStore] = indexeddb_transact(/** @type {IDBDatabase} */ (idbPersistence.db), [updatesStoreName]) // , 'readonly') 16546 return getAll(updatesStore, createIDBKeyRangeLowerBound(idbPersistence._dbref, false)).then(updates => { 16547 if (!idbPersistence._destroyed) { 16548 beforeApplyUpdatesCallback(updatesStore) 16549 transact(idbPersistence.doc, () => { 16550 updates.forEach(val => applyUpdate(idbPersistence.doc, val)) 16551 }, idbPersistence, false) 16552 afterApplyUpdatesCallback(updatesStore) 16553 } 16554 }) 16555 .then(() => getLastKey(updatesStore).then(lastKey => { idbPersistence._dbref = lastKey + 1 })) 16556 .then(() => count(updatesStore).then(cnt => { idbPersistence._dbsize = cnt })) 16557 .then(() => updatesStore) 16558} 16559 16560/** 16561 * @param {IndexeddbPersistence} idbPersistence 16562 * @param {boolean} forceStore 16563 */ 16564const storeState = (idbPersistence, forceStore = true) => 16565 fetchUpdates(idbPersistence) 16566 .then(updatesStore => { 16567 if (forceStore || idbPersistence._dbsize >= PREFERRED_TRIM_SIZE) { 16568 addAutoKey(updatesStore, encodeStateAsUpdate(idbPersistence.doc)) 16569 .then(() => del(updatesStore, createIDBKeyRangeUpperBound(idbPersistence._dbref, true))) 16570 .then(() => count(updatesStore).then(cnt => { idbPersistence._dbsize = cnt })) 16571 } 16572 }) 16573 16574/** 16575 * @param {string} name 16576 */ 16577const clearDocument = name => idb.deleteDB(name) 16578 16579/** 16580 * @extends Observable<string> 16581 */ 16582class IndexeddbPersistence extends observable_Observable { 16583 /** 16584 * @param {string} name 16585 * @param {Y.Doc} doc 16586 */ 16587 constructor (name, doc) { 16588 super() 16589 this.doc = doc 16590 this.name = name 16591 this._dbref = 0 16592 this._dbsize = 0 16593 this._destroyed = false 16594 /** 16595 * @type {IDBDatabase|null} 16596 */ 16597 this.db = null 16598 this.synced = false 16599 this._db = openDB(name, db => 16600 createStores(db, [ 16601 ['updates', { autoIncrement: true }], 16602 ['custom'] 16603 ]) 16604 ) 16605 /** 16606 * @type {Promise<IndexeddbPersistence>} 16607 */ 16608 this.whenSynced = promise_create(resolve => this.on('synced', () => resolve(this))) 16609 16610 this._db.then(db => { 16611 this.db = db 16612 /** 16613 * @param {IDBObjectStore} updatesStore 16614 */ 16615 const beforeApplyUpdatesCallback = (updatesStore) => addAutoKey(updatesStore, encodeStateAsUpdate(doc)) 16616 const afterApplyUpdatesCallback = () => { 16617 if (this._destroyed) return this 16618 this.synced = true
16619 this.emit('synced', [this]) 16620 } 16621 fetchUpdates(this, beforeApplyUpdatesCallback, afterApplyUpdatesCallback) 16622 }) 16623 /** 16624 * Timeout in ms untill data is merged and persisted in idb. 16625 */ 16626 this._storeTimeout = 1000 16627 /** 16628 * @type {any} 16629 */ 16630 this._storeTimeoutId = null 16631 /** 16632 * @param {Uint8Array} update 16633 * @param {any} origin 16634 */ 16635 this._storeUpdate = (update, origin) => { 16636 if (this.db && origin !== this) { 16637 const [updatesStore] = indexeddb_transact(/** @type {IDBDatabase} */ (this.db), [updatesStoreName]) 16638 addAutoKey(updatesStore, update) 16639 if (++this._dbsize >= PREFERRED_TRIM_SIZE) { 16640 // debounce store call 16641 if (this._storeTimeoutId !== null) { 16642 clearTimeout(this._storeTimeoutId) 16643 } 16644 this._storeTimeoutId = setTimeout(() => { 16645 storeState(this, false) 16646 this._storeTimeoutId = null 16647 }, this._storeTimeout) 16648 } 16649 } 16650 } 16651 doc.on('update', this._storeUpdate) 16652 this.destroy = this.destroy.bind(this) 16653 doc.on('destroy', this.destroy) 16654 } 16655 16656 destroy () { 16657 if (this._storeTimeoutId) { 16658 clearTimeout(this._storeTimeoutId) 16659 } 16660 this.doc.off('update', this._storeUpdate) 16661 this.doc.off('destroy', this.destroy) 16662 this._destroyed = true 16663 return this._db.then(db => { 16664 db.close() 16665 }) 16666 } 16667 16668 /** 16669 * Destroys this instance and removes all data from indexeddb. 16670 * 16671 * @return {Promise<void>} 16672 */ 16673 clearData () { 16674 return this.destroy().then(() => { 16675 deleteDB(this.name) 16676 }) 16677 } 16678 16679 /** 16680 * @param {String | number | ArrayBuffer | Date} key 16681 * @return {Promise<String | number | ArrayBuffer | Date | any>} 16682 */ 16683 get (key) { 16684 return this._db.then(db => { 16685 const [custom] = indexeddb_transact(db, [customStoreName], 'readonly') 16686 return get(custom, key) 16687 }) 16688 } 16689 16690 /** 16691 * @param {String | number | ArrayBuffer | Date} key 16692 * @param {String | number | ArrayBuffer | Date} value 16693 * @return {Promise<String | number | ArrayBuffer | Date>} 16694 */ 16695 set (key, value) { 16696 return this._db.then(db => { 16697 const [custom] = indexeddb_transact(db, [customStoreName]) 16698 return put(custom, value, key) 16699 }) 16700 } 16701 16702 /** 16703 * @param {String | number | ArrayBuffer | Date} key 16704 * @return {Promise<undefined>} 16705 */ 16706 del (key) { 16707 return this._db.then(db => { 16708 const [custom] = indexeddb_transact(db, [customStoreName]) 16709 return del(custom, key) 16710 }) 16711 } 16712} 16713 16714;// CONCATENATED MODULE: ./packages/sync/build-module/connect-indexdb.js 16715/** 16716 * External dependencies 16717 */ 16718// @ts-ignore 16719 16720 16721/** @typedef {import('./types').ObjectType} ObjectType */ 16722/** @typedef {import('./types').ObjectID} ObjectID */ 16723/** @typedef {import('./types').CRDTDoc} CRDTDoc */ 16724/** @typedef {import('./types').ConnectDoc} ConnectDoc */ 16725/** @typedef {import('./types').SyncProvider} SyncProvider */ 16726 16727/** 16728 * Connect function to the IndexedDB persistence provider. 16729 * 16730 * @param {ObjectID} objectId The object ID. 16731 * @param {ObjectType} objectType The object type. 16732 * @param {CRDTDoc} doc The CRDT document. 16733 * 16734 * @return {Promise<() => void>} Promise that resolves when the connection is established. 16735 */ 16736function connectIndexDb(objectId, objectType, doc) { 16737 const docName = `${objectType}-${objectId}`; 16738 const provider = new IndexeddbPersistence(docName, doc); 16739 return new Promise(resolve => { 16740 provider.on('synced', () => { 16741 resolve(() => provider.destroy()); 16742 }); 16743 }); 16744} 16745 16746;// CONCATENATED MODULE: ./node_modules/lib0/websocket.js 16747/* eslint-env browser */ 16748 16749/** 16750 * Tiny websocket connection handler. 16751 * 16752 * Implements exponential backoff reconnects, ping/pong, and a nice event system using [lib0/observable]. 16753 * 16754 * @module websocket 16755 */ 16756 16757 16758 16759 16760 16761const reconnectTimeoutBase = 1200 16762const maxReconnectTimeout = 2500 16763// @todo - this should depend on awareness.outdatedTime 16764const messageReconnectTimeout = 30000 16765 16766/** 16767 * @param {WebsocketClient} wsclient 16768 */ 16769const setupWS = (wsclient) => { 16770 if (wsclient.shouldConnect && wsclient.ws === null) { 16771 const websocket = new WebSocket(wsclient.url) 16772 const binaryType = wsclient.binaryType 16773 /** 16774 * @type {any} 16775 */ 16776 let pingTimeout = null 16777 if (binaryType) {
vendor: 4,229 bytes, lines 16778-16931
16778 websocket.binaryType = binaryType 16779 } 16780 wsclient.ws = websocket 16781 wsclient.connecting = true 16782 wsclient.connected = false 16783 websocket.onmessage = event => { 16784 wsclient.lastMessageReceived = getUnixTime() 16785 const data = event.data 16786 const message = typeof data === 'string' ? JSON.parse(data) : data 16787 if (message && message.type === 'pong') { 16788 clearTimeout(pingTimeout) 16789 pingTimeout = setTimeout(sendPing, messageReconnectTimeout / 2) 16790 } 16791 wsclient.emit('message', [message, wsclient]) 16792 } 16793 /** 16794 * @param {any} error 16795 */ 16796 const onclose = error => { 16797 if (wsclient.ws !== null) { 16798 wsclient.ws = null 16799 wsclient.connecting = false 16800 if (wsclient.connected) { 16801 wsclient.connected = false 16802 wsclient.emit('disconnect', [{ type: 'disconnect', error }, wsclient]) 16803 } else { 16804 wsclient.unsuccessfulReconnects++ 16805 } 16806 // Start with no reconnect timeout and increase timeout by 16807 // log10(wsUnsuccessfulReconnects). 16808 // The idea is to increase reconnect timeout slowly and have no reconnect 16809 // timeout at the beginning (log(1) = 0) 16810 setTimeout(setupWS, min(log10(wsclient.unsuccessfulReconnects + 1) * reconnectTimeoutBase, maxReconnectTimeout), wsclient) 16811 } 16812 clearTimeout(pingTimeout) 16813 } 16814 const sendPing = () => { 16815 if (wsclient.ws === websocket) { 16816 wsclient.send({ 16817 type: 'ping' 16818 }) 16819 } 16820 } 16821 websocket.onclose = () => onclose(null) 16822 websocket.onerror = error => onclose(error) 16823 websocket.onopen = () => { 16824 wsclient.lastMessageReceived = getUnixTime() 16825 wsclient.connecting = false 16826 wsclient.connected = true 16827 wsclient.unsuccessfulReconnects = 0 16828 wsclient.emit('connect', [{ type: 'connect' }, wsclient]) 16829 // set ping 16830 pingTimeout = setTimeout(sendPing, messageReconnectTimeout / 2) 16831 } 16832 } 16833} 16834 16835/** 16836 * @extends Observable<string> 16837 */ 16838class WebsocketClient extends observable_Observable { 16839 /** 16840 * @param {string} url 16841 * @param {object} opts 16842 * @param {'arraybuffer' | 'blob' | null} [opts.binaryType] Set `ws.binaryType` 16843 */ 16844 constructor (url, { binaryType } = {}) { 16845 super() 16846 this.url = url 16847 /** 16848 * @type {WebSocket?} 16849 */ 16850 this.ws = null 16851 this.binaryType = binaryType || null 16852 this.connected = false 16853 this.connecting = false 16854 this.unsuccessfulReconnects = 0 16855 this.lastMessageReceived = 0 16856 /** 16857 * Whether to connect to other peers or not 16858 * @type {boolean} 16859 */ 16860 this.shouldConnect = true 16861 this._checkInterval = setInterval(() => { 16862 if (this.connected && messageReconnectTimeout < getUnixTime() - this.lastMessageReceived) { 16863 // no message received in a long time - not even your own awareness 16864 // updates (which are updated every 15 seconds) 16865 /** @type {WebSocket} */ (this.ws).close() 16866 } 16867 }, messageReconnectTimeout / 2) 16868 setupWS(this) 16869 } 16870 16871 /** 16872 * @param {any} message 16873 */ 16874 send (message) { 16875 if (this.ws) { 16876 this.ws.send(JSON.stringify(message)) 16877 } 16878 } 16879 16880 destroy () { 16881 clearInterval(this._checkInterval) 16882 this.disconnect() 16883 super.destroy() 16884 } 16885 16886 disconnect () { 16887 this.shouldConnect = false 16888 if (this.ws !== null) { 16889 this.ws.close() 16890 } 16891 } 16892 16893 connect () { 16894 this.shouldConnect = true 16895 if (!this.connected && this.ws === null) { 16896 setupWS(this) 16897 } 16898 } 16899} 16900 16901;// CONCATENATED MODULE: ./node_modules/lib0/broadcastchannel.js 16902/* eslint-env browser */ 16903 16904/** 16905 * Helpers for cross-tab communication using broadcastchannel with LocalStorage fallback. 16906 * 16907 * ```js 16908 * // In browser window A: 16909 * broadcastchannel.subscribe('my events', data => console.log(data)) 16910 * broadcastchannel.publish('my events', 'Hello world!') // => A: 'Hello world!' fires synchronously in same tab 16911 * 16912 * // In browser window B: 16913 * broadcastchannel.publish('my events', 'hello from tab B') // => A: 'hello from tab B' 16914 * ``` 16915 * 16916 * @module broadcastchannel 16917 */ 16918 16919// @todo before next major: use Uint8Array instead as buffer object 16920 16921 16922 16923 16924 16925 16926/** 16927 * @typedef {Object} Channel 16928 * @property {Set<function(any, any):any>} Channel.subs 16929 * @property {any} Channel.bc 16930 */ 16931
16932/** 16933 * @type {Map<string, Channel>} 16934 */ 16935const channels = new Map() 16936 16937/* c8 ignore start */ 16938class LocalStoragePolyfill { 16939 /** 16940 * @param {string} room 16941 */ 16942 constructor (room) { 16943 this.room = room 16944 /** 16945 * @type {null|function({data:ArrayBuffer}):void} 16946 */ 16947 this.onmessage = null 16948 /** 16949 * @param {any} e 16950 */ 16951 this._onChange = e => e.key === room && this.onmessage !== null && this.onmessage({ data: fromBase64(e.newValue || '') }) 16952 onChange(this._onChange) 16953 } 16954 16955 /** 16956 * @param {ArrayBuffer} buf 16957 */ 16958 postMessage (buf) { 16959 varStorage.setItem(this.room, toBase64(createUint8ArrayFromArrayBuffer(buf))) 16960 } 16961 16962 close () { 16963 offChange(this._onChange) 16964 } 16965} 16966/* c8 ignore stop */ 16967 16968// Use BroadcastChannel or Polyfill 16969/* c8 ignore next */ 16970const BC = typeof BroadcastChannel === 'undefined' ? LocalStoragePolyfill : BroadcastChannel 16971 16972/** 16973 * @param {string} room 16974 * @return {Channel} 16975 */ 16976const getChannel = room => 16977 setIfUndefined(channels, room, () => { 16978 const subs = set_create() 16979 const bc = new BC(room) 16980 /** 16981 * @param {{data:ArrayBuffer}} e 16982 */ 16983 /* c8 ignore next */ 16984 bc.onmessage = e => subs.forEach(sub => sub(e.data, 'broadcastchannel')) 16985 return { 16986 bc, subs 16987 } 16988 }) 16989 16990/** 16991 * Subscribe to global `publish` events. 16992 * 16993 * @function 16994 * @param {string} room 16995 * @param {function(any, any):any} f 16996 */ 16997const subscribe = (room, f) => { 16998 getChannel(room).subs.add(f) 16999 return f 17000} 17001 17002/** 17003 * Unsubscribe from `publish` global events. 17004 * 17005 * @function 17006 * @param {string} room 17007 * @param {function(any, any):any} f 17008 */ 17009const unsubscribe = (room, f) => { 17010 const channel = getChannel(room) 17011 const unsubscribed = channel.subs.delete(f) 17012 if (unsubscribed && channel.subs.size === 0) { 17013 channel.bc.close() 17014 channels.delete(room) 17015 } 17016 return unsubscribed 17017} 17018 17019/** 17020 * Publish data to all subscribers (including subscribers on this tab) 17021 * 17022 * @function 17023 * @param {string} room 17024 * @param {any} data 17025 * @param {any} [origin] 17026 */ 17027const publish = (room, data, origin = null) => { 17028 const c = getChannel(room) 17029 c.bc.postMessage(data) 17030 c.subs.forEach(sub => sub(data, origin)) 17031} 17032 17033;// CONCATENATED MODULE: ./node_modules/lib0/mutex.js 17034/** 17035 * Mutual exclude for JavaScript. 17036 * 17037 * @module mutex 17038 */ 17039 17040/** 17041 * @callback mutex 17042 * @param {function():void} cb Only executed when this mutex is not in the current stack 17043 * @param {function():void} [elseCb] Executed when this mutex is in the current stack 17044 */ 17045 17046/** 17047 * Creates a mutual exclude function with the following property: 17048 * 17049 * ```js 17050 * const mutex = createMutex() 17051 * mutex(() => { 17052 * // This function is immediately executed 17053 * mutex(() => { 17054 * // This function is not executed, as the mutex is already active. 17055 * }) 17056 * }) 17057 * ``` 17058 * 17059 * @return {mutex} A mutual exclude function 17060 * @public 17061 */ 17062const createMutex = () => { 17063 let token = true 17064 return (f, g) => { 17065 if (token) { 17066 token = false 17067 try { 17068 f() 17069 } finally { 17070 token = true 17071 } 17072 } else if (g !== undefined) { 17073 g() 17074 } 17075 } 17076} 17077 17078// EXTERNAL MODULE: ./node_modules/simple-peer/simplepeer.min.js 17079var simplepeer_min = __webpack_require__(2248); 17080;// CONCATENATED MODULE: ./node_modules/y-protocols/sync.js 17081/** 17082 * @module sync-protocol 17083 */ 17084 17085 17086 17087 17088 17089/** 17090 * @typedef {Map<number, number>} StateMap 17091 */ 17092 17093/** 17094 * Core Yjs defines two message types: 17095 * ⢠YjsSyncStep1: Includes the State Set of the sending client. When received, the client should reply with YjsSyncStep2. 17096 * ⢠YjsSyncStep2: Includes all missing structs and the complete delete set. When received, the client is assured that it 17097 * received all information from the remote client. 17098 * 17099 * In a peer-to-peer network, you may want to introduce a SyncDone message type. Both parties should initiate the connection 17100 * with SyncStep1. When a client received SyncStep2, it should reply with SyncDone. When the local client received both 17101 * SyncStep2 and SyncDone, it is assured that it is synced to the remote client. 17102 * 17103 * In a client-server model, you want to handle this differently: The client should initiate the connection with SyncStep1. 17104 * When the server receives SyncStep1, it should reply with SyncStep2 immediately followed by SyncStep1. The client replies 17105 * with SyncStep2 when it receives SyncStep1. Optionally the server may send a SyncDone after it received SyncStep2, so the 17106 * client knows that the sync is finished. There are two reasons for this more elaborated sync model: 1. This protocol can 17107 * easily be implemented on top of http and websockets. 2. The server shoul only reply to requests, and not initiate them. 17108 * Therefore it is necesarry that the client initiates the sync. 17109 * 17110 * Construction of a message: 17111 * [messageType : varUint, message definition..] 17112 * 17113 * Note: A message does not include information about the room name. This must to be handled by the upper layer protocol! 17114 * 17115 * stringify[messageType] stringifies a message definition (messageType is already read from the bufffer) 17116 */ 17117 17118const messageYjsSyncStep1 = 0 17119const messageYjsSyncStep2 = 1 17120const messageYjsUpdate = 2 17121 17122/** 17123 * Create a sync step 1 message based on the state of the current shared document. 17124 * 17125 * @param {encoding.Encoder} encoder 17126 * @param {Y.Doc} doc 17127 */ 17128const writeSyncStep1 = (encoder, doc) => { 17129 writeVarUint(encoder, messageYjsSyncStep1) 17130 const sv = encodeStateVector(doc) 17131 writeVarUint8Array(encoder, sv) 17132} 17133 17134/** 17135 * @param {encoding.Encoder} encoder 17136 * @param {Y.Doc} doc 17137 * @param {Uint8Array} [encodedStateVector] 17138 */ 17139const writeSyncStep2 = (encoder, doc, encodedStateVector) => { 17140 writeVarUint(encoder, messageYjsSyncStep2) 17141 writeVarUint8Array(encoder, encodeStateAsUpdate(doc, encodedStateVector)) 17142} 17143 17144/** 17145 * Read SyncStep1 message and reply with SyncStep2. 17146 * 17147 * @param {decoding.Decoder} decoder The reply to the received message 17148 * @param {encoding.Encoder} encoder The received message 17149 * @param {Y.Doc} doc 17150 */ 17151const readSyncStep1 = (decoder, encoder, doc) => 17152 writeSyncStep2(encoder, doc, readVarUint8Array(decoder)) 17153 17154/** 17155 * Read and apply Structs and then DeleteStore to a y instance. 17156 * 17157 * @param {decoding.Decoder} decoder 17158 * @param {Y.Doc} doc 17159 * @param {any} transactionOrigin 17160 */ 17161const readSyncStep2 = (decoder, doc, transactionOrigin) => { 17162 try { 17163 applyUpdate(doc, readVarUint8Array(decoder), transactionOrigin) 17164 } catch (error) { 17165 // This catches errors that are thrown by event handlers 17166 console.error('Caught error while handling a Yjs update', error) 17167 } 17168} 17169 17170/** 17171 * @param {encoding.Encoder} encoder 17172 * @param {Uint8Array} update 17173 */ 17174const writeUpdate = (encoder, update) => { 17175 writeVarUint(encoder, messageYjsUpdate) 17176 writeVarUint8Array(encoder, update) 17177} 17178 17179/** 17180 * Read and apply Structs and then DeleteStore to a y instance. 17181 * 17182 * @param {decoding.Decoder} decoder 17183 * @param {Y.Doc} doc 17184 * @param {any} transactionOrigin 17185 */ 17186const sync_readUpdate = readSyncStep2 17187 17188/** 17189 * @param {decoding.Decoder} decoder A message received from another client 17190 * @param {encoding.Encoder} encoder The reply message. Will not be sent if empty. 17191 * @param {Y.Doc} doc 17192 * @param {any} transactionOrigin 17193 */ 17194const readSyncMessage = (decoder, encoder, doc, transactionOrigin) => { 17195 const messageType = readVarUint(decoder) 17196 switch (messageType) { 17197 case messageYjsSyncStep1: 17198 readSyncStep1(decoder, encoder, doc) 17199 break 17200 case messageYjsSyncStep2: 17201 readSyncStep2(decoder, doc, transactionOrigin) 17202 break 17203 case messageYjsUpdate: 17204 sync_readUpdate(decoder, doc, transactionOrigin) 17205 break 17206 default: 17207 throw new Error('Unknown message type') 17208 } 17209 return messageType 17210} 17211 17212;// CONCATENATED MODULE: ./node_modules/y-protocols/awareness.js 17213/** 17214 * @module awareness-protocol 17215 */ 17216 17217 17218 17219 17220 17221 17222 17223 // eslint-disable-line 17224 17225const outdatedTimeout = 30000 17226 17227/** 17228 * @typedef {Object} MetaClientState 17229 * @property {number} MetaClientState.clock 17230 * @property {number} MetaClientState.lastUpdated unix timestamp 17231 */ 17232 17233/** 17234 * The Awareness class implements a simple shared state protocol that can be used for non-persistent data like awareness information 17235 * (cursor, username, status, ..). Each client can update its own local state and listen to state changes of 17236 * remote clients. Every client may set a state of a remote peer to `null` to mark the client as offline. 17237 * 17238 * Each client is identified by a unique client id (something we borrow from `doc.clientID`). A client can override 17239 * its own state by propagating a message with an increasing timestamp (`clock`). If such a message is received, it is 17240 * applied if the known state of that client is older than the new state (`clock < newClock`). If a client thinks that 17241 * a remote client is offline, it may propagate a message with 17242 * `{ clock: currentClientClock, state: null, client: remoteClient }`. If such a 17243 * message is received, and the known clock of that client equals the received clock, it will override the state with `null`. 17244 * 17245 * Before a client disconnects, it should propagate a `null` state with an updated clock. 17246 * 17247 * Awareness states must be updated every 30 seconds. Otherwise the Awareness instance will delete the client state. 17248 * 17249 * @extends {Observable<string>} 17250 */ 17251class Awareness extends observable_Observable { 17252 /** 17253 * @param {Y.Doc} doc 17254 */ 17255 constructor (doc) { 17256 super() 17257 this.doc = doc 17258 /** 17259 * @type {number} 17260 */ 17261 this.clientID = doc.clientID 17262 /** 17263 * Maps from client id to client state 17264 * @type {Map<number, Object<string, any>>} 17265 */ 17266 this.states = new Map() 17267 /** 17268 * @type {Map<number, MetaClientState>} 17269 */ 17270 this.meta = new Map() 17271 this._checkInterval = /** @type {any} */ (setInterval(() => { 17272 const now = getUnixTime() 17273 if (this.getLocalState() !== null && (outdatedTimeout / 2 <= now - /** @type {{lastUpdated:number}} */ (this.meta.get(this.clientID)).lastUpdated)) { 17274 // renew local clock 17275 this.setLocalState(this.getLocalState()) 17276 } 17277 /** 17278 * @type {Array<number>} 17279 */ 17280 const remove = [] 17281 this.meta.forEach((meta, clientid) => { 17282 if (clientid !== this.clientID && outdatedTimeout <= now - meta.lastUpdated && this.states.has(clientid
17282)) { 17283 remove.push(clientid) 17284 } 17285 }) 17286 if (remove.length > 0) { 17287 removeAwarenessStates(this, remove, 'timeout') 17288 } 17289 }, floor(outdatedTimeout / 10))) 17290 doc.on('destroy', () => { 17291 this.destroy() 17292 }) 17293 this.setLocalState({}) 17294 } 17295 17296 destroy () { 17297 this.emit('destroy', [this]) 17298 this.setLocalState(null) 17299 super.destroy() 17300 clearInterval(this._checkInterval) 17301 } 17302 17303 /** 17304 * @return {Object<string,any>|null} 17305 */ 17306 getLocalState () { 17307 return this.states.get(this.clientID) || null 17308 } 17309 17310 /** 17311 * @param {Object<string,any>|null} state 17312 */ 17313 setLocalState (state) { 17314 const clientID = this.clientID 17315 const currLocalMeta = this.meta.get(clientID) 17316 const clock = currLocalMeta === undefined ? 0 : currLocalMeta.clock + 1 17317 const prevState = this.states.get(clientID) 17318 if (state === null) { 17319 this.states.delete(clientID) 17320 } else { 17321 this.states.set(clientID, state) 17322 } 17323 this.meta.set(clientID, { 17324 clock, 17325 lastUpdated: getUnixTime() 17326 }) 17327 const added = [] 17328 const updated = [] 17329 const filteredUpdated = [] 17330 const removed = [] 17331 if (state === null) { 17332 removed.push(clientID) 17333 } else if (prevState == null) { 17334 if (state != null) { 17335 added.push(clientID) 17336 } 17337 } else { 17338 updated.push(clientID) 17339 if (!equalityDeep(prevState, state)) { 17340 filteredUpdated.push(clientID) 17341 } 17342 } 17343 if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) { 17344 this.emit('change', [{ added, updated: filteredUpdated, removed }, 'local']) 17345 } 17346 this.emit('update', [{ added, updated, removed }, 'local']) 17347 } 17348 17349 /** 17350 * @param {string} field 17351 * @param {any} value 17352 */ 17353 setLocalStateField (field, value) { 17354 const state = this.getLocalState() 17355 if (state !== null) { 17356 this.setLocalState({ 17357 ...state, 17358 [field]: value 17359 }) 17360 } 17361 } 17362 17363 /** 17364 * @return {Map<number,Object<string,any>>} 17365 */ 17366 getStates () { 17367 return this.states 17368 } 17369} 17370 17371/** 17372 * Mark (remote) clients as inactive and remove them from the list of active peers. 17373 * This change will be propagated to remote clients. 17374 * 17375 * @param {Awareness} awareness 17376 * @param {Array<number>} clients 17377 * @param {any} origin 17378 */ 17379const removeAwarenessStates = (awareness, clients, origin) => { 17380 const removed = [] 17381 for (let i = 0; i < clients.length; i++) { 17382 const clientID = clients[i] 17383 if (awareness.states.has(clientID)) { 17384 awareness.states.delete(clientID) 17385 if (clientID === awareness.clientID) { 17386 const curMeta = /** @type {MetaClientState} */ (awareness.meta.get(clientID)) 17387 awareness.meta.set(clientID, { 17388 clock: curMeta.clock + 1, 17389 lastUpdated: getUnixTime() 17390 }) 17391 } 17392 removed.push(clientID) 17393 } 17394 } 17395 if (removed.length > 0) { 17396 awareness.emit('change', [{ added: [], updated: [], removed }, origin]) 17397 awareness.emit('update', [{ added: [], updated: [], removed }, origin]) 17398 } 17399} 17400 17401/** 17402 * @param {Awareness} awareness 17403 * @param {Array<number>} clients 17404 * @return {Uint8Array} 17405 */ 17406const encodeAwarenessUpdate = (awareness, clients, states = awareness.states) => { 17407 const len = clients.length 17408 const encoder = createEncoder() 17409 writeVarUint(encoder, len) 17410 for (let i = 0; i < len; i++) { 17411 const clientID = clients[i] 17412 const state = states.get(clientID) || null 17413 const clock = /** @type {MetaClientState} */ (awareness.meta.get(clientID)).clock 17414 writeVarUint(encoder, clientID) 17415 writeVarUint(encoder, clock) 17416 writeVarString(encoder, JSON.stringify(state)) 17417 } 17418 return toUint8Array(encoder) 17419} 17420 17421/** 17422 * Modify the content of an awareness update before re-encoding it to an awareness update. 17423 * 17424 * This might be useful when you have a central server that wants to ensure that clients 17425 * cant hijack somebody elses identity. 17426 * 17427 * @param {Uint8Array} update 17428 * @param {function(any):any} modify 17429 * @return {Uint8Array} 17430 */ 17431const modifyAwarenessUpdate = (update, modify) => { 17432 const decoder = decoding.createDecoder(update) 17433 const encoder = encoding.createEncoder() 17434 const len = decoding.readVarUint(decoder) 17435 encoding.writeVarUint(encoder, len) 17436 for (let i = 0; i < len; i++) { 17437 const clientID = decoding.readVarUint(decoder) 17438 const clock = decoding.readVarUint(decoder) 17439 const state = JSON.parse(decoding.readVarString(decoder)) 17440 const modifiedState = modify(state) 17441 encoding.writeVarUint(encoder, clientID) 17442 encoding.writeVarUint(encoder, clock) 17443 encoding.writeVarString(encoder, JSON.stringify(modifiedState)) 17444 } 17445 return encoding.toUint8Array(encoder) 17446} 17447 17448/** 17449 * @param {Awareness} awareness 17450 * @param {Uint8Array} update 17451 * @param {any} origin This will be added to the emitted change event 17452 */ 17453const applyAwarenessUpdate = (awareness, update, origin) => { 17454 const decoder = createDecoder(update) 17455 const timestamp = getUnixTime() 17456 const added = [] 17457 const updated = [] 17458 const filteredUpdated = [] 17459 const removed = [] 17460 const len = readVarUint(decoder) 17461 for (let i = 0; i < len; i++) { 17462 const clientID = readVarUint(decoder)
17463 let clock = readVarUint(decoder) 17464 const state = JSON.parse(readVarString(decoder)) 17465 const clientMeta = awareness.meta.get(clientID) 17466 const prevState = awareness.states.get(clientID) 17467 const currClock = clientMeta === undefined ? 0 : clientMeta.clock 17468 if (currClock < clock || (currClock === clock && state === null && awareness.states.has(clientID))) { 17469 if (state === null) { 17470 // never let a remote client remove this local state 17471 if (clientID === awareness.clientID && awareness.getLocalState() != null) { 17472 // remote client removed the local state. Do not remote state. Broadcast a message indicating 17473 // that this client still exists by increasing the clock 17474 clock++ 17475 } else { 17476 awareness.states.delete(clientID) 17477 } 17478 } else { 17479 awareness.states.set(clientID, state) 17480 } 17481 awareness.meta.set(clientID, { 17482 clock, 17483 lastUpdated: timestamp 17484 }) 17485 if (clientMeta === undefined && state !== null) { 17486 added.push(clientID) 17487 } else if (clientMeta !== undefined && state === null) { 17488 removed.push(clientID) 17489 } else if (state !== null) { 17490 if (!equalityDeep(state, prevState)) { 17491 filteredUpdated.push(clientID) 17492 } 17493 updated.push(clientID) 17494 } 17495 } 17496 } 17497 if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) { 17498 awareness.emit('change', [{ 17499 added, updated: filteredUpdated, removed 17500 }, origin]) 17501 } 17502 if (added.length > 0 || updated.length > 0 || removed.length > 0) { 17503 awareness.emit('update', [{ 17504 added, updated, removed 17505 }, origin]) 17506 } 17507} 17508 17509;// CONCATENATED MODULE: ./node_modules/y-webrtc/src/crypto.js 17510/* eslint-env browser */ 17511 17512 17513 17514 17515 17516 17517 17518/** 17519 * @param {string} secret 17520 * @param {string} roomName 17521 * @return {PromiseLike<CryptoKey>} 17522 */ 17523const deriveKey = (secret, roomName) => { 17524 const secretBuffer = encodeUtf8(secret).buffer 17525 const salt = encodeUtf8(roomName).buffer 17526 return crypto.subtle.importKey( 17527 'raw', 17528 secretBuffer, 17529 'PBKDF2', 17530 false, 17531 ['deriveKey'] 17532 ).then(keyMaterial => 17533 crypto.subtle.deriveKey( 17534 { 17535 name: 'PBKDF2', 17536 salt, 17537 iterations: 100000, 17538 hash: 'SHA-256' 17539 }, 17540 keyMaterial, 17541 { 17542 name: 'AES-GCM', 17543 length: 256 17544 }, 17545 true, 17546 ['encrypt', 'decrypt'] 17547 ) 17548 ) 17549} 17550 17551/** 17552 * @param {Uint8Array} data data to be encrypted 17553 * @param {CryptoKey?} key 17554 * @return {PromiseLike<Uint8Array>} encrypted, base64 encoded message 17555 */ 17556const encrypt = (data, key) => { 17557 if (!key) { 17558 return /** @type {PromiseLike<Uint8Array>} */ (resolve(data)) 17559 } 17560 const iv = crypto.getRandomValues(new Uint8Array(12)) 17561 return crypto.subtle.encrypt( 17562 { 17563 name: 'AES-GCM', 17564 iv 17565 }, 17566 key, 17567 data 17568 ).then(cipher => { 17569 const encryptedDataEncoder = createEncoder() 17570 writeVarString(encryptedDataEncoder, 'AES-GCM') 17571 writeVarUint8Array(encryptedDataEncoder, iv) 17572 writeVarUint8Array(encryptedDataEncoder, new Uint8Array(cipher)) 17573 return toUint8Array(encryptedDataEncoder) 17574 }) 17575} 17576 17577/** 17578 * @param {Object} data data to be encrypted 17579 * @param {CryptoKey?} key 17580 * @return {PromiseLike<Uint8Array>} encrypted data, if key is provided 17581 */ 17582const encryptJson = (data, key) => { 17583 const dataEncoder = createEncoder() 17584 writeAny(dataEncoder, data) 17585 return encrypt(toUint8Array(dataEncoder), key) 17586} 17587 17588/** 17589 * @param {Uint8Array} data 17590 * @param {CryptoKey?} key 17591 * @return {PromiseLike<Uint8Array>} decrypted buffer 17592 */ 17593const decrypt = (data, key) => { 17594 if (!key) { 17595 return /** @type {PromiseLike<Uint8Array>} */ (resolve(data)) 17596 } 17597 const dataDecoder = createDecoder(data) 17598 const algorithm = readVarString(dataDecoder) 17599 if (algorithm !== 'AES-GCM') { 17600 reject(error_create('Unknown encryption algorithm')) 17601 } 17602 const iv = readVarUint8Array(dataDecoder) 17603 const cipher = readVarUint8Array(dataDecoder) 17604 return crypto.subtle.decrypt( 17605 { 17606 name: 'AES-GCM', 17607 iv 17608 }, 17609 key, 17610 cipher 17611 ).then(data => new Uint8Array(data)) 17612} 17613 17614/** 17615 * @param {Uint8Array} data 17616 * @param {CryptoKey?} key 17617 * @return {PromiseLike<Object>} decrypted object 17618 */ 17619const decryptJson = (data, key) => 17620 decrypt(data, key).then(decryptedValue => 17621 readAny(createDecoder(new Uint8Array(decryptedValue))) 17622 ) 17623 17624;// CONCATENATED MODULE: ./node_modules/y-webrtc/src/y-webrtc.js 17625 17626 17627 17628 17629 17630 17631 17632 17633 17634 17635 17636 17637 17638 17639 // eslint-disable-line 17640 17641 17642 17643 17644 17645 17646 17647const y_webrtc_log = logging_createModuleLogger('y-webrtc') 17648 17649const messageSync = 0 17650const messageQueryAwareness = 3 17651const messageAwareness = 1 17652const messageBcPeerId = 4 17653 17654/** 17655 * @type {Map<string, SignalingConn>} 17656 */ 17657const signalingConns = new Map() 17658 17659/** 17660 * @type {Map<string,Room>} 17661 */ 17662const rooms = new Map() 17663 17664/** 17665 * @param {Room} room 17666 */ 17667const checkIsSynced = room => { 17668 let synced = true 17669 room.webrtcConns.forEach(peer => { 17670 if (!peer.synced) { 17671 synced = false 17672 } 17673 }) 17674 if ((!synced && room.synced) || (synced && !room.synced)) { 17675 room.synced = synced 17676 room.provider.emit('synced', [{ synced }]) 17677 y_webrtc_log('synced ', BOLD, room.name, UNBOLD, ' with all peers') 17678 } 17679} 17680 17681/** 17682 * @param {Room} room 17683 * @param {Uint8Array} buf 17684 * @param {function} syncedCallback 17685 * @return {encoding.Encoder?} 17686 */ 17687const readMessage = (room, buf, syncedCallback) => { 17688 const decoder = createDecoder(buf) 17689 const encoder = createEncoder() 17690 const messageType = readVarUint(decoder) 17691 if (room === undefined) { 17692 return null 17693 } 17694 const awareness = room.awareness 17695 const doc = room.doc 17696 let sendReply = false 17697 switch (messageType) { 17698 case messageSync: { 17699 writeVarUint(encoder, messageSync) 17700 const syncMessageType = readSyncMessage(decoder, encoder, doc, room) 17701 if (syncMessageType === messageYjsSyncStep2 && !room.synced) { 17702 syncedCallback() 17703 } 17704 if (syncMessageType === messageYjsSyncStep1) { 17705 sendReply = true 17706 } 17707 break 17708 } 17709 case messageQueryAwareness: 17710 writeVarUint(encoder, messageAwareness) 17711 writeVarUint8Array(encoder, encodeAwarenessUpdate(awareness, Array.from(awareness.getStates().keys()))) 17712 sendReply = true 17713 break 17714 case messageAwareness: 17715 applyAwarenessUpdate(awareness, readVarUint8Array(decoder), room) 17716 break 17717 case messageBcPeerId: { 17718 const add = readUint8(decoder) === 1 17719 const peerName = readVarString(decoder) 17720 if (peerName !== room.peerId && ((room.bcConns.has(peerName) && !add) || (!room.bcConns.has(peerName) && add))) { 17721 const removed = [] 17722 const added = [] 17723 if (add) { 17724 room.bcConns.add(peerName) 17725 added.push(peerName) 17726 } else { 17727 room.bcConns.delete(peerName) 17728 removed.push(peerName) 17729 } 17730 room.provider.emit('peers', [{ 17731 added, 17732 removed, 17733 webrtcPeers: Array.from(room.webrtcConns.keys()), 17734 bcPeers: Array.from(room.bcConns) 17735 }]) 17736 broadcastBcPeerId(room) 17737 } 17738 break 17739 } 17740 default: 17741 console.error('Unable to compute message') 17742 return encoder 17743 } 17744 if (!sendReply) { 17745 // nothing has been written, no answer created 17746 return null 17747 } 17748 return encoder 17749} 17750 17751/** 17752 * @param {WebrtcConn} peerConn 17753 * @param {Uint8Array} buf 17754 * @return {encoding.Encoder?} 17755 */ 17756const readPeerMessage = (peerConn, buf) => { 17757 const room = peerConn.room 17758 y_webrtc_log('received message from ', BOLD, peerConn.remotePeerId, GREY, ' (', room.name, ')', UNBOLD, UNCOLOR) 17759 return readMessage(room, buf, () => { 17760 peerConn.synced = true 17761 y_webrtc_log('synced ', BOLD, room.name, UNBOLD, ' with ', BOLD, peerConn.remotePeerId) 17762 checkIsSynced(room) 17763 }) 17764} 17765 17766/** 17767 * @param {WebrtcConn} webrtcConn 17768 * @param {encoding.Encoder} encoder 17769 */ 17770const sendWebrtcConn = (webrtcConn, encoder) => { 17771 y_webrtc_log('send message to ', BOLD, webrtcConn.remotePeerId, UNBOLD, GREY, ' (', webrtcConn.room.name, ')', UNCOLOR) 17772 try { 17773 webrtcConn.peer.send(toUint8Array(encoder)) 17774 } catch (e) {} 17775} 17776 17777/** 17778 * @param {Room} room 17779 * @param {Uint8Array} m 17780 */ 17781const broadcastWebrtcConn = (room, m) => { 17782 y_webrtc_log('broadcast message in ', BOLD, room.name, UNBOLD) 17783 room.webrtcConns.forEach(conn => { 17784 try { 17785 conn.peer.send(m) 17786 } catch (e) {} 17787 }) 17788} 17789 17790class WebrtcConn { 17791 /** 17792 * @param {SignalingConn} signalingConn 17793 * @param {boolean} initiator 17794 * @param {string} remotePeerId 17795 * @param {Room} room 17796 */ 17797 constructor (signalingConn, initiator, remotePeerId, room) { 17798 y_webrtc_log('establishing connection to ', BOLD, remotePeerId) 17799 this.room = room 17800 this.remotePeerId = remotePeerId 17801 this.closed = false 17802 this.connected = false 17803 this.synced = false 17804 /** 17805 * @type {any} 17806 */ 17807 this.peer = new simplepeer_min({ initiator, ...room.provider.peerOpts }) 17808 this.peer.on('signal', signal => { 17809 publishSignalingMessage(signalingConn, room, { to: remotePeerId, from: room.peerId, type: 'signal', signal }) 17810 }) 17811 this.peer.on('connect', () => { 17812 y_webrtc_log('connected to ', BOLD, remotePeerId) 17813 this.connected = true 17814 // send sync step 1 17815 const provider = room.provider 17816 const doc = provider.doc 17817 const awareness = room.awareness 17818 const encoder = createEncoder() 17819 writeVarUint(encoder, messageSync) 17820 writeSyncStep1(encoder, doc) 17821 sendWebrtcConn(this, encoder) 17822 const awarenessStates = awareness.getStates() 17823 if (awarenessStates.size > 0) { 17824 const encoder = createEncoder() 17825 writeVarUint(encoder, messageAwareness) 17826 writeVarUint8Array(encoder, encodeAwarenessUpdate(awareness, Array.from(awarenessStates.keys()))) 17827 sendWebrtcConn(this, encoder) 17828 } 17829 }) 17830 this.peer.on('close', () => { 17831 this.connected = false 17832 this.closed = true 17833 if (room.webrtcConns.has(this.remotePeerId)) { 17834 room.webrtcConns.delete(this.remotePeerId) 17835 room.provider.emit('peers', [{ 17836 removed: [this.remotePeerId], 17837 added: [], 17838 webrtcPeers: Array.from(room.webrtcConns.keys()), 17839 bcPeers: Array.from(room.bcConns) 17840 }]) 17841 } 17842 checkIsSynced(room) 17843 this.peer.destroy() 17844 y_webrtc_log('closed connection to ', BOLD, remotePeerId) 17845 announceSignalingInfo(room) 17846 }) 17847 this.peer.on('error', err => { 17848 y_webrtc_log('Error in connection to ', BOLD, remotePeerId, ': ', err) 17849 announceSignalingInfo(room) 17850 }) 17851 this.peer.on('data', data => { 17852 const answer = readPeerMessage(this, data) 17853 if (answer !== null) { 17854 sendWebrtcConn(this, answer) 17855 } 17856 }) 17857 } 17858 17859 destroy () { 17860 this.peer.destroy() 17861 } 17862} 17863 17864/** 17865 * @param {Room} room 17866 * @param {Uint8Array} m 17867 */ 17868const broadcastBcMessage = (room, m) => encrypt(m, room.key).then(data => 17869 room.mux(() => 17870 publish(room.name, data) 17871 ) 17872) 17873 17874/** 17875 * @param {Room} room 17876 * @param {Uint8Array} m 17877 */
17878const broadcastRoomMessage = (room, m) => { 17879 if (room.bcconnected) { 17880 broadcastBcMessage(room, m) 17881 } 17882 broadcastWebrtcConn(room, m) 17883} 17884 17885/** 17886 * @param {Room} room 17887 */ 17888const announceSignalingInfo = room => { 17889 signalingConns.forEach(conn => { 17890 // only subcribe if connection is established, otherwise the conn automatically subscribes to all rooms 17891 if (conn.connected) { 17892 conn.send({ type: 'subscribe', topics: [room.name] }) 17893 if (room.webrtcConns.size < room.provider.maxConns) { 17894 publishSignalingMessage(conn, room, { type: 'announce', from: room.peerId }) 17895 } 17896 } 17897 }) 17898} 17899 17900/** 17901 * @param {Room} room 17902 */ 17903const broadcastBcPeerId = room => { 17904 if (room.provider.filterBcConns) { 17905 // broadcast peerId via broadcastchannel 17906 const encoderPeerIdBc = createEncoder() 17907 writeVarUint(encoderPeerIdBc, messageBcPeerId) 17908 writeUint8(encoderPeerIdBc, 1) 17909 writeVarString(encoderPeerIdBc, room.peerId) 17910 broadcastBcMessage(room, toUint8Array(encoderPeerIdBc)) 17911 } 17912} 17913 17914class Room { 17915 /** 17916 * @param {Y.Doc} doc
17917 * @param {WebrtcProvider} provider 17918 * @param {string} name 17919 * @param {CryptoKey|null} key 17920 */ 17921 constructor (doc, provider, name, key) { 17922 /** 17923 * Do not assume that peerId is unique. This is only meant for sending signaling messages. 17924 * 17925 * @type {string} 17926 */ 17927 this.peerId = uuidv4() 17928 this.doc = doc 17929 /** 17930 * @type {awarenessProtocol.Awareness} 17931 */ 17932 this.awareness = provider.awareness 17933 this.provider = provider 17934 this.synced = false 17935 this.name = name 17936 // @todo make key secret by scoping 17937 this.key = key 17938 /** 17939 * @type {Map<string, WebrtcConn>} 17940 */ 17941 this.webrtcConns = new Map() 17942 /** 17943 * @type {Set<string>} 17944 */ 17945 this.bcConns = new Set() 17946 this.mux = createMutex() 17947 this.bcconnected = false 17948 /** 17949 * @param {ArrayBuffer} data 17950 */ 17951 this._bcSubscriber = data => 17952 decrypt(new Uint8Array(data), key).then(m => 17953 this.mux(() => { 17954 const reply = readMessage(this, m, () => {}) 17955 if (reply) { 17956 broadcastBcMessage(this, toUint8Array(reply)) 17957 } 17958 }) 17959 ) 17960 /** 17961 * Listens to Yjs updates and sends them to remote peers 17962 * 17963 * @param {Uint8Array} update 17964 * @param {any} origin 17965 */ 17966 this._docUpdateHandler = (update, origin) => { 17967 const encoder = createEncoder() 17968 writeVarUint(encoder, messageSync) 17969 writeUpdate(encoder, update) 17970 broadcastRoomMessage(this, toUint8Array(encoder)) 17971 } 17972 /** 17973 * Listens to Awareness updates and sends them to remote peers 17974 * 17975 * @param {any} changed 17976 * @param {any} origin 17977 */ 17978 this._awarenessUpdateHandler = ({ added, updated, removed }, origin) => { 17979 const changedClients = added.concat(updated).concat(removed) 17980 const encoderAwareness = createEncoder() 17981 writeVarUint(encoderAwareness, messageAwareness) 17982 writeVarUint8Array(encoderAwareness, encodeAwarenessUpdate(this.awareness, changedClients)) 17983 broadcastRoomMessage(this, toUint8Array(encoderAwareness)) 17984 } 17985 17986 this._beforeUnloadHandler = () => { 17987 removeAwarenessStates(this.awareness, [doc.clientID], 'window unload') 17988 rooms.forEach(room => { 17989 room.disconnect() 17990 }) 17991 } 17992 17993 if (typeof window !== 'undefined') { 17994 window.addEventListener('beforeunload', this._beforeUnloadHandler) 17995 } else if (typeof process !== 'undefined') { 17996 process.on('exit', this._beforeUnloadHandler) 17997 } 17998 } 17999 18000 connect () { 18001 this.doc.on('update', this._docUpdateHandler) 18002 this.awareness.on('update', this._awarenessUpdateHandler) 18003 // signal through all available signaling connections 18004 announceSignalingInfo(this) 18005 const roomName = this.name 18006 subscribe(roomName, this._bcSubscriber) 18007 this.bcconnected = true 18008 // broadcast peerId via broadcastchannel 18009 broadcastBcPeerId(this) 18010 // write sync step 1 18011 const encoderSync = createEncoder() 18012 writeVarUint(encoderSync, messageSync) 18013 writeSyncStep1(encoderSync, this.doc) 18014 broadcastBcMessage(this, toUint8Array(encoderSync)) 18015 // broadcast local state 18016 const encoderState = createEncoder() 18017 writeVarUint(encoderState, messageSync) 18018 writeSyncStep2(encoderState, this.doc) 18019 broadcastBcMessage(this, toUint8Array(encoderState)) 18020 // write queryAwareness 18021 const encoderAwarenessQuery = createEncoder() 18022 writeVarUint(encoderAwarenessQuery, messageQueryAwareness) 18023 broadcastBcMessage(this, toUint8Array(encoderAwarenessQuery)) 18024 // broadcast local awareness state 18025 const encoderAwarenessState = createEncoder() 18026 writeVarUint(encoderAwarenessState, messageAwareness) 18027 writeVarUint8Array(encoderAwarenessState, encodeAwarenessUpdate(this.awareness, [this.doc.clientID])) 18028 broadcastBcMessage(this, toUint8Array(encoderAwarenessState)) 18029 } 18030 18031 disconnect () { 18032 // signal through all available signaling connections 18033 signalingConns.forEach(conn => { 18034 if (conn.connected) { 18035 conn.send({ type: 'unsubscribe', topics: [this.name] }) 18036 } 18037 }) 18038 removeAwarenessStates(this.awareness, [this.doc.clientID], 'disconnect') 18039 // broadcast peerId removal via broadcastchannel 18040 const encoderPeerIdBc = createEncoder() 18041 writeVarUint(encoderPeerIdBc, messageBcPeerId) 18042 writeUint8(encoderPeerIdBc, 0) // remove peerId from other bc peers 18043 writeVarString(encoderPeerIdBc, this.peerId) 18044 broadcastBcMessage(this, toUint8Array(encoderPeerIdBc)) 18045 18046 unsubscribe(this.name, this._bcSubscriber) 18047 this.bcconnected = false
18048 this.doc.off('update', this._docUpdateHandler) 18049 this.awareness.off('update', this._awarenessUpdateHandler) 18050 this.webrtcConns.forEach(conn => conn.destroy()) 18051 } 18052 18053 destroy () { 18054 this.disconnect() 18055 if (typeof window !== 'undefined') { 18056 window.removeEventListener('beforeunload', this._beforeUnloadHandler) 18057 } else if (typeof process !== 'undefined') { 18058 process.off('exit', this._beforeUnloadHandler) 18059 } 18060 } 18061} 18062 18063/** 18064 * @param {Y.Doc} doc 18065 * @param {WebrtcProvider} provider 18066 * @param {string} name 18067 * @param {CryptoKey|null} key 18068 * @return {Room} 18069 */ 18070const openRoom = (doc, provider, name, key) => { 18071 // there must only be one room 18072 if (rooms.has(name)) { 18073 throw error_create(`A Yjs Doc connected to room "${name}" already exists!`) 18074 } 18075 const room = new Room(doc, provider, name, key) 18076 rooms.set(name, /** @type {Room} */ (room)) 18077 return room 18078} 18079 18080/** 18081 * @param {SignalingConn} conn 18082 * @param {Room} room 18083 * @param {any} data 18084 */ 18085const publishSignalingMessage = (conn, room, data) => { 18086 if (room.key) { 18087 encryptJson(data, room.key).then(data => { 18088 conn.send({ type: 'publish', topic: room.name, data: toBase64(data) }) 18089 }) 18090 } else { 18091 conn.send({ type: 'publish', topic: room.name, data }) 18092 } 18093} 18094 18095class SignalingConn extends WebsocketClient { 18096 constructor (url) { 18097 super(url) 18098 /** 18099 * @type {Set<WebrtcProvider>} 18100 */ 18101 this.providers = new Set() 18102 this.on('connect', () => { 18103 y_webrtc_log(`connected (${url})`) 18104 const topics = Array.from(rooms.keys()) 18105 this.send({ type: 'subscribe', topics }) 18106 rooms.forEach(room => 18107 publishSignalingMessage(this, room, { type: 'announce', from: room.peerId }) 18108 ) 18109 }) 18110 this.on('message', m => { 18111 switch (m.type) { 18112 case 'publish': { 18113 const roomName = m.topic 18114 const room = rooms.get(roomName) 18115 if (room == null || typeof roomName !== 'string') { 18116 return 18117 } 18118 const execMessage = data => { 18119 const webrtcConns = room.webrtcConns 18120 const peerId = room.peerId 18121 if (data == null || data.from === peerId || (data.to !== undefined && data.to !== peerId) || room.bcConns.has(data.from)) { 18122 // ignore messages that are not addressed to this conn, or from clients that are connected via broadcastchannel 18123 return 18124 } 18125 const emitPeerChange = webrtcConns.has(data.from) 18126 ? () => {} 18127 : () => 18128 room.provider.emit('peers', [{ 18129 removed: [], 18130 added: [data.from], 18131 webrtcPeers: Array.from(room.webrtcConns.keys()), 18132 bcPeers: Array.from(room.bcConns) 18133 }]) 18134 switch (data.type) { 18135 case 'announce': 18136 if (webrtcConns.size < room.provider.maxConns) { 18137 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(this, true, data.from, room)) 18138 emitPeerChange() 18139 } 18140 break 18141 case 'signal': 18142 if (data.to === peerId) { 18143 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(this, false, data.from, room)).peer.signal(data.signal) 18144 emitPeerChange() 18145 } 18146 break 18147 } 18148 } 18149 if (room.key) { 18150 if (typeof m.data === 'string') { 18151 decryptJson(fromBase64(m.data), room.key).then(execMessage) 18152 } 18153 } else { 18154 execMessage(m.data) 18155 } 18156 } 18157 } 18158 }) 18159 this.on('disconnect', () => y_webrtc_log(`disconnect (${url})`)) 18160 } 18161} 18162 18163/** 18164 * @typedef {Object} ProviderOptions 18165 * @property {Array<string>} [signaling] 18166 * @property {string} [password] 18167 * @property {awarenessProtocol.Awareness} [awareness] 18168 * @property {number} [maxConns] 18169 * @property {boolean} [filterBcConns] 18170 * @property {any} [peerOpts] 18171 */ 18172
18173/** 18174 * @extends Observable<string> 18175 */ 18176class WebrtcProvider extends observable_Observable { 18177 /** 18178 * @param {string} roomName 18179 * @param {Y.Doc} doc 18180 * @param {ProviderOptions?} opts 18181 */ 18182 constructor ( 18183 roomName, 18184 doc, 18185 { 18186 signaling = ['wss://y-webrtc-eu.fly.dev'], 18187 password = null, 18188 awareness = new Awareness(doc), 18189 maxConns = 20 + floor(rand() * 15), // the random factor reduces the chance that n clients form a cluster 18190 filterBcConns = true, 18191 peerOpts = {} // simple-peer options. See https://github.com/feross/simple-peer#peer--new-peeropts 18192 } = {} 18193 ) { 18194 super() 18195 this.roomName = roomName 18196 this.doc = doc 18197 this.filterBcConns = filterBcConns 18198 /** 18199 * @type {awarenessProtocol.Awareness} 18200 */ 18201 this.awareness = awareness 18202 this.shouldConnect = false 18203 this.signalingUrls = signaling 18204 this.signalingConns = [] 18205 this.maxConns = maxConns 18206 this.peerOpts = peerOpts 18207 /** 18208 * @type {PromiseLike<CryptoKey | null>} 18209 */ 18210 this.key = password ? deriveKey(password, roomName) : /** @type {PromiseLike<null>} */ (resolve(null)) 18211 /** 18212 * @type {Room|null} 18213 */ 18214 this.room = null 18215 this.key.then(key => { 18216 this.room = openRoom(doc, this, roomName, key) 18217 if (this.shouldConnect) { 18218 this.room.connect() 18219 } else { 18220 this.room.disconnect() 18221 } 18222 }) 18223 this.connect() 18224 this.destroy = this.destroy.bind(this) 18225 doc.on('destroy', this.destroy) 18226 } 18227 18228 /** 18229 * @type {boolean} 18230 */ 18231 get connected () { 18232 return this.room !== null && this.shouldConnect 18233 } 18234 18235 connect () { 18236 this.shouldConnect = true 18237 this.signalingUrls.forEach(url => { 18238 const signalingConn = setIfUndefined(signalingConns, url, () => new SignalingConn(url)) 18239 this.signalingConns.push(signalingConn) 18240 signalingConn.providers.add(this) 18241 }) 18242 if (this.room) { 18243 this.room.connect() 18244 } 18245 } 18246 18247 disconnect () { 18248 this.shouldConnect = false 18249 this.signalingConns.forEach(conn => { 18250 conn.providers.delete(this) 18251 if (conn.providers.size === 0) { 18252 conn.destroy() 18253 signalingConns.delete(conn.url) 18254 } 18255 }) 18256 if (this.room) { 18257 this.room.disconnect() 18258 } 18259 } 18260 18261 destroy () { 18262 this.doc.off('destroy', this.destroy) 18263 // need to wait for key before deleting room 18264 this.key.then(() => { 18265 /** @type {Room} */ (this.room).destroy() 18266 rooms.delete(this.roomName) 18267 }) 18268 super.destroy() 18269 } 18270} 18271 18272;// CONCATENATED MODULE: ./packages/sync/build-module/connect-webrtc.js 18273/** 18274 * External dependencies 18275 */ 18276// @ts-ignore 18277 18278 18279/** @typedef {import('./types').ObjectType} ObjectType */ 18280/** @typedef {import('./types').ObjectID} ObjectID */ 18281/** @typedef {import('./types').CRDTDoc} CRDTDoc */ 18282 18283/** 18284 * Connect function to the WebRTC provider. 18285 * 18286 * @param {ObjectID} objectId The object ID. 18287 * @param {ObjectType} objectType The object type. 18288 * @param {CRDTDoc} doc The CRDT document. 18289 * 18290 * @return {Promise<() => void>} Promise that resolves when the connection is established. 18291 */ 18292function connectWebRTC(objectId, objectType, doc) { 18293 const docName = `${objectType}-${objectId}`; 18294 new WebrtcProvider(docName, doc, { 18295 // @ts-ignore 18296 password: window.__experimentalCollaborativeEditingSecret 18297 }); 18298 return Promise.resolve(() => true); 18299} 18300 18301;// CONCATENATED MODULE: ./packages/core-data/build-module/sync.js 18302/** 18303 * WordPress dependencies 18304 */ 18305 18306let syncProvider; 18307function getSyncProvider() { 18308 if (!syncProvider) { 18309 syncProvider = createSyncProvider(connectIndexDb, connectWebRTC); 18310 } 18311 return syncProvider; 18312} 18313 18314;// CONCATENATED MODULE: ./packages/core-data/build-module/actions.js 18315/** 18316 * External dependencies 18317 */ 18318 18319 18320 18321/** 18322 * WordPress dependencies 18323 */ 18324 18325 18326 18327 18328/** 18329 * Internal dependencies 18330 */ 18331 18332 18333 18334 18335 18336 18337 18338/** 18339 * Returns an action object used in signalling that authors have been received. 18340 * Ignored from documentation as it's internal to the data store. 18341 * 18342 * @ignore 18343 * 18344 * @param {string} queryID Query ID. 18345 * @param {Array|Object} users Users received. 18346 * 18347 * @return {Object} Action object. 18348 */ 18349function receiveUserQuery(queryID, users) { 18350 return { 18351 type: 'RECEIVE_USER_QUERY', 18352 users: Array.isArray(users) ? users : [users], 18353 queryID 18354 }; 18355} 18356 18357/** 18358 * Returns an action used in signalling that the current user has been received. 18359 * Ignored from documentation as it's internal to the data store. 18360 * 18361 * @ignore 18362 * 18363 * @param {Object} currentUser Current user object. 18364 * 18365 * @return {Object} Action object. 18366 */ 18367function receiveCurrentUser(currentUser) { 18368 return { 18369 type: 'RECEIVE_CURRENT_USER', 18370 currentUser 18371 }; 18372} 18373 18374/** 18375 * Returns an action object used in adding new entities. 18376 * 18377 * @param {Array} entities Entities received. 18378 * 18379 * @return {Object} Action object. 18380 */ 18381function addEntities(entities) { 18382 return { 18383 type: 'ADD_ENTITIES', 18384 entities 18385 }; 18386} 18387 18388/** 18389 * Returns an action object used in signalling that entity records have been received. 18390 * 18391 * @param {string} kind Kind of the received entity record. 18392 * @param {string} name Name of the received entity record. 18393 * @param {Array|Object}
18393 records Records received. 18394 * @param {?Object} query Query Object. 18395 * @param {?boolean} invalidateCache Should invalidate query caches. 18396 * @param {?Object} edits Edits to reset. 18397 * @return {Object} Action object. 18398 */ 18399function receiveEntityRecords(kind, name, records, query, invalidateCache = false, edits) { 18400 // Auto drafts should not have titles, but some plugins rely on them so we can't filter this 18401 // on the server. 18402 if (kind === 'postType') { 18403 records = (Array.isArray(records) ? records : [records]).map(record => record.status === 'auto-draft' ? { 18404 ...record, 18405 title: '' 18406 } : record); 18407 } 18408 let action; 18409 if (query) { 18410 action = receiveQueriedItems(records, query, edits); 18411 } else { 18412 action = receiveItems(records, edits); 18413 } 18414 return { 18415 ...action, 18416 kind, 18417 name, 18418 invalidateCache 18419 }; 18420} 18421 18422/** 18423 * Returns an action object used in signalling that the current theme has been received. 18424 * Ignored from documentation as it's internal to the data store. 18425 * 18426 * @ignore 18427 * 18428 * @param {Object} currentTheme The current theme. 18429 * 18430 * @return {Object} Action object. 18431 */ 18432function receiveCurrentTheme(currentTheme) { 18433 return { 18434 type: 'RECEIVE_CURRENT_THEME', 18435 currentTheme 18436 }; 18437} 18438 18439/** 18440 * Returns an action object used in signalling that the current global styles id has been received. 18441 * Ignored from documentation as it's internal to the data store. 18442 * 18443 * @ignore 18444 * 18445 * @param {string} currentGlobalStylesId The current global styles id. 18446 * 18447 * @return {Object} Action object. 18448 */ 18449function __experimentalReceiveCurrentGlobalStylesId(currentGlobalStylesId) { 18450 return { 18451 type: 'RECEIVE_CURRENT_GLOBAL_STYLES_ID', 18452 id: currentGlobalStylesId 18453 }; 18454} 18455 18456/** 18457 * Returns an action object used in signalling that the theme base global styles have been received 18458 * Ignored from documentation as it's internal to the data store. 18459 * 18460 * @ignore 18461 * 18462 * @param {string} stylesheet The theme's identifier 18463 * @param {Object} globalStyles The global styles object. 18464 * 18465 * @return {Object} Action object. 18466 */ 18467function __experimentalReceiveThemeBaseGlobalStyles(stylesheet, globalStyles) { 18468 return { 18469 type: 'RECEIVE_THEME_GLOBAL_STYLES', 18470 stylesheet, 18471 globalStyles 18472 }; 18473} 18474 18475/** 18476 * Returns an action object used in signalling that the theme global styles variations have been received. 18477 * Ignored from documentation as it's internal to the data store. 18478 * 18479 * @ignore 18480 * 18481 * @param {string} stylesheet The theme's identifier 18482 * @param {Array} variations The global styles variations. 18483 * 18484 * @return {Object} Action object. 18485 */ 18486function __experimentalReceiveThemeGlobalStyleVariations(stylesheet, variations) { 18487 return { 18488 type: 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS', 18489 stylesheet, 18490 variations 18491 }; 18492} 18493 18494/** 18495 * Returns an action object used in signalling that the index has been received. 18496 * 18497 * @deprecated since WP 5.9, this is not useful anymore, use the selector direclty. 18498 * 18499 * @return {Object} Action object. 18500 */ 18501function receiveThemeSupports() { 18502 external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveThemeSupports", { 18503 since: '5.9' 18504 }); 18505 return { 18506 type: 'DO_NOTHING' 18507 }; 18508} 18509 18510/** 18511 * Returns an action object used in signalling that the theme global styles CPT post revisions have been received. 18512 * Ignored from documentation as it's internal to the data store. 18513 * 18514 * @ignore 18515 * 18516 * @param {number} currentId The post id. 18517 * @param {Array} revisions The global styles revisions. 18518 * 18519 * @return {Object} Action object. 18520 */ 18521function receiveThemeGlobalStyleRevisions(currentId, revisions) { 18522 return { 18523 type: 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS', 18524 currentId, 18525 revisions 18526 }; 18527} 18528 18529/** 18530 * Returns an action object used in signalling that the preview data for 18531 * a given URl has been received. 18532 * Ignored from documentation as it's internal to the data store. 18533 * 18534 * @ignore 18535 * 18536 * @param {string} url URL to preview the embed for. 18537 * @param {*} preview Preview data. 18538 * 18539 * @return {Object} Action object. 18540 */ 18541function receiveEmbedPreview(url, preview) { 18542 return { 18543 type: 'RECEIVE_EMBED_PREVIEW', 18544 url, 18545 preview 18546 }; 18547} 18548 18549/** 18550 * Action triggered to delete an entity record. 18551 * 18552 * @param {string} kind Kind of the deleted entity. 18553 * @param {string} name Name of the deleted entity. 18554 * @param {string} recordId Record ID of the deleted entity. 18555 * @param {?Object} query Special query parameters for the 18556 * DELETE API call. 18557 * @param {Object} [options] Delete options. 18558 * @param {Function} [options.__unstableFetch] Internal use only. Function to 18559 * call instead of `apiFetch()`. 18560 * Must return a promise. 18561 * @param {boolean} [options.throwOnError=false] If false, this action suppresses all 18562 * the exceptions. Defaults to false. 18563 */ 18564const deleteEntityRecord = (kind, name, recordId, query, { 18565 __unstableFetch = (external_wp_apiFetch_default()), 18566 throwOnError = false 18567} = {}) => async ({ 18568 dispatch 18569}) => { 18570 const configs = await dispatch(getOrLoadEntitiesConfig(kind)); 18571 const entityConfig = configs.find(config => config.kind === kind && config.name === name); 18572 let error; 18573 let deletedRecord = false;
18574 if (!entityConfig || entityConfig?.__experimentalNoFetch) { 18575 return; 18576 } 18577 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, recordId], { 18578 exclusive: true 18579 }); 18580 try { 18581 dispatch({ 18582 type: 'DELETE_ENTITY_RECORD_START', 18583 kind, 18584 name, 18585 recordId 18586 }); 18587 let hasError = false; 18588 try { 18589 let path = `${entityConfig.baseURL}/${recordId}`; 18590 if (query) { 18591 path = (0,external_wp_url_namespaceObject.addQueryArgs)(path, query); 18592 } 18593 deletedRecord = await __unstableFetch({ 18594 path, 18595 method: 'DELETE' 18596 }); 18597 await dispatch(removeItems(kind, name, recordId, true)); 18598 } catch (_error) { 18599 hasError = true; 18600 error = _error; 18601 } 18602 dispatch({ 18603 type: 'DELETE_ENTITY_RECORD_FINISH', 18604 kind, 18605 name, 18606 recordId, 18607 error 18608 }); 18609 if (hasError && throwOnError) { 18610 throw error; 18611 } 18612 return deletedRecord; 18613 } finally { 18614 dispatch.__unstableReleaseStoreLock(lock); 18615 } 18616}; 18617 18618/** 18619 * Returns an action object that triggers an 18620 * edit to an entity record. 18621 * 18622 * @param {string} kind Kind of the edited entity record. 18623 * @param {string} name Name of the edited entity record. 18624 * @param {number|string} recordId Record ID of the edited entity record. 18625 * @param {Object} edits The edits. 18626 * @param {Object} options Options for the edit. 18627 * @param {boolean} [options.undoIgnore] Whether to ignore the edit in undo history or not. 18628 * 18629 * @return {Object} Action object. 18630 */ 18631const editEntityRecord = (kind, name, recordId, edits, options = {}) => ({ 18632 select, 18633 dispatch 18634}) => { 18635 const entityConfig = select.getEntityConfig(kind, name); 18636 if (!entityConfig) { 18637 throw new Error(`The entity being edited (${kind}, ${name}) does not have a loaded config.`); 18638 } 18639 const { 18640 mergedEdits = {} 18641 } = entityConfig; 18642 const record = select.getRawEntityRecord(kind, name, recordId); 18643 const editedRecord = select.getEditedEntityRecord(kind, name, recordId); 18644 const edit = { 18645 kind, 18646 name, 18647 recordId, 18648 // Clear edits when they are equal to their persisted counterparts 18649 // so that the property is not considered dirty. 18650 edits: Object.keys(edits).reduce((acc, key) => { 18651 const recordValue = record[key]; 18652 const editedRecordValue = editedRecord[key]; 18653 const value = mergedEdits[key] ? { 18654 ...editedRecordValue, 18655 ...edits[key] 18656 } : edits[key]; 18657 acc[key] = es6_default()(recordValue, value) ? undefined : value; 18658 return acc; 18659 }, {}) 18660 }; 18661 if (window.__experimentalEnableSync && entityConfig.syncConfig) { 18662 if (true) { 18663 const objectId = entityConfig.getSyncObjectId(recordId); 18664 getSyncProvider().update(entityConfig.syncObjectType + '--edit', objectId, edit.edits); 18665 } 18666 } else { 18667 if (!options.undoIgnore) { 18668 select.getUndoManager().addRecord([{ 18669 id: { 18670 kind, 18671 name, 18672 recordId 18673 }, 18674 changes: Object.keys(edits).reduce((acc, key) => { 18675 acc[key] = { 18676 from: editedRecord[key], 18677 to: edits[key] 18678 }; 18679 return acc; 18680 }, {}) 18681 }], options.isCached); 18682 } 18683 dispatch({ 18684 type: 'EDIT_ENTITY_RECORD', 18685 ...edit 18686 }); 18687 } 18688}; 18689 18690/** 18691 * Action triggered to undo the last edit to 18692 * an entity record, if any. 18693 */ 18694const undo = () => ({ 18695 select, 18696 dispatch 18697}) => { 18698 const undoRecord = select.getUndoManager().undo(); 18699 if (!undoRecord) { 18700 return; 18701 } 18702 dispatch({ 18703 type: 'UNDO', 18704 record: undoRecord 18705 }); 18706}; 18707 18708/** 18709 * Action triggered to redo the last undoed 18710 * edit to an entity record, if any. 18711 */ 18712const redo = () => ({ 18713 select, 18714 dispatch 18715}) => { 18716 const redoRecord = select.getUndoManager().redo(); 18717 if (!redoRecord) { 18718 return; 18719 } 18720 dispatch({ 18721 type: 'REDO', 18722 record: redoRecord 18723 }); 18724}; 18725 18726/** 18727 * Forces the creation of a new undo level. 18728 * 18729 * @return {Object} Action object. 18730 */ 18731const __unstableCreateUndoLevel = () => ({ 18732 select 18733}) => { 18734 select.getUndoManager().addRecord(); 18735}; 18736 18737/** 18738 * Action triggered to save an entity record. 18739 * 18740 * @param {string} kind Kind of the received entity. 18741 * @param {string} name Name of the received entity. 18742 * @param {Object} record Record to be saved. 18743 * @param {Object} options Saving options. 18744 * @param {boolean} [options.isAutosave=false] Whether this is an autosave. 18745 * @param {Function} [options.__unstableFetch] Internal use only. Function to 18746 * call instead of `apiFetch()`. 18747 * Must return a promise. 18748 * @param {boolean} [options.throwOnError=false] If false, this action suppresses all 18749 * the exceptions. Defaults to false. 18750 */ 18751const saveEntityRecord = (kind, name, record, { 18752 isAutosave = false, 18753 __unstableFetch = (external_wp_apiFetch_default()), 18754 throwOnError = false 18755} = {}) => async ({ 18756 select, 18757 resolveSelect, 18758 dispatch 18759}) => { 18760 const configs = await dispatch(getOrLoadEntitiesConfig(kind)); 18761 const entityConfig = configs.find(config => config.kind === kind && config.name === name); 18762 if (!entityConfig || entityConfig?.__experimentalNoFetch) { 18763 return; 18764 } 18765 const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY; 18766 const recordId = record[entityIdKey]; 18767 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, recordId || esm_browser_v4()], { 18768 exclusive: true 18769 }); 18770 try { 18771 // Evaluate optimized edits. 18772 // (Function edits that should be evaluated on save to avoid expensive computations on every edit.) 18773 for (const [key, value] of Object.entries(record)) { 18774 if (typeof value === 'function') { 18775 const evaluatedValue = value(select.getEditedEntityRecord(kind, name, recordId)); 18776 dispatch.editEntityRecord(kind, name, recordId, { 18777 [key]: evaluatedValue 18778 }, { 18779 undoIgnore: true 18780 });
18781 record[key] = evaluatedValue; 18782 } 18783 } 18784 dispatch({ 18785 type: 'SAVE_ENTITY_RECORD_START', 18786 kind, 18787 name, 18788 recordId, 18789 isAutosave 18790 }); 18791 let updatedRecord; 18792 let error; 18793 let hasError = false; 18794 try { 18795 const path = `${entityConfig.baseURL}${recordId ? '/' + recordId : ''}`; 18796 const persistedRecord = select.getRawEntityRecord(kind, name, recordId); 18797 if (isAutosave) { 18798 // Most of this autosave logic is very specific to posts. 18799 // This is fine for now as it is the only supported autosave, 18800 // but ideally this should all be handled in the back end, 18801 // so the client just sends and receives objects. 18802 const currentUser = select.getCurrentUser(); 18803 const currentUserId = currentUser ? currentUser.id : undefined; 18804 const autosavePost = await resolveSelect.getAutosave(persistedRecord.type, persistedRecord.id, currentUserId); 18805 // Autosaves need all expected fields to be present. 18806 // So we fallback to the previous autosave and then 18807 // to the actual persisted entity if the edits don't 18808 // have a value. 18809 let data = { 18810 ...persistedRecord, 18811 ...autosavePost, 18812 ...record 18813 }; 18814 data = Object.keys(data).reduce((acc, key) => { 18815 if (['title', 'excerpt', 'content', 'meta'].includes(key)) { 18816 acc[key] = data[key]; 18817 } 18818 return acc; 18819 }, { 18820 status: data.status === 'auto-draft' ? 'draft' : data.status 18821 }); 18822 updatedRecord = await __unstableFetch({ 18823 path: `${path}/autosaves`, 18824 method: 'POST', 18825 data 18826 }); 18827 18828 // An autosave may be processed by the server as a regular save 18829 // when its update is requested by the author and the post had 18830 // draft or auto-draft status. 18831 if (persistedRecord.id === updatedRecord.id) { 18832 let newRecord = { 18833 ...persistedRecord, 18834 ...data, 18835 ...updatedRecord 18836 }; 18837 newRecord = Object.keys(newRecord).reduce((acc, key) => { 18838 // These properties are persisted in autosaves. 18839 if (['title', 'excerpt', 'content'].includes(key)) { 18840 acc[key] = newRecord[key]; 18841 } else if (key === 'status') { 18842 // Status is only persisted in autosaves when going from 18843 // "auto-draft" to "draft". 18844 acc[key] = persistedRecord.status === 'auto-draft' && newRecord.status === 'draft' ? newRecord.status : persistedRecord.status; 18845 } else { 18846 // These properties are not persisted in autosaves. 18847 acc[key] = persistedRecord[key]; 18848 } 18849 return acc; 18850 }, {}); 18851 dispatch.receiveEntityRecords(kind, name, newRecord, undefined, true); 18852 } else { 18853 dispatch.receiveAutosaves(persistedRecord.id, updatedRecord); 18854 } 18855 } else { 18856 let edits = record; 18857 if (entityConfig.__unstablePrePersist) { 18858 edits = { 18859 ...edits, 18860 ...entityConfig.__unstablePrePersist(persistedRecord, edits) 18861 }; 18862 } 18863 updatedRecord = await __unstableFetch({ 18864 path, 18865 method: recordId ? 'PUT' : 'POST', 18866 data: edits 18867 }); 18868 dispatch.receiveEntityRecords(kind, name, updatedRecord, undefined, true, edits); 18869 } 18870 } catch (_error) { 18871 hasError = true; 18872 error = _error; 18873 } 18874 dispatch({ 18875 type: 'SAVE_ENTITY_RECORD_FINISH', 18876 kind, 18877 name, 18878 recordId, 18879 error, 18880 isAutosave 18881 }); 18882 if (hasError && throwOnError) { 18883 throw error; 18884 } 18885 return updatedRecord; 18886 } finally { 18887 dispatch.__unstableReleaseStoreLock(lock); 18888 } 18889}; 18890 18891/** 18892 * Runs multiple core-data actions at the same time using one API request. 18893 * 18894 * Example: 18895 * 18896 * ``` 18897 * const [ savedRecord, updatedRecord, deletedRecord ] = 18898 * await dispatch( 'core' ).__experimentalBatch( [ 18899 * ( { saveEntityRecord } ) => saveEntityRecord( 'root', 'widget', widget ), 18900 * ( { saveEditedEntityRecord } ) => saveEntityRecord( 'root', 'widget', 123 ), 18901 * ( { deleteEntityRecord } ) => deleteEntityRecord( 'root', 'widget', 123, null ), 18902 * ] ); 18903 * ``` 18904 * 18905 * @param {Array} requests Array of functions which are invoked simultaneously.
18906 * Each function is passed an object containing 18907 * `saveEntityRecord`, `saveEditedEntityRecord`, and 18908 * `deleteEntityRecord`. 18909 * 18910 * @return {(thunkArgs: Object) => Promise} A promise that resolves to an array containing the return 18911 * values of each function given in `requests`. 18912 */ 18913const __experimentalBatch = requests => async ({ 18914 dispatch 18915}) => { 18916 const batch = createBatch(); 18917 const api = { 18918 saveEntityRecord(kind, name, record, options) { 18919 return batch.add(add => dispatch.saveEntityRecord(kind, name, record, { 18920 ...options, 18921 __unstableFetch: add 18922 })); 18923 }, 18924 saveEditedEntityRecord(kind, name, recordId, options) { 18925 return batch.add(add => dispatch.saveEditedEntityRecord(kind, name, recordId, { 18926 ...options, 18927 __unstableFetch: add 18928 })); 18929 }, 18930 deleteEntityRecord(kind, name, recordId, query, options) { 18931 return batch.add(add => dispatch.deleteEntityRecord(kind, name, recordId, query, { 18932 ...options, 18933 __unstableFetch: add 18934 })); 18935 } 18936 }; 18937 const resultPromises = requests.map(request => request(api)); 18938 const [, ...results] = await Promise.all([batch.run(), ...resultPromises]); 18939 return results; 18940}; 18941 18942/** 18943 * Action triggered to save an entity record's edits. 18944 * 18945 * @param {string} kind Kind of the entity. 18946 * @param {string} name Name of the entity. 18947 * @param {Object} recordId ID of the record. 18948 * @param {Object} options Saving options. 18949 */ 18950const saveEditedEntityRecord = (kind, name, recordId, options) => async ({ 18951 select, 18952 dispatch 18953}) => { 18954 if (!select.hasEditsForEntityRecord(kind, name, recordId)) { 18955 return; 18956 } 18957 const configs = await dispatch(getOrLoadEntitiesConfig(kind)); 18958 const entityConfig = configs.find(config => config.kind === kind && config.name === name); 18959 if (!entityConfig) { 18960 return; 18961 } 18962 const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY; 18963 const edits = select.getEntityRecordNonTransientEdits(kind, name, recordId); 18964 const record = { 18965 [entityIdKey]: recordId, 18966 ...edits 18967 }; 18968 return await dispatch.saveEntityRecord(kind, name, record, options); 18969}; 18970 18971/** 18972 * Action triggered to save only specified properties for the entity. 18973 * 18974 * @param {string} kind Kind of the entity. 18975 * @param {string} name Name of the entity. 18976 * @param {Object} recordId ID of the record. 18977 * @param {Array} itemsToSave List of entity properties or property paths to save. 18978 * @param {Object} options Saving options. 18979 */ 18980const __experimentalSaveSpecifiedEntityEdits = (kind, name, recordId, itemsToSave, options) => async ({ 18981 select, 18982 dispatch 18983}) => { 18984 if (!select.hasEditsForEntityRecord(kind, name, recordId)) { 18985 return; 18986 } 18987 const edits = select.getEntityRecordNonTransientEdits(kind, name, recordId); 18988 const editsToSave = {}; 18989 for (const item of itemsToSave) { 18990 setNestedValue(editsToSave, item, getNestedValue(edits, item)); 18991 } 18992 const configs = await dispatch(getOrLoadEntitiesConfig(kind)); 18993 const entityConfig = configs.find(config => config.kind === kind && config.name === name); 18994 const entityIdKey = entityConfig?.key || DEFAULT_ENTITY_KEY; 18995 18996 // If a record key is provided then update the existing record. 18997 // This necessitates providing `recordKey` to saveEntityRecord as part of the 18998 // `record` argument (here called `editsToSave`) to stop that action creating 18999 // a new record and instead cause it to update the existing record. 19000 if (recordId) { 19001 editsToSave[entityIdKey] = recordId; 19002 } 19003 return await dispatch.saveEntityRecord(kind, name, editsToSave, options); 19004}; 19005 19006/** 19007 * Returns an action object used in signalling that Upload permissions have been received. 19008 * 19009 * @deprecated since WP 5.9, use receiveUserPermission instead. 19010 * 19011 * @param {boolean} hasUploadPermissions Does the user have permission to upload files? 19012 * 19013 * @return {Object} Action object. 19014 */ 19015function receiveUploadPermissions(hasUploadPermissions) { 19016 external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveUploadPermissions", { 19017 since: '5.9', 19018 alternative: 'receiveUserPermission' 19019 }); 19020 return receiveUserPermission('create/media', hasUploadPermissions); 19021} 19022 19023/** 19024 * Returns an action object used in signalling that the current user has 19025 * permission to perform an action on a REST resource. 19026 * Ignored from documentation as it's internal to the data store. 19027 * 19028 * @ignore 19029 * 19030 * @param {string} key A key that represents the action and REST resource. 19031 * @param {boolean} isAllowed Whether or not the user can perform the action. 19032 * 19033 * @return {Object} Action object. 19034 */ 19035function receiveUserPermission(key, isAllowed) { 19036 return { 19037 type: 'RECEIVE_USER_PERMISSION', 19038 key, 19039 isAllowed 19040 }; 19041} 19042 19043/** 19044 * Returns an action object used in signalling that the autosaves for a 19045 * post have been received. 19046 * Ignored from documentation as it's internal to the data store. 19047 * 19048 * @ignore 19049 * 19050 * @param {number} postId The id of the post that is parent to the autosave. 19051 * @param {Array|Object} autosaves An array of autosaves or singular autosave object. 19052 * 19053 * @return {Object} Action object. 19054 */ 19055function receiveAutosaves(postId, autosaves) { 19056 return { 19057 type: 'RECEIVE_AUTOSAVES', 19058 postId, 19059 autosaves: Array.isArray(autosaves) ? autosaves : [autosaves] 19060 }; 19061} 19062 19063/** 19064 * Returns an action object signalling that the fallback Navigation 19065 * Menu id has been received. 19066 * 19067 * @param {integer} fallbackId the id of the fallback Navigation Menu 19068 * @return {Object} Action object. 19069 */ 19070function receiveNavigationFallbackId(fallbackId) { 19071 return { 19072 type: 'RECEIVE_NAVIGATION_FALLBACK_ID', 19073 fallbackId 19074 }; 19075} 19076 19077;// CONCATENATED MODULE: ./packages/core-data/build-module/entities.js 19078/** 19079 * External dependencies 19080 */ 19081 19082 19083/** 19084 * WordPress dependencies 19085 */ 19086 19087 19088 19089/** 19090 * Internal dependencies 19091 */ 19092 19093 19094const DEFAULT_ENTITY_KEY = 'id';
19095const POST_RAW_ATTRIBUTES = ['title', 'excerpt', 'content']; 19096const rootEntitiesConfig = [{ 19097 label: (0,external_wp_i18n_namespaceObject.__)('Base'), 19098 kind: 'root', 19099 name: '__unstableBase', 19100 baseURL: '/', 19101 baseURLParams: { 19102 _fields: ['description', 'gmt_offset', 'home', 'name', 'site_icon', 'site_icon_url', 'site_logo', 'timezone_string', 'url'].join(',') 19103 }, 19104 syncConfig: { 19105 fetch: async () => { 19106 return external_wp_apiFetch_default()({ 19107 path: '/' 19108 }); 19109 }, 19110 applyChangesToDoc: (doc, changes) => { 19111 const document = doc.getMap('document'); 19112 Object.entries(changes).forEach(([key, value]) => { 19113 if (document.get(key) !== value) { 19114 document.set(key, value); 19115 } 19116 }); 19117 }, 19118 fromCRDTDoc: doc => { 19119 return doc.getMap('document').toJSON(); 19120 } 19121 }, 19122 syncObjectType: 'root/base', 19123 getSyncObjectId: () => 'index' 19124}, { 19125 label: (0,external_wp_i18n_namespaceObject.__)('Site'), 19126 name: 'site', 19127 kind: 'root', 19128 baseURL: '/wp/v2/settings', 19129 getTitle: record => { 19130 var _record$title; 19131 return (_record$title = record?.title) !== null && _record$title !== void 0 ? _record$title : (0,external_wp_i18n_namespaceObject.__)('Site Title'); 19132 }, 19133 syncConfig: { 19134 fetch: async () => { 19135 return external_wp_apiFetch_default()({ 19136 path: '/wp/v2/settings' 19137 }); 19138 }, 19139 applyChangesToDoc: (doc, changes) => { 19140 const document = doc.getMap('document'); 19141 Object.entries(changes).forEach(([key, value]) => { 19142 if (document.get(key) !== value) { 19143 document.set(key, value); 19144 } 19145 }); 19146 }, 19147 fromCRDTDoc: doc => { 19148 return doc.getMap('document').toJSON(); 19149 } 19150 }, 19151 syncObjectType: 'root/site', 19152 getSyncObjectId: () => 'index' 19153}, { 19154 label: (0,external_wp_i18n_namespaceObject.__)('Post Type'), 19155 name: 'postType', 19156 kind: 'root', 19157 key: 'slug', 19158 baseURL: '/wp/v2/types', 19159 baseURLParams: { 19160 context: 'edit' 19161 }, 19162 syncConfig: { 19163 fetch: async id => { 19164 return external_wp_apiFetch_default()({ 19165 path: `/wp/v2/types/${id}?context=edit` 19166 }); 19167 }, 19168 applyChangesToDoc: (doc, changes) => { 19169 const document = doc.getMap('document'); 19170 Object.entries(changes).forEach(([key, value]) => { 19171 if (document.get(key) !== value) { 19172 document.set(key, value); 19173 } 19174 }); 19175 }, 19176 fromCRDTDoc: doc => { 19177 return doc.getMap('document').toJSON(); 19178 } 19179 }, 19180 syncObjectType: 'root/postType',
19181 getSyncObjectId: id => id 19182}, { 19183 name: 'media', 19184 kind: 'root', 19185 baseURL: '/wp/v2/media', 19186 baseURLParams: { 19187 context: 'edit' 19188 }, 19189 plural: 'mediaItems', 19190 label: (0,external_wp_i18n_namespaceObject.__)('Media'), 19191 rawAttributes: ['caption', 'title', 'description'] 19192}, { 19193 name: 'taxonomy', 19194 kind: 'root', 19195 key: 'slug', 19196 baseURL: '/wp/v2/taxonomies', 19197 baseURLParams: { 19198 context: 'edit' 19199 }, 19200 plural: 'taxonomies', 19201 label: (0,external_wp_i18n_namespaceObject.__)('Taxonomy') 19202}, { 19203 name: 'sidebar', 19204 kind: 'root', 19205 baseURL: '/wp/v2/sidebars', 19206 baseURLParams: { 19207 context: 'edit' 19208 }, 19209 plural: 'sidebars', 19210 transientEdits: { 19211 blocks: true 19212 }, 19213 label: (0,external_wp_i18n_namespaceObject.__)('Widget areas') 19214}, { 19215 name: 'widget', 19216 kind: 'root', 19217 baseURL: '/wp/v2/widgets', 19218 baseURLParams: { 19219 context: 'edit' 19220 }, 19221 plural: 'widgets', 19222 transientEdits: { 19223 blocks: true 19224 }, 19225 label: (0,external_wp_i18n_namespaceObject.__)('Widgets') 19226}, { 19227 name: 'widgetType', 19228 kind: 'root', 19229 baseURL: '/wp/v2/widget-types', 19230 baseURLParams: { 19231 context: 'edit' 19232 }, 19233 plural: 'widgetTypes', 19234 label: (0,external_wp_i18n_namespaceObject.__)('Widget types') 19235}, { 19236 label: (0,external_wp_i18n_namespaceObject.__)('User'), 19237 name: 'user', 19238 kind: 'root', 19239 baseURL: '/wp/v2/users', 19240 baseURLParams: { 19241 context: 'edit' 19242 }, 19243 plural: 'users' 19244}, { 19245 name: 'comment', 19246 kind: 'root', 19247 baseURL: '/wp/v2/comments', 19248 baseURLParams: { 19249 context: 'edit' 19250 }, 19251 plural: 'comments', 19252 label: (0,external_wp_i18n_namespaceObject.__)('Comment') 19253}, { 19254 name: 'menu', 19255 kind: 'root', 19256 baseURL: '/wp/v2/menus', 19257 baseURLParams: { 19258 context: 'edit' 19259 }, 19260 plural: 'menus', 19261 label: (0,external_wp_i18n_namespaceObject.__)('Menu') 19262}, { 19263 name: 'menuItem', 19264 kind: 'root', 19265 baseURL: '/wp/v2/menu-items', 19266 baseURLParams: { 19267 context: 'edit' 19268 }, 19269 plural: 'menuItems', 19270 label: (0,external_wp_i18n_namespaceObject.__)('Menu Item'), 19271 rawAttributes: ['title'] 19272}, { 19273 name: 'menuLocation', 19274 kind: 'root', 19275 baseURL: '/wp/v2/menu-locations', 19276 baseURLParams: { 19277 context: 'edit' 19278 }, 19279 plural: 'menuLocations', 19280 label: (0,external_wp_i18n_namespaceObject.__)('Menu Location'), 19281 key: 'name' 19282}, { 19283 label: (0,external_wp_i18n_namespaceObject.__)('Global Styles'), 19284 name: 'globalStyles', 19285 kind: 'root', 19286 baseURL: '/wp/v2/global-styles', 19287 baseURLParams: { 19288 context: 'edit' 19289 }, 19290 plural: 'globalStylesVariations', 19291 // Should be different than name. 19292 getTitle: record => record?.title?.rendered || record?.title 19293}, { 19294 label: (0,external_wp_i18n_namespaceObject.__)('Themes'), 19295 name: 'theme', 19296 kind: 'root', 19297 baseURL: '/wp/v2/themes', 19298 baseURLParams: { 19299 context: 'edit' 19300 }, 19301 key: 'stylesheet' 19302}, { 19303 label: (0,external_wp_i18n_namespaceObject.__)('Plugins'), 19304 name: 'plugin', 19305 kind: 'root', 19306 baseURL: '/wp/v2/plugins', 19307 baseURLParams: { 19308 context: 'edit' 19309 }, 19310 key: 'plugin' 19311}]; 19312const additionalEntityConfigLoaders = [{ 19313 kind: 'postType', 19314 loadEntities: loadPostTypeEntities 19315}, { 19316 kind: 'taxonomy', 19317 loadEntities: loadTaxonomyEntities 19318}]; 19319 19320/** 19321 * Returns a function to be used to retrieve extra edits to apply before persisting a post type. 19322 * 19323 * @param {Object} persistedRecord Already persisted Post 19324 * @param {Object} edits Edits. 19325 * @return {Object} Updated edits. 19326 */ 19327const prePersistPostType = (persistedRecord, edits) => { 19328 const newEdits = {}; 19329 if (persistedRecord?.status === 'auto-draft') { 19330 // Saving an auto-draft should create a draft by default. 19331 if (!edits.status && !newEdits.status) { 19332 newEdits.status = 'draft'; 19333 } 19334 19335 // Fix the auto-draft default title. 19336 if ((!edits.title || edits.title === 'Auto Draft') && !newEdits.title && (!persistedRecord?.title || persistedRecord?.title === 'Auto Draft')) { 19337 newEdits.title = ''; 19338 } 19339 } 19340 return newEdits; 19341}; 19342 19343/** 19344 * Returns the list of post type entities. 19345 * 19346 * @return {Promise} Entities promise 19347 */ 19348async function loadPostTypeEntities() { 19349 const postTypes = await external_wp_apiFetch_default()({ 19350 path: '/wp/v2/types?context=view' 19351 }); 19352 return Object.entries(postTypes !== null && postTypes !== void 0 ? postTypes : {}).map(([name, postType]) => { 19353 var _postType$rest_namesp; 19354 const isTemplate = ['wp_template', 'wp_template_part'].includes(name); 19355 const namespace = (_postType$rest_namesp = postType?.rest_namespace) !== null && _postType$rest_namesp !== void 0 ? _postType$rest_namesp : 'wp/v2'; 19356 return { 19357 kind: 'postType', 19358 baseURL: `/${namespace}/${postType.rest_base}`, 19359 baseURLParams: { 19360 context: 'edit' 19361 }, 19362 name, 19363 label: postType.name, 19364 transientEdits: { 19365 blocks: true, 19366 selection: true 19367 }, 19368 mergedEdits: { 19369 meta: true 19370 }, 19371 rawAttributes: POST_RAW_ATTRIBUTES, 19372 getTitle: record => { 19373 var _record$slug;
19374 return record?.title?.rendered || record?.title || (isTemplate ? capitalCase((_record$slug = record.slug) !== null && _record$slug !== void 0 ? _record$slug : '') : String(record.id)); 19375 }, 19376 __unstablePrePersist: isTemplate ? undefined : prePersistPostType, 19377 __unstable_rest_base: postType.rest_base, 19378 syncConfig: { 19379 fetch: async id => { 19380 return external_wp_apiFetch_default()({ 19381 path: `/${namespace}/${postType.rest_base}/${id}?context=edit` 19382 }); 19383 }, 19384 applyChangesToDoc: (doc, changes) => { 19385 const document = doc.getMap('document'); 19386 Object.entries(changes).forEach(([key, value]) => { 19387 if (document.get(key) !== value && typeof value !== 'function') { 19388 document.set(key, value); 19389 } 19390 }); 19391 }, 19392 fromCRDTDoc: doc => { 19393 return doc.getMap('document').toJSON(); 19394 } 19395 }, 19396 syncObjectType: 'postType/' + postType.name, 19397 getSyncObjectId: id => id 19398 }; 19399 }); 19400} 19401 19402/** 19403 * Returns the list of the taxonomies entities. 19404 * 19405 * @return {Promise} Entities promise 19406 */ 19407async function loadTaxonomyEntities() { 19408 const taxonomies = await external_wp_apiFetch_default()({ 19409 path: '/wp/v2/taxonomies?context=view' 19410 }); 19411 return Object.entries(taxonomies !== null && taxonomies !== void 0 ? taxonomies : {}).map(([name, taxonomy]) => { 19412 var _taxonomy$rest_namesp; 19413 const namespace = (_taxonomy$rest_namesp = taxonomy?.rest_namespace) !== null && _taxonomy$rest_namesp !== void 0 ? _taxonomy$rest_namesp : 'wp/v2'; 19414 return { 19415 kind: 'taxonomy', 19416 baseURL: `/${namespace}/${taxonomy.rest_base}`, 19417 baseURLParams: { 19418 context: 'edit' 19419 }, 19420 name, 19421 label: taxonomy.name 19422 }; 19423 }); 19424} 19425 19426/** 19427 * Returns the entity's getter method name given its kind and name. 19428 * 19429 * @example 19430 * ```js 19431 * const nameSingular = getMethodName( 'root', 'theme', 'get' ); 19432 * // nameSingular is getRootTheme 19433 * 19434 * const namePlural = getMethodName( 'root', 'theme', 'set' ); 19435 * // namePlural is setRootThemes 19436 * ``` 19437 * 19438 * @param {string} kind Entity kind. 19439 * @param {string} name Entity name. 19440 * @param {string} prefix Function prefix. 19441 * @param {boolean} usePlural Whether to use the plural form or not. 19442 * 19443 * @return {string} Method name 19444 */ 19445const getMethodName = (kind, name, prefix = 'get', usePlural = false) => { 19446 const entityConfig = rootEntitiesConfig.find(config => config.kind === kind && config.name === name); 19447 const kindPrefix = kind === 'root' ? '' : pascalCase(kind); 19448 const nameSuffix = pascalCase(name) + (usePlural ? 's' : ''); 19449 const suffix = usePlural && 'plural' in entityConfig && entityConfig?.plural ? pascalCase(entityConfig.plural) : nameSuffix; 19450 return `${prefix}${kindPrefix}${suffix}`; 19451}; 19452function registerSyncConfigs(configs) { 19453 configs.forEach(({ 19454 syncObjectType, 19455 syncConfig 19456 }) => { 19457 getSyncProvider().register(syncObjectType, syncConfig); 19458 const editSyncConfig = { 19459 ...syncConfig 19460 }; 19461 delete editSyncConfig.fetch; 19462 getSyncProvider().register(syncObjectType + '--edit', editSyncConfig); 19463 }); 19464} 19465 19466/** 19467 * Loads the kind entities into the store. 19468 * 19469 * @param {string} kind Kind 19470 * 19471 * @return {(thunkArgs: object) => Promise<Array>} Entities 19472 */ 19473const getOrLoadEntitiesConfig = kind => async ({ 19474 select, 19475 dispatch 19476}) => { 19477 let configs = select.getEntitiesConfig(kind); 19478 if (configs && configs.length !== 0) { 19479 if (window.__experimentalEnableSync) { 19480 if (true) { 19481 registerSyncConfigs(configs); 19482 } 19483 } 19484 return configs; 19485 } 19486 const loader = additionalEntityConfigLoaders.find(l => l.kind === kind); 19487 if (!loader) { 19488 return []; 19489 } 19490 configs = await loader.loadEntities(); 19491 if (window.__experimentalEnableSync) { 19492 if (true) { 19493 registerSyncConfigs(configs); 19494 } 19495 } 19496 dispatch(addEntities(configs)); 19497 return configs; 19498}; 19499 19500;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/get-normalized-comma-separable.js 19501/** 19502 * Given a value which can be specified as one or the other of a comma-separated 19503 * string or an array, returns a value normalized to an array of str
19503ings, or 19504 * null if the value cannot be interpreted as either. 19505 * 19506 * @param {string|string[]|*} value 19507 * 19508 * @return {?(string[])} Normalized field value. 19509 */ 19510function getNormalizedCommaSeparable(value) { 19511 if (typeof value === 'string') { 19512 return value.split(','); 19513 } else if (Array.isArray(value)) { 19514 return value; 19515 } 19516 return null; 19517} 19518/* harmony default export */ const get_normalized_comma_separable = (getNormalizedCommaSeparable); 19519 19520;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/with-weak-map-cache.js 19521/** 19522 * Given a function, returns an enhanced function which caches the result and 19523 * tracks in WeakMap. The result is only cached if the original function is 19524 * passed a valid object-like argument (requirement for WeakMap key). 19525 * 19526 * @param {Function} fn Original function. 19527 * 19528 * @return {Function} Enhanced caching function. 19529 */ 19530function withWeakMapCache(fn) { 19531 const cache = new WeakMap(); 19532 return key => { 19533 let value; 19534 if (cache.has(key)) { 19535 value = cache.get(key); 19536 } else { 19537 value = fn(key); 19538 19539 // Can reach here if key is not valid for WeakMap, since `has` 19540 // will return false for invalid key. Since `set` will throw, 19541 // ensure that key is valid before setting into cache. 19542 if (key !== null && typeof key === 'object') { 19543 cache.set(key, value); 19544 } 19545 } 19546 return value; 19547 }; 19548} 19549/* harmony default export */ const with_weak_map_cache = (withWeakMapCache); 19550 19551;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/get-query-parts.js 19552/** 19553 * WordPress dependencies 19554 */ 19555 19556 19557/** 19558 * Internal dependencies 19559 */ 19560 19561 19562/** 19563 * An object of properties describing a specific query. 19564 * 19565 * @typedef {Object} WPQueriedDataQueryParts 19566 * 19567 * @property {number} page The query page (1-based index, default 1). 19568 * @property {number} perPage Items per page for query (default 10). 19569 * @property {string} stableKey An encoded stable string of all non- 19570 * pagination, non-fields query parameters. 19571 * @property {?(string[])} fields Target subset of fields to derive from 19572 * item objects. 19573 * @property {?(number[])} include Specific item IDs to include. 19574 * @property {string} context Scope under which the request is made; 19575 * determines returned fields in response. 19576 */ 19577 19578/** 19579 * Given a query object, returns an object of parts, including pagination 19580 * details (`page` and `perPage`, or default values). All other properties are 19581 * encoded into a stable (idempotent) `stableKey` value. 19582 * 19583 * @param {Object} query Optional query object. 19584 * 19585 * @return {WPQueriedDataQueryParts} Query parts. 19586 */ 19587function getQueryParts(query) { 19588 /** 19589 * @type {WPQueriedDataQueryParts} 19590 */ 19591 const parts = { 19592 stableKey: '', 19593 page: 1, 19594 perPage: 10, 19595 fields: null, 19596 include: null, 19597 context: 'default' 19598 }; 19599 19600 // Ensure stable key by sorting keys. Also more efficient for iterating. 19601 const keys = Object.keys(query).sort(); 19602 for (let i = 0; i < keys.length; i++) { 19603 const key = keys[i]; 19604 let value = query[key]; 19605 switch (key) { 19606 case 'page': 19607 parts[key] = Number(value); 19608 break; 19609 case 'per_page': 19610 parts.perPage = Number(value); 19611 break; 19612 case 'context': 19613 parts.context = value; 19614 break; 19615 default: 19616 // While in theory, we could exclude "_fields" from the stableKey 19617 // because two request with different fields have the same results 19618 // We're not able to ensure that because the server can decide to omit 19619 // fields from the response even if we explicitly asked for it. 19620 // Example: Asking for titles in posts without title support. 19621 if (key === '_fields') { 19622 var _getNormalizedCommaSe; 19623 parts.fields = (_getNormalizedCommaSe = get_normalized_comma_separable(value)) !== null && _getNormalizedCommaSe !== void 0 ? _getNormalizedCommaSe : []; 19624 // Make sure to normalize value for `stableKey` 19625 value = parts.fields.join(); 19626 } 19627 19628 // Two requests with different include values cannot have same results. 19629 if (key === 'include') { 19630 var _getNormalizedCommaSe2; 19631 if (typeof value === 'number') { 19632 value = value.toString(); 19633 } 19634 parts.include = ((_getNormalizedCommaSe2 = get_normalized_comma_separable(value)) !== null && _getNormalizedCommaSe2 !== void 0 ? _getNormalizedCommaSe2 : []).map(Number); 19635 // Normalize value for `stableKey`. 19636 value = parts.include.join(); 19637 } 19638 19639 // While it could be any deterministic string, for simplicity's 19640 // sake mimic querystring encoding for stable key. 19641 // 19642 // TODO: For consistency with PHP implementation, addQueryArgs 19643 // should accept a key value pair, which may optimize its 19644 // implementation for our use here, vs. iterating an object 19645 // with only a single key. 19646 parts.stableKey += (parts.stableKey ? '&' : '') + (0,external_wp_url_namespaceObject.addQueryArgs)('', { 19647 [key]: value 19648 }).slice(1); 19649 } 19650 } 19651 return parts; 19652} 19653/* harmony default export */ const get_query_parts = (with_weak_map_cache(getQueryParts)); 19654 19655;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/reducer.js 19656/** 19657 * WordPress dependencies 19658 */ 19659 19660 19661 19662/** 19663 * Internal dependencies 19664 */ 19665 19666 19667 19668function getContextFromAction(action) { 19669 const { 19670 query 19671 } = action; 19672 if (!query) { 19673 return 'default'; 19674 } 19675 const queryParts = get_query_parts(query); 19676 return queryParts.context; 19677} 19678 19679/** 19680 * Returns a merged array of item IDs, given details of the received paginated 19681 * items. The array is sparse-like with `undefined` entries where holes exist. 19682 * 19683 * @param {?Array<number>} itemIds Original item IDs (default empty array). 19684 * @param {number[]} nextItemIds Item IDs to merge. 19685 * @param {number} page Page of items merged. 19686 * @param {number} perPage Number of items per page. 19687 * 19688 * @return {number[]} Merged array of item IDs. 19689 */ 19690function getMergedItemIds(itemIds, nextItemIds, page, perPage) { 19691 var _itemIds$length; 19692 const receivedAllIds = page === 1 && perPage === -1; 19693 if (receivedAllIds) { 19694 return nextItemIds; 19695 } 19696 const nextItemIdsStartIndex = (page - 1) * perPage; 19697 19698 // If later page has already been received, default to the larger known 19699 // size of the existing array, else calculate as extending the existing. 19700 const size = Math.max((_itemIds$length = itemIds?.length) !== null && _itemIds$length !== void 0 ? _itemIds$length : 0, nextItemIdsStartIndex + nextItemIds.length); 19701 19702 // Preallocate array since size is known. 19703 const mergedItemIds = new Array(size); 19704 for (let i = 0; i < size; i++) { 19705 // Preserve existing item ID except for subset of range of next items. 19706 const isInNextItemsRange = i >= nextItemIdsStartIndex && i < nextItemIdsStartIndex + nextItemIds.length; 19707 mergedItemIds[i] = isInNextItemsRange ? nextItemIds[i - nextItemIdsStartIndex] : itemIds?.[i]; 19708 } 19709 return mergedItemIds; 19710} 19711 19712/** 19713 * Helper function to filter out entities with certain IDs. 19714 * Entities are keyed by their ID. 19715 * 19716 * @param {Object} entities Entity objects, keyed by entity ID. 19717 * @param {Array} ids Entity IDs to filter out. 19718 * 19719 * @return {Object} Filtered entities. 19720 */ 19721function removeEntitiesById(entities, ids) { 19722 return Object.fromEntries(Object.entries(entities).filter(([id]) => !ids.some(itemId => { 19723 if (Number.isInteger(itemId)) { 19724 return itemId === +id; 19725 } 19726 return itemId === id; 19727 }))); 19728} 19729 19730/** 19731 * Reducer tracking items state, keyed by ID. Items are assumed to be normal, 19732 * where identifiers are common across all queries. 19733 * 19734 * @param {Object} state Current state. 19735 * @param {Object}
19735 action Dispatched action. 19736 * 19737 * @return {Object} Next state. 19738 */ 19739function items(state = {}, action) { 19740 switch (action.type) { 19741 case 'RECEIVE_ITEMS': 19742 { 19743 const context = getContextFromAction(action); 19744 const key = action.key || DEFAULT_ENTITY_KEY; 19745 return { 19746 ...state, 19747 [context]: { 19748 ...state[context], 19749 ...action.items.reduce((accumulator, value) => { 19750 const itemId = value[key]; 19751 accumulator[itemId] = conservativeMapItem(state?.[context]?.[itemId], value); 19752 return accumulator; 19753 }, {}) 19754 } 19755 }; 19756 } 19757 case 'REMOVE_ITEMS': 19758 return Object.fromEntries(Object.entries(state).map(([itemId, contextState]) => [itemId, removeEntitiesById(contextState, action.itemIds)])); 19759 } 19760 return state; 19761} 19762 19763/** 19764 * Reducer tracking item completeness, keyed by ID. A complete item is one for 19765 * which all fields are known. This is used in supporting `_fields` queries, 19766 * where not all properties associated with an entity are necessarily returned. 19767 * In such cases, completeness is used as an indication of whether it would be 19768 * safe to use queried data for a non-`_fields`-limited request. 19769 * 19770 * @param {Object<string,Object<string,boolean>>} state Current state. 19771 * @param {Object} action Dispatched action. 19772 * 19773 * @return {Object<string,Object<string,boolean>>} Next state. 19774 */ 19775function itemIsComplete(state = {}, action) { 19776 switch (action.type) { 19777 case 'RECEIVE_ITEMS': 19778 { 19779 const context = getContextFromAction(action); 19780 const { 19781 query, 19782 key = DEFAULT_ENTITY_KEY 19783 } = action; 19784 19785 // An item is considered complete if it is received without an associated 19786 // fields query. Ideally, this would be implemented in such a way where the 19787 // complete aggregate of all fields would satisfy completeness. Since the 19788 // fields are not consistent across all entities, this would require 19789 // introspection on the REST schema for each entity to know which fields 19790 // compose a complete item for that entity. 19791 const queryParts = query ? get_query_parts(query) : {}; 19792 const isCompleteQuery = !query || !Array.isArray(queryParts.fields); 19793 return { 19794 ...state, 19795 [context]: { 19796 ...state[context], 19797 ...action.items.reduce((result, item) => { 19798 const itemId = item[key]; 19799 19800 // Defer to completeness if already assigned. Technically the 19801 // data may be outdated if receiving items for a field subset. 19802 result[itemId] = state?.[context]?.[itemId] || isCompleteQuery; 19803 return result; 19804 }, {}) 19805 } 19806 }; 19807 } 19808 case 'REMOVE_ITEMS': 19809 return Object.fromEntries(Object.entries(state).map(([itemId, contextState]) => [itemId, removeEntitiesById(contextState, action.itemIds)])); 19810 } 19811 return state; 19812} 19813 19814/** 19815 * Reducer tracking queries state, keyed by stable query key. Each reducer 19816 * query object includes `itemIds` and `requestingPageByPerPage`. 19817 * 19818 * @param {Object} state Current state. 19819 * @param {Object} action Dispatched action. 19820 * 19821 * @return {Object} Next state. 19822 */ 19823const receiveQueries = (0,external_wp_compose_namespaceObject.compose)([ 19824// Limit to matching action type so we don't attempt to replace action on 19825// an unhandled action. 19826if_matching_action(action => 'query' in action), 19827// Inject query parts into action for use both in `onSubKey` and reducer. 19828replace_action(action => { 19829 // `ifMatchingAction` still passes on initialization, where state is 19830 // undefined and a query is not assigned. Avoid attempting to parse 19831 // parts. `onSubKey` will omit by lack of `stableKey`. 19832 if (action.query) { 19833 return { 19834 ...action, 19835 ...get_query_parts(action.query) 19836 }; 19837 } 19838 return action; 19839}), on_sub_key('context'), 19840// Queries shape is shared, but keyed by query `stableKey` part. Original 19841// reducer tracks only a single query object. 19842on_sub_key('stableKey')])((state = null, action) => { 19843 const { 19844 type, 19845 page, 19846 perPage, 19847 key = DEFAULT_ENTITY_KEY 19848 } = action; 19849 if (type !== 'RECEIVE_ITEMS') { 19850 return state; 19851 } 19852 return getMergedItemIds(state || [], action.items.map(item => item[key]), page, perPage); 19853}); 19854 19855/** 19856 * Reducer tracking queries state. 19857 * 19858 * @param {Object} state Current state. 19859 * @param {Object}
19859 action Dispatched action. 19860 * 19861 * @return {Object} Next state. 19862 */ 19863const queries = (state = {}, action) => { 19864 switch (action.type) { 19865 case 'RECEIVE_ITEMS': 19866 return receiveQueries(state, action); 19867 case 'REMOVE_ITEMS': 19868 const removedItems = action.itemIds.reduce((result, itemId) => { 19869 result[itemId] = true; 19870 return result; 19871 }, {}); 19872 return Object.fromEntries(Object.entries(state).map(([queryGroup, contextQueries]) => [queryGroup, Object.fromEntries(Object.entries(contextQueries).map(([query, queryItems]) => [query, queryItems.filter(queryId => !removedItems[queryId])]))])); 19873 default: 19874 return state; 19875 } 19876}; 19877/* harmony default export */ const reducer = ((0,external_wp_data_namespaceObject.combineReducers)({ 19878 items, 19879 itemIsComplete, 19880 queries 19881})); 19882 19883;// CONCATENATED MODULE: ./packages/core-data/build-module/reducer.js 19884/** 19885 * External dependencies 19886 */ 19887 19888 19889/** 19890 * WordPress dependencies 19891 */ 19892 19893 19894 19895 19896/** 19897 * Internal dependencies 19898 */ 19899 19900 19901 19902 19903/** @typedef {import('./types').AnyFunction} AnyFunction */ 19904 19905/** 19906 * Reducer managing terms state. Keyed by taxonomy slug, the value is either 19907 * undefined (if no request has been made for given taxonomy), null (if a 19908 * request is in-flight for given taxonomy), or the array of terms for the 19909 * taxonomy. 19910 * 19911 * @param {Object} state Current state. 19912 * @param {Object} action Dispatched action. 19913 * 19914 * @return {Object} Updated state. 19915 */ 19916function terms(state = {}, action) { 19917 switch (action.type) { 19918 case 'RECEIVE_TERMS': 19919 return { 19920 ...state, 19921 [action.taxonomy]: action.terms 19922 }; 19923 } 19924 return state; 19925} 19926 19927/** 19928 * Reducer managing authors state. Keyed by id. 19929 * 19930 * @param {Object} state Current state. 19931 * @param {Object} action Dispatched action. 19932 * 19933 * @return {Object} Updated state. 19934 */ 19935function users(state = { 19936 byId: {}, 19937 queries: {} 19938}, action) { 19939 switch (action.type) { 19940 case 'RECEIVE_USER_QUERY': 19941 return { 19942 byId: { 19943 ...state.byId, 19944 // Key users by their ID. 19945 ...action.users.reduce((newUsers, user) => ({ 19946 ...newUsers, 19947 [user.id]: user 19948 }), {}) 19949 }, 19950 queries: { 19951 ...state.queries, 19952 [action.queryID]: action.users.map(user => user.id) 19953 } 19954 }; 19955 } 19956 return state; 19957} 19958 19959/** 19960 * Reducer managing current user state. 19961 * 19962 * @param {Object} state Current state. 19963 * @param {Object} action Dispatched action. 19964 * 19965 * @return {Object} Updated state. 19966 */ 19967function currentUser(state = {}, action) { 19968 switch (action.type) { 19969 case 'RECEIVE_CURRENT_USER': 19970 return action.currentUser; 19971 } 19972 return state; 19973} 19974 19975/** 19976 * Reducer managing taxonomies. 19977 * 19978 * @param {Object} state Current state. 19979 * @param {Object} action Dispatched action. 19980 * 19981 * @return {Object} Updated state. 19982 */ 19983function taxonomies(state = [], action) { 19984 switch (action.type) { 19985 case 'RECEIVE_TAXONOMIES': 19986 return action.taxonomies; 19987 } 19988 return state; 19989} 19990 19991/** 19992 * Reducer managing the current theme. 19993 * 19994 * @param {string|undefined} state Current state. 19995 * @param {Object} action Dispatched action. 19996 * 19997 * @return {string|undefined} Updated state. 19998 */ 19999function currentTheme(state = undefined, action) { 20000 switch (action.type) { 20001 case 'RECEIVE_CURRENT_THEME': 20002 return action.currentTheme.stylesheet; 20003 } 20004 return state; 20005} 20006 20007/** 20008 * Reducer managing the current global styles id. 20009 * 20010 * @param {string|undefined} state Current state. 20011 * @param {Object} action Dispatched action. 20012 * 20013 * @return {string|undefined} Updated state. 20014 */ 20015function currentGlobalStylesId(state = undefined, action) { 20016 switch (action.type) { 20017 case 'RECEIVE_CURRENT_GLOBAL_STYLES_ID': 20018 return action.id; 20019 } 20020 return state; 20021} 20022 20023/** 20024 * Reducer managing the theme base global styles. 20025 * 20026 * @param {Record<string, object>} state Current state. 20027 * @param {Object} action Dispatched action. 20028 * 20029 * @return {Record<string, object>} Updated state. 20030 */ 20031function themeBaseGlobalStyles(state = {}, action) { 20032 switch (action.type) { 20033 case 'RECEIVE_THEME_GLOBAL_STYLES': 20034 return { 20035 ...state, 20036 [action.stylesheet]: action.globalStyles 20037 }; 20038 } 20039 return state; 20040} 20041 20042/** 20043 * Reducer managing the theme global styles variations. 20044 * 20045 * @param {Record<string, object>} state Current state. 20046 * @param {Object}
20046 action Dispatched action. 20047 * 20048 * @return {Record<string, object>} Updated state. 20049 */ 20050function themeGlobalStyleVariations(state = {}, action) { 20051 switch (action.type) { 20052 case 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS': 20053 return { 20054 ...state, 20055 [action.stylesheet]: action.variations 20056 }; 20057 } 20058 return state; 20059} 20060const withMultiEntityRecordEdits = reducer => (state, action) => { 20061 if (action.type === 'UNDO' || action.type === 'REDO') { 20062 const { 20063 record 20064 } = action; 20065 let newState = state; 20066 record.forEach(({ 20067 id: { 20068 kind, 20069 name, 20070 recordId 20071 }, 20072 changes 20073 }) => { 20074 newState = reducer(newState, { 20075 type: 'EDIT_ENTITY_RECORD', 20076 kind, 20077 name, 20078 recordId, 20079 edits: Object.entries(changes).reduce((acc, [key, value]) => { 20080 acc[key] = action.type === 'UNDO' ? value.from : value.to; 20081 return acc; 20082 }, {}) 20083 }); 20084 }); 20085 return newState; 20086 } 20087 return reducer(state, action); 20088}; 20089 20090/** 20091 * Higher Order Reducer for a given entity config. It supports: 20092 * 20093 * - Fetching 20094 * - Editing 20095 * - Saving 20096 * 20097 * @param {Object} entityConfig Entity config. 20098 * 20099 * @return {AnyFunction} Reducer. 20100 */ 20101function entity(entityConfig) { 20102 return (0,external_wp_compose_namespaceObject.compose)([withMultiEntityRecordEdits, 20103 // Limit to matching action type so we don't attempt to replace action on 20104 // an unhandled action. 20105 if_matching_action(action => action.name && action.kind && action.name === entityConfig.name && action.kind === entityConfig.kind), 20106 // Inject the entity config into the action. 20107 replace_action(action => { 20108 return { 20109 ...action, 20110 key: entityConfig.key || DEFAULT_ENTITY_KEY 20111 }; 20112 })])((0,external_wp_data_namespaceObject.combineReducers)({ 20113 queriedData: reducer, 20114 edits: (state = {}, action) => { 20115 var _action$query$context; 20116 switch (action.type) { 20117 case 'RECEIVE_ITEMS': 20118 const context = (_action$query$context = action?.query?.context) !== null && _action$query$context !== void 0 ? _action$query$context : 'default'; 20119 if (context !== 'default') { 20120 return state; 20121 } 20122 const nextState = { 20123 ...state 20124 }; 20125 for (const record of action.items) { 20126 const recordId = record[action.key]; 20127 const edits = nextState[recordId]; 20128 if (!edits) { 20129 continue; 20130 } 20131 const nextEdits = Object.keys(edits).reduce((acc, key) => { 20132 var _record$key$raw; 20133 // If the edited value is still different to the persisted value, 20134 // keep the edited value in edits. 20135 if ( 20136 // Edits are the "raw" attribute values, but records may have 20137 // objects with more properties, so we use `get` here for the 20138 // comparison. 20139 !es6_default()(edits[key], (_record$key$raw = record[key]?.raw) !== null && _record$key$raw !== void 0 ? _record$key$raw : record[key]) && ( 20140 // Sometimes the server alters the sent value which means 20141 // we need to also remove the edits before the api request. 20142 !action.persistedEdits || !es6_default()(edits[key], action.persistedEdits[key]))) { 20143 acc[key] = edits[key]; 20144 } 20145 return acc; 20146 }, {}); 20147 if (Object.keys(nextEdits).length) { 20148 nextState[recordId] = nextEdits; 20149 } else { 20150 delete nextState[recordId]; 20151 } 20152 } 20153 return nextState; 20154 case 'EDIT_ENTITY_RECORD': 20155 const nextEdits = { 20156 ...state[action.recordId], 20157 ...action.edits 20158 }; 20159 Object.keys(nextEdits).forEach(key => { 20160 // Delete cleared edits so that the properties 20161 // are not considered dirty. 20162 if (nextEdits[key] === undefined) { 20163 delete nextEdits[key]; 20164 } 20165 }); 20166 return { 20167 ...state, 20168 [action.recordId]: nextEdits 20169 }; 20170 } 20171 return state; 20172 }, 20173 saving: (state = {}, action) => { 20174 switch (action.type) { 20175 case 'SAVE_ENTITY_RECORD_START': 20176 case 'SAVE_ENTITY_RECORD_FINISH': 20177 return { 20178 ...state, 20179 [action.recordId]: { 20180 pending: action.type === 'SAVE_ENTITY_RECORD_START', 20181 error: action.error, 20182 isAutosave: action.isAutosave 20183 } 20184 }; 20185 } 20186 return state; 20187 }, 20188 deleting: (state = {}, action) => { 20189 switch (action.type) {
20190 case 'DELETE_ENTITY_RECORD_START': 20191 case 'DELETE_ENTITY_RECORD_FINISH': 20192 return { 20193 ...state, 20194 [action.recordId]: { 20195 pending: action.type === 'DELETE_ENTITY_RECORD_START', 20196 error: action.error 20197 } 20198 }; 20199 } 20200 return state; 20201 } 20202 })); 20203} 20204 20205/** 20206 * Reducer keeping track of the registered entities. 20207 * 20208 * @param {Object} state Current state. 20209 * @param {Object} action Dispatched action. 20210 * 20211 * @return {Object} Updated state. 20212 */ 20213function entitiesConfig(state = rootEntitiesConfig, action) { 20214 switch (action.type) { 20215 case 'ADD_ENTITIES': 20216 return [...state, ...action.entities]; 20217 } 20218 return state; 20219} 20220 20221/** 20222 * Reducer keeping track of the registered entities config and data. 20223 * 20224 * @param {Object} state Current state. 20225 * @param {Object} action Dispatched action. 20226 * 20227 * @return {Object} Updated state. 20228 */ 20229const entities = (state = {}, action) => { 20230 const newConfig = entitiesConfig(state.config, action); 20231 20232 // Generates a dynamic reducer for the entities. 20233 let entitiesDataReducer = state.reducer; 20234 if (!entitiesDataReducer || newConfig !== state.config) { 20235 const entitiesByKind = newConfig.reduce((acc, record) => { 20236 const { 20237 kind 20238 } = record; 20239 if (!acc[kind]) { 20240 acc[kind] = []; 20241 } 20242 acc[kind].push(record); 20243 return acc; 20244 }, {}); 20245 entitiesDataReducer = (0,external_wp_data_namespaceObject.combineReducers)(Object.entries(entitiesByKind).reduce((memo, [kind, subEntities]) => { 20246 const kindReducer = (0,external_wp_data_namespaceObject.combineReducers)(subEntities.reduce((kindMemo, entityConfig) => ({ 20247 ...kindMemo, 20248 [entityConfig.name]: entity(entityConfig) 20249 }), {})); 20250 memo[kind] = kindReducer; 20251 return memo; 20252 }, {})); 20253 } 20254 const newData = entitiesDataReducer(state.records, action); 20255 if (newData === state.records && newConfig === state.config && entitiesDataReducer === state.reducer) { 20256 return state; 20257 } 20258 return { 20259 reducer: entitiesDataReducer, 20260 records: newData, 20261 config: newConfig 20262 }; 20263}; 20264 20265/** 20266 * @type {UndoManager} 20267 */ 20268function undoManager(state = createUndoManager()) { 20269 return state; 20270} 20271function editsReference(state = {}, action) { 20272 switch (action.type) { 20273 case 'EDIT_ENTITY_RECORD': 20274 case 'UNDO': 20275 case 'REDO': 20276 return {}; 20277 } 20278 return state; 20279} 20280 20281/** 20282 * Reducer managing embed preview data. 20283 * 20284 * @param {Object} state Current state. 20285 * @param {Object} action Dispatched action. 20286 * 20287 * @return {Object} Updated state. 20288 */ 20289function embedPreviews(state = {}, action) { 20290 switch (action.type) { 20291 case 'RECEIVE_EMBED_PREVIEW': 20292 const { 20293 url, 20294 preview 20295 } = action; 20296 return { 20297 ...state, 20298 [url]: preview 20299 }; 20300 } 20301 return state; 20302} 20303 20304/** 20305 * State which tracks whether the user can perform an action on a REST 20306 * resource. 20307 * 20308 * @param {Object} state Current state. 20309 * @param {Object} action Dispatched action. 20310 * 20311 * @return {Object} Updated state. 20312 */ 20313function userPermissions(state = {}, action) { 20314 switch (action.type) { 20315 case 'RECEIVE_USER_PERMISSION': 20316 return { 20317 ...state, 20318 [action.key]: action.isAllowed 20319 }; 20320 } 20321 return state; 20322} 20323 20324/** 20325 * Reducer returning autosaves keyed by their parent's post id. 20326 * 20327 * @param {Object} state Current state. 20328 * @param {Object} action Dispatched action. 20329 * 20330 * @return {Object} Updated state. 20331 */ 20332function autosaves(state = {}, action) { 20333 switch (action.type) { 20334 case 'RECEIVE_AUTOSAVES': 20335 const { 20336 postId, 20337 autosaves: autosavesData 20338 } = action; 20339 return { 20340 ...state, 20341 [postId]: autosavesData 20342 }; 20343 } 20344 return state; 20345} 20346function blockPatterns(state = [], action) { 20347 switch (action.type) { 20348 case 'RECEIVE_BLOCK_PATTERNS': 20349 return action.patterns; 20350 } 20351 return state; 20352} 20353function blockPatternCategories(state = [], action) { 20354 switch (action.type) { 20355 case 'RECEIVE_BLOCK_PATTERN_CATEGORIES': 20356 return action.categories; 20357 } 20358 return state; 20359} 20360function userPatternCategories(state = [], action) { 20361 switch (action.type) { 20362 case 'RECEIVE_USER_PATTERN_CATEGORIES': 20363 return action.patternCategories; 20364 } 20365 return state; 20366} 20367function navigationFallbackId(state = null, action) { 20368 switch (action.type) { 20369 case 'RECEIVE_NAVIGATION_FALLBACK_ID': 20370 return action.fallbackId; 20371 } 20372 return state; 20373} 20374 20375/** 20376 * Reducer managing the theme global styles revisions. 20377 * 20378 * @param {Record<string, object>} state Current state. 20379 * @param {Object}
20379 action Dispatched action. 20380 * 20381 * @return {Record<string, object>} Updated state. 20382 */ 20383function themeGlobalStyleRevisions(state = {}, action) { 20384 switch (action.type) { 20385 case 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS': 20386 return { 20387 ...state, 20388 [action.currentId]: action.revisions 20389 }; 20390 } 20391 return state; 20392} 20393/* harmony default export */ const build_module_reducer = ((0,external_wp_data_namespaceObject.combineReducers)({ 20394 terms, 20395 users, 20396 currentTheme, 20397 currentGlobalStylesId, 20398 currentUser, 20399 themeGlobalStyleVariations, 20400 themeBaseGlobalStyles, 20401 themeGlobalStyleRevisions, 20402 taxonomies, 20403 entities, 20404 editsReference, 20405 undoManager, 20406 embedPreviews, 20407 userPermissions, 20408 autosaves, 20409 blockPatterns, 20410 blockPatternCategories, 20411 userPatternCategories, 20412 navigationFallbackId 20413})); 20414 20415;// CONCATENATED MODULE: ./node_modules/rememo/rememo.js 20416 20417 20418/** @typedef {(...args: any[]) => *[]} GetDependants */ 20419 20420/** @typedef {() => void} Clear */ 20421 20422/** 20423 * @typedef {{ 20424 * getDependants: GetDependants, 20425 * clear: Clear 20426 * }} EnhancedSelector 20427 */ 20428 20429/** 20430 * Internal cache entry. 20431 * 20432 * @typedef CacheNode 20433 * 20434 * @property {?CacheNode|undefined} [prev] Previous node. 20435 * @property {?CacheNode|undefined} [next] Next node. 20436 * @property {*[]} args Function arguments for cache entry. 20437 * @property {*} val Function result. 20438 */ 20439 20440/** 20441 * @typedef Cache 20442 * 20443 * @property {Clear} clear Function to clear cache. 20444 * @property {boolean} [isUniqueByDependants] Whether dependants are valid in 20445 * considering cache uniqueness. A cache is unique if dependents are all arrays 20446 * or objects. 20447 * @property {CacheNode?} [head] Cache head. 20448 * @property {*[]} [lastDependants] Dependants from previous invocation. 20449 */ 20450 20451/** 20452 * Arbitrary value used as key for referencing cache object in WeakMap tree. 20453 * 20454 * @type {{}} 20455 */ 20456var LEAF_KEY = {}; 20457 20458/** 20459 * Returns the first argument as the sole entry in an array. 20460 * 20461 * @template T 20462 * 20463 * @param {T} value Value to return. 20464 * 20465 * @return {[T]} Value returned as entry in array. 20466 */ 20467function arrayOf(value) { 20468 return [value]; 20469} 20470 20471/** 20472 * Returns true if the value passed is object-like, or false otherwise. A value 20473 * is object-like if it can support property assignment, e.g. object or array. 20474 * 20475 * @param {*} value Value to test. 20476 * 20477 * @return {boolean} Whether value is object-like. 20478 */ 20479function isObjectLike(value) { 20480 return !!value && 'object' === typeof value; 20481} 20482 20483/** 20484 * Creates and returns a new cache object. 20485 * 20486 * @return {Cache} Cache object. 20487 */ 20488function createCache() { 20489 /** @type {Cache} */ 20490 var cache = { 20491 clear: function () { 20492 cache.head = null; 20493 }, 20494 }; 20495 20496 return cache; 20497} 20498 20499/** 20500 * Returns true if entries within the two arrays are strictly equal by 20501 * reference from a starting index. 20502 * 20503 * @param {*[]} a First array. 20504 * @param {*[]} b Second array. 20505 * @param {number} fromIndex Index from which to start comparison. 20506 * 20507 * @return {boolean} Whether arrays are shallowly equal. 20508 */ 20509function isShallowEqual(a, b, fromIndex) { 20510 var i; 20511 20512 if (a.length !== b.length) { 20513 return false; 20514 } 20515 20516 for (i = fromIndex; i < a.length; i++) { 20517 if (a[i] !== b[i]) { 20518 return false; 20519 } 20520 } 20521 20522 return true; 20523} 20524 20525/** 20526 * Returns a memoized selector function. The getDependants function argument is 20527 * called before the memoized selector and is expected to return an immutable 20528 * reference or array of references on which the selector depends for computing 20529 * its own return value. The memoize cache is preserved only as long as those 20530 * dependant references remain the same. If getDependants returns a different 20531 * reference(s), the cache is cleared and the selector value regenerated. 20532 * 20533 * @template {(...args: *[]) => *} S 20534 * 20535 * @param {S} selector Selector function. 20536 * @param {GetDependants=} getDependants Dependant getter returning an array of 20537 * references used in cache bust consideration. 20538 */ 20539/* harmony default export */ function rememo(selector, getDependants) { 20540 /** @type {WeakMap<*,*>} */ 20541 var rootCache; 20542 20543 /** @type {GetDependants} */ 20544 var normalizedGetDependants = getDependants ? getDependants : arrayOf; 20545 20546 /** 20547 * Returns the cache for a given dependants array. When possible, a WeakMap 20548 * will be used to create a unique cache for each set of dependants. This 20549 * is feasible due to the nature of WeakMap in allowing garbage collection 20550 * to occur on entries where the key object is no longer referenced. Since 20551 * WeakMap requires the key to be an object, this is only possible when the 20552 * dependant is object-like. The root cache is created as a hierarchy where 20553 * each top-level key is the first entry in a dependants set, the value a 20554 * WeakMap where each key is the next dependant, and so on. This continues
20555 * so long as the dependants are object-like. If no dependants are object- 20556 * like, then the cache is shared across all invocations. 20557 * 20558 * @see isObjectLike 20559 * 20560 * @param {*[]} dependants Selector dependants. 20561 * 20562 * @return {Cache} Cache object. 20563 */ 20564 function getCache(dependants) { 20565 var caches = rootCache, 20566 isUniqueByDependants = true, 20567 i, 20568 dependant, 20569 map, 20570 cache; 20571 20572 for (i = 0; i < dependants.length; i++) { 20573 dependant = dependants[i]; 20574 20575 // Can only compose WeakMap from object-like key. 20576 if (!isObjectLike(dependant)) { 20577 isUniqueByDependants = false; 20578 break; 20579 } 20580 20581 // Does current segment of cache already have a WeakMap? 20582 if (caches.has(dependant)) { 20583 // Traverse into nested WeakMap. 20584 caches = caches.get(dependant); 20585 } else { 20586 // Create, set, and traverse into a new one. 20587 map = new WeakMap(); 20588 caches.set(dependant, map); 20589 caches = map; 20590 } 20591 } 20592 20593 // We use an arbitrary (but consistent) object as key for the last item 20594 // in the WeakMap to serve as our running cache. 20595 if (!caches.has(LEAF_KEY)) { 20596 cache = createCache(); 20597 cache.isUniqueByDependants = isUniqueByDependants; 20598 caches.set(LEAF_KEY, cache); 20599 } 20600 20601 return caches.get(LEAF_KEY); 20602 } 20603 20604 /** 20605 * Resets root memoization cache. 20606 */ 20607 function clear() { 20608 rootCache = new WeakMap(); 20609 } 20610 20611 /* eslint-disable jsdoc/check-param-names */ 20612 /** 20613 * The augmented selector call, considering first whether dependants have 20614 * changed before passing it to underlying memoize function. 20615 * 20616 * @param {*} source Source object for derivation. 20617 * @param {...*} extraArgs Additional arguments to pass to selector. 20618 * 20619 * @return {*} Selector result. 20620 */ 20621 /* eslint-enable jsdoc/check-param-names */ 20622 function callSelector(/* source, ...extraArgs */) { 20623 var len = arguments.length, 20624 cache, 20625 node, 20626 i, 20627 args, 20628 dependants; 20629 20630 // Create copy of arguments (avoid leaking deoptimization). 20631 args = new Array(len); 20632 for (i = 0; i < len; i++) { 20633 args[i] = arguments[i]; 20634 } 20635 20636 dependants = normalizedGetDependants.apply(null, args); 20637 cache = getCache(dependants); 20638 20639 // If not guaranteed uniqueness by dependants (primitive type), shallow 20640 // compare against last dependants and, if references have changed, 20641 // destroy cache to recalculate result. 20642 if (!cache.isUniqueByDependants) { 20643 if ( 20644 cache.lastDependants && 20645 !isShallowEqual(dependants, cache.lastDependants, 0) 20646 ) { 20647 cache.clear(); 20648 } 20649 20650 cache.lastDependants = dependants; 20651 } 20652 20653 node = cache.head; 20654 while (node) { 20655 // Check whether node arguments match arguments 20656 if (!isShallowEqual(node.args, args, 1)) { 20657 node = node.next; 20658 continue; 20659 } 20660 20661 // At this point we can assume we've found a match 20662 20663 // Surface matched node to head if not already 20664 if (node !== cache.head) { 20665 // Adjust siblings to point to each other. 20666 /** @type {CacheNode} */ (node.prev).next = node.next; 20667 if (node.next) { 20668 node.next.prev = node.prev; 20669 } 20670 20671 node.next = cache.head; 20672 node.prev = null; 20673 /** @type {CacheNode} */ (cache.head).prev = node; 20674 cache.head = node; 20675 } 20676 20677 // Return immediately 20678 return node.val; 20679 } 20680 20681 // No cached value found. Continue to insertion phase: 20682 20683 node = /** @type {CacheNode} */ ({ 20684 // Generate the result from original function 20685 val: selector.apply(null, args), 20686 }); 20687 20688 // Avoid including the source object in the cache. 20689 args[0] = null; 20690 node.args = args; 20691 20692 // Don't need to check whether node is already head, since it would 20693 // have been returned above already if it was 20694 20695 // Shift existing head down list 20696 if (cache.head) { 20697 cache.head.prev = node; 20698 node.next = cache.head; 20699 } 20700 20701 cache.head = node; 20702 20703 return node.val; 20704 } 20705 20706 callSelector.getDependants = normalizedGetDependants; 20707 callSelector.clear = clear; 20708 clear(); 20709 20710 return /** @type {S & EnhancedSelector} */ (callSelector); 20711} 20712 20713// EXTERNAL MODULE: ./node_modules/equivalent-key-map/equivalent-key-map.js 20714var equivalent_key_map = __webpack_require__(2167); 20715var equivalent_key_map_default = /*#__PURE__*/__webpack_require__.n(equivalent_key_map); 20716;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/selectors.js 20717/** 20718 * External dependencies 20719 */ 20720 20721 20722 20723/** 20724 * Internal dependencies 20725 */ 20726 20727 20728 20729/**
20730 * Cache of state keys to EquivalentKeyMap where the inner map tracks queries 20731 * to their resulting items set. WeakMap allows garbage collection on expired 20732 * state references. 20733 * 20734 * @type {WeakMap<Object,EquivalentKeyMap>} 20735 */ 20736const queriedItemsCacheByState = new WeakMap(); 20737 20738/** 20739 * Returns items for a given query, or null if the items are not known. 20740 * 20741 * @param {Object} state State object. 20742 * @param {?Object} query Optional query. 20743 * 20744 * @return {?Array} Query items. 20745 */ 20746function getQueriedItemsUncached(state, query) { 20747 const { 20748 stableKey, 20749 page, 20750 perPage, 20751 include, 20752 fields, 20753 context 20754 } = get_query_parts(query); 20755 let itemIds; 20756 if (state.queries?.[context]?.[stableKey]) { 20757 itemIds = state.queries[context][stableKey]; 20758 } 20759 if (!itemIds) { 20760 return null; 20761 } 20762 const startOffset = perPage === -1 ? 0 : (page - 1) * perPage; 20763 const endOffset = perPage === -1 ? itemIds.length : Math.min(startOffset + perPage, itemIds.length); 20764 const items = []; 20765 for (let i = startOffset; i < endOffset; i++) { 20766 const itemId = itemIds[i]; 20767 if (Array.isArray(include) && !include.includes(itemId)) { 20768 continue; 20769 } 20770 20771 // Having a target item ID doesn't guarantee that this object has been queried. 20772 if (!state.items[context]?.hasOwnProperty(itemId)) { 20773 return null; 20774 } 20775 const item = state.items[context][itemId]; 20776 let filteredItem; 20777 if (Array.isArray(fields)) { 20778 filteredItem = {}; 20779 for (let f = 0; f < fields.length; f++) { 20780 const field = fields[f].split('.'); 20781 let value = item; 20782 field.forEach(fieldName => { 20783 value = value?.[fieldName]; 20784 }); 20785 setNestedValue(filteredItem, field, value); 20786 } 20787 } else { 20788 // If expecting a complete item, validate that completeness, or 20789 // otherwise abort. 20790 if (!state.itemIsComplete[context]?.[itemId]) { 20791 return null; 20792 } 20793 filteredItem = item; 20794 } 20795 items.push(filteredItem); 20796 } 20797 return items; 20798} 20799 20800/** 20801 * Returns items for a given query, or null if the items are not known. Caches 20802 * result both per state (by reference) and per query (by deep equality). 20803 * The caching approach is intended to be durable to query objects which are 20804 * deeply but not referentially equal, since otherwise: 20805 * 20806 * `getQueriedItems( state, {} ) !== getQueriedItems( state, {} )` 20807 * 20808 * @param {Object} state State object. 20809 * @param {?Object} query Optional query. 20810 * 20811 * @return {?Array} Query items. 20812 */ 20813const getQueriedItems = rememo((state, query = {}) => { 20814 let queriedItemsCache = queriedItemsCacheByState.get(state); 20815 if (queriedItemsCache) { 20816 const queriedItems = queriedItemsCache.get(query); 20817 if (queriedItems !== undefined) { 20818 return queriedItems; 20819 } 20820 } else { 20821 queriedItemsCache = new (equivalent_key_map_default())(); 20822 queriedItemsCacheByState.set(state, queriedItemsCache); 20823 } 20824 const items = getQueriedItemsUncached(state, query); 20825 queriedItemsCache.set(query, items); 20826 return items; 20827}); 20828 20829;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/is-raw-attribute.js 20830/** 20831 * Checks whether the attribute is a "raw" attribute or not. 20832 * 20833 * @param {Object} entity Entity record. 20834 * @param {string} attribute Attribute name. 20835 * 20836 * @return {boolean} Is the attribute raw 20837 */ 20838function isRawAttribute(entity, attribute) { 20839 return (entity.rawAttributes || []).includes(attribute); 20840} 20841 20842;// CONCATENATED MODULE: ./packages/core-data/build-module/selectors.js 20843/** 20844 * External dependencies 20845 */ 20846 20847 20848/** 20849 * WordPress dependencies 20850 */ 20851 20852 20853 20854 20855/** 20856 * Internal dependencies 20857 */ 20858 20859 20860 20861 20862/** 20863 * Shared reference to an empty object for cases where it is important to avoid 20864 * returning a new object reference on every invocation, as in a connected or 20865 * other pure component which performs `shouldComponentUpdate` check on props. 20866 * This should be used as a last resort, since the normalized data should be 20867 * maintained by the reducer result in state. 20868 */ 20869const EMPTY_OBJECT = {}; 20870 20871/** 20872 * Returns true if a request is in progress for embed preview data, or false 20873 * otherwise. 20874 * 20875 * @param state Data state.
20876 * @param url URL the preview would be for. 20877 * 20878 * @return Whether a request is in progress for an embed preview. 20879 */ 20880const isRequestingEmbedPreview = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, url) => { 20881 return select(STORE_NAME).isResolving('getEmbedPreview', [url]); 20882}); 20883 20884/** 20885 * Returns all available authors. 20886 * 20887 * @deprecated since 11.3. Callers should use `select( 'core' ).getUsers({ who: 'authors' })` instead. 20888 * 20889 * @param state Data state. 20890 * @param query Optional object of query parameters to 20891 * include with request. For valid query parameters see the [Users page](https://developer.wordpress.org/rest-api/reference/users/) in the REST API Handbook and see the arguments for [List Users](https://developer.wordpress.org/rest-api/reference/users/#list-users) and [Retrieve a User](https://developer.wordpress.org/rest-api/reference/users/#retrieve-a-user). 20892 * @return Authors list. 20893 */ 20894function getAuthors(state, query) { 20895 external_wp_deprecated_default()("select( 'core' ).getAuthors()", { 20896 since: '5.9', 20897 alternative: "select( 'core' ).getUsers({ who: 'authors' })" 20898 }); 20899 const path = (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/users/?who=authors&per_page=100', query); 20900 return getUserQueryResults(state, path); 20901} 20902 20903/** 20904 * Returns the current user. 20905 * 20906 * @param state Data state. 20907 * 20908 * @return Current user object. 20909 */ 20910function getCurrentUser(state) { 20911 return state.currentUser; 20912} 20913 20914/** 20915 * Returns all the users returned by a query ID. 20916 * 20917 * @param state Data state. 20918 * @param queryID Query ID. 20919 * 20920 * @return Users list. 20921 */ 20922const getUserQueryResults = rememo((state, queryID) => { 20923 var _state$users$queries$; 20924 const queryResults = (_state$users$queries$ = state.users.queries[queryID]) !== null && _state$users$queries$ !== void 0 ? _state$users$queries$ : []; 20925 return queryResults.map(id => state.users.byId[id]); 20926}, (state, queryID) => [state.users.queries[queryID], state.users.byId]); 20927 20928/** 20929 * Returns the loaded entities for the given kind. 20930 * 20931 * @deprecated since WordPress 6.0. Use getEntitiesConfig instead 20932 * @param state Data state. 20933 * @param kind Entity kind. 20934 * 20935 * @return Array of entities with config matching kind. 20936 */ 20937function getEntitiesByKind(state, kind) { 20938 external_wp_deprecated_default()("wp.data.select( 'core' ).getEntitiesByKind()", { 20939 since: '6.0', 20940 alternative: "wp.data.select( 'core' ).getEntitiesConfig()" 20941 }); 20942 return getEntitiesConfig(state, kind); 20943} 20944 20945/** 20946 * Returns the loaded entities for the given kind. 20947 * 20948 * @param state Data state. 20949 * @param kind Entity kind. 20950 * 20951 * @return Array of entities with config matching kind. 20952 */ 20953function getEntitiesConfig(state, kind) { 20954 return state.entities.config.filter(entity => entity.kind === kind); 20955} 20956 20957/** 20958 * Returns the entity config given its kind and name. 20959 * 20960 * @deprecated since WordPress 6.0. Use getEntityConfig instead 20961 * @param state Data state. 20962 * @param kind Entity kind. 20963 * @param name Entity name. 20964 * 20965 * @return Entity config 20966 */ 20967function getEntity(state, kind, name) { 20968 external_wp_deprecated_default()("wp.data.select( 'core' ).getEntity()", { 20969 since: '6.0', 20970 alternative: "wp.data.select( 'core' ).getEntityConfig()" 20971 }); 20972 return getEntityConfig(state, kind, name); 20973} 20974 20975/** 20976 * Returns the entity config given its kind and name. 20977 * 20978 * @param state Data state. 20979 * @param kind Entity kind. 20980 * @param name Entity name. 20981 * 20982 * @return Entity config 20983 */ 20984function getEntityConfig(state, kind, name) { 20985 return state.entities.config?.find(config => config.kind === kind && config.name === name); 20986} 20987 20988/** 20989 * GetEntityRecord is declared as a *callable interface* with 20990 * two signatures to work around the fact that TypeScript doesn't 20991 * allow currying generic functions: 20992 * 20993 * ```ts 20994 * type CurriedState = F extends ( state: any, ...args: infer P ) => infer R 20995 * ? ( ...args: P ) => R 20996 * : F; 20997 * type Selector = <K extends string | number>( 20998 * state: any, 20999 * kind: K, 21000 * key: K extends string ? 'string value' : false 21001 * ) => K; 21002 * type BadlyInferredSignature = CurriedState< Selector > 21003 * // BadlyInferredSignature evaluates to: 21004 * // (kind: string number, key: false | "string value") => string number 21005 * ``` 21006 * 21007 * The signature without the state parameter shipped as CurriedSignature 21008 * is used in the return value of `select( coreStore )`. 21009 * 21010 * See https://github.com/WordPress/gutenberg/pull/41578 for more details. 21011 */ 21012 21013/** 21014 * Returns the Entity's record object by key. Returns `null` if the value is not 21015 * yet received, undefined if the value entity is known to not exist, or the 21016 * entity object if it exists and is received. 21017 * 21018 * @param state State tree 21019 * @param kind Entity kind. 21020 * @param name Entity name. 21021 * @param key Record's key 21022 * @param query Optional query. If requesting specific
21023 * fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available "Retrieve a [Entity kind]". 21024 * 21025 * @return Record. 21026 */ 21027const getEntityRecord = rememo((state, kind, name, key, query) => { 21028 var _query$context; 21029 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData; 21030 if (!queriedState) { 21031 return undefined; 21032 } 21033 const context = (_query$context = query?.context) !== null && _query$context !== void 0 ? _query$context : 'default'; 21034 if (query === undefined) { 21035 // If expecting a complete item, validate that completeness. 21036 if (!queriedState.itemIsComplete[context]?.[key]) { 21037 return undefined; 21038 } 21039 return queriedState.items[context][key]; 21040 } 21041 const item = queriedState.items[context]?.[key]; 21042 if (item && query._fields) { 21043 var _getNormalizedCommaSe; 21044 const filteredItem = {}; 21045 const fields = (_getNormalizedCommaSe = get_normalized_comma_separable(query._fields)) !== null && _getNormalizedCommaSe !== void 0 ? _getNormalizedCommaSe : []; 21046 for (let f = 0; f < fields.length; f++) { 21047 const field = fields[f].split('.'); 21048 let value = item; 21049 field.forEach(fieldName => { 21050 value = value?.[fieldName]; 21051 }); 21052 setNestedValue(filteredItem, field, value); 21053 } 21054 return filteredItem; 21055 } 21056 return item; 21057}, (state, kind, name, recordId, query) => { 21058 var _query$context2; 21059 const context = (_query$context2 = query?.context) !== null && _query$context2 !== void 0 ? _query$context2 : 'default'; 21060 return [state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]]; 21061}); 21062 21063/** 21064 * Returns the Entity's record object by key. Doesn't trigger a resolver nor requests the entity records from the API if the entity record isn't available in the local state. 21065 * 21066 * @param state State tree 21067 * @param kind Entity kind. 21068 * @param name Entity name. 21069 * @param key Record's key 21070 * 21071 * @return Record. 21072 */ 21073function __experimentalGetEntityRecordNoResolver(state, kind, name, key) { 21074 return getEntityRecord(state, kind, name, key); 21075} 21076 21077/** 21078 * Returns the entity's record object by key, 21079 * with its attributes mapped to their raw values. 21080 * 21081 * @param state State tree. 21082 * @param kind Entity kind. 21083 * @param name Entity name. 21084 * @param key Record's key. 21085 * 21086 * @return Object with the entity's raw attributes. 21087 */ 21088const getRawEntityRecord = rememo((state, kind, name, key) => { 21089 const record = getEntityRecord(state, kind, name, key); 21090 return record && Object.keys(record).reduce((accumulator, _key) => { 21091 if (isRawAttribute(getEntityConfig(state, kind, name), _key)) { 21092 var _record$_key$raw; 21093 // Because edits are the "raw" attribute values, 21094 // we return those from record selectors to make rendering, 21095 // comparisons, and joins with edits easier. 21096 accumulator[_key] = (_record$_key$raw = record[_key]?.raw) !== null && _record$_key$raw !== void 0 ? _record$_key$raw : record[_key]; 21097 } else { 21098 accumulator[_key] = record[_key]; 21099 } 21100 return accumulator; 21101 }, {}); 21102}, (state, kind, name, recordId, query) => { 21103 var _query$context3; 21104 const context = (_query$context3 = query?.context) !== null && _query$context3 !== void 0 ? _query$context3 : 'default'; 21105 return [state.entities.config, state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]]; 21106}); 21107 21108/** 21109 * Returns true if records have been received for the given set of parameters, 21110 * or false otherwise. 21111 * 21112 * @param state State tree 21113 * @param kind Entity kind. 21114 * @param name Entity name. 21115 * @param query Optional terms query. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s". 21116 * 21117 * @return Whether entity records have been received. 21118 */ 21119function hasEntityRecords(state, kind, name, query) { 21120 return Array.isArray(getEntityRecords(state, kind, name, query)); 21121} 21122 21123/** 21124 * GetEntityRecord is declared as a *callable interface* with
21125 * two signatures to work around the fact that TypeScript doesn't 21126 * allow currying generic functions. 21127 * 21128 * @see GetEntityRecord 21129 * @see https://github.com/WordPress/gutenberg/pull/41578 21130 */ 21131 21132/** 21133 * Returns the Entity's records. 21134 * 21135 * @param state State tree 21136 * @param kind Entity kind. 21137 * @param name Entity name. 21138 * @param query Optional terms query. If requesting specific 21139 * fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s". 21140 * 21141 * @return Records. 21142 */ 21143const getEntityRecords = (state, kind, name, query) => { 21144 // Queried data state is prepopulated for all known entities. If this is not 21145 // assigned for the given parameters, then it is known to not exist. 21146 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData; 21147 if (!queriedState) { 21148 return null; 21149 } 21150 return getQueriedItems(queriedState, query); 21151}; 21152/** 21153 * Returns the list of dirty entity records. 21154 * 21155 * @param state State tree. 21156 * 21157 * @return The list of updated records 21158 */ 21159const __experimentalGetDirtyEntityRecords = rememo(state => { 21160 const { 21161 entities: { 21162 records 21163 } 21164 } = state; 21165 const dirtyRecords = [];
21166 Object.keys(records).forEach(kind => { 21167 Object.keys(records[kind]).forEach(name => { 21168 const primaryKeys = Object.keys(records[kind][name].edits).filter(primaryKey => 21169 // The entity record must exist (not be deleted), 21170 // and it must have edits. 21171 getEntityRecord(state, kind, name, primaryKey) && hasEditsForEntityRecord(state, kind, name, primaryKey)); 21172 if (primaryKeys.length) { 21173 const entityConfig = getEntityConfig(state, kind, name); 21174 primaryKeys.forEach(primaryKey => { 21175 const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey); 21176 dirtyRecords.push({ 21177 // We avoid using primaryKey because it's transformed into a string 21178 // when it's used as an object key. 21179 key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined, 21180 title: entityConfig?.getTitle?.(entityRecord) || '', 21181 name, 21182 kind 21183 }); 21184 }); 21185 } 21186 }); 21187 }); 21188 return dirtyRecords; 21189}, state => [state.entities.records]); 21190 21191/** 21192 * Returns the list of entities currently being saved. 21193 * 21194 * @param state State tree. 21195 * 21196 * @return The list of records being saved. 21197 */ 21198const __experimentalGetEntitiesBeingSaved = rememo(state => { 21199 const { 21200 entities: { 21201 records 21202 } 21203 } = state; 21204 const recordsBeingSaved = [];
21205 Object.keys(records).forEach(kind => { 21206 Object.keys(records[kind]).forEach(name => { 21207 const primaryKeys = Object.keys(records[kind][name].saving).filter(primaryKey => isSavingEntityRecord(state, kind, name, primaryKey)); 21208 if (primaryKeys.length) { 21209 const entityConfig = getEntityConfig(state, kind, name); 21210 primaryKeys.forEach(primaryKey => { 21211 const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey); 21212 recordsBeingSaved.push({ 21213 // We avoid using primaryKey because it's transformed into a string 21214 // when it's used as an object key. 21215 key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined, 21216 title: entityConfig?.getTitle?.(entityRecord) || '', 21217 name, 21218 kind 21219 }); 21220 }); 21221 } 21222 }); 21223 }); 21224 return recordsBeingSaved; 21225}, state => [state.entities.records]); 21226 21227/** 21228 * Returns the specified entity record's edits. 21229 * 21230 * @param state State tree. 21231 * @param kind Entity kind. 21232 * @param name Entity name. 21233 * @param recordId Record ID. 21234 * 21235 * @return The entity record's edits. 21236 */ 21237function getEntityRecordEdits(state, kind, name, recordId) { 21238 return state.entities.records?.[kind]?.[name]?.edits?.[recordId]; 21239} 21240 21241/** 21242 * Returns the specified entity record's non transient edits. 21243 * 21244 * Transient edits don't create an undo level, and 21245 * are not considered for change detection. 21246 * They are defined in the entity's config. 21247 * 21248 * @param state State tree. 21249 * @param kind Entity kind. 21250 * @param name Entity name. 21251 * @param recordId Record ID. 21252 * 21253 * @return The entity record's non transient edits. 21254 */ 21255const getEntityRecordNonTransientEdits = rememo((state, kind, name, recordId) => { 21256 const { 21257 transientEdits 21258 } = getEntityConfig(state, kind, name) || {}; 21259 const edits = getEntityRecordEdits(state, kind, name, recordId) || {}; 21260 if (!transientEdits) { 21261 return edits; 21262 } 21263 return Object.keys(edits).reduce((acc, key) => { 21264 if (!transientEdits[key]) { 21265 acc[key] = edits[key]; 21266 } 21267 return acc; 21268 }, {}); 21269}, (state, kind, name, recordId) => [state.entities.config, state.entities.records?.[kind]?.[name]?.edits?.[recordId]]); 21270 21271/** 21272 * Returns true if the specified entity record has edits, 21273 * and false otherwise. 21274 * 21275 * @param state State tree. 21276 * @param kind Entity kind. 21277 * @param name Entity name. 21278 * @param recordId Record ID. 21279 * 21280 * @return Whether the entity record has edits or not. 21281 */ 21282function hasEditsForEntityRecord(state, kind, name, recordId) { 21283 return isSavingEntityRecord(state, kind, name, recordId) || Object.keys(getEntityRecordNonTransientEdits(state, kind, name, recordId)).length > 0; 21284} 21285 21286/** 21287 * Returns the specified entity record, merged with its edits. 21288 * 21289 * @param state State tree. 21290 * @param kind Entity kind. 21291 * @param name Entity name. 21292 * @param recordId Record ID. 21293 * 21294 * @return The entity record, merged with its edits. 21295 */ 21296const getEditedEntityRecord = rememo((state, kind, name, recordId) => ({ 21297 ...getRawEntityRecord(state, kind, name, recordId), 21298 ...getEntityRecordEdits(state, kind, name, recordId) 21299}), (state, kind, name, recordId, query) => { 21300 var _query$context4; 21301 const context = (_query$context4 = query?.context) !== null && _query$context4 !== void 0 ? _query$context4 : 'default'; 21302 return [state.entities.config, state.entities.records?.[kind]?.[name]?.queriedData.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData.itemIsComplete[context]?.[recordId], state.entities.records?.[kind]?.[name]?.edits?.[recordId]]; 21303}); 21304 21305/** 21306 * Returns true if the specified entity record is autosaving, and false otherwise. 21307 * 21308 * @param state State tree. 21309 * @param kind Entity kind. 21310 * @param name Entity name. 21311 * @param recordId Record ID. 21312 * 21313 * @return Whether the entity record is autosaving or not. 21314 */ 21315function isAutosavingEntityRecord(state, kind, name, recordId) { 21316 var _state$entities$recor; 21317 const { 21318 pending, 21319 isAutosave 21320 } = (_state$entities$recor = state.entities.records?.[kind]?.[name]?.saving?.[recordId]) !== null && _state$entities$recor !== void 0 ? _state$entities$recor : {}; 21321 return Boolean(pending && isAutosave); 21322} 21323 21324/** 21325 * Returns true if the specified entity record is saving, and false otherwise. 21326 * 21327 * @param state State tree. 21328 * @param kind Entity kind. 21329 * @param name Entity name. 21330 * @param recordId Record ID. 21331 * 21332 * @return Whether the entity record is saving or not. 21333 */ 21334function isSavingEntityRecord(state, kind, name, recordId) { 21335 var _state$entities$recor2; 21336 return (_state$entities$recor2 = state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.pending) !== null && _state$entities$recor2 !== void 0 ? _state$entities$recor2 : false;
21337} 21338 21339/** 21340 * Returns true if the specified entity record is deleting, and false otherwise. 21341 * 21342 * @param state State tree. 21343 * @param kind Entity kind. 21344 * @param name Entity name. 21345 * @param recordId Record ID. 21346 * 21347 * @return Whether the entity record is deleting or not. 21348 */ 21349function isDeletingEntityRecord(state, kind, name, recordId) { 21350 var _state$entities$recor3; 21351 return (_state$entities$recor3 = state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.pending) !== null && _state$entities$recor3 !== void 0 ? _state$entities$recor3 : false; 21352} 21353 21354/** 21355 * Returns the specified entity record's last save error. 21356 * 21357 * @param state State tree. 21358 * @param kind Entity kind. 21359 * @param name Entity name. 21360 * @param recordId Record ID. 21361 * 21362 * @return The entity record's save error. 21363 */ 21364function getLastEntitySaveError(state, kind, name, recordId) { 21365 return state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.error; 21366} 21367 21368/** 21369 * Returns the specified entity record's last delete error. 21370 * 21371 * @param state State tree. 21372 * @param kind Entity kind. 21373 * @param name Entity name. 21374 * @param recordId Record ID. 21375 * 21376 * @return The entity record's save error. 21377 */ 21378function getLastEntityDeleteError(state, kind, name, recordId) { 21379 return state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.error; 21380} 21381 21382/** 21383 * Returns the previous edit from the current undo offset 21384 * for the entity records edits history, if any. 21385 * 21386 * @deprecated since 6.3 21387 * 21388 * @param state State tree. 21389 * 21390 * @return The edit. 21391 */ 21392function getUndoEdit(state) { 21393 external_wp_deprecated_default()("select( 'core' ).getUndoEdit()", { 21394 since: '6.3' 21395 }); 21396 return undefined; 21397} 21398 21399/** 21400 * Returns the next edit from the current undo offset 21401 * for the entity records edits history, if any. 21402 * 21403 * @deprecated since 6.3 21404 * 21405 * @param state State tree. 21406 * 21407 * @return The edit. 21408 */ 21409function getRedoEdit(state) { 21410 external_wp_deprecated_default()("select( 'core' ).getRedoEdit()", { 21411 since: '6.3' 21412 }); 21413 return undefined; 21414} 21415 21416/** 21417 * Returns true if there is a previous edit from the current undo offset 21418 * for the entity records edits history, and false otherwise. 21419 * 21420 * @param state State tree. 21421 * 21422 * @return Whether there is a previous edit or not. 21423 */ 21424function hasUndo(state) { 21425 return state.undoManager.hasUndo(); 21426} 21427 21428/** 21429 * Returns true if there is a next edit from the current undo offset 21430 * for the entity records edits history, and false otherwise. 21431 * 21432 * @param state State tree. 21433 * 21434 * @return Whether there is a next edit or not. 21435 */ 21436function hasRedo(state) { 21437 return state.undoManager.hasRedo(); 21438} 21439 21440/** 21441 * Return the current theme. 21442 * 21443 * @param state Data state. 21444 * 21445 * @return The current theme. 21446 */ 21447function getCurrentTheme(state) { 21448 return getEntityRecord(state, 'root', 'theme', state.currentTheme); 21449} 21450 21451/** 21452 * Return the ID of the current global styles object. 21453 * 21454 * @param state Data state. 21455 * 21456 * @return The current global styles ID. 21457 */ 21458function __experimentalGetCurrentGlobalStylesId(state) { 21459 return state.currentGlobalStylesId; 21460} 21461 21462/** 21463 * Return theme supports data in the index. 21464 * 21465 * @param state Data state. 21466 * 21467 * @return Index data. 21468 */ 21469function getThemeSupports(state) { 21470 var _getCurrentTheme$them; 21471 return (_getCurrentTheme$them = getCurrentTheme(state)?.theme_supports) !== null && _getCurrentTheme$them !== void 0 ? _getCurrentTheme$them : EMPTY_OBJECT; 21472} 21473 21474/** 21475 * Returns the embed preview for the given URL. 21476 * 21477 * @param state Data state. 21478 * @param url Embedded URL. 21479 * 21480 * @return Undefined if the preview has not been fetched, otherwise, the preview fetched from the embed preview API. 21481 */ 21482function getEmbedPreview(state, url) { 21483 return state.embedPreviews[url]; 21484} 21485 21486/** 21487 * Determines if the returned preview is an oEmbed link fallback. 21488 * 21489 * WordPress can be configured to return a simple link to a URL if it is not embeddable. 21490 * We need to be able to determine if a URL is embeddable or not, based on what we 21491 * get back from the oEmbed preview API. 21492 * 21493 * @param state Data state. 21494 * @param url Embedded URL. 21495 * 21496 * @return Is the preview for the URL an oEmbed link fallback. 21497 */ 21498function isPreviewEmbedFallback(state, url) { 21499 const preview = state.embedPreviews[url]; 21500 const oEmbedLinkCheck = '<a href="' + url + '">' + url + '</a>'; 21501 if (!preview) { 21502 return false;
21503 } 21504 return preview.html === oEmbedLinkCheck; 21505} 21506 21507/** 21508 * Returns whether the current user can perform the given action on the given 21509 * REST resource. 21510 * 21511 * Calling this may trigger an OPTIONS request to the REST API via the 21512 * `canUser()` resolver. 21513 * 21514 * https://developer.wordpress.org/rest-api/reference/ 21515 * 21516 * @param state Data state. 21517 * @param action Action to check. One of: 'create', 'read', 'update', 'delete'. 21518 * @param resource REST resource to check, e.g. 'media' or 'posts'. 21519 * @param id Optional ID of the rest resource to check. 21520 * 21521 * @return Whether or not the user can perform the action, 21522 * or `undefined` if the OPTIONS request is still being made. 21523 */ 21524function canUser(state, action, resource, id) { 21525 const key = [action, resource, id].filter(Boolean).join('/'); 21526 return state.userPermissions[key]; 21527} 21528 21529/** 21530 * Returns whether the current user can edit the given entity. 21531 * 21532 * Calling this may trigger an OPTIONS request to the REST API via the 21533 * `canUser()` resolver. 21534 * 21535 * https://developer.wordpress.org/rest-api/reference/ 21536 * 21537 * @param state Data state. 21538 * @param kind Entity kind. 21539 * @param name Entity name. 21540 * @param recordId Record's id. 21541 * @return Whether or not the user can edit, 21542 * or `undefined` if the OPTIONS request is still being made. 21543 */ 21544function canUserEditEntityRecord(state, kind, name, recordId) { 21545 const entityConfig = getEntityConfig(state, kind, name); 21546 if (!entityConfig) { 21547 return false; 21548 } 21549 const resource = entityConfig.__unstable_rest_base; 21550 return canUser(state, 'update', resource, recordId); 21551} 21552 21553/** 21554 * Returns the latest autosaves for the post. 21555 * 21556 * May return multiple autosaves since the backend stores one autosave per 21557 * author for each post. 21558 * 21559 * @param state State tree. 21560 * @param postType The type of the parent post. 21561 * @param postId The id of the parent post. 21562 * 21563 * @return An array of autosaves for the post, or undefined if there is none. 21564 */ 21565function getAutosaves(state, postType, postId) { 21566 return state.autosaves[postId]; 21567} 21568 21569/** 21570 * Returns the autosave for the post and author. 21571 * 21572 * @param state State tree. 21573 * @param postType The type of the parent post. 21574 * @param postId The id of the parent post. 21575 * @param authorId The id of the author. 21576 * 21577 * @return The autosave for the post and author. 21578 */ 21579function getAutosave(state, postType, postId, authorId) { 21580 if (authorId === undefined) { 21581 return; 21582 } 21583 const autosaves = state.autosaves[postId]; 21584 return autosaves?.find(autosave => autosave.author === authorId); 21585} 21586 21587/** 21588 * Returns true if the REST request for autosaves has completed. 21589 * 21590 * @param state State tree. 21591 * @param postType The type of the parent post. 21592 * @param postId The id of the parent post. 21593 * 21594 * @return True if the REST request was completed. False otherwise. 21595 */ 21596const hasFetchedAutosaves = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, postType, postId) => { 21597 return select(STORE_NAME).hasFinishedResolution('getAutosaves', [postType, postId]); 21598}); 21599 21600/** 21601 * Returns a new reference when edited values have changed. This is useful in 21602 * inferring where an edit has been made between states by comparison of the 21603 * return values using strict equality. 21604 * 21605 * @example 21606 * 21607 * ``` 21608 * const hasEditOccurred = ( 21609 * getReferenceByDistinctEdits( beforeState ) !== 21610 * getReferenceByDistinctEdits( afterState ) 21611 * ); 21612 * ``` 21613 * 21614 * @param state Editor state. 21615 * 21616 * @return A value whose reference will change only when an edit occurs. 21617 */ 21618function getReferenceByDistinctEdits(state) { 21619 return state.editsReference; 21620} 21621 21622/** 21623 * Retrieve the frontend template used for a given link. 21624 * 21625 * @param state Editor state. 21626 * @param link Link. 21627 * 21628 * @return The template record. 21629 */ 21630function __experimentalGetTemplateForLink(state, link) { 21631 const records = getEntityRecords(state, 'postType', 'wp_template', { 21632 'find-template': link 21633 }); 21634 if (records?.length) { 21635 return getEditedEntityRecord(state, 'postType', 'wp_template', records[0].id); 21636 } 21637 return null; 21638} 21639 21640/** 21641 * Retrieve the current theme's base global styles 21642 * 21643 * @param state Editor state. 21644 * 21645 * @return The Global Styles object. 21646 */ 21647function __experimentalGetCurrentThemeBaseGlobalStyles(state) { 21648 const currentTheme = getCurrentTheme(state); 21649 if (!currentTheme) { 21650 return null; 21651 } 21652 return state.themeBaseGlobalStyles[currentTheme.stylesheet]; 21653} 21654 21655/** 21656 * Return the ID of the current global styles object. 21657 * 21658 * @param state Data state. 21659 * 21660 * @return The current global styles ID. 21661 */ 21662function __experimentalGetCurrentThemeGlobalStylesVariations(state) { 21663 const currentTheme = getCurrentTheme(state); 21664 if (!currentTheme) { 21665 return null; 21666 } 21667 return state.themeGlobalStyleVariations[currentTheme.stylesheet]; 21668} 21669 21670/** 21671 * Retrieve the list of registered block patterns. 21672 * 21673 * @param state Data state. 21674 * 21675 * @return Block pattern list. 21676 */ 21677function getBlockPatterns(state) { 21678 return state.blockPatterns; 21679} 21680 21681/** 21682 * Retrieve the list of registered block pattern categories. 21683 * 21684 * @param state Data state. 21685 * 21686 * @return Block pattern category list. 21687 */ 21688function getBlockPatternCategories(state) { 21689 return state.blockPatternCategories; 21690} 21691 21692/** 21693 * Retrieve the registered user pattern categories. 21694 * 21695 * @param state Data state. 21696 * 21697 * @return User patterns category array. 21698 */ 21699 21700function getUserPatternCategories(state) { 21701 return state.userPatternCategories; 21702} 21703 21704/** 21705 * Returns the revisions of the current global styles theme. 21706 * 21707 * @param state Data state. 21708 * 21709 * @return The current global styles. 21710 */ 21711function getCurrentThemeGlobalStylesRevisions(state) { 21712 const currentGlobalStylesId = __experimentalGetCurrentGlobalStylesId(state); 21713 if (!currentGlobalStylesId) { 21714 return null; 21715 } 21716 return state.themeGlobalStyleRevisions[currentGlobalStylesId]; 21717} 21718 21719;// CONCATENATED MODULE: ./packages/core-data/build-module/private-selectors.js 21720/** 21721 * Internal dependencies 21722 */ 21723
21724/** 21725 * Returns the previous edit from the current undo offset 21726 * for the entity records edits history, if any. 21727 * 21728 * @param state State tree. 21729 * 21730 * @return The undo manager. 21731 */ 21732function getUndoManager(state) { 21733 return state.undoManager; 21734} 21735 21736/** 21737 * Retrieve the fallback Navigation. 21738 * 21739 * @param state Data state. 21740 * @return The ID for the fallback Navigation post. 21741 */ 21742function getNavigationFallbackId(state) { 21743 return state.navigationFallbackId; 21744} 21745 21746;// CONCATENATED MODULE: ./node_modules/camel-case/dist.es2015/index.js 21747 21748 21749function camelCaseTransform(input, index) { 21750 if (index === 0) 21751 return input.toLowerCase(); 21752 return pascalCaseTransform(input, index); 21753} 21754function camelCaseTransformMerge(input, index) { 21755 if (index === 0) 21756 return input.toLowerCase(); 21757 return pascalCaseTransformMerge(input); 21758} 21759function camelCase(input, options) { 21760 if (options === void 0) { options = {}; } 21761 return pascalCase(input, __assign({ transform: camelCaseTransform }, options)); 21762} 21763 21764;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/forward-resolver.js 21765/** 21766 * Higher-order function which forward the resolution to another resolver with the same arguments. 21767 * 21768 * @param {string} resolverName forwarded resolver. 21769 * 21770 * @return {Function} Enhanced resolver. 21771 */ 21772const forwardResolver = resolverName => (...args) => async ({ 21773 resolveSelect 21774}) => { 21775 await resolveSelect[resolverName](...args); 21776}; 21777/* harmony default export */ const forward_resolver = (forwardResolver); 21778 21779;// CONCATENATED MODULE: ./packages/core-data/build-module/resolvers.js 21780/** 21781 * External dependencies 21782 */ 21783 21784 21785/** 21786 * WordPress dependencies 21787 */ 21788 21789 21790 21791/** 21792 * Internal dependencies 21793 */ 21794 21795 21796 21797 21798 21799/** 21800 * Requests authors from the REST API. 21801 * 21802 * @param {Object|undefined} query Optional object of query parameters to 21803 * include with request. 21804 */ 21805const resolvers_getAuthors = query => async ({ 21806 dispatch 21807}) => { 21808 const path = (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/users/?who=authors&per_page=100', query); 21809 const users = await external_wp_apiFetch_default()({ 21810 path 21811 }); 21812 dispatch.receiveUserQuery(path, users); 21813}; 21814 21815/** 21816 * Requests the current user from the REST API. 21817 */ 21818const resolvers_getCurrentUser = () => async ({ 21819 dispatch 21820}) => { 21821 const currentUser = await external_wp_apiFetch_default()({ 21822 path: '/wp/v2/users/me' 21823 }); 21824 dispatch.receiveCurrentUser(currentUser); 21825}; 21826 21827/** 21828 * Requests an entity's record from the REST API. 21829 * 21830 * @param {string} kind Entity kind. 21831 * @param {string} name Entity name. 21832 * @param {number|string} key Record's key 21833 * @param {Object|undefined} query Optional object of query parameters to 21834 * include with request. If requesting specific 21835 * fields, fields must always include the ID. 21836 */ 21837const resolvers_getEntityRecord = (kind, name, key = '', query) => async ({ 21838 select, 21839 dispatch 21840}) => { 21841 const configs = await dispatch(getOrLoadEntitiesConfig(kind)); 21842 const entityConfig = configs.find(config => config.name === name && config.kind === kind); 21843 if (!entityConfig || entityConfig?.__experimentalNoFetch) { 21844 return; 21845 } 21846 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, key], { 21847 exclusive: false 21848 }); 21849 try { 21850 // Entity supports configs, 21851 // use the sync algorithm instead of the old fetch behavior. 21852 if (window.__experimentalEnableSync && entityConfig.syncConfig && !query) { 21853 if (true) { 21854 const objectId = entityConfig.getSyncObjectId(key); 21855 21856 // Loads the persisted document. 21857 await getSyncProvider().bootstrap(entityConfig.syncObjectType, objectId, record => { 21858 dispatch.receiveEntityRecords(kind, name, record, query); 21859 }); 21860 21861 // Boostraps the edited document as well (and load from peers). 21862 await getSyncProvider().bootstrap(entityConfig.syncObjectType + '--edit', objectId, record => { 21863 dispatch({ 21864 type: 'EDIT_ENTITY_RECORD', 21865 kind, 21866 name, 21867 recordId: key, 21868 edits: record, 21869 meta: { 21870 undo: undefined 21871 } 21872 }); 21873 }); 21874 } 21875 } else { 21876 if (query !== undefined && query._fields) { 21877 // If requesting specific fields, items and query association to said 21878 // records are stored by ID reference. Thus, fields must al
21878ways include 21879 // the ID. 21880 query = { 21881 ...query, 21882 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.key || DEFAULT_ENTITY_KEY])].join() 21883 }; 21884 } 21885 21886 // Disable reason: While true that an early return could leave `path` 21887 // unused, it's important that path is derived using the query prior to 21888 // additional query modifications in the condition below, since those 21889 // modifications are relevant to how the data is tracked in state, and not 21890 // for how the request is made to the REST API. 21891 21892 // eslint-disable-next-line @wordpress/no-unused-vars-before-return 21893 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.baseURL + (key ? '/' + key : ''), { 21894 ...entityConfig.baseURLParams, 21895 ...query 21896 }); 21897 if (query !== undefined) { 21898 query = { 21899 ...query, 21900 include: [key] 21901 }; 21902 21903 // The resolution cache won't consider query as reusable based on the 21904 // fields, so it's tested here, prior to initiating the REST request, 21905 // and without causing `getEntityRecords` resolution to occur. 21906 const hasRecords = select.hasEntityRecords(kind, name, query); 21907 if (hasRecords) { 21908 return; 21909 } 21910 } 21911 const record = await external_wp_apiFetch_default()({ 21912 path 21913 }); 21914 dispatch.receiveEntityRecords(kind, name, record, query); 21915 } 21916 } finally { 21917 dispatch.__unstableReleaseStoreLock(lock); 21918 } 21919}; 21920 21921/** 21922 * Requests an entity's record from the REST API. 21923 */ 21924const resolvers_getRawEntityRecord = forward_resolver('getEntityRecord'); 21925 21926/** 21927 * Requests an entity's record from the REST API. 21928 */ 21929const resolvers_getEditedEntityRecord = forward_resolver('getEntityRecord'); 21930 21931/** 21932 * Requests the entity's records from the REST API. 21933 * 21934 * @param {string} kind Entity kind. 21935 * @param {string} name Entity name. 21936 * @param {Object?} query Query Object. If requesting specific fields, fields 21937 * must always include the ID. 21938 */ 21939const resolvers_getEntityRecords = (kind, name, query = {}) => async ({ 21940 dispatch 21941}) => { 21942 const configs = await dispatch(getOrLoadEntitiesConfig(kind)); 21943 const entityConfig = configs.find(config => config.name === name && config.kind === kind); 21944 if (!entityConfig || entityConfig?.__experimentalNoFetch) { 21945 return; 21946 } 21947 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name], { 21948 exclusive: false 21949 }); 21950 try { 21951 if (query._fields) { 21952 // If requesting specific fields, items and query association to said 21953 // records are stored by ID reference. Thus, fields must always include 21954 // the ID. 21955 query = { 21956 ...query, 21957 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.key || DEFAULT_ENTITY_KEY])].join() 21958 }; 21959 } 21960 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.baseURL, { 21961 ...entityConfig.baseURLParams, 21962 ...query 21963 }); 21964 let records = Object.values(await external_wp_apiFetch_default()({ 21965 path 21966 })); 21967 // If we request fields but the result doesn't contain the fields, 21968 // explicitly set these fields as "undefined"
21969 // that way we consider the query "fullfilled". 21970 if (query._fields) { 21971 records = records.map(record => { 21972 query._fields.split(',').forEach(field => { 21973 if (!record.hasOwnProperty(field)) { 21974 record[field] = undefined; 21975 } 21976 }); 21977 return record; 21978 }); 21979 } 21980 dispatch.receiveEntityRecords(kind, name, records, query); 21981 21982 // When requesting all fields, the list of results can be used to 21983 // resolve the `getEntityRecord` selector in addition to `getEntityRecords`. 21984 // See https://github.com/WordPress/gutenberg/pull/26575 21985 if (!query?._fields && !query.context) { 21986 const key = entityConfig.key || DEFAULT_ENTITY_KEY; 21987 const resolutionsArgs = records.filter(record => record[key]).map(record => [kind, name, record[key]]); 21988 dispatch({ 21989 type: 'START_RESOLUTIONS', 21990 selectorName: 'getEntityRecord', 21991 args: resolutionsArgs 21992 }); 21993 dispatch({ 21994 type: 'FINISH_RESOLUTIONS', 21995 selectorName: 'getEntityRecord', 21996 args: resolutionsArgs 21997 }); 21998 } 21999 } finally { 22000 dispatch.__unstableReleaseStoreLock(lock); 22001 } 22002}; 22003resolvers_getEntityRecords.shouldInvalidate = (action, kind, name) => { 22004 return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && kind === action.kind && name === action.name; 22005}; 22006 22007/** 22008 * Requests the current theme. 22009 */ 22010const resolvers_getCurrentTheme = () => async ({ 22011 dispatch, 22012 resolveSelect 22013}) => { 22014 const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', { 22015 status: 'active' 22016 }); 22017 dispatch.receiveCurrentTheme(activeThemes[0]); 22018}; 22019 22020/** 22021 * Requests theme supports data from the index. 22022 */ 22023const resolvers_getThemeSupports = forward_resolver('getCurrentTheme'); 22024 22025/** 22026 * Requests a preview from the from the Embed API. 22027 * 22028 * @param {string} url URL to get the preview for. 22029 */ 22030const resolvers_getEmbedPreview = url => async ({ 22031 dispatch 22032}) => { 22033 try { 22034 const embedProxyResponse = await external_wp_apiFetch_default()({ 22035 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/oembed/1.0/proxy', { 22036 url 22037 }) 22038 }); 22039 dispatch.receiveEmbedPreview(url, embedProxyResponse); 22040 } catch (error) { 22041 // Embed API 404s if the URL cannot be embedded, so we have to catch the error from the apiRequest here. 22042 dispatch.receiveEmbedPreview(url, false); 22043 } 22044}; 22045 22046/** 22047 * Checks whether the current user can perform the given action on the given 22048 * REST resource. 22049 * 22050 * @param {string} requestedAction Action to check. One of: 'create', 'read', 'update', 22051 * 'delete'. 22052 * @param {string} resource REST resource to check, e.g. 'media' or 'posts'. 22053 * @param {?string} id ID of the rest resource to check. 22054 */ 22055const resolvers_canUser = (requestedAction, resource, id) => async ({ 22056 dispatch, 22057 registry 22058}) => { 22059 const { 22060 hasStartedResolution 22061 } = registry.select(STORE_NAME); 22062 const resourcePath = id ? `${resource}/${id}` : resource; 22063 const retrievedActions = ['create', 'read', 'update', 'delete']; 22064 if (!retrievedActions.includes(requestedAction)) { 22065 throw new Error(`'${requestedAction}' is not a valid action.`); 22066 } 22067 22068 // Prevent resolving the same resource twice. 22069 for (const relatedAction of retrievedActions) { 22070 if (relatedAction === requestedAction) { 22071 continue; 22072 } 22073 const isAlreadyResolving = hasStartedResolution('canUser', [relatedAction, resource, id]); 22074 if (isAlreadyResolving) { 22075 return; 22076 } 22077 } 22078 let response; 22079 try { 22080 response = await external_wp_apiFetch_default()({ 22081 path: `/wp/v2/${resourcePath}`, 22082 method: 'OPTIONS', 22083 parse: false 22084 }); 22085 } catch (error) { 22086 // Do nothing if our OPTIONS request comes back with an API error (4xx or 22087 // 5xx). The previously determined isAllowed value will remain in the store. 22088 return; 22089 } 22090 22091 // Optional chaining operator is used here because the API requests don't 22092 // return the expected result in the native version. Instead, API requests 22093 // only return the result, without including response properties like the headers. 22094 const allowHeader = response.headers?.get('allow'); 22095 const allowedMethods = allowHeader?.allow || allowHeader || ''; 22096 const permissions = {}; 22097 const methods = { 22098 create: 'POST', 22099 read: 'GET', 22100 update: 'PUT', 22101 delete: 'DELETE' 22102 }; 22103 for (const [actionName, methodName] of Object.entries(methods)) { 22104 permissions[actionName] = allowedMethods.includes(methodName); 22105 } 22106 for (const action of retrievedActions) { 22107 dispatch.receiveUserPermission(`${action}/${resourcePath}`, permissions[action]); 22108 } 22109}; 22110 22111/** 22112 * Checks whether the current user can perform the given action on the given 22113 * REST resource. 22114 * 22115 * @param {string} kind Entity kind. 22116 * @param {string} name Entity name. 22117 * @param {string} recordId Record's id. 22118 */ 22119const resolvers_canUserEditEntityRecord = (kind, name, recordId) => async ({ 22120 dispatch 22121}) => { 22122 const configs = await dispatch(getOrLoadEntitiesConfig(kind)); 22123 const entityConfig = configs.find(config => config.name === name && config.kind === kind); 22124 if (!entityConfig) { 22125 return; 22126 } 22127 const resource = entityConfig.__unstable_rest_base; 22128 await dispatch(resolvers_canUser('update', resource, recordId)); 22129}; 22130 22131/** 22132 * Request autosave data from the REST API. 22133 * 22134 * @param {string} postType The type of the parent post. 22135 * @param {number} postId The id of the parent post. 22136 */ 22137const resolvers_getAutosaves = (postType, postId) => async ({ 22138 dispatch, 22139 resolveSelect 22140}) => { 22141 const { 22142 rest_base: restBase, 22143 rest_namespace: restNamespace = 'wp/v2' 22144 } = await resolveSelect.getPostType(postType); 22145 const autosaves = await external_wp_apiFetch_default()({ 22146 path: `/${restNamespace}/${restBase}/${postId}/autosaves?context=edit` 22147 }); 22148 if (autosaves && autosaves.length) { 22149 dispatch.receiveAutosaves(postId, autosaves); 22150 } 22151}; 22152 22153/** 22154 * Request autosave data from the REST API. 22155 * 22156 * This resolver exists to ensure the underlying autosaves are fetched via 22157 * `getAutosaves` when a call to the `getAutosave` selector is made. 22158 * 22159 * @param {string} postType The type of the parent post. 22160 * @param {number} postId The id of the parent post. 22161 */ 22162const resolvers_getAutosave = (postType, postId) => async ({ 22163 resolveSelect 22164}) => { 22165 await resolveSelect.getAutosaves(postType, postId); 22166}; 22167 22168/** 22169 * Retrieve the frontend template used for a given link. 22170 * 22171 * @param {string} link Link. 22172 */ 22173const resolvers_experimentalGetTemplateForLink = link => async ({ 22174 dispatch, 22175 resolveSelect 22176}) => { 22177 let template; 22178 try { 22179 // This is NOT calling a REST endpoint but rather ends up with a response from 22180 // an Ajax function which has a different shape from a WP_REST_Response. 22181 template = await external_wp_apiFetch_default()({ 22182 url: (0,external_wp_url_namespaceObject.addQueryArgs)(link, { 22183 '_wp-find-template': true 22184 }) 22185 }).then(({ 22186 data 22187 }) => data); 22188 } catch (e) { 22189 // For non-FSE themes, it is possible that this request returns an error. 22190 } 22191 if (!template) { 22192 return; 22193 } 22194 const record = await resolveSelect.getEntityRecord('postType', 'wp_template', template.id); 22195 if (record) { 22196 dispatch.receiveEntityRecords('postType', 'wp_template', [record], { 22197 'find-template': link 22198 }); 22199 } 22200}; 22201resolvers_experimentalGetTemplateForLink.shouldInvalidate = action => { 22202 return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && action.kind === 'postType' && action.name === 'wp_template'; 22203}; 22204const resolvers_experimentalGetCurrentGlobalStylesId = () => async ({ 22205 dispatch, 22206 resolveSelect 22207}) => { 22208 const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', { 22209 status: 'active' 22210 }); 22211 const globalStylesURL = activeThemes?.[0]?._links?.['wp:user-global-styles']?.[0]?.href; 22212 if (globalStylesURL) { 22213 const globalStylesObject = await external_wp_apiFetch_default()({ 22214 url: globalStylesURL 22215 }); 22216 dispatch.__experimentalReceiveCurrentGlobalStylesId(globalStylesObject.id); 22217 } 22218}; 22219const resolvers_experimentalGetCurrentThemeBaseGlobalStyles = () => async ({ 22220 resolveSelect, 22221 dispatch 22222}) => {
22223 const currentTheme = await resolveSelect.getCurrentTheme(); 22224 const themeGlobalStyles = await external_wp_apiFetch_default()({ 22225 path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}` 22226 }); 22227 dispatch.__experimentalReceiveThemeBaseGlobalStyles(currentTheme.stylesheet, themeGlobalStyles); 22228}; 22229const resolvers_experimentalGetCurrentThemeGlobalStylesVariations = () => async ({ 22230 resolveSelect, 22231 dispatch 22232}) => { 22233 const currentTheme = await resolveSelect.getCurrentTheme(); 22234 const variations = await external_wp_apiFetch_default()({ 22235 path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}/variations` 22236 }); 22237 dispatch.__experimentalReceiveThemeGlobalStyleVariations(currentTheme.stylesheet, variations); 22238}; 22239 22240/** 22241 * Fetches and returns the revisions of the current global styles theme. 22242 */ 22243const resolvers_getCurrentThemeGlobalStylesRevisions = () => async ({ 22244 resolveSelect, 22245 dispatch 22246}) => { 22247 const globalStylesId = await resolveSelect.__experimentalGetCurrentGlobalStylesId(); 22248 const record = globalStylesId ? await resolveSelect.getEntityRecord('root', 'globalStyles', globalStylesId) : undefined; 22249 const revisionsURL = record?._links?.['version-history']?.[0]?.href; 22250 if (revisionsURL) { 22251 const resetRevisions = await external_wp_apiFetch_default()({ 22252 url: revisionsURL 22253 }); 22254 const revisions = resetRevisions?.map(revision => Object.fromEntries(Object.entries(revision).map(([key, value]) => [camelCase(key), value]))); 22255 dispatch.receiveThemeGlobalStyleRevisions(globalStylesId, revisions); 22256 } 22257}; 22258resolvers_getCurrentThemeGlobalStylesRevisions.shouldInvalidate = action => { 22259 return action.type === 'SAVE_ENTITY_RECORD_FINISH' && action.kind === 'root' && !action.error && action.name === 'globalStyles'; 22260}; 22261const resolvers_getBlockPatterns = () => async ({ 22262 dispatch 22263}) => { 22264 const restPatterns = await external_wp_apiFetch_default()({ 22265 path: '/wp/v2/block-patterns/patterns' 22266 }); 22267 const patterns = restPatterns?.map(pattern => Object.fromEntries(Object.entries(pattern).map(([key, value]) => [camelCase(key), value]))); 22268 dispatch({ 22269 type: 'RECEIVE_BLOCK_PATTERNS', 22270 patterns 22271 }); 22272}; 22273const resolvers_getBlockPatternCategories = () => async ({ 22274 dispatch 22275}) => { 22276 const categories = await external_wp_apiFetch_default()({ 22277 path: '/wp/v2/block-patterns/categories' 22278 }); 22279 dispatch({ 22280 type: 'RECEIVE_BLOCK_PATTERN_CATEGORIES', 22281 categories 22282 }); 22283}; 22284const resolvers_getUserPatternCategories = () => async ({ 22285 dispatch, 22286 resolveSelect 22287}) => { 22288 const patternCategories = await resolveSelect.getEntityRecords('taxonomy', 'wp_pattern_category', { 22289 per_page: -1, 22290 _fields: 'id,name,description,slug', 22291 context: 'view' 22292 }); 22293 const mappedPatternCategories = patternCategories?.map(userCategory => ({ 22294 ...userCategory, 22295 label: userCategory.name, 22296 name: userCategory.slug 22297 })) || []; 22298 dispatch({ 22299 type: 'RECEIVE_USER_PATTERN_CATEGORIES', 22300 patternCategories: mappedPatternCategories 22301 }); 22302}; 22303const resolvers_getNavigationFallbackId = () => async ({ 22304 dispatch, 22305 select 22306}) => { 22307 const fallback = await external_wp_apiFetch_default()({ 22308 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp-block-editor/v1/navigation-fallback', { 22309 _embed: true 22310 }) 22311 }); 22312 const record = fallback?._embedded?.self; 22313 dispatch.receiveNavigationFallbackId(fallback?.id); 22314 if (record) { 22315 // If the fallback is already in the store, don't invalidate navigation queries. 22316 // Otherwise, invalidate the cache for the scenario where there were no Navigation 22317 // posts in the state and the fallback created one. 22318 const existingFallbackEntityRecord = select.getEntityRecord('postType', 'wp_navigation', fallback?.id); 22319 const invalidateNavigationQueries = !existingFallbackEntityRecord; 22320 dispatch.receiveEntityRecords('postType', 'wp_navigation', record, undefined, invalidateNavigationQueries); 22321 22322 // Resolve to avoid further network requests. 22323 dispatch.finishResolution('getEntityRecord', ['postType', 'wp_navigation', fallback?.id]); 22324 } 22325}; 22326 22327;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/utils.js 22328function deepCopyLocksTreePath(tree, path) { 22329 const newTree = { 22330 ...tree 22331 }; 22332 let currentNode = newTree; 22333 for (const branchName of path) { 22334 currentNode.children = { 22335 ...currentNode.children, 22336 [branchName]: { 22337 locks: [], 22338 children: {}, 22339 ...currentNode.children[branchName] 22340 } 22341 }; 22342 currentNode = currentNode.children[branchName]; 22343 } 22344 return newTree; 22345} 22346function getNode(tree, path) { 22347 let currentNode = tree; 22348 for (const branchName of path) { 22349 const nextNode = currentNode.children[branchName]; 22350 if (!nextNode) { 22351 return null; 22352 } 22353 currentNode = nextNode; 22354 } 22355 return currentNode; 22356} 22357function* iteratePath(tree, path) { 22358 let currentNode = tree; 22359 yield currentNode; 22360 for (const branchName of path) { 22361 const nextNode = currentNode.children[branchName]; 22362 if (!nextNode) { 22363 break; 22364 } 22365 yield nextNode; 22366 currentNode = nextNode; 22367 } 22368} 22369function* iterateDescendants(node) { 22370 const stack = Object.values(node.children); 22371 while (stack.length) { 22372 const childNode = stack.pop(); 22373 yield childNode; 22374 stack.push(...Object.values(childNode.children)); 22375 } 22376} 22377function hasConflictingLock({ 22378 exclusive 22379}, locks) { 22380 if (exclusive && locks.length) { 22381 return true; 22382 } 22383 if (!exclusive && locks.filter(lock => lock.exclusive).length) { 22384 return true; 22385 } 22386 return false;
22387} 22388 22389;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/reducer.js 22390/** 22391 * Internal dependencies 22392 */ 22393 22394const DEFAULT_STATE = { 22395 requests: [], 22396 tree: { 22397 locks: [], 22398 children: {} 22399 } 22400}; 22401 22402/** 22403 * Reducer returning locks. 22404 * 22405 * @param {Object} state Current state. 22406 * @param {Object} action Dispatched action. 22407 * 22408 * @return {Object} Updated state. 22409 */ 22410function locks(state = DEFAULT_STATE, action) { 22411 switch (action.type) { 22412 case 'ENQUEUE_LOCK_REQUEST': 22413 { 22414 const { 22415 request 22416 } = action; 22417 return { 22418 ...state, 22419 requests: [request, ...state.requests] 22420 }; 22421 } 22422 case 'GRANT_LOCK_REQUEST': 22423 { 22424 const { 22425 lock, 22426 request 22427 } = action; 22428 const { 22429 store, 22430 path 22431 } = request; 22432 const storePath = [store, ...path]; 22433 const newTree = deepCopyLocksTreePath(state.tree, storePath); 22434 const node = getNode(newTree, storePath); 22435 node.locks = [...node.locks, lock]; 22436 return { 22437 ...state, 22438 requests: state.requests.filter(r => r !== request), 22439 tree: newTree 22440 }; 22441 } 22442 case 'RELEASE_LOCK': 22443 { 22444 const { 22445 lock 22446 } = action; 22447 const storePath = [lock.store, ...lock.path]; 22448 const newTree = deepCopyLocksTreePath(state.tree, storePath); 22449 const node = getNode(newTree, storePath); 22450 node.locks = node.locks.filter(l => l !== lock); 22451 return { 22452 ...state, 22453 tree: newTree 22454 }; 22455 } 22456 } 22457 return state; 22458} 22459 22460;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/selectors.js 22461/** 22462 * Internal dependencies 22463 */ 22464 22465function getPendingLockRequests(state) { 22466 return state.requests; 22467} 22468function isLockAvailable(state, store, path, { 22469 exclusive 22470}) { 22471 const storePath = [store, ...path]; 22472 const locks = state.tree; 22473 22474 // Validate all parents and the node itself 22475 for (const node of iteratePath(locks, storePath)) { 22476 if (hasConflictingLock({ 22477 exclusive 22478 }, node.locks)) { 22479 return false; 22480 } 22481 } 22482 22483 // iteratePath terminates early if path is unreachable, let's 22484 // re-fetch the node and check it exists in the tree. 22485 const node = getNode(locks, storePath); 22486 if (!node) { 22487 return true; 22488 } 22489 22490 // Validate all nested nodes 22491 for (const descendant of iterateDescendants(node)) { 22492 if (hasConflictingLock({ 22493 exclusive 22494 }, descendant.locks)) { 22495 return false; 22496 } 22497 } 22498 return true; 22499} 22500 22501;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/engine.js 22502/** 22503 * Internal dependencies 22504 */ 22505 22506 22507function createLocks() { 22508 let state = locks(undefined, { 22509 type: '@@INIT' 22510 }); 22511 function processPendingLockRequests() { 22512 for (const request of getPendingLockRequests(state)) { 22513 const { 22514 store, 22515 path, 22516 exclusive, 22517 notifyAcquired 22518 } = request; 22519 if (isLockAvailable(state, store, path, { 22520 exclusive 22521 })) { 22522 const lock = { 22523 store, 22524 path, 22525 exclusive 22526 }; 22527 state = locks(state, { 22528 type: 'GRANT_LOCK_REQUEST', 22529 lock, 22530 request 22531 }); 22532 notifyAcquired(lock); 22533 } 22534 } 22535 } 22536 function acquire(store, path, exclusive) { 22537 return new Promise(resolve => { 22538 state = locks(state, { 22539 type: 'ENQUEUE_LOCK_REQUEST', 22540 request: { 22541 store, 22542 path, 22543 exclusive, 22544 notifyAcquired: resolve 22545 } 22546 }); 22547 processPendingLockRequests(); 22548 }); 22549 } 22550 function release(lock) { 22551 state = locks(state, { 22552 type: 'RELEASE_LOCK', 22553 lock 22554 }); 22555 processPendingLockRequests(); 22556 } 22557 return { 22558 acquire, 22559 release 22560 }; 22561} 22562 22563;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/actions.js 22564/** 22565 * Internal dependencies 22566 */ 22567 22568function createLocksActions() { 22569 const locks = createLocks(); 22570 function __unstableAcquireStoreLock(store, path, { 22571 exclusive 22572 }) { 22573 return () => locks.acquire(store, path, exclusive); 22574 } 22575 function __unstableReleaseStoreLock(lock) { 22576 return () => locks.release(lock); 22577 } 22578 return { 22579 __unstableAcquireStoreLock, 22580 __unstableReleaseStoreLock 22581 }; 22582} 22583 22584;
22584// CONCATENATED MODULE: external ["wp","privateApis"] 22585const external_wp_privateApis_namespaceObject = window["wp"]["privateApis"]; 22586;// CONCATENATED MODULE: ./packages/core-data/build-module/private-apis.js 22587/** 22588 * WordPress dependencies 22589 */ 22590 22591const { 22592 lock, 22593 unlock 22594} = (0,external_wp_privateApis_namespaceObject.__dangerousOptInToUnstableAPIsOnlyForCoreModules)('I know using unstable features means my theme or plugin will inevitably break in the next version of WordPress.', '@wordpress/core-data'); 22595 22596;// CONCATENATED MODULE: external ["wp","element"] 22597const external_wp_element_namespaceObject = window["wp"]["element"]; 22598;// CONCATENATED MODULE: external ["wp","blocks"] 22599const external_wp_blocks_namespaceObject = window["wp"]["blocks"]; 22600;// CONCATENATED MODULE: external ["wp","blockEditor"] 22601const external_wp_blockEditor_namespaceObject = window["wp"]["blockEditor"]; 22602;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/get-rich-text-values-cached.js 22603/** 22604 * WordPress dependencies 22605 */ 22606 22607 22608/** 22609 * Internal dependencies 22610 */ 22611 22612 22613// TODO: The following line should have been: 22614// 22615// const unlockedApis = unlock( blockEditorPrivateApis ); 22616// 22617// But there are hidden circular dependencies in RNMobile code, specifically in 22618// certain native components in the `components` package that depend on 22619// `block-editor`. What follows is a workaround that defers the `unlock` call 22620// to prevent native code from failing. 22621// 22622// Fix once https://github.com/WordPress/gutenberg/issues/52692 is closed. 22623let unlockedApis; 22624const cache = new WeakMap(); 22625function getRichTextValuesCached(block) { 22626 if (!unlockedApis) { 22627 unlockedApis = unlock(external_wp_blockEditor_namespaceObject.privateApis); 22628 } 22629 if (!cache.has(block)) { 22630 const values = unlockedApis.getRichTextValues([block]); 22631 cache.set(block, values); 22632 } 22633 return cache.get(block); 22634} 22635 22636;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/get-footnotes-order.js 22637/** 22638 * Internal dependencies 22639 */ 22640 22641const get_footnotes_order_cache = new WeakMap(); 22642function getBlockFootnotesOrder(block) { 22643 if (!get_footnotes_order_cache.has(block)) { 22644 const content = getRichTextValuesCached(block).join(''); 22645 const newOrder = []; 22646 22647 // https://github.com/WordPress/gutenberg/pull/43204 lands. We can then 22648 // get the order directly from the rich text values. 22649 if (content.indexOf('data-fn') !== -1) { 22650 const regex = /data-fn="([^"]+)"/g; 22651 let match; 22652 while ((match = regex.exec(content)) !== null) { 22653 newOrder.push(match[1]); 22654 } 22655 } 22656 get_footnotes_order_cache.set(block, newOrder); 22657 } 22658 return get_footnotes_order_cache.get(block); 22659} 22660function getFootnotesOrder(blocks) { 22661 return blocks.flatMap(getBlockFootnotesOrder); 22662} 22663 22664;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/index.js 22665/** 22666 * Internal dependencies 22667 */ 22668 22669let oldFootnotes = {}; 22670function updateFootnotesFromMeta(blocks, meta) { 22671 const output = { 22672 blocks 22673 }; 22674 if (!meta) return output; 22675 22676 // If meta.footnotes is empty, it means the meta is not registered. 22677 if (meta.footnotes === undefined) return output; 22678 const newOrder = getFootnotesOrder(blocks); 22679 const footnotes = meta.footnotes ? JSON.parse(meta.footnotes) : []; 22680 const currentOrder = footnotes.map(fn => fn.id); 22681 if (currentOrder.join('') === newOrder.join('')) return output; 22682 const newFootnotes = newOrder.map(fnId => footnotes.find(fn => fn.id === fnId) || oldFootnotes[fnId] || { 22683 id: fnId, 22684 content: '' 22685 }); 22686 function updateAttributes(attributes) { 22687 // Only attempt to update attributes, if attributes is an object. 22688 if (!attributes || Array.isArray(attributes) || typeof attributes !== 'object') { 22689 return attributes; 22690 } 22691 attributes = { 22692 ...attributes 22693 }; 22694 for (const key in attributes) { 22695 const value = attributes[key]; 22696 if (Array.isArray(value)) { 22697 attributes[key] = value.map(updateAttributes); 22698 continue; 22699 } 22700 if (typeof value !== 'string') { 22701 continue; 22702 } 22703 if (value.indexOf('data-fn') === -1) { 22704 continue; 22705 } 22706 22707 // When we store rich text values, this would no longer 22708 // require a regex. 22709 const regex = /(<sup[^>]+data-fn="([^"]+)"[^>]*><a[^>]*>)[\d*]*<\/a><\/sup>/g; 22710 attributes[key] = value.replace(regex, (match, opening, fnId) => { 22711 const index = newOrder.indexOf(fnId); 22712 return `${opening}${index + 1}</a></sup>`;
22713 }); 22714 const compatRegex = /<a[^>]+data-fn="([^"]+)"[^>]*>\*<\/a>/g; 22715 attributes[key] = attributes[key].replace(compatRegex, (match, fnId) => { 22716 const index = newOrder.indexOf(fnId); 22717 return `<sup data-fn="${fnId}" class="fn"><a href="#${fnId}" id="${fnId}-link">${index + 1}</a></sup>`; 22718 }); 22719 } 22720 return attributes; 22721 } 22722 function updateBlocksAttributes(__blocks) { 22723 return __blocks.map(block => { 22724 return { 22725 ...block, 22726 attributes: updateAttributes(block.attributes), 22727 innerBlocks: updateBlocksAttributes(block.innerBlocks) 22728 }; 22729 }); 22730 } 22731 22732 // We need to go through all block attributes deeply and update the 22733 // footnote anchor numbering (textContent) to match the new order. 22734 const newBlocks = updateBlocksAttributes(blocks); 22735 oldFootnotes = { 22736 ...oldFootnotes, 22737 ...footnotes.reduce((acc, fn) => { 22738 if (!newOrder.includes(fn.id)) { 22739 acc[fn.id] = fn; 22740 } 22741 return acc; 22742 }, {}) 22743 }; 22744 return { 22745 meta: { 22746 ...meta, 22747 footnotes: JSON.stringify(newFootnotes) 22748 }, 22749 blocks: newBlocks 22750 }; 22751} 22752 22753;// CONCATENATED MODULE: ./packages/core-data/build-module/entity-provider.js 22754 22755/** 22756 * WordPress dependencies 22757 */ 22758 22759 22760 22761 22762/** 22763 * Internal dependencies 22764 */ 22765 22766 22767 22768/** @typedef {import('@wordpress/blocks').WPBlock} WPBlock */ 22769 22770const EMPTY_ARRAY = []; 22771 22772/** 22773 * Internal dependencies 22774 */ 22775 22776const entityContexts = { 22777 ...rootEntitiesConfig.reduce((acc, loader) => { 22778 if (!acc[loader.kind]) { 22779 acc[loader.kind] = {}; 22780 } 22781 acc[loader.kind][loader.name] = { 22782 context: (0,external_wp_element_namespaceObject.createContext)(undefined) 22783 }; 22784 return acc; 22785 }, {}), 22786 ...additionalEntityConfigLoaders.reduce((acc, loader) => { 22787 acc[loader.kind] = {}; 22788 return acc; 22789 }, {}) 22790}; 22791const getEntityContext = (kind, name) => { 22792 if (!entityContexts[kind]) { 22793 throw new Error(`Missing entity config for kind: ${kind}.`); 22794 } 22795 if (!entityContexts[kind][name]) { 22796 entityContexts[kind][name] = { 22797 context: (0,external_wp_element_namespaceObject.createContext)(undefined) 22798 }; 22799 } 22800 return entityContexts[kind][name].context; 22801}; 22802 22803/** 22804 * Context provider component for providing 22805 * an entity for a specific entity. 22806 * 22807 * @param {Object} props The component's props. 22808 * @param {string} props.kind The entity kind. 22809 * @param {string} props.type The entity name. 22810 * @param {number} props.id The entity ID. 22811 * @param {*} props.children The children to wrap. 22812 * 22813 * @return {Object} The provided children, wrapped with 22814 * the entity's context provider. 22815 */ 22816function EntityProvider({ 22817 kind, 22818 type: name, 22819 id, 22820 children 22821}) { 22822 const Provider = getEntityContext(kind, name).Provider; 22823 return (0,external_wp_element_namespaceObject.createElement)(Provider, { 22824 value: id 22825 }, children); 22826} 22827 22828/** 22829 * Hook that returns the ID for the nearest 22830 * provided entity of the specified type. 22831 * 22832 * @param {string} kind The entity kind. 22833 * @param {string} name The entity name. 22834 */ 22835function useEntityId(kind, name) { 22836 return (0,external_wp_element_namespaceObject.useContext)(getEntityContext(kind, name)); 22837} 22838 22839/** 22840 * Hook that returns the value and a setter for the 22841 * specified property of the nearest provided 22842 * entity of the specified type. 22843 * 22844 * @param {string} kind The entity kind. 22845 * @param {string} name The entity name. 22846 * @param {string} prop The property name. 22847 * @param {string} [_id] An entity ID to use instead of the context-provided one. 22848 * 22849 * @return {[*, Function, *]} An array where the first item is the 22850 * property value, the second is the 22851 * setter and the third is the full value 22852 * object from REST API containing more 22853 * information like `raw`, `rendered` and 22854 * `protected` props. 22855 */ 22856function useEntityProp(kind, name, prop, _id) { 22857 const providerId = useEntityId(kind, name); 22858 const id = _id !== null && _id !== void 0 ? _id : providerId; 22859 const { 22860 value, 22861 fullValue 22862 } = (0,external_wp_data_namespaceObject.useSelect)(select => { 22863 const { 22864 getEntityRecord, 22865 getEditedEntityRecord 22866 } = select(STORE_NAME); 22867 const record = getEntityRecord(kind, name, id);
22867 // Trigger resolver. 22868 const editedRecord = getEditedEntityRecord(kind, name, id); 22869 return record && editedRecord ? { 22870 value: editedRecord[prop], 22871 fullValue: record[prop] 22872 } : {}; 22873 }, [kind, name, id, prop]); 22874 const { 22875 editEntityRecord 22876 } = (0,external_wp_data_namespaceObject.useDispatch)(STORE_NAME); 22877 const setValue = (0,external_wp_element_namespaceObject.useCallback)(newValue => { 22878 editEntityRecord(kind, name, id, { 22879 [prop]: newValue 22880 }); 22881 }, [editEntityRecord, kind, name, id, prop]); 22882 return [value, setValue, fullValue]; 22883} 22884 22885/** 22886 * Hook that returns block content getters and setters for 22887 * the nearest provided entity of the specified type. 22888 * 22889 * The return value has the shape `[ blocks, onInput, onChange ]`. 22890 * `onInput` is for block changes that don't create undo levels 22891 * or dirty the post, non-persistent changes, and `onChange` is for 22892 * persistent changes. They map directly to the props of a 22893 * `BlockEditorProvider` and are intended to be used with it, 22894 * or similar components or hooks. 22895 * 22896 * @param {string} kind The entity kind. 22897 * @param {string} name The entity name. 22898 * @param {Object} options 22899 * @param {string} [options.id] An entity ID to use instead of the context-provided one. 22900 * 22901 * @return {[WPBlock[], Function, Function]} The block array and setters. 22902 */ 22903function useEntityBlockEditor(kind, name, { 22904 id: _id 22905} = {}) { 22906 const providerId = useEntityId(kind, name); 22907 const id = _id !== null && _id !== void 0 ? _id : providerId; 22908 const { 22909 content, 22910 editedBlocks, 22911 meta 22912 } = (0,external_wp_data_namespaceObject.useSelect)(select => { 22913 const { 22914 getEditedEntityRecord 22915 } = select(STORE_NAME); 22916 const editedRecord = getEditedEntityRecord(kind, name, id); 22917 return { 22918 editedBlocks: editedRecord.blocks, 22919 content: editedRecord.content, 22920 meta: editedRecord.meta 22921 }; 22922 }, [kind, name, id]); 22923 const { 22924 __unstableCreateUndoLevel, 22925 editEntityRecord 22926 } = (0,external_wp_data_namespaceObject.useDispatch)(STORE_NAME); 22927 const blocks = (0,external_wp_element_namespaceObject.useMemo)(() => { 22928 if (editedBlocks) { 22929 return editedBlocks; 22930 } 22931 return content && typeof content !== 'function' ? (0,external_wp_blocks_namespaceObject.parse)(content) : EMPTY_ARRAY; 22932 }, [editedBlocks, content]); 22933 const updateFootnotes = (0,external_wp_element_namespaceObject.useCallback)(_blocks => updateFootnotesFromMeta(_blocks, meta), [meta]); 22934 const onChange = (0,external_wp_element_namespaceObject.useCallback)((newBlocks, options) => { 22935 const noChange = blocks === newBlocks; 22936 if (noChange) { 22937 return __unstableCreateUndoLevel(kind, name, id); 22938 } 22939 const { 22940 selection 22941 } = options; 22942 22943 // We create a new function here on every persistent edit 22944 // to make sure the edit makes the post dirty and creates 22945 // a new undo level. 22946 const edits = { 22947 selection, 22948 content: ({ 22949 blocks: blocksForSerialization = [] 22950 }) => (0,external_wp_blocks_namespaceObject.__unstableSerializeAndClean)(blocksForSerialization), 22951 ...updateFootnotes(newBlocks) 22952 }; 22953 editEntityRecord(kind, name, id, edits, { 22954 isCached: false 22955 }); 22956 }, [kind, name, id, blocks, updateFootnotes, __unstableCreateUndoLevel, editEntityRecord]); 22957 const onInput = (0,external_wp_element_namespaceObject.useCallback)((newBlocks, options) => { 22958 const { 22959 selection 22960 } = options; 22961 const footnotesChanges = updateFootnotes(newBlocks); 22962 const edits = { 22963 selection, 22964 ...footnotesChanges 22965 }; 22966 editEntityRecord(kind, name, id, edits, { 22967 isCached: true 22968 }); 22969 }, [kind, name, id, updateFootnotes, editEntityRecord]); 22970 return [blocks, onInput, onChange]; 22971} 22972 22973;// CONCATENATED MODULE: external ["wp","htmlEntities"] 22974const external_wp_htmlEntities_namespaceObject = window["wp"]["htmlEntities"]; 22975;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/__experimental-fetch-link-suggestions.js 22976/** 22977 * WordPress dependencies 22978 */ 22979 22980 22981 22982 22983 22984/** 22985 * Filters the search by type 22986 * 22987 * @typedef { 'attachment' | 'post' | 'term' | 'post-format' } WPLinkSearchType 22988 */ 22989 22990/** 22991 * A link with an id may be of kind post-type or taxonomy 22992 * 22993 * @typedef { 'post-type' | 'taxonomy' } WPKind 22994 */ 22995
22996/** 22997 * @typedef WPLinkSearchOptions 22998 * 22999 * @property {boolean} [isInitialSuggestions] Displays initial search suggestions, when true. 23000 * @property {WPLinkSearchType} [type] Filters by search type. 23001 * @property {string} [subtype] Slug of the post-type or taxonomy. 23002 * @property {number} [page] Which page of results to return. 23003 * @property {number} [perPage] Search results per page. 23004 */ 23005 23006/** 23007 * @typedef WPLinkSearchResult 23008 * 23009 * @property {number} id Post or term id. 23010 * @property {string} url Link url. 23011 * @property {string} title Title of the link. 23012 * @property {string} type The taxonomy or post type slug or type URL. 23013 * @property {WPKind} [kind] Link kind of post-type or taxonomy 23014 */ 23015 23016/** 23017 * @typedef WPLinkSearchResultAugments 23018 * 23019 * @property {{kind: WPKind}} [meta] Contains kind information. 23020 * @property {WPKind} [subtype] Optional subtype if it exists. 23021 */ 23022 23023/** 23024 * @typedef {WPLinkSearchResult & WPLinkSearchResultAugments} WPLinkSearchResultAugmented 23025 */ 23026 23027/** 23028 * @typedef WPEditorSettings 23029 * 23030 * @property {boolean} [ disablePostFormats ] Disables post formats, when true. 23031 */ 23032 23033/** 23034 * Fetches link suggestions from the API. 23035 * 23036 * @async 23037 * @param {string} search 23038 * @param {WPLinkSearchOptions} [searchOptions] 23039 * @param {WPEditorSettings} [settings] 23040 * 23041 * @example 23042 * ```js 23043 * import { __experimentalFetchLinkSuggestions as fetchLinkSuggestions } from '@wordpress/core-data'; 23044 * 23045 * //... 23046 * 23047 * export function initialize( id, settings ) { 23048 * 23049 * settings.__experimentalFetchLinkSuggestions = ( 23050 * search, 23051 * searchOptions 23052 * ) => fetchLinkSuggestions( search, searchOptions, settings ); 23053 * ``` 23054 * @return {Promise< WPLinkSearchResult[] >} List of search suggestions 23055 */ 23056const fetchLinkSuggestions = async (search, searchOptions = {}, settings = {}) => { 23057 const { 23058 isInitialSuggestions = false, 23059 type = undefined, 23060 subtype = undefined, 23061 page = undefined, 23062 perPage = isInitialSuggestions ? 3 : 20 23063 } = searchOptions; 23064 const { 23065 disablePostFormats = false 23066 } = settings; 23067 23068 /** @type {Promise<WPLinkSearchResult>[]} */ 23069 const queries = []; 23070 if (!type || type === 'post') { 23071 queries.push(external_wp_apiFetch_default()({ 23072 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', { 23073 search, 23074 page, 23075 per_page: perPage, 23076 type: 'post', 23077 subtype 23078 }) 23079 }).then(results => { 23080 return results.map(result => { 23081 return { 23082 ...result, 23083 meta: { 23084 kind: 'post-type', 23085 subtype 23086 } 23087 }; 23088 }); 23089 }).catch(() => []) // Fail by returning no results. 23090 ); 23091 } 23092 23093 if (!type || type === 'term') { 23094 queries.push(external_wp_apiFetch_default()({ 23095 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', { 23096 search, 23097 page, 23098 per_page: perPage, 23099 type: 'term', 23100 subtype 23101 }) 23102 }).then(results => { 23103 return results.map(result => { 23104 return { 23105 ...result, 23106 meta: { 23107 kind: 'taxonomy', 23108 subtype 23109 } 23110 }; 23111 }); 23112 }).catch(() => []) // Fail by returning no results. 23113 ); 23114 } 23115 23116 if (!disablePostFormats && (!type || type === 'post-format')) { 23117 queries.push(external_wp_apiFetch_default()({ 23118 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', { 23119 search, 23120 page, 23121 per_page: perPage, 23122 type: 'post-format', 23123 subtype 23124 }) 23125 }).then(results => { 23126 return results.map(result => { 23127 return { 23128 ...result, 23129 meta: { 23130 kind: 'taxonomy', 23131 subtype 23132 } 23133 }; 23134 }); 23135 }).catch(() => []) // Fail by returning no results. 23136 ); 23137 } 23138 23139 if (!type || type === 'attachment') { 23140 queries.push(external_wp_apiFetch_default()({ 23141 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/media', { 23142 search, 23143 page, 23144 per_page: perPage 23145 }) 23146 }).then(results => { 23147 return results.map(result => { 23148 return { 23149 ...result, 23150 meta: { 23151 kind: 'media' 23152 } 23153 }; 23154 }); 23155 }).catch(() => []) // Fail by returning no results. 23156 ); 23157 } 23158 23159 return Promise.all(queries).then(results => { 23160 return results.reduce(( /** @type {WPLinkSearchResult[]} */accumulator, current) => accumulator.concat(current), 23161 // Flatten list. 23162 []).filter( 23163 /** 23164 * @param {{ id: number }} result 23165 */ 23166 result => { 23167 return !!result.id; 23168 }).slice(0, perPage).map(( /** @type {WPLinkSearchResultAugmented} */result) => { 23169 const isMedia = result.type === 'attachment'; 23170 return { 23171 id: result.id, 23172 // @ts-ignore fix when we make this a TS file 23173 url: isMedia ? result.source_url : result.url, 23174 title: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(isMedia ? 23175 // @ts-ignore fix when we make this a TS file 23176 result.title.rendered : result.title || '') || (0,external_wp_i18n_namespaceObject.__)('(no title)'), 23177 type: result.subtype || result.type, 23178 kind: result?.meta?.kind 23179 }; 23180 }); 23181 }); 23182}; 23183/* harmony default export */ const _experimental_fetch_link_suggestions = (fetchLinkSuggestions); 23184 23185;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/__experimental-fetch-url-data.js 23186/** 23187 * WordPress dependencies 23188 */ 23189 23190 23191 23192/** 23193 * A simple in-memory cache for requests.
23194 * This avoids repeat HTTP requests which may be beneficial 23195 * for those wishing to preserve low-bandwidth. 23196 */ 23197const CACHE = new Map(); 23198 23199/** 23200 * @typedef WPRemoteUrlData 23201 * 23202 * @property {string} title contents of the remote URL's `<title>` tag. 23203 */ 23204 23205/** 23206 * Fetches data about a remote URL. 23207 * eg: <title> tag, favicon...etc. 23208 * 23209 * @async 23210 * @param {string} url the URL to request details from. 23211 * @param {Object?} options any options to pass to the underlying fetch. 23212 * @example 23213 * ```js 23214 * import { __experimentalFetchUrlData as fetchUrlData } from '@wordpress/core-data'; 23215 * 23216 * //... 23217 * 23218 * export function initialize( id, settings ) { 23219 * 23220 * settings.__experimentalFetchUrlData = ( 23221 * url 23222 * ) => fetchUrlData( url ); 23223 * ``` 23224 * @return {Promise< WPRemoteUrlData[] >} Remote URL data. 23225 */ 23226const fetchUrlData = async (url, options = {}) => { 23227 const endpoint = '/wp-block-editor/v1/url-details'; 23228 const args = { 23229 url: (0,external_wp_url_namespaceObject.prependHTTP)(url) 23230 }; 23231 if (!(0,external_wp_url_namespaceObject.isURL)(url)) { 23232 return Promise.reject(`${url} is not a valid URL.`); 23233 } 23234 23235 // Test for "http" based URL as it is possible for valid 23236 // yet unusable URLs such as `tel:123456` to be passed. 23237 const protocol = (0,external_wp_url_namespaceObject.getProtocol)(url); 23238 if (!protocol || !(0,external_wp_url_namespaceObject.isValidProtocol)(protocol) || !protocol.startsWith('http') || !/^https?:\/\/[^\/\s]/i.test(url)) { 23239 return Promise.reject(`${url} does not have a valid protocol. URLs must be "http" based`); 23240 } 23241 if (CACHE.has(url)) { 23242 return CACHE.get(url); 23243 } 23244 return external_wp_apiFetch_default()({ 23245 path: (0,external_wp_url_namespaceObject.addQueryArgs)(endpoint, args), 23246 ...options 23247 }).then(res => { 23248 CACHE.set(url, res); 23249 return res; 23250 }); 23251}; 23252/* harmony default export */ const _experimental_fetch_url_data = (fetchUrlData); 23253 23254;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/index.js 23255 23256 23257 23258;// CONCATENATED MODULE: ./node_modules/memize/dist/index.js 23259/** 23260 * Memize options object. 23261 * 23262 * @typedef MemizeOptions 23263 * 23264 * @property {number} [maxSize] Maximum size of the cache. 23265 */ 23266 23267/** 23268 * Internal cache entry. 23269 * 23270 * @typedef MemizeCacheNode 23271 * 23272 * @property {?MemizeCacheNode|undefined} [prev] Previous node. 23273 * @property {?MemizeCacheNode|undefined} [next] Next node. 23274 * @property {Array<*>} args Function arguments for cache 23275 * entry. 23276 * @property {*} val Function result. 23277 */ 23278 23279/** 23280 * Properties of the enhanced function for controlling cache. 23281 * 23282 * @typedef MemizeMemoizedFunction 23283 * 23284 * @property {()=>void} clear Clear the cache. 23285 */ 23286 23287/** 23288 * Accepts a function to be memoized, and returns a new memoized function, with 23289 * optional options. 23290 * 23291 * @template {(...args: any[]) => any} F 23292 * 23293 * @param {F} fn Function to memoize. 23294 * @param {MemizeOptions} [options] Options object. 23295 * 23296 * @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function. 23297 */ 23298function memize(fn, options) { 23299 var size = 0; 23300 23301 /** @type {?MemizeCacheNode|undefined} */ 23302 var head; 23303 23304 /** @type {?MemizeCacheNode|undefined} */ 23305 var tail; 23306 23307 options = options || {}; 23308 23309 function memoized(/* ...args */) { 23310 var node = head, 23311 len = arguments.length, 23312 args, 23313 i; 23314 23315 searchCache: while (node) { 23316 // Perform a shallow equality test to confirm that whether the node 23317 // under test is a candidate for the arguments passed. Two arrays 23318 // are shallowly equal if their length matches and each entry is 23319 // strictly equal between the two sets. Avoid abstracting to a 23320 // function which could incur an arguments leaking deoptimization. 23321 23322 // Check whether node arguments match arguments length 23323 if (node.args.length !== arguments.length) { 23324 node = node.next; 23325 continue; 23326 } 23327 23328 // Check whether node arguments match arguments values 23329 for (i = 0; i < len; i++) { 23330 if (node.args[i] !== arguments[i]) { 23331 node = node.next; 23332 continue searchCache; 23333 } 23334 } 23335 23336 // At this point we can assume we've found a match 23337 23338 // Surface matched node to head if not already 23339 if (node !== head) { 23340 // As tail, shift to previous. Must only shift if not also 23341 // head, since if both head and tail, there is no previous. 23342 if (node === tail) { 23343 tail = node.prev; 23344 } 23345 23346 // Adjust siblings to point to each other. If node was tail, 23347 // this also handles new tail's empty `next` assignment. 23348 /** @type {MemizeCacheNode} */ (node.prev).next = node.next; 23349 if (node.next) { 23350 node.next.prev = node.prev; 23351 } 23352 23353 node.next = head; 23354 node.prev = null; 23355 /** @type {MemizeCacheNode} */ (head).prev = node; 23356 head = node; 23357 } 23358 23359 // Return immediately 23360 return node.val; 23361 } 23362 23363 // No cached value found. Continue to insertion phase: 23364 23365 // Create a copy of arguments (avoid leaking deoptimization) 23366 args = new Array(len); 23367 for (i = 0; i < len; i++) { 23368 args[i] = arguments[i]; 23369 } 23370 23371 node = { 23372 args: args, 23373 23374 // Generate the result from original function
23375 val: fn.apply(null, args), 23376 }; 23377 23378 // Don't need to check whether node is already head, since it would 23379 // have been returned above already if it was 23380 23381 // Shift existing head down list 23382 if (head) { 23383 head.prev = node; 23384 node.next = head; 23385 } else { 23386 // If no head, follows that there's no tail (at initial or reset) 23387 tail = node; 23388 } 23389 23390 // Trim tail if we're reached max size and are pending cache insertion 23391 if (size === /** @type {MemizeOptions} */ (options).maxSize) { 23392 tail = /** @type {MemizeCacheNode} */ (tail).prev; 23393 /** @type {MemizeCacheNode} */ (tail).next = null; 23394 } else { 23395 size++; 23396 } 23397 23398 head = node; 23399 23400 return node.val; 23401 } 23402 23403 memoized.clear = function () { 23404 head = null; 23405 tail = null; 23406 size = 0; 23407 }; 23408 23409 // Ignore reason: There's not a clear solution to create an intersection of 23410 // the function with additional properties, where the goal is to retain the 23411 // function signature of the incoming argument and add control properties 23412 // on the return value. 23413 23414 // @ts-ignore 23415 return memoized; 23416} 23417 23418 23419 23420;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/memoize.js 23421/** 23422 * External dependencies 23423 */ 23424 23425 23426// re-export due to restrictive esModuleInterop setting 23427/* harmony default export */ const memoize = (memize); 23428 23429;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/constants.js 23430let Status = /*#__PURE__*/function (Status) { 23431 Status["Idle"] = "IDLE"; 23432 Status["Resolving"] = "RESOLVING"; 23433 Status["Error"] = "ERROR"; 23434 Status["Success"] = "SUCCESS"; 23435 return Status; 23436}({}); 23437 23438;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-query-select.js 23439/** 23440 * WordPress dependencies 23441 */ 23442 23443 23444/** 23445 * Internal dependencies 23446 */ 23447 23448 23449const META_SELECTORS = ['getIsResolving', 'hasStartedResolution', 'hasFinishedResolution', 'isResolving', 'getCachedResolvers']; 23450/** 23451 * Like useSelect, but the selectors return objects containing 23452 * both the original data AND the resolution info. 23453 * 23454 * @since 6.1.0 Introduced in WordPress core. 23455 * @private 23456 * 23457 * @param {Function} mapQuerySelect see useSelect 23458 * @param {Array} deps see useSelect 23459 * 23460 * @example 23461 * ```js 23462 * import { useQuerySelect } from '@wordpress/data'; 23463 * import { store as coreDataStore } from '@wordpress/core-data'; 23464 * 23465 * function PageTitleDisplay( { id } ) { 23466 * const { data: page, isResolving } = useQuerySelect( ( query ) => { 23467 * return query( coreDataStore ).getEntityRecord( 'postType', 'page', id ) 23468 * }, [ id ] ); 23469 * 23470 * if ( isResolving ) { 23471 * return 'Loading...'; 23472 * } 23473 * 23474 * return page.title; 23475 * } 23476 * 23477 * // Rendered in the application: 23478 * // <PageTitleDisplay id={ 10 } /> 23479 * ``` 23480 * 23481 * In the above example, when `PageTitleDisplay` is rendered into an 23482 * application, the page and the resolution details will be retrieved from 23483 * the store state using the `mapSelect` callback on `useQuerySelect`. 23484 * 23485 * If the id prop changes then any page in the state for that id is 23486 * retrieved. If the id prop doesn't change and other props are passed in 23487 * that do change, the title will not change because the dependency is just 23488 * the id. 23489 * @see useSelect 23490 * 23491 * @return {QuerySelectResponse} Queried data. 23492 */ 23493function useQuerySelect(mapQuerySelect, deps) { 23494 return (0,external_wp_data_namespaceObject.useSelect)((select, registry) => { 23495 const resolve = store => enrichSelectors(select(store)); 23496 return mapQuerySelect(resolve, registry); 23497 }, deps); 23498} 23499/** 23500 * Transform simple selectors into ones that return an object with the 23501 * original return value AND the resolution info. 23502 * 23503 * @param {Object} selectors Selectors to enrich 23504 * @return {EnrichedSelectors} Enriched selectors 23505 */ 23506const enrichSelectors = memoize(selectors => { 23507 const resolvers = {}; 23508 for (const selectorName in selectors) { 23509 if (META_SELECTORS.includes(selectorName)) { 23510 continue; 23511 } 23512 Object.defineProperty(resolvers, selectorName, { 23513 get: () => (...args) => { 23514 const { 23515 getIsResolving, 23516 hasFinishedResolution 23517 } = selectors; 23518 const isResolving = !!getIsResolving(selectorName, args);
23519 const hasResolved = !isResolving && hasFinishedResolution(selectorName, args); 23520 const data = selectors[selectorName](...args); 23521 let status; 23522 if (isResolving) { 23523 status = Status.Resolving; 23524 } else if (hasResolved) { 23525 if (data) { 23526 status = Status.Success; 23527 } else { 23528 status = Status.Error; 23529 } 23530 } else { 23531 status = Status.Idle; 23532 } 23533 return { 23534 data, 23535 status, 23536 isResolving, 23537 hasResolved 23538 }; 23539 } 23540 }); 23541 } 23542 return resolvers; 23543}); 23544 23545;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-entity-record.js 23546/** 23547 * WordPress dependencies 23548 */ 23549 23550 23551 23552 23553/** 23554 * Internal dependencies 23555 */ 23556 23557 23558/** 23559 * Resolves the specified entity record. 23560 * 23561 * @since 6.1.0 Introduced in WordPress core. 23562 * 23563 * @param kind Kind of the entity, e.g. `root` or a `postType`. See rootEntitiesConfig in ../entities.ts for a list of available kinds. 23564 * @param name Name of the entity, e.g. `plugin` or a `post`. See rootEntitiesConfig in ../entities.ts for a list of available names. 23565 * @param recordId ID of the requested entity record. 23566 * @param options Optional hook options. 23567 * @example 23568 * ```js 23569 * import { useEntityRecord } from '@wordpress/core-data'; 23570 * 23571 * function PageTitleDisplay( { id } ) { 23572 * const { record, isResolving } = useEntityRecord( 'postType', 'page', id ); 23573 * 23574 * if ( isResolving ) { 23575 * return 'Loading...'; 23576 * } 23577 * 23578 * return record.title; 23579 * } 23580 * 23581 * // Rendered in the application: 23582 * // <PageTitleDisplay id={ 1 } /> 23583 * ``` 23584 * 23585 * In the above example, when `PageTitleDisplay` is rendered into an 23586 * application, the page and the resolution details will be retrieved from 23587 * the store state using `getEntityRecord()`, or resolved if missing. 23588 * 23589 * @example 23590 * ```js 23591 * import { useDispatch } from '@wordpress/data'; 23592 * import { useCallback } from '@wordpress/element'; 23593 * import { __ } from '@wordpress/i18n'; 23594 * import { TextControl } from '@wordpress/components'; 23595 * import { store as noticeStore } from '@wordpress/notices'; 23596 * import { useEntityRecord } from '@wordpress/core-data'; 23597 * 23598 * function PageRenameForm( { id } ) { 23599 * const page = useEntityRecord( 'postType', 'page', id ); 23600 * const { createSuccessNotice, createErrorNotice } = 23601 * useDispatch( noticeStore ); 23602 * 23603 * const setTitle = useCallback( ( title ) => { 23604 * page.edit( { title } ); 23605 * }, [ page.edit ] ); 23606 * 23607 * if ( page.isResolving ) { 23608 * return 'Loading...'; 23609 * } 23610 * 23611 * async function onRename( event ) { 23612 * event.preventDefault(); 23613 * try { 23614 * await page.save(); 23615 * createSuccessNotice( __( 'Page renamed.' ), { 23616 * type: 'snackbar', 23617 * } ); 23618 * } catch ( error ) { 23619 * createErrorNotice( error.message, { type: 'snackbar' } ); 23620 * } 23621 * } 23622 * 23623 * return ( 23624 * <form onSubmit={ onRename }> 23625 * <TextControl 23626 * label={ __( 'Name' ) } 23627 * value={ page.editedRecord.title } 23628 * onChange={ setTitle } 23629 * /> 23630 * <button type="submit">{ __( 'Save' ) }</button> 23631 * </form> 23632 * ); 23633 * } 23634 * 23635 * // Rendered in the application: 23636 * // <PageRenameForm id={ 1 } /> 23637 * ``` 23638 * 23639 * In the above example, updating and saving the page title is handled 23640 * via the `edit()` and `save()` mutation helpers provided by 23641 * `useEntityRecord()`; 23642 * 23643 * @return Entity record data. 23644 * @template RecordType 23645 */ 23646function useEntityRecord(kind, name, recordId, options = { 23647 enabled: true 23648}) { 23649 const { 23650 editEntityRecord, 23651 saveEditedEntityRecord 23652 } = (0,external_wp_data_namespaceObject.useDispatch)(store); 23653 const mutations = (0,external_wp_element_namespaceObject.useMemo)(() => ({ 23654 edit: (record, editOptions = {}) => editEntityRecord(kind, name, recordId, record, editOptions), 23655 save: (saveOptions = {}) => saveEditedEntityRecord(kind, name, recordId, { 23656 throwOnError: true, 23657 ...saveOptions 23658 }) 23659 }), [editEntityRecord, kind, name, recordId, saveEditedEntityRecord]); 23660 const { 23661 editedRecord, 23662 hasEdits, 23663 edits 23664 } = (0,external_wp_data_namespaceObject.useSelect)(select => ({ 23665 editedRecord: select(store).getEditedEntityRecord(kind, name, recordId), 23666 hasEdits: select(store).hasEditsForEntityRecord(kind, name, recordId), 23667 edits: select(store).getEntityRecordNonTransientEdits(kind, name, recordId) 23668 }), [kind, name, recordId]); 23669 const { 23670 data: record, 23671 ...querySelectRest 23672 } = useQuerySelect(query => { 23673 if (!options.enabled) { 23674 return { 23675 data: null 23676 }; 23677 } 23678 return query(store).getEntityRecord(kind, name, recordId); 23679 }, [kind, name, recordId, options.enabled]); 23680 return { 23681 record, 23682 editedRecord, 23683 hasEdits, 23684 edits, 23685 ...querySelectRest, 23686 ...mutations 23687 }; 23688} 23689function __experimentalUseEntityRecord(kind, name, recordId, options) { 23690 external_wp_deprecated_default()(`wp.data.__experimentalUseEntityRecord`, { 23691 alternative: 'wp.data.useEntityRecord', 23692 since: '6.1' 23693 }); 23694 return useEntityRecord(kind, name, recordId, options); 23695} 23696 23697;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-entity-records.js 23698/** 23699 * WordPress dependencies 23700 */ 23701 23702 23703 23704/** 23705 * Internal dependencies 23706 */ 23707 23708 23709const use_entity_records_EMPTY_ARRAY = []; 23710 23711/** 23712 * Resolves the specified entity records. 23713 * 23714 * @since 6.1.0 Introduced in WordPress core. 23715 * 23716 * @param kind Kind of the entity, e.g. `root` or a `postType`. See rootEntitiesConfig in ../entities.ts for a list of available kinds. 23717 * @param name Name of the entity, e.g. `plugin` or a `post`. See rootEntitiesConfig in ../entities.ts for a list of available names. 23718 * @param queryArgs Optional HTTP query description for how to fetch the data, passed to the requested API endpoint. 23719 * @param options Optional hook options. 23720 * @example 23721 * ```js 23722 * import { useEntityRecords } from '@wordpress/core-data'; 23723 * 23724 * function PageTitlesList() { 23725 * const { records, isResolving } = useEntityRecords( 'postType', 'page' ); 23726 * 23727 * if ( isResolving ) { 23728 * return 'Loading...'; 23729 * } 23730 * 23731 * return ( 23732 * <ul> 23733 * {records.map(( page ) => ( 23734 * <li>{ page.title }</li> 23735 * ))} 23736 * </ul> 23737 * ); 23738 * } 23739 * 23740 * // Rendered in the application: 23741 * // <PageTitlesList /> 23742 * ``` 23743 * 23744 * In the above example, when `PageTitlesList` is rendered into an 23745 * application, the list of records and the resolution details will be retrieved from
23746 * the store state using `getEntityRecords()`, or resolved if missing. 23747 * 23748 * @return Entity records data. 23749 * @template RecordType 23750 */ 23751function useEntityRecords(kind, name, queryArgs = {}, options = { 23752 enabled: true 23753}) { 23754 // Serialize queryArgs to a string that can be safely used as a React dep. 23755 // We can't just pass queryArgs as one of the deps, because if it is passed 23756 // as an object literal, then it will be a different object on each call even 23757 // if the values remain the same. 23758 const queryAsString = (0,external_wp_url_namespaceObject.addQueryArgs)('', queryArgs); 23759 const { 23760 data: records, 23761 ...rest 23762 } = useQuerySelect(query => { 23763 if (!options.enabled) { 23764 return { 23765 // Avoiding returning a new reference on every execution. 23766 data: use_entity_records_EMPTY_ARRAY 23767 }; 23768 } 23769 return query(store).getEntityRecords(kind, name, queryArgs); 23770 }, [kind, name, queryAsString, options.enabled]); 23771 return { 23772 records, 23773 ...rest 23774 }; 23775} 23776function __experimentalUseEntityRecords(kind, name, queryArgs, options) { 23777 external_wp_deprecated_default()(`wp.data.__experimentalUseEntityRecords`, { 23778 alternative: 'wp.data.useEntityRecords', 23779 since: '6.1' 23780 }); 23781 return useEntityRecords(kind, name, queryArgs, options); 23782} 23783 23784;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-resource-permissions.js 23785/** 23786 * WordPress dependencies 23787 */ 23788 23789 23790/** 23791 * Internal dependencies 23792 */ 23793 23794 23795 23796/** 23797 * Resolves resource permissions. 23798 * 23799 * @since 6.1.0 Introduced in WordPress core. 23800 * 23801 * @param resource The resource in question, e.g. media. 23802 * @param id ID of a specific resource entry, if needed, e.g. 10. 23803 * 23804 * @example 23805 * ```js 23806 * import { useResourcePermissions } from '@wordpress/core-data'; 23807 * 23808 * function PagesList() { 23809 * const { canCreate, isResolving } = useResourcePermissions( 'pages' ); 23810 * 23811 * if ( isResolving ) { 23812 * return 'Loading ...'; 23813 * } 23814 * 23815 * return ( 23816 * <div> 23817 * {canCreate ? (<button>+ Create a new page</button>) : false} 23818 * // ... 23819 * </div> 23820 * ); 23821 * } 23822 * 23823 * // Rendered in the application: 23824 * // <PagesList /> 23825 * ``` 23826 * 23827 * @example 23828 * ```js 23829 * import { useResourcePermissions } from '@wordpress/core-data'; 23830 * 23831 * function Page({ pageId }) { 23832 * const { 23833 * canCreate, 23834 * canUpdate, 23835 * canDelete, 23836 * isResolving 23837 * } = useResourcePermissions( 'pages', pageId ); 23838 * 23839 * if ( isResolving ) { 23840 * return 'Loading ...'; 23841 * } 23842 * 23843 * return ( 23844 * <div> 23845 * {canCreate ? (<button>+ Create a new page</button>) : false} 23846 * {canUpdate ? (<button>Edit page</button>) : false} 23847 * {canDelete ? (<button>Delete page</button>) : false} 23848 * // ... 23849 * </div> 23850 * ); 23851 * } 23852 * 23853 * // Rendered in the application: 23854 * // <Page pageId={ 15 } /> 23855 * ``` 23856 * 23857 * In the above example, when `PagesList` is rendered into an 23858 * application, the appropriate permissions and the resolution details will be retrieved from 23859 * the store state using `canUser()`, or resolved if missing. 23860 * 23861 * @return Entity records data. 23862 * @template IdType 23863 */ 23864function useResourcePermissions(resource, id) { 23865 return useQuerySelect(resolve => { 23866 const { 23867 canUser 23868 } = resolve(store); 23869 const create = canUser('create', resource); 23870 if (!id) { 23871 const read = canUser('read', resource); 23872 const isResolving = create.isResolving || read.isResolving; 23873 const hasResolved = create.hasResolved && read.hasResolved; 23874 let status = Status.Idle; 23875 if (isResolving) { 23876 status = Status.Resolving; 23877 } else if (hasResolved) { 23878 status = Status.Success; 23879 } 23880 return { 23881 status, 23882 isResolving, 23883 hasResolved, 23884 canCreate: create.hasResolved && create.data, 23885 canRead: read.hasResolved && read.data 23886 }; 23887 } 23888 const read = canUser('read', resource, id); 23889 const update = canUser('update', resource, id); 23890 const _delete = canUser('delete', resource, id); 23891 const isResolving = read.isResolving || create.isResolving || update.isResolving || _delete.isResolving; 23892 const hasResolved = read.hasResolved && create.hasResolved && update.hasResolved && _delete.hasResolved; 23893 let status = Status.Idle; 23894 if (isResolving) { 23895 status = Status.Resolving; 23896 } else if (hasResolved) { 23897 status = Status.Success; 23898 } 23899 return { 23900 status, 23901 isResolving, 23902 hasResolved, 23903 canRead: hasResolved && read.data, 23904 canCreate: hasResolved && create.data, 23905 canUpdate: hasResolved && update.data, 23906 canDelete: hasResolved && _delete.data 23907 }; 23908 }, [resource, id]); 23909} 23910function __experimentalUseResourcePermissions(resource, id) { 23911 external_wp_deprecated_default()(`wp.data.__experimentalUseResourcePermissions`, { 23912 alternative: 'wp.data.useResourcePermissions', 23913 since: '6.1' 23914 }); 23915 return useResourcePermissions(resource, id); 23916} 23917 23918;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/index.js 23919 23920 23921 23922 23923;// CONCATENATED MODULE: ./packages/core-data/build-module/index.js 23924/** 23925 * WordPress dependencies 23926 */ 23927 23928 23929/** 23930 * Internal dependencies 23931 */ 23932 23933 23934 23935 23936 23937 23938 23939 23940 23941 23942// The entity selectors/resolvers and actions are shortcuts to their generic equivalents 23943// (getEntityRecord, getEntityRecords, updateEntityRecord, updateEntityRecords) 23944// Instead of getEntityRecord, the consumer could use more user-friendly named selector: getPostType, getTaxonomy... 23945// The "kind" and the "name" of the entity are combined to generate these shortcuts. 23946 23947const entitySelectors = rootEntitiesConfig.reduce((result, entity) => { 23948 const { 23949 kind, 23950 name 23951 } = entity;
23952 result[getMethodName(kind, name)] = (state, key, query) => getEntityRecord(state, kind, name, key, query); 23953 result[getMethodName(kind, name, 'get', true)] = (state, query) => getEntityRecords(state, kind, name, query); 23954 return result; 23955}, {}); 23956const entityResolvers = rootEntitiesConfig.reduce((result, entity) => { 23957 const { 23958 kind, 23959 name 23960 } = entity; 23961 result[getMethodName(kind, name)] = (key, query) => resolvers_getEntityRecord(kind, name, key, query); 23962 const pluralMethodName = getMethodName(kind, name, 'get', true); 23963 result[pluralMethodName] = (...args) => resolvers_getEntityRecords(kind, name, ...args); 23964 result[pluralMethodName].shouldInvalidate = action => resolvers_getEntityRecords.shouldInvalidate(action, kind, name); 23965 return result; 23966}, {}); 23967const entityActions = rootEntitiesConfig.reduce((result, entity) => { 23968 const { 23969 kind, 23970 name 23971 } = entity; 23972 result[getMethodName(kind, name, 'save')] = key => saveEntityRecord(kind, name, key); 23973 result[getMethodName(kind, name, 'delete')] = (key, query) => deleteEntityRecord(kind, name, key, query); 23974 return result; 23975}, {}); 23976const storeConfig = () => ({ 23977 reducer: build_module_reducer, 23978 actions: { 23979 ...build_module_actions_namespaceObject, 23980 ...entityActions, 23981 ...createLocksActions() 23982 }, 23983 selectors: { 23984 ...build_module_selectors_namespaceObject, 23985 ...entitySelectors 23986 }, 23987 resolvers: { 23988 ...resolvers_namespaceObject, 23989 ...entityResolvers 23990 } 23991}); 23992 23993/** 23994 * Store definition for the code data namespace. 23995 * 23996 * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore 23997 */ 23998const store = (0,external_wp_data_namespaceObject.createReduxStore)(STORE_NAME, storeConfig()); 23999unlock(store).registerPrivateSelectors(private_selectors_namespaceObject); 24000(0,external_wp_data_namespaceObject.register)(store); // Register store after unlocking private selectors to allow resolvers to use them. 24001 24002 24003 24004 24005 24006 24007 24008})(); 24009 24010(window.wp = window.wp || {}).coreData = __webpack_exports__; 24011/******/ })() 24012;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.