PluginProbe
Gutenberg / 17.2.4
Gutenberg v17.2.4
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
gutenberg / build / core-data / index.js

index.js in Gutenberg 17.2.4, at build/core-data/index.js

24,890 lines 795.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /******/ (function() { // webpackBootstrap
2 /******/ var __webpack_modules__ = ({
3
4 /***/ 2167:
5 /***/ (function(module) {
6
7 "use strict";
8
9
10 function _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
24 function _classCallCheck(instance, Constructor) {
25 if (!(instance instanceof Constructor)) {
26 throw new TypeError("Cannot call a class as a function");
27 }
28 }
29
30 function _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
40 function _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 */
57 function 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
111 var EquivalentKeyMap =
112 /*#__PURE__*/
113 function () {
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
314 module.exports = EquivalentKeyMap;
315
316
317 /***/ }),
318
319 /***/ 5619:
320 /***/ (function(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
331 module.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 /***/ (function(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;if("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)}function 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)},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;if(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`.")},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("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=>(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;if(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;for(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("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;if(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)},{"../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))})});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(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_CANDIDATE"))})}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();else 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}_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)};if(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 /******/ !function() {
440 /******/ // getDefaultExport function for compatibility with non-harmony modules
441 /******/ __webpack_require__.n = function(module) {
442 /******/ var getter = module && module.__esModule ?
443 /******/ function() { return module['default']; } :
444 /******/ function() { return module; };
445 /******/ __webpack_require__.d(getter, { a: getter });
446 /******/ return getter;
447 /******/ };
448 /******/ }();
449 /******/
450 /******/ /* webpack/runtime/define property getters */
451 /******/ !function() {
452 /******/ // define getter functions for harmony exports
453 /******/ __webpack_require__.d = function(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 /******/ !function() {
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 /******/ !function() {
476 /******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
477 /******/ }();
478 /******/
479 /******/ /* webpack/runtime/make namespace object */
480 /******/ !function() {
481 /******/ // define __esModule on exports
482 /******/ __webpack_require__.r = function(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 /************************************************************************/
491 var __webpack_exports__ = {};
492 // This entry need to be wrapped in an IIFE because it need to be in strict mode.
493 !function() {
494 "use strict";
495 // ESM COMPAT FLAG
496 __webpack_require__.r(__webpack_exports__);
497
498 // EXPORTS
499 __webpack_require__.d(__webpack_exports__, {
500 EntityProvider: function() { return /* reexport */ EntityProvider; },
501 __experimentalFetchLinkSuggestions: function() { return /* reexport */ _experimental_fetch_link_suggestions; },
502 __experimentalFetchUrlData: function() { return /* reexport */ _experimental_fetch_url_data; },
503 __experimentalUseEntityRecord: function() { return /* reexport */ __experimentalUseEntityRecord; },
504 __experimentalUseEntityRecords: function() { return /* reexport */ __experimentalUseEntityRecords; },
505 __experimentalUseResourcePermissions: function() { return /* reexport */ __experimentalUseResourcePermissions; },
506 store: function() { return /* binding */ store; },
507 useEntityBlockEditor: function() { return /* reexport */ useEntityBlockEditor; },
508 useEntityId: function() { return /* reexport */ useEntityId; },
509 useEntityProp: function() { return /* reexport */ useEntityProp; },
510 useEntityRecord: function() { return /* reexport */ useEntityRecord; },
511 useEntityRecords: function() { return /* reexport */ useEntityRecords; },
512 useResourcePermissions: function() { return /* reexport */ useResourcePermissions; }
513 });
514
515 // NAMESPACE OBJECT: ./packages/core-data/build-module/actions.js
516 var build_module_actions_namespaceObject = {};
517 __webpack_require__.r(build_module_actions_namespaceObject);
518 __webpack_require__.d(build_module_actions_namespaceObject, {
519 __experimentalBatch: function() { return __experimentalBatch; },
520 __experimentalReceiveCurrentGlobalStylesId: function() { return __experimentalReceiveCurrentGlobalStylesId; },
521 __experimentalReceiveThemeBaseGlobalStyles: function() { return __experimentalReceiveThemeBaseGlobalStyles; },
522 __experimentalReceiveThemeGlobalStyleVariations: function() { return __experimentalReceiveThemeGlobalStyleVariations; },
523 __experimentalSaveSpecifiedEntityEdits: function() { return __experimentalSaveSpecifiedEntityEdits; },
524 __unstableCreateUndoLevel: function() { return __unstableCreateUndoLevel; },
525 addEntities: function() { return addEntities; },
526 deleteEntityRecord: function() { return deleteEntityRecord; },
527 editEntityRecord: function() { return editEntityRecord; },
528 receiveAutosaves: function() { return receiveAutosaves; },
529 receiveCurrentTheme: function() { return receiveCurrentTheme; },
530 receiveCurrentUser: function() { return receiveCurrentUser; },
531 receiveDefaultTemplateId: function() { return receiveDefaultTemplateId; },
532 receiveEmbedPreview: function() { return receiveEmbedPreview; },
533 receiveEntityRecords: function() { return receiveEntityRecords; },
534 receiveNavigationFallbackId: function() { return receiveNavigationFallbackId; },
535 receiveRevisions: function() { return receiveRevisions; },
536 receiveThemeGlobalStyleRevisions: function() { return receiveThemeGlobalStyleRevisions; },
537 receiveThemeSupports: function() { return receiveThemeSupports; },
538 receiveUploadPermissions: function() { return receiveUploadPermissions; },
539 receiveUserPermission: function() { return receiveUserPermission; },
540 receiveUserQuery: function() { return receiveUserQuery; },
541 redo: function() { return redo; },
542 saveEditedEntityRecord: function() { return saveEditedEntityRecord; },
543 saveEntityRecord: function() { return saveEntityRecord; },
544 undo: function() { return undo; }
545 });
546
547 // NAMESPACE OBJECT: ./packages/core-data/build-module/selectors.js
548 var build_module_selectors_namespaceObject = {};
549 __webpack_require__.r(build_module_selectors_namespaceObject);
550 __webpack_require__.d(build_module_selectors_namespaceObject, {
551 __experimentalGetCurrentGlobalStylesId: function() { return __experimentalGetCurrentGlobalStylesId; },
552 __experimentalGetCurrentThemeBaseGlobalStyles: function() { return __experimentalGetCurrentThemeBaseGlobalStyles; },
553 __experimentalGetCurrentThemeGlobalStylesVariations: function() { return __experimentalGetCurrentThemeGlobalStylesVariations; },
554 __experimentalGetDirtyEntityRecords: function() { return __experimentalGetDirtyEntityRecords; },
555 __experimentalGetEntitiesBeingSaved: function() { return __experimentalGetEntitiesBeingSaved; },
556 __experimentalGetEntityRecordNoResolver: function() { return __experimentalGetEntityRecordNoResolver; },
557 __experimentalGetTemplateForLink: function() { return __experimentalGetTemplateForLink; },
558 canUser: function() { return canUser; },
559 canUserEditEntityRecord: function() { return canUserEditEntityRecord; },
560 getAuthors: function() { return getAuthors; },
561 getAutosave: function() { return getAutosave; },
562 getAutosaves: function() { return getAutosaves; },
563 getBlockPatternCategories: function() { return getBlockPatternCategories; },
564 getBlockPatterns: function() { return getBlockPatterns; },
565 getCurrentTheme: function() { return getCurrentTheme; },
566 getCurrentThemeGlobalStylesRevisions: function() { return getCurrentThemeGlobalStylesRevisions; },
567 getCurrentUser: function() { return getCurrentUser; },
568 getDefaultTemplateId: function() { return getDefaultTemplateId; },
569 getEditedEntityRecord: function() { return getEditedEntityRecord; },
570 getEmbedPreview: function() { return getEmbedPreview; },
571 getEntitiesByKind: function() { return getEntitiesByKind; },
572 getEntitiesConfig: function() { return getEntitiesConfig; },
573 getEntity: function() { return getEntity; },
574 getEntityConfig: function() { return getEntityConfig; },
575 getEntityRecord: function() { return getEntityRecord; },
576 getEntityRecordEdits: function() { return getEntityRecordEdits; },
577 getEntityRecordNonTransientEdits: function() { return getEntityRecordNonTransientEdits; },
578 getEntityRecords: function() { return getEntityRecords; },
579 getEntityRecordsTotalItems: function() { return getEntityRecordsTotalItems; },
580 getEntityRecordsTotalPages: function() { return getEntityRecordsTotalPages; },
581 getLastEntityDeleteError: function() { return getLastEntityDeleteError; },
582 getLastEntitySaveError: function() { return getLastEntitySaveError; },
583 getRawEntityRecord: function() { return getRawEntityRecord; },
584 getRedoEdit: function() { return getRedoEdit; },
585 getReferenceByDistinctEdits: function() { return getReferenceByDistinctEdits; },
586 getRevision: function() { return getRevision; },
587 getRevisions: function() { return getRevisions; },
588 getThemeSupports: function() { return getThemeSupports; },
589 getUndoEdit: function() { return getUndoEdit; },
590 getUserPatternCategories: function() { return getUserPatternCategories; },
591 getUserQueryResults: function() { return getUserQueryResults; },
592 hasEditsForEntityRecord: function() { return hasEditsForEntityRecord; },
593 hasEntityRecords: function() { return hasEntityRecords; },
594 hasFetchedAutosaves: function() { return hasFetchedAutosaves; },
595 hasRedo: function() { return hasRedo; },
596 hasUndo: function() { return hasUndo; },
597 isAutosavingEntityRecord: function() { return isAutosavingEntityRecord; },
598 isDeletingEntityRecord: function() { return isDeletingEntityRecord; },
599 isPreviewEmbedFallback: function() { return isPreviewEmbedFallback; },
600 isRequestingEmbedPreview: function() { return isRequestingEmbedPreview; },
601 isSavingEntityRecord: function() { return isSavingEntityRecord; }
602 });
603
604 // NAMESPACE OBJECT: ./packages/core-data/build-module/private-selectors.js
605 var private_selectors_namespaceObject = {};
606 __webpack_require__.r(private_selectors_namespaceObject);
607 __webpack_require__.d(private_selectors_namespaceObject, {
608 getNavigationFallbackId: function() { return getNavigationFallbackId; },
609 getUndoManager: function() { return getUndoManager; }
610 });
611
612 // NAMESPACE OBJECT: ./packages/core-data/build-module/resolvers.js
613 var resolvers_namespaceObject = {};
614 __webpack_require__.r(resolvers_namespaceObject);
615 __webpack_require__.d(resolvers_namespaceObject, {
616 __experimentalGetCurrentGlobalStylesId: function() { return resolvers_experimentalGetCurrentGlobalStylesId; },
617 __experimentalGetCurrentThemeBaseGlobalStyles: function() { return resolvers_experimentalGetCurrentThemeBaseGlobalStyles; },
618 __experimentalGetCurrentThemeGlobalStylesVariations: function() { return resolvers_experimentalGetCurrentThemeGlobalStylesVariations; },
619 __experimentalGetTemplateForLink: function() { return resolvers_experimentalGetTemplateForLink; },
620 canUser: function() { return resolvers_canUser; },
621 canUserEditEntityRecord: function() { return resolvers_canUserEditEntityRecord; },
622 getAuthors: function() { return resolvers_getAuthors; },
623 getAutosave: function() { return resolvers_getAutosave; },
624 getAutosaves: function() { return resolvers_getAutosaves; },
625 getBlockPatternCategories: function() { return resolvers_getBlockPatternCategories; },
626 getBlockPatterns: function() { return resolvers_getBlockPatterns; },
627 getCurrentTheme: function() { return resolvers_getCurrentTheme; },
628 getCurrentThemeGlobalStylesRevisions: function() { return resolvers_getCurrentThemeGlobalStylesRevisions; },
629 getCurrentUser: function() { return resolvers_getCurrentUser; },
630 getDefaultTemplateId: function() { return resolvers_getDefaultTemplateId; },
631 getEditedEntityRecord: function() { return resolvers_getEditedEntityRecord; },
632 getEmbedPreview: function() { return resolvers_getEmbedPreview; },
633 getEntityRecord: function() { return resolvers_getEntityRecord; },
634 getEntityRecords: function() { return resolvers_getEntityRecords; },
635 getNavigationFallbackId: function() { return resolvers_getNavigationFallbackId; },
636 getRawEntityRecord: function() { return resolvers_getRawEntityRecord; },
637 getRevision: function() { return resolvers_getRevision; },
638 getRevisions: function() { return resolvers_getRevisions; },
639 getThemeSupports: function() { return resolvers_getThemeSupports; },
640 getUserPatternCategories: function() { return resolvers_getUserPatternCategories; }
641 });
642
643 ;// CONCATENATED MODULE: external ["wp","data"]
644 var external_wp_data_namespaceObject = window["wp"]["data"];
645 // EXTERNAL MODULE: ./node_modules/fast-deep-equal/es6/index.js
646 var es6 = __webpack_require__(5619);
647 var es6_default = /*#__PURE__*/__webpack_require__.n(es6);
648 ;// CONCATENATED MODULE: external ["wp","compose"]
649 var external_wp_compose_namespaceObject = window["wp"]["compose"];
650 ;// CONCATENATED MODULE: external ["wp","isShallowEqual"]
651 var external_wp_isShallowEqual_namespaceObject = window["wp"]["isShallowEqual"];
652 var external_wp_isShallowEqual_default = /*#__PURE__*/__webpack_require__.n(external_wp_isShallowEqual_namespaceObject);
653 ;// CONCATENATED MODULE: ./packages/undo-manager/build-module/index.js
654 /**
655 * WordPress dependencies
656 */
657
658
659 /** @typedef {import('./types').HistoryRecord} HistoryRecord */
660 /** @typedef {import('./types').HistoryChange} HistoryChange */
661 /** @typedef {import('./types').HistoryChanges} HistoryChanges */
662 /** @typedef {import('./types').UndoManager} UndoManager */
663
664 /**
665 * Merge changes for a single item into a record of changes.
666 *
667 * @param {Record< string, HistoryChange >} changes1 Previous changes
668 * @param {Record< string, HistoryChange >} changes2 NextChanges
669 *
670 * @return {Record< string, HistoryChange >} Merged changes
671 */
672 function mergeHistoryChanges(changes1, changes2) {
673 /**
674 * @type {Record< string, HistoryChange >}
675 */
676 const newChanges = {
677 ...changes1
678 };
679 Object.entries(changes2).forEach(([key, value]) => {
680 if (newChanges[key]) {
681 newChanges[key] = {
682 ...newChanges[key],
683 to: value.to
684 };
685 } else {
686 newChanges[key] = value;
687 }
688 });
689 return newChanges;
690 }
691
692 /**
693 * Adds history changes for a single item into a record of changes.
694 *
695 * @param {HistoryRecord} record The record to merge into.
696 * @param {HistoryChanges} changes The changes to merge.
697 */
698 const addHistoryChangesIntoRecord = (record, changes) => {
699 const existingChangesIndex = record?.findIndex(({
700 id: recordIdentifier
701 }) => {
702 return typeof recordIdentifier === 'string' ? recordIdentifier === changes.id : external_wp_isShallowEqual_default()(recordIdentifier, changes.id);
703 });
704 const nextRecord = [...record];
705 if (existingChangesIndex !== -1) {
706 // If the edit is already in the stack leave the initial "from" value.
707 nextRecord[existingChangesIndex] = {
708 id: changes.id,
709 changes: mergeHistoryChanges(nextRecord[existingChangesIndex].changes, changes.changes)
710 };
711 } else {
712 nextRecord.push(changes);
713 }
714 return nextRecord;
715 };
716
717 /**
718 * Creates an undo manager.
719 *
720 * @return {UndoManager} Undo manager.
721 */
722 function createUndoManager() {
723 /**
724 * @type {HistoryRecord[]}
725 */
726 let history = [];
727 /**
728 * @type {HistoryRecord}
729 */
730 let stagedRecord = [];
731 /**
732 * @type {number}
733 */
734 let offset = 0;
735 const dropPendingRedos = () => {
736 history = history.slice(0, offset || undefined);
737 offset = 0;
738 };
739 const appendStagedRecordToLatestHistoryRecord = () => {
740 var _history$index;
741 const index = history.length === 0 ? 0 : history.length - 1;
742 let latestRecord = (_history$index = history[index]) !== null && _history$index !== void 0 ? _history$index : [];
743 stagedRecord.forEach(changes => {
744 latestRecord = addHistoryChangesIntoRecord(latestRecord, changes);
745 });
746 stagedRecord = [];
747 history[index] = latestRecord;
748 };
749
750 /**
751 * Checks whether a record is empty.
752 * A record is considered empty if it the changes keep the same values.
753 * Also updates to function values are ignored.
754 *
755 * @param {HistoryRecord} record
756 * @return {boolean} Whether the record is empty.
757 */
758 const isRecordEmpty = record => {
759 const filteredRecord = record.filter(({
760 changes
761 }) => {
762 return Object.values(changes).some(({
763 from,
764 to
765 }) => typeof from !== 'function' && typeof to !== 'function' && !external_wp_isShallowEqual_default()(from, to));
766 });
767 return !filteredRecord.length;
768 };
769 return {
770 /**
771 * Record changes into the history.
772 *
773 * @param {HistoryRecord=} record A record of changes to record.
774 * @param {boolean} isStaged Whether to immediately create an undo point or not.
775 */
776 addRecord(record, isStaged = false) {
777 const isEmpty = !record || isRecordEmpty(record);
778 if (isStaged) {
779 if (isEmpty) {
780 return;
781 }
782 record.forEach(changes => {
783 stagedRecord = addHistoryChangesIntoRecord(stagedRecord, changes);
784 });
785 } else {
786 dropPendingRedos();
787 if (stagedRecord.length) {
788 appendStagedRecordToLatestHistoryRecord();
789 }
790 if (isEmpty) {
791 return;
792 }
793 history.push(record);
794 }
795 },
796 undo() {
797 if (stagedRecord.length) {
798 dropPendingRedos();
799 appendStagedRecordToLatestHistoryRecord();
800 }
801 const undoRecord = history[history.length - 1 + offset];
802 if (!undoRecord) {
803 return;
804 }
805 offset -= 1;
806 return undoRecord;
807 },
808 redo() {
809 const redoRecord = history[history.length + offset];
810 if (!redoRecord) {
811 return;
812 }
813 offset += 1;
814 return redoRecord;
815 },
816 hasUndo() {
817 return !!history[history.length - 1 + offset];
818 },
819 hasRedo() {
820 return !!history[history.length + offset];
821 }
822 };
823 }
824
825 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/if-matching-action.js
826 /** @typedef {import('../types').AnyFunction} AnyFunction */
827
828 /**
829 * A higher-order reducer creator which invokes the original reducer only if
830 * the dispatching action matches the given predicate, **OR** if state is
831 * initializing (undefined).
832 *
833 * @param {AnyFunction} isMatch Function predicate for allowing reducer call.
834 *
835 * @return {AnyFunction} Higher-order reducer.
836 */
837 const ifMatchingAction = isMatch => reducer => (state, action) => {
838 if (state === undefined || isMatch(action)) {
839 return reducer(state, action);
840 }
841 return state;
842 };
843 /* harmony default export */ var if_matching_action = (ifMatchingAction);
844
845 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/replace-action.js
846 /** @typedef {import('../types').AnyFunction} AnyFunction */
847
848 /**
849 * Higher-order reducer creator which substitutes the action object before
850 * passing to the original reducer.
851 *
852 * @param {AnyFunction} replacer Function mapping original action to replacement.
853 *
854 * @return {AnyFunction} Higher-order reducer.
855 */
856 const replaceAction = replacer => reducer => (state, action) => {
857 return reducer(state, replacer(action));
858 };
859 /* harmony default export */ var replace_action = (replaceAction);
860
861 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/conservative-map-item.js
862 /**
863 * External dependencies
864 */
865
866
867 /**
868 * Given the current and next item entity record, returns the minimally "modified"
869 * result of the next item, preferring value references from the original item
870 * if equal. If all values match, the original item is returned.
871 *
872 * @param {Object} item Original item.
873 * @param {Object} nextItem Next item.
874 *
875 * @return {Object} Minimally modified merged item.
876 */
877 function conservativeMapItem(item, nextItem) {
878 // Return next item in its entirety if there is no original item.
879 if (!item) {
880 return nextItem;
881 }
882 let hasChanges = false;
883 const result = {};
884 for (const key in nextItem) {
885 if (es6_default()(item[key], nextItem[key])) {
886 result[key] = item[key];
887 } else {
888 hasChanges = true;
889 result[key] = nextItem[key];
890 }
891 }
892 if (!hasChanges) {
893 return item;
894 }
895
896 // Only at this point, backfill properties from the original item which
897 // weren't explicitly set into the result above. This is an optimization
898 // to allow `hasChanges` to return early.
899 for (const key in item) {
900 if (!result.hasOwnProperty(key)) {
901 result[key] = item[key];
902 }
903 }
904 return result;
905 }
906
907 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/on-sub-key.js
908 /** @typedef {import('../types').AnyFunction} AnyFunction */
909
910 /**
911 * Higher-order reducer creator which creates a combined reducer object, keyed
912 * by a property on the action object.
913 *
914 * @param {string} actionProperty Action property by which to key object.
915 *
916 * @return {AnyFunction} Higher-order reducer.
917 */
918 const onSubKey = actionProperty => reducer => (state = {}, action) => {
919 // Retrieve subkey from action. Do not track if undefined; useful for cases
920 // where reducer is scoped by action shape.
921 const key = action[actionProperty];
922 if (key === undefined) {
923 return state;
924 }
925
926 // Avoid updating state if unchanged. Note that this also accounts for a
927 // reducer which returns undefined on a key which is not yet tracked.
928 const nextKeyState = reducer(state[key], action);
929 if (nextKeyState === state[key]) {
930 return state;
931 }
932 return {
933 ...state,
934 [key]: nextKeyState
935 };
936 };
937 /* harmony default export */ var on_sub_key = (onSubKey);
938
939 ;// CONCATENATED MODULE: ./node_modules/tslib/tslib.es6.mjs
940 /******************************************************************************
941 Copyright (c) Microsoft Corporation.
942
943 Permission to use, copy, modify, and/or distribute this software for any
944 purpose with or without fee is hereby granted.
945
946 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
947 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
948 AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
949 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
950 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
951 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
952 PERFORMANCE OF THIS SOFTWARE.
953 ***************************************************************************** */
954 /* global Reflect, Promise, SuppressedError, Symbol */
955
956 var extendStatics = function(d, b) {
957 extendStatics = Object.setPrototypeOf ||
958 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
959 function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
960 return extendStatics(d, b);
961 };
962
963 function __extends(d, b) {
964 if (typeof b !== "function" && b !== null)
965 throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
966 extendStatics(d, b);
967 function __() { this.constructor = d; }
968 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
969 }
970
971 var __assign = function() {
972 __assign = Object.assign || function __assign(t) {
973 for (var s, i = 1, n = arguments.length; i < n; i++) {
974 s = arguments[i];
975 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
976 }
977 return t;
978 }
979 return __assign.apply(this, arguments);
980 }
981
982 function __rest(s, e) {
983 var t = {};
984 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
985 t[p] = s[p];
986 if (s != null && typeof Object.getOwnPropertySymbols === "function")
987 for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
988 if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
989 t[p[i]] = s[p[i]];
990 }
991 return t;
992 }
993
994 function __decorate(decorators, target, key, desc) {
995 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
996 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
997 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
998 return c > 3 && r && Object.defineProperty(target, key, r), r;
999 }
1000
1001 function __param(paramIndex, decorator) {
1002 return function (target, key) { decorator(target, key, paramIndex); }
1003 }
1004
1005 function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
1006 function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
1007 var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
1008 var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
1009 var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
1010 var _, done = false;
1011 for (var i = decorators.length - 1; i >= 0; i--) {
1012 var context = {};
1013 for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
1014 for (var p in contextIn.access) context.access[p] = contextIn.access[p];
1015 context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
1016 var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
1017 if (kind === "accessor") {
1018 if (result === void 0) continue;
1019 if (result === null || typeof result !== "object") throw new TypeError("Object expected");
1020 if (_ = accept(result.get)) descriptor.get = _;
1021 if (_ = accept(result.set)) descriptor.set = _;
1022 if (_ = accept(result.init)) initializers.unshift(_);
1023 }
1024 else if (_ = accept(result)) {
1025 if (kind === "field") initializers.unshift(_);
1026 else descriptor[key] = _;
1027 }
1028 }
1029 if (target) Object.defineProperty(target, contextIn.name, descriptor);
1030 done = true;
1031 };
1032
1033 function __runInitializers(thisArg, initializers, value) {
1034 var useValue = arguments.length > 2;
1035 for (var i = 0; i < initializers.length; i++) {
1036 value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
1037 }
1038 return useValue ? value : void 0;
1039 };
1040
1041 function __propKey(x) {
1042 return typeof x === "symbol" ? x : "".concat(x);
1043 };
1044
1045 function __setFunctionName(f, name, prefix) {
1046 if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
1047 return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
1048 };
1049
1050 function __metadata(metadataKey, metadataValue) {
1051 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
1052 }
1053
1054 function __awaiter(thisArg, _arguments, P, generator) {
1055 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1056 return new (P || (P = Promise))(function (resolve, reject) {
1057 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1058 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1059 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1060 step((generator = generator.apply(thisArg, _arguments || [])).next());
1061 });
1062 }
1063
1064 function __generator(thisArg, body) {
1065 var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
1066 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
1067 function verb(n) { return function (v) { return step([n, v]); }; }
1068 function step(op) {
1069 if (f) throw new TypeError("Generator is already executing.");
1070 while (g && (g = 0, op[0] && (_ = 0)), _) try {
1071 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;
1072 if (y = 0, t) op = [op[0] & 2, t.value];
1073 switch (op[0]) {
1074 case 0: case 1: t = op; break;
1075 case 4: _.label++; return { value: op[1], done: false };
1076 case 5: _.label++; y = op[1]; op = [0]; continue;
1077 case 7: op = _.ops.pop(); _.trys.pop(); continue;
1078 default:
1079 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
1080 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
1081 if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
1082 if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
1083 if (t[2]) _.ops.pop();
1084 _.trys.pop(); continue;
1085 }
1086 op = body.call(thisArg, _);
1087 } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
1088 if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
1089 }
1090 }
1091
1092 var __createBinding = Object.create ? (function(o, m, k, k2) {
1093 if (k2 === undefined) k2 = k;
1094 var desc = Object.getOwnPropertyDescriptor(m, k);
1095 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1096 desc = { enumerable: true, get: function() { return m[k]; } };
1097 }
1098 Object.defineProperty(o, k2, desc);
1099 }) : (function(o, m, k, k2) {
1100 if (k2 === undefined) k2 = k;
1101 o[k2] = m[k];
1102 });
1103
1104 function __exportStar(m, o) {
1105 for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);
1106 }
1107
1108 function __values(o) {
1109 var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
1110 if (m) return m.call(o);
1111 if (o && typeof o.length === "number") return {
1112 next: function () {
1113 if (o && i >= o.length) o = void 0;
1114 return { value: o && o[i++], done: !o };
1115 }
1116 };
1117 throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
1118 }
1119
1120 function __read(o, n) {
1121 var m = typeof Symbol === "function" && o[Symbol.iterator];
1122 if (!m) return o;
1123 var i = m.call(o), r, ar = [], e;
1124 try {
1125 while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
1126 }
1127 catch (error) { e = { error: error }; }
1128 finally {
1129 try {
1130 if (r && !r.done && (m = i["return"])) m.call(i);
1131 }
1132 finally { if (e) throw e.error; }
1133 }
1134 return ar;
1135 }
1136
1137 /** @deprecated */
1138 function __spread() {
1139 for (var ar = [], i = 0; i < arguments.length; i++)
1140 ar = ar.concat(__read(arguments[i]));
1141 return ar;
1142 }
1143
1144 /** @deprecated */
1145 function __spreadArrays() {
1146 for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
1147 for (var r = Array(s), k = 0, i = 0; i < il; i++)
1148 for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
1149 r[k] = a[j];
1150 return r;
1151 }
1152
1153 function __spreadArray(to, from, pack) {
1154 if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
1155 if (ar || !(i in from)) {
1156 if (!ar) ar = Array.prototype.slice.call(from, 0, i);
1157 ar[i] = from[i];
1158 }
1159 }
1160 return to.concat(ar || Array.prototype.slice.call(from));
1161 }
1162
1163 function __await(v) {
1164 return this instanceof __await ? (this.v = v, this) : new __await(v);
1165 }
1166
1167 function __asyncGenerator(thisArg, _arguments, generator) {
1168 if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
1169 var g = generator.apply(thisArg, _arguments || []), i, q = [];
1170 return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
1171 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); }); }; }
1172 function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
1173 function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
1174 function fulfill(value) { resume("next", value); }
1175 function reject(value) { resume("throw", value); }
1176 function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
1177 }
1178
1179 function __asyncDelegator(o) {
1180 var i, p;
1181 return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
1182 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; }
1183 }
1184
1185 function __asyncValues(o) {
1186 if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
1187 var m = o[Symbol.asyncIterator], i;
1188 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);
1189 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); }); }; }
1190 function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
1191 }
1192
1193 function __makeTemplateObject(cooked, raw) {
1194 if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
1195 return cooked;
1196 };
1197
1198 var __setModuleDefault = Object.create ? (function(o, v) {
1199 Object.defineProperty(o, "default", { enumerable: true, value: v });
1200 }) : function(o, v) {
1201 o["default"] = v;
1202 };
1203
1204 function __importStar(mod) {
1205 if (mod && mod.__esModule) return mod;
1206 var result = {};
1207 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
1208 __setModuleDefault(result, mod);
1209 return result;
1210 }
1211
1212 function __importDefault(mod) {
1213 return (mod && mod.__esModule) ? mod : { default: mod };
1214 }
1215
1216 function __classPrivateFieldGet(receiver, state, kind, f) {
1217 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
1218 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");
1219 return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
1220 }
1221
1222 function __classPrivateFieldSet(receiver, state, value, kind, f) {
1223 if (kind === "m") throw new TypeError("Private method is not writable");
1224 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
1225 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");
1226 return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
1227 }
1228
1229 function __classPrivateFieldIn(state, receiver) {
1230 if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object");
1231 return typeof state === "function" ? receiver === state : state.has(receiver);
1232 }
1233
1234 function __addDisposableResource(env, value, async) {
1235 if (value !== null && value !== void 0) {
1236 if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
1237 var dispose;
1238 if (async) {
1239 if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
1240 dispose = value[Symbol.asyncDispose];
1241 }
1242 if (dispose === void 0) {
1243 if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
1244 dispose = value[Symbol.dispose];
1245 }
1246 if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
1247 env.stack.push({ value: value, dispose: dispose, async: async });
1248 }
1249 else if (async) {
1250 env.stack.push({ async: true });
1251 }
1252 return value;
1253 }
1254
1255 var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1256 var e = new Error(message);
1257 return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1258 };
1259
1260 function __disposeResources(env) {
1261 function fail(e) {
1262 env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
1263 env.hasError = true;
1264 }
1265 function next() {
1266 while (env.stack.length) {
1267 var rec = env.stack.pop();
1268 try {
1269 var result = rec.dispose && rec.dispose.call(rec.value);
1270 if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
1271 }
1272 catch (e) {
1273 fail(e);
1274 }
1275 }
1276 if (env.hasError) throw env.error;
1277 }
1278 return next();
1279 }
1280
1281 /* harmony default export */ var tslib_es6 = ({
1282 __extends,
1283 __assign,
1284 __rest,
1285 __decorate,
1286 __param,
1287 __metadata,
1288 __awaiter,
1289 __generator,
1290 __createBinding,
1291 __exportStar,
1292 __values,
1293 __read,
1294 __spread,
1295 __spreadArrays,
1296 __spreadArray,
1297 __await,
1298 __asyncGenerator,
1299 __asyncDelegator,
1300 __asyncValues,
1301 __makeTemplateObject,
1302 __importStar,
1303 __importDefault,
1304 __classPrivateFieldGet,
1305 __classPrivateFieldSet,
1306 __classPrivateFieldIn,
1307 __addDisposableResource,
1308 __disposeResources,
1309 });
1310
1311 ;// CONCATENATED MODULE: ./node_modules/lower-case/dist.es2015/index.js
1312 /**
1313 * Source: ftp://ftp.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt
1314 */
1315 var SUPPORTED_LOCALE = {
1316 tr: {
1317 regexp: /\u0130|\u0049|\u0049\u0307/g,
1318 map: {
1319 İ: "\u0069",
1320 I: "\u0131",
1321 İ: "\u0069",
1322 },
1323 },
1324 az: {
1325 regexp: /\u0130/g,
1326 map: {
1327 İ: "\u0069",
1328 I: "\u0131",
1329 İ: "\u0069",
1330 },
1331 },
1332 lt: {
1333 regexp: /\u0049|\u004A|\u012E|\u00CC|\u00CD|\u0128/g,
1334 map: {
1335 I: "\u0069\u0307",
1336 J: "\u006A\u0307",
1337 Į: "\u012F\u0307",
1338 Ì: "\u0069\u0307\u0300",
1339 Í: "\u0069\u0307\u0301",
1340 Ĩ: "\u0069\u0307\u0303",
1341 },
1342 },
1343 };
1344 /**
1345 * Localized lower case.
1346 */
1347 function localeLowerCase(str, locale) {
1348 var lang = SUPPORTED_LOCALE[locale.toLowerCase()];
1349 if (lang)
1350 return lowerCase(str.replace(lang.regexp, function (m) { return lang.map[m]; }));
1351 return lowerCase(str);
1352 }
1353 /**
1354 * Lower case as a function.
1355 */
1356 function lowerCase(str) {
1357 return str.toLowerCase();
1358 }
1359
1360 ;// CONCATENATED MODULE: ./node_modules/no-case/dist.es2015/index.js
1361
1362 // Support camel case ("camelCase" -> "camel Case" and "CAMELCase" -> "CAMEL Case").
1363 var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g];
1364 // Remove all non-word characters.
1365 var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;
1366 /**
1367 * Normalize the string into something other libraries can manipulate easier.
1368 */
1369 function noCase(input, options) {
1370 if (options === void 0) { options = {}; }
1371 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;
1372 var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0");
1373 var start = 0;
1374 var end = result.length;
1375 // Trim the delimiter from around the output string.
1376 while (result.charAt(start) === "\0")
1377 start++;
1378 while (result.charAt(end - 1) === "\0")
1379 end--;
1380 // Transform each token independently.
1381 return result.slice(start, end).split("\0").map(transform).join(delimiter);
1382 }
1383 /**
1384 * Replace `re` in the input string with the replacement value.
1385 */
1386 function replace(input, re, value) {
1387 if (re instanceof RegExp)
1388 return input.replace(re, value);
1389 return re.reduce(function (input, re) { return input.replace(re, value); }, input);
1390 }
1391
1392 ;// CONCATENATED MODULE: ./node_modules/upper-case-first/dist.es2015/index.js
1393 /**
1394 * Upper case the first character of an input string.
1395 */
1396 function upperCaseFirst(input) {
1397 return input.charAt(0).toUpperCase() + input.substr(1);
1398 }
1399
1400 ;// CONCATENATED MODULE: ./node_modules/capital-case/dist.es2015/index.js
1401
1402
1403
1404 function capitalCaseTransform(input) {
1405 return upperCaseFirst(input.toLowerCase());
1406 }
1407 function capitalCase(input, options) {
1408 if (options === void 0) { options = {}; }
1409 return noCase(input, __assign({ delimiter: " ", transform: capitalCaseTransform }, options));
1410 }
1411
1412 ;// CONCATENATED MODULE: ./node_modules/pascal-case/dist.es2015/index.js
1413
1414
1415 function pascalCaseTransform(input, index) {
1416 var firstChar = input.charAt(0);
1417 var lowerChars = input.substr(1).toLowerCase();
1418 if (index > 0 && firstChar >= "0" && firstChar <= "9") {
1419 return "_" + firstChar + lowerChars;
1420 }
1421 return "" + firstChar.toUpperCase() + lowerChars;
1422 }
1423 function dist_es2015_pascalCaseTransformMerge(input) {
1424 return input.charAt(0).toUpperCase() + input.slice(1).toLowerCase();
1425 }
1426 function pascalCase(input, options) {
1427 if (options === void 0) { options = {}; }
1428 return noCase(input, __assign({ delimiter: "", transform: pascalCaseTransform }, options));
1429 }
1430
1431 ;// CONCATENATED MODULE: external ["wp","apiFetch"]
1432 var external_wp_apiFetch_namespaceObject = window["wp"]["apiFetch"];
1433 var external_wp_apiFetch_default = /*#__PURE__*/__webpack_require__.n(external_wp_apiFetch_namespaceObject);
1434 ;// CONCATENATED MODULE: external ["wp","i18n"]
1435 var external_wp_i18n_namespaceObject = window["wp"]["i18n"];
1436 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/rng.js
1437 // Unique ID creation requires a high quality random # generator. In the browser we therefore
1438 // require the crypto API and do not support built-in fallback to lower quality random number
1439 // generators (like Math.random()).
1440 var rng_getRandomValues;
1441 var rnds8 = new Uint8Array(16);
1442 function rng() {
1443 // lazy load so that environments that need to polyfill have a chance to do so
1444 if (!rng_getRandomValues) {
1445 // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also,
1446 // find the complete implementation of crypto (msCrypto) on IE11.
1447 rng_getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto);
1448
1449 if (!rng_getRandomValues) {
1450 throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
1451 }
1452 }
1453
1454 return rng_getRandomValues(rnds8);
1455 }
1456 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/regex.js
1457 /* harmony default export */ var 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);
1458 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/validate.js
1459
1460
1461 function validate(uuid) {
1462 return typeof uuid === 'string' && regex.test(uuid);
1463 }
1464
1465 /* harmony default export */ var esm_browser_validate = (validate);
1466 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/stringify.js
1467
1468 /**
1469 * Convert array of 16 byte values to UUID string format of the form:
1470 * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
1471 */
1472
1473 var byteToHex = [];
1474
1475 for (var i = 0; i < 256; ++i) {
1476 byteToHex.push((i + 0x100).toString(16).substr(1));
1477 }
1478
1479 function stringify(arr) {
1480 var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
1481 // Note: Be careful editing this code! It's been tuned for performance
1482 // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
1483 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
1484 // of the following:
1485 // - One or more input array values don't map to a hex octet (leading to
1486 // "undefined" in the uuid)
1487 // - Invalid input values for the RFC `version` or `variant` fields
1488
1489 if (!esm_browser_validate(uuid)) {
1490 throw TypeError('Stringified UUID is invalid');
1491 }
1492
1493 return uuid;
1494 }
1495
1496 /* harmony default export */ var esm_browser_stringify = (stringify);
1497 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/v4.js
1498
1499
1500
1501 function v4(options, buf, offset) {
1502 options = options || {};
1503 var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
1504
1505 rnds[6] = rnds[6] & 0x0f | 0x40;
1506 rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
1507
1508 if (buf) {
1509 offset = offset || 0;
1510
1511 for (var i = 0; i < 16; ++i) {
1512 buf[offset + i] = rnds[i];
1513 }
1514
1515 return buf;
1516 }
1517
1518 return esm_browser_stringify(rnds);
1519 }
1520
1521 /* harmony default export */ var esm_browser_v4 = (v4);
1522 ;// CONCATENATED MODULE: external ["wp","url"]
1523 var external_wp_url_namespaceObject = window["wp"]["url"];
1524 ;// CONCATENATED MODULE: external ["wp","deprecated"]
1525 var external_wp_deprecated_namespaceObject = window["wp"]["deprecated"];
1526 var external_wp_deprecated_default = /*#__PURE__*/__webpack_require__.n(external_wp_deprecated_namespaceObject);
1527 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/set-nested-value.js
1528 /**
1529 * Sets the value at path of object.
1530 * If a portion of path doesn’t exist, it’s created.
1531 * Arrays are created for missing index properties while objects are created
1532 * for all other missing properties.
1533 *
1534 * Path is specified as either:
1535 * - a string of properties, separated by dots, for example: "x.y".
1536 * - an array of properties, for example `[ 'x', 'y' ]`.
1537 *
1538 * This function intentionally mutates the input object.
1539 *
1540 * Inspired by _.set().
1541 *
1542 * @see https://lodash.com/docs/4.17.15#set
1543 *
1544 * @todo Needs to be deduplicated with its copy in `@wordpress/edit-site`.
1545 *
1546 * @param {Object} object Object to modify
1547 * @param {Array|string} path Path of the property to set.
1548 * @param {*} value Value to set.
1549 */
1550 function setNestedValue(object, path, value) {
1551 if (!object || typeof object !== 'object') {
1552 return object;
1553 }
1554 const normalizedPath = Array.isArray(path) ? path : path.split('.');
1555 normalizedPath.reduce((acc, key, idx) => {
1556 if (acc[key] === undefined) {
1557 if (Number.isInteger(normalizedPath[idx + 1])) {
1558 acc[key] = [];
1559 } else {
1560 acc[key] = {};
1561 }
1562 }
1563 if (idx === normalizedPath.length - 1) {
1564 acc[key] = value;
1565 }
1566 return acc[key];
1567 }, object);
1568 return object;
1569 }
1570
1571 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/get-nested-value.js
1572 /**
1573 * Helper util to return a value from a certain path of the object.
1574 * Path is specified as either:
1575 * - a string of properties, separated by dots, for example: "x.y".
1576 * - an array of properties, for example `[ 'x', 'y' ]`.
1577 * You can also specify a default value in case the result is nullish.
1578 *
1579 * @param {Object} object Input object.
1580 * @param {string|Array} path Path to the object property.
1581 * @param {*} defaultValue Default value if the value at the specified path is undefined.
1582 * @return {*} Value of the object property at the specified path.
1583 */
1584 function getNestedValue(object, path, defaultValue) {
1585 if (!object || typeof object !== 'object' || typeof path !== 'string' && !Array.isArray(path)) {
1586 return object;
1587 }
1588 const normalizedPath = Array.isArray(path) ? path : path.split('.');
1589 let value = object;
1590 normalizedPath.forEach(fieldName => {
1591 value = value?.[fieldName];
1592 });
1593 return value !== undefined ? value : defaultValue;
1594 }
1595
1596 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/actions.js
1597 /**
1598 * Returns an action object used in signalling that items have been received.
1599 *
1600 * @param {Array} items Items received.
1601 * @param {?Object} edits Optional edits to reset.
1602 * @param {?Object} meta Meta information about pagination.
1603 *
1604 * @return {Object} Action object.
1605 */
1606 function receiveItems(items, edits, meta) {
1607 return {
1608 type: 'RECEIVE_ITEMS',
1609 items: Array.isArray(items) ? items : [items],
1610 persistedEdits: edits,
1611 meta
1612 };
1613 }
1614
1615 /**
1616 * Returns an action object used in signalling that entity records have been
1617 * deleted and they need to be removed from entities state.
1618 *
1619 * @param {string} kind Kind of the removed entities.
1620 * @param {string} name Name of the removed entities.
1621 * @param {Array|number|string} records Record IDs of the removed entities.
1622 * @param {boolean} invalidateCache Controls whether we want to invalidate the cache.
1623 * @return {Object} Action object.
1624 */
1625 function removeItems(kind, name, records, invalidateCache = false) {
1626 return {
1627 type: 'REMOVE_ITEMS',
1628 itemIds: Array.isArray(records) ? records : [records],
1629 kind,
1630 name,
1631 invalidateCache
1632 };
1633 }
1634
1635 /**
1636 * Returns an action object used in signalling that queried data has been
1637 * received.
1638 *
1639 * @param {Array} items Queried items received.
1640 * @param {?Object} query Optional query object.
1641 * @param {?Object} edits Optional edits to reset.
1642 * @param {?Object} meta Meta information about pagination.
1643 *
1644 * @return {Object} Action object.
1645 */
1646 function receiveQueriedItems(items, query = {}, edits, meta) {
1647 return {
1648 ...receiveItems(items, edits, meta),
1649 query
1650 };
1651 }
1652
1653 ;// CONCATENATED MODULE: ./packages/core-data/build-module/batch/default-processor.js
1654 /**
1655 * WordPress dependencies
1656 */
1657
1658
1659 /**
1660 * Maximum number of requests to place in a single batch request. Obtained by
1661 * sending a preflight OPTIONS request to /batch/v1/.
1662 *
1663 * @type {number?}
1664 */
1665 let maxItems = null;
1666 function chunk(arr, chunkSize) {
1667 const tmp = [...arr];
1668 const cache = [];
1669 while (tmp.length) {
1670 cache.push(tmp.splice(0, chunkSize));
1671 }
1672 return cache;
1673 }
1674
1675 /**
1676 * Default batch processor. Sends its input requests to /batch/v1.
1677 *
1678 * @param {Array} requests List of API requests to perform at once.
1679 *
1680 * @return {Promise} Promise that resolves to a list of objects containing
1681 * either `output` (if that request was successful) or `error`
1682 * (if not ).
1683 */
1684 async function defaultProcessor(requests) {
1685 if (maxItems === null) {
1686 const preflightResponse = await external_wp_apiFetch_default()({
1687 path: '/batch/v1',
1688 method: 'OPTIONS'
1689 });
1690 maxItems = preflightResponse.endpoints[0].args.requests.maxItems;
1691 }
1692 const results = [];
1693
1694 // @ts-ignore We would have crashed or never gotten to this point if we hadn't received the maxItems count.
1695 for (const batchRequests of chunk(requests, maxItems)) {
1696 const batchResponse = await external_wp_apiFetch_default()({
1697 path: '/batch/v1',
1698 method: 'POST',
1699 data: {
1700 validation: 'require-all-validate',
1701 requests: batchRequests.map(request => ({
1702 path: request.path,
1703 body: request.data,
1704 // Rename 'data' to 'body'.
1705 method: request.method,
1706 headers: request.headers
1707 }))
1708 }
1709 });
1710 let batchResults;
1711 if (batchResponse.failed) {
1712 batchResults = batchResponse.responses.map(response => ({
1713 error: response?.body
1714 }));
1715 } else {
1716 batchResults = batchResponse.responses.map(response => {
1717 const result = {};
1718 if (response.status >= 200 && response.status < 300) {
1719 result.output = response.body;
1720 } else {
1721 result.error = response.body;
1722 }
1723 return result;
1724 });
1725 }
1726 results.push(...batchResults);
1727 }
1728 return results;
1729 }
1730
1731 ;// CONCATENATED MODULE: ./packages/core-data/build-module/batch/create-batch.js
1732 /**
1733 * Internal dependencies
1734 */
1735
1736
1737 /**
1738 * Creates a batch, which can be used to combine multiple API requests into one
1739 * API request using the WordPress batch processing API (/v1/batch).
1740 *
1741 * ```
1742 * const batch = createBatch();
1743 * const dunePromise = batch.add( {
1744 * path: '/v1/books',
1745 * method: 'POST',
1746 * data: { title: 'Dune' }
1747 * } );
1748 * const lotrPromise = batch.add( {
1749 * path: '/v1/books',
1750 * method: 'POST',
1751 * data: { title: 'Lord of the Rings' }
1752 * } );
1753 * const isSuccess = await batch.run(); // Sends one POST to /v1/batch.
1754 * if ( isSuccess ) {
1755 * console.log(
1756 * 'Saved two books:',
1757 * await dunePromise,
1758 * await lotrPromise
1759 * );
1760 * }
1761 * ```
1762 *
1763 * @param {Function} [processor] Processor function. Can be used to replace the
1764 * default functionality which is to send an API
1765 * request to /v1/batch. Is given an array of
1766 * inputs and must return a promise that
1767 * resolves to an array of objects containing
1768 * either `output` or `error`.
1769 */
1770 function createBatch(processor = defaultProcessor) {
1771 let lastId = 0;
1772 /** @type {Array<{ input: any; resolve: ( value: any ) => void; reject: ( error: any ) => void }>} */
1773 let queue = [];
1774 const pending = new ObservableSet();
1775 return {
1776 /**
1777 * Adds an input to the batch and returns a promise that is resolved or
1778 * rejected when the input is processed by `batch.run()`.
1779 *
1780 * You may also pass a thunk which allows inputs to be added
1781 * asychronously.
1782 *
1783 * ```
1784 * // Both are allowed:
1785 * batch.add( { path: '/v1/books', ... } );
1786 * batch.add( ( add ) => add( { path: '/v1/books', ... } ) );
1787 * ```
1788 *
1789 * If a thunk is passed, `batch.run()` will pause until either:
1790 *
1791 * - The thunk calls its `add` argument, or;
1792 * - The thunk returns a promise and that promise resolves, or;
1793 * - The thunk returns a non-promise.
1794 *
1795 * @param {any|Function} inputOrThunk Input to add or thunk to execute.
1796 *
1797 * @return {Promise|any} If given an input, returns a promise that
1798 * is resolved or rejected when the batch is
1799 * processed. If given a thunk, returns the return
1800 * value of that thunk.
1801 */
1802 add(inputOrThunk) {
1803 const id = ++lastId;
1804 pending.add(id);
1805 const add = input => new Promise((resolve, reject) => {
1806 queue.push({
1807 input,
1808 resolve,
1809 reject
1810 });
1811 pending.delete(id);
1812 });
1813 if (typeof inputOrThunk === 'function') {
1814 return Promise.resolve(inputOrThunk(add)).finally(() => {
1815 pending.delete(id);
1816 });
1817 }
1818 return add(inputOrThunk);
1819 },
1820 /**
1821 * Runs the batch. This calls `batchProcessor` and resolves or rejects
1822 * all promises returned by `add()`.
1823 *
1824 * @return {Promise<boolean>} A promise that resolves to a boolean that is true
1825 * if the processor returned no errors.
1826 */
1827 async run() {
1828 if (pending.size) {
1829 await new Promise(resolve => {
1830 const unsubscribe = pending.subscribe(() => {
1831 if (!pending.size) {
1832 unsubscribe();
1833 resolve(undefined);
1834 }
1835 });
1836 });
1837 }
1838 let results;
1839 try {
1840 results = await processor(queue.map(({
1841 input
1842 }) => input));
1843 if (results.length !== queue.length) {
1844 throw new Error('run: Array returned by processor must be same size as input array.');
1845 }
1846 } catch (error) {
1847 for (const {
1848 reject
1849 } of queue) {
1850 reject(error);
1851 }
1852 throw error;
1853 }
1854 let isSuccess = true;
1855 results.forEach((result, key) => {
1856 const queueItem = queue[key];
1857 if (result?.error) {
1858 queueItem?.reject(result.error);
1859 isSuccess = false;
1860 } else {
1861 var _result$output;
1862 queueItem?.resolve((_result$output = result?.output) !== null && _result$output !== void 0 ? _result$output : result);
1863 }
1864 });
1865 queue = [];
1866 return isSuccess;
1867 }
1868 };
1869 }
1870 class ObservableSet {
1871 constructor(...args) {
1872 this.set = new Set(...args);
1873 this.subscribers = new Set();
1874 }
1875 get size() {
1876 return this.set.size;
1877 }
1878 add(value) {
1879 this.set.add(value);
1880 this.subscribers.forEach(subscriber => subscriber());
1881 return this;
1882 }
1883 delete(value) {
1884 const isSuccess = this.set.delete(value);
1885 this.subscribers.forEach(subscriber => subscriber());
1886 return isSuccess;
1887 }
1888 subscribe(subscriber) {
1889 this.subscribers.add(subscriber);
1890 return () => {
1891 this.subscribers.delete(subscriber);
1892 };
1893 }
1894 }
1895
1896 ;// CONCATENATED MODULE: ./packages/core-data/build-module/name.js
1897 /**
1898 * The reducer key used by core data in store registration.
1899 * This is defined in a separate file to avoid cycle-dependency
1900 *
1901 * @type {string}
1902 */
1903 const STORE_NAME = 'core';
1904
1905 ;// CONCATENATED MODULE: ./node_modules/lib0/map.js
1906 /**
1907 * Utility module to work with key-value stores.
1908 *
1909 * @module map
1910 */
1911
1912 /**
1913 * Creates a new Map instance.
1914 *
1915 * @function
1916 * @return {Map<any, any>}
1917 *
1918 * @function
1919 */
1920 const create = () => new Map()
1921
1922 /**
1923 * Copy a Map object into a fresh Map object.
1924 *
1925 * @function
1926 * @template X,Y
1927 * @param {Map<X,Y>} m
1928 * @return {Map<X,Y>}
1929 */
1930 const copy = m => {
1931 const r = create()
1932 m.forEach((v, k) => { r.set(k, v) })
1933 return r
1934 }
1935
1936 /**
1937 * Get map property. Create T if property is undefined and set T on map.
1938 *
1939 * ```js
1940 * const listeners = map.setIfUndefined(events, 'eventName', set.create)
1941 * listeners.add(listener)
1942 * ```
1943 *
1944 * @function
1945 * @template V,K
1946 * @template {Map<K,V>} MAP
1947 * @param {MAP} map
1948 * @param {K} key
1949 * @param {function():V} createT
1950 * @return {V}
1951 */
1952 const setIfUndefined = (map, key, createT) => {
1953 let set = map.get(key)
1954 if (set === undefined) {
1955 map.set(key, set = createT())
1956 }
1957 return set
1958 }
1959
1960 /**
1961 * Creates an Array and populates it with the content of all key-value pairs using the `f(value, key)` function.
1962 *
1963 * @function
1964 * @template K
1965 * @template V
1966 * @template R
1967 * @param {Map<K,V>} m
1968 * @param {function(V,K):R} f
1969 * @return {Array<R>}
1970 */
1971 const map_map = (m, f) => {
1972 const res = []
1973 for (const [key, value] of m) {
1974 res.push(f(value, key))
1975 }
1976 return res
1977 }
1978
1979 /**
1980 * Tests whether any key-value pairs pass the test implemented by `f(value, key)`.
1981 *
1982 * @todo should rename to some - similarly to Array.some
1983 *
1984 * @function
1985 * @template K
1986 * @template V
1987 * @param {Map<K,V>} m
1988 * @param {function(V,K):boolean} f
1989 * @return {boolean}
1990 */
1991 const any = (m, f) => {
1992 for (const [key, value] of m) {
1993 if (f(value, key)) {
1994 return true
1995 }
1996 }
1997 return false
1998 }
1999
2000 /**
2001 * Tests whether all key-value pairs pass the test implemented by `f(value, key)`.
2002 *
2003 * @function
2004 * @template K
2005 * @template V
2006 * @param {Map<K,V>} m
2007 * @param {function(V,K):boolean} f
2008 * @return {boolean}
2009 */
2010 const map_all = (m, f) => {
2011 for (const [key, value] of m) {
2012 if (!f(value, key)) {
2013 return false
2014 }
2015 }
2016 return true
2017 }
2018
2019 ;// CONCATENATED MODULE: ./node_modules/lib0/set.js
2020 /**
2021 * Utility module to work with sets.
2022 *
2023 * @module set
2024 */
2025
2026 const set_create = () => new Set()
2027
2028 /**
2029 * @template T
2030 * @param {Set<T>} set
2031 * @return {Array<T>}
2032 */
2033 const toArray = set => Array.from(set)
2034
2035 /**
2036 * @template T
2037 * @param {Set<T>} set
2038 * @return {T}
2039 */
2040 const first = set =>
2041 set.values().next().value || undefined
2042
2043 /**
2044 * @template T
2045 * @param {Iterable<T>} entries
2046 * @return {Set<T>}
2047 */
2048 const from = entries => new Set(entries)
2049
2050 ;// CONCATENATED MODULE: ./node_modules/lib0/array.js
2051 /**
2052 * Utility module to work with Arrays.
2053 *
2054 * @module array
2055 */
2056
2057
2058
2059 /**
2060 * Return the last element of an array. The element must exist
2061 *
2062 * @template L
2063 * @param {ArrayLike<L>} arr
2064 * @return {L}
2065 */
2066 const last = arr => arr[arr.length - 1]
2067
2068 /**
2069 * @template C
2070 * @return {Array<C>}
2071 */
2072 const array_create = () => /** @type {Array<C>} */ ([])
2073
2074 /**
2075 * @template D
2076 * @param {Array<D>} a
2077 * @return {Array<D>}
2078 */
2079 const array_copy = a => /** @type {Array<D>} */ (a.slice())
2080
2081 /**
2082 * Append elements from src to dest
2083 *
2084 * @template M
2085 * @param {Array<M>} dest
2086 * @param {Array<M>} src
2087 */
2088 const appendTo = (dest, src) => {
2089 for (let i = 0; i < src.length; i++) {
2090 dest.push(src[i])
2091 }
2092 }
2093
2094 /**
2095 * Transforms something array-like to an actual Array.
2096 *
2097 * @function
2098 * @template T
2099 * @param {ArrayLike<T>|Iterable<T>} arraylike
2100 * @return {T}
2101 */
2102 const array_from = Array.from
2103
2104 /**
2105 * True iff condition holds on every element in the Array.
2106 *
2107 * @function
2108 * @template ITEM
2109 * @template {ArrayLike<ITEM>} ARR
2110 *
2111 * @param {ARR} arr
2112 * @param {function(ITEM, number, ARR):boolean} f
2113 * @return {boolean}
2114 */
2115 const every = (arr, f) => {
2116 for (let i = 0; i < arr.length; i++) {
2117 if (!f(arr[i], i, arr)) {
2118 return false
2119 }
2120 }
2121 return true
2122 }
2123
2124 /**
2125 * True iff condition holds on some element in the Array.
2126 *
2127 * @function
2128 * @template S
2129 * @template {ArrayLike<S>} ARR
2130 * @param {ARR} arr
2131 * @param {function(S, number, ARR):boolean} f
2132 * @return {boolean}
2133 */
2134 const some = (arr, f) => {
2135 for (let i = 0; i < arr.length; i++) {
2136 if (f(arr[i], i, arr)) {
2137 return true
2138 }
2139 }
2140 return false
2141 }
2142
2143 /**
2144 * @template ELEM
2145 *
2146 * @param {ArrayLike<ELEM>} a
2147 * @param {ArrayLike<ELEM>} b
2148 * @return {boolean}
2149 */
2150 const equalFlat = (a, b) => a.length === b.length && every(a, (item, index) => item === b[index])
2151
2152 /**
2153 * @template ELEM
2154 * @param {Array<Array<ELEM>>} arr
2155 * @return {Array<ELEM>}
2156 */
2157 const flatten = arr => fold(arr, /** @type {Array<ELEM>} */ ([]), (acc, val) => acc.concat(val))
2158
2159 /**
2160 * @template T
2161 * @param {number} len
2162 * @param {function(number, Array<T>):T} f
2163 * @return {Array<T>}
2164 */
2165 const unfold = (len, f) => {
2166 const array = new Array(len)
2167 for (let i = 0; i < len; i++) {
2168 array[i] = f(i, array)
2169 }
2170 return array
2171 }
2172
2173 /**
2174 * @template T
2175 * @template RESULT
2176 * @param {Array<T>} arr
2177 * @param {RESULT} seed
2178 * @param {function(RESULT, T, number):RESULT} folder
2179 */
2180 const fold = (arr, seed, folder) => arr.reduce(folder, seed)
2181
2182 const isArray = Array.isArray
2183
2184 /**
2185 * @template T
2186 * @param {Array<T>} arr
2187 * @return {Array<T>}
2188 */
2189 const unique = arr => array_from(set.from(arr))
2190
2191 /**
2192 * @template T
2193 * @template M
2194 * @param {ArrayLike<T>} arr
2195 * @param {function(T):M} mapper
2196 * @return {Array<T>}
2197 */
2198 const uniqueBy = (arr, mapper) => {
2199 /**
2200 * @type {Set<M>}
2201 */
2202 const happened = set.create()
2203 /**
2204 * @type {Array<T>}
2205 */
2206 const result = []
2207 for (let i = 0; i < arr.length; i++) {
2208 const el = arr[i]
2209 const mapped = mapper(el)
2210 if (!happened.has(mapped)) {
2211 happened.add(mapped)
2212 result.push(el)
2213 }
2214 }
2215 return result
2216 }
2217
2218 /**
2219 * @template {ArrayLike<any>} ARR
2220 * @template {function(ARR extends ArrayLike<infer T> ? T : never, number, ARR):any} MAPPER
2221 * @param {ARR} arr
2222 * @param {MAPPER} mapper
2223 * @return {Array<MAPPER extends function(...any): infer M ? M : never>}
2224 */
2225 const array_map = (arr, mapper) => {
2226 /**
2227 * @type {Array<any>}
2228 */
2229 const res = Array(arr.length)
2230 for (let i = 0; i < arr.length; i++) {
2231 res[i] = mapper(/** @type {any} */ (arr[i]), i, /** @type {any} */ (arr))
2232 }
2233 return /** @type {any} */ (res)
2234 }
2235
2236 ;// CONCATENATED MODULE: ./node_modules/lib0/observable.js
2237 /**
2238 * Observable class prototype.
2239 *
2240 * @module observable
2241 */
2242
2243
2244
2245
2246
2247 /**
2248 * Handles named events.
2249 *
2250 * @template N
2251 */
2252 class observable_Observable {
2253 constructor () {
2254 /**
2255 * Some desc.
2256 * @type {Map<N, any>}
2257 */
2258 this._observers = create()
2259 }
2260
2261 /**
2262 * @param {N} name
2263 * @param {function} f
2264 */
2265 on (name, f) {
2266 setIfUndefined(this._observers, name, set_create).add(f)
2267 }
2268
2269 /**
2270 * @param {N} name
2271 * @param {function} f
2272 */
2273 once (name, f) {
2274 /**
2275 * @param {...any} args
2276 */
2277 const _f = (...args) => {
2278 this.off(name, _f)
2279 f(...args)
2280 }
2281 this.on(name, _f)
2282 }
2283
2284 /**
2285 * @param {N} name
2286 * @param {function} f
2287 */
2288 off (name, f) {
2289 const observers = this._observers.get(name)
2290 if (observers !== undefined) {
2291 observers.delete(f)
2292 if (observers.size === 0) {
2293 this._observers.delete(name)
2294 }
2295 }
2296 }
2297
2298 /**
2299 * Emit a named event. All registered event listeners that listen to the
2300 * specified name will receive the event.
2301 *
2302 * @todo This should catch exceptions
2303 *
2304 * @param {N} name The event name.
2305 * @param {Array<any>} args The arguments that are applied to the event listener.
2306 */
2307 emit (name, args) {
2308 // 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.
2309 return array_from((this._observers.get(name) || create()).values()).forEach(f => f(...args))
2310 }
2311
2312 destroy () {
2313 this._observers = create()
2314 }
2315 }
2316
2317 ;// CONCATENATED MODULE: ./node_modules/lib0/math.js
2318 /**
2319 * Common Math expressions.
2320 *
2321 * @module math
2322 */
2323
2324 const floor = Math.floor
2325 const ceil = Math.ceil
2326 const abs = Math.abs
2327 const imul = Math.imul
2328 const round = Math.round
2329 const log10 = Math.log10
2330 const log2 = Math.log2
2331 const log = Math.log
2332 const sqrt = Math.sqrt
2333
2334 /**
2335 * @function
2336 * @param {number} a
2337 * @param {number} b
2338 * @return {number} The sum of a and b
2339 */
2340 const add = (a, b) => a + b
2341
2342 /**
2343 * @function
2344 * @param {number} a
2345 * @param {number} b
2346 * @return {number} The smaller element of a and b
2347 */
2348 const min = (a, b) => a < b ? a : b
2349
2350 /**
2351 * @function
2352 * @param {number} a
2353 * @param {number} b
2354 * @return {number} The bigger element of a and b
2355 */
2356 const max = (a, b) => a > b ? a : b
2357
2358 const math_isNaN = Number.isNaN
2359
2360 const pow = Math.pow
2361 /**
2362 * Base 10 exponential function. Returns the value of 10 raised to the power of pow.
2363 *
2364 * @param {number} exp
2365 * @return {number}
2366 */
2367 const exp10 = exp => Math.pow(10, exp)
2368
2369 const sign = Math.sign
2370
2371 /**
2372 * @param {number} n
2373 * @return {boolean} Wether n is negative. This function also differentiates between -0 and +0
2374 */
2375 const isNegativeZero = n => n !== 0 ? n < 0 : 1 / n < 0
2376
2377 ;// CONCATENATED MODULE: ./node_modules/lib0/string.js
2378
2379
2380 /**
2381 * Utility module to work with strings.
2382 *
2383 * @module string
2384 */
2385
2386 const fromCharCode = String.fromCharCode
2387 const fromCodePoint = String.fromCodePoint
2388
2389 /**
2390 * The largest utf16 character.
2391 * Corresponds to Uint8Array([255, 255]) or charcodeof(2x2^8)
2392 */
2393 const MAX_UTF16_CHARACTER = fromCharCode(65535)
2394
2395 /**
2396 * @param {string} s
2397 * @return {string}
2398 */
2399 const toLowerCase = s => s.toLowerCase()
2400
2401 const trimLeftRegex = /^\s*/g
2402
2403 /**
2404 * @param {string} s
2405 * @return {string}
2406 */
2407 const trimLeft = s => s.replace(trimLeftRegex, '')
2408
2409 const fromCamelCaseRegex = /([A-Z])/g
2410
2411 /**
2412 * @param {string} s
2413 * @param {string} separator
2414 * @return {string}
2415 */
2416 const fromCamelCase = (s, separator) => trimLeft(s.replace(fromCamelCaseRegex, match => `${separator}${toLowerCase(match)}`))
2417
2418 /**
2419 * Compute the utf8ByteLength
2420 * @param {string} str
2421 * @return {number}
2422 */
2423 const utf8ByteLength = str => unescape(encodeURIComponent(str)).length
2424
2425 /**
2426 * @param {string} str
2427 * @return {Uint8Array}
2428 */
2429 const _encodeUtf8Polyfill = str => {
2430 const encodedString = unescape(encodeURIComponent(str))
2431 const len = encodedString.length
2432 const buf = new Uint8Array(len)
2433 for (let i = 0; i < len; i++) {
2434 buf[i] = /** @type {number} */ (encodedString.codePointAt(i))
2435 }
2436 return buf
2437 }
2438
2439 /* c8 ignore next */
2440 const utf8TextEncoder = /** @type {TextEncoder} */ (typeof TextEncoder !== 'undefined' ? new TextEncoder() : null)
2441
2442 /**
2443 * @param {string} str
2444 * @return {Uint8Array}
2445 */
2446 const _encodeUtf8Native = str => utf8TextEncoder.encode(str)
2447
2448 /**
2449 * @param {string} str
2450 * @return {Uint8Array}
2451 */
2452 /* c8 ignore next */
2453 const encodeUtf8 = utf8TextEncoder ? _encodeUtf8Native : _encodeUtf8Polyfill
2454
2455 /**
2456 * @param {Uint8Array} buf
2457 * @return {string}
2458 */
2459 const _decodeUtf8Polyfill = buf => {
2460 let remainingLen = buf.length
2461 let encodedString = ''
2462 let bufPos = 0
2463 while (remainingLen > 0) {
2464 const nextLen = remainingLen < 10000 ? remainingLen : 10000
2465 const bytes = buf.subarray(bufPos, bufPos + nextLen)
2466 bufPos += nextLen
2467 // Starting with ES5.1 we can supply a generic array-like object as arguments
2468 encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes))
2469 remainingLen -= nextLen
2470 }
2471 return decodeURIComponent(escape(encodedString))
2472 }
2473
2474 /* c8 ignore next */
2475 let utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf-8', { fatal: true, ignoreBOM: true })
2476
2477 /* c8 ignore start */
2478 if (utf8TextDecoder && utf8TextDecoder.decode(new Uint8Array()).length === 1) {
2479 // Safari doesn't handle BOM correctly.
2480 // This fixes a bug in Safari 13.0.5 where it produces a BOM the first time it is called.
2481 // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the first call and
2482 // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the second call
2483 // Another issue is that from then on no BOM chars are recognized anymore
2484 /* c8 ignore next */
2485 utf8TextDecoder = null
2486 }
2487 /* c8 ignore stop */
2488
2489 /**
2490 * @param {Uint8Array} buf
2491 * @return {string}
2492 */
2493 const _decodeUtf8Native = buf => /** @type {TextDecoder} */ (utf8TextDecoder).decode(buf)
2494
2495 /**
2496 * @param {Uint8Array} buf
2497 * @return {string}
2498 */
2499 /* c8 ignore next */
2500 const decodeUtf8 = (/* unused pure expression or super */ null && (utf8TextDecoder ? _decodeUtf8Native : _decodeUtf8Polyfill))
2501
2502 /**
2503 * @param {string} str The initial string
2504 * @param {number} index Starting position
2505 * @param {number} remove Number of characters to remove
2506 * @param {string} insert New content to insert
2507 */
2508 const splice = (str, index, remove, insert = '') => str.slice(0, index) + insert + str.slice(index + remove)
2509
2510 /**
2511 * @param {string} source
2512 * @param {number} n
2513 */
2514 const repeat = (source, n) => array.unfold(n, () => source).join('')
2515
2516 ;// CONCATENATED MODULE: ./node_modules/lib0/conditions.js
2517 /**
2518 * Often used conditions.
2519 *
2520 * @module conditions
2521 */
2522
2523 /**
2524 * @template T
2525 * @param {T|null|undefined} v
2526 * @return {T|null}
2527 */
2528 /* c8 ignore next */
2529 const undefinedToNull = v => v === undefined ? null : v
2530
2531 ;// CONCATENATED MODULE: ./node_modules/lib0/storage.js
2532 /* eslint-env browser */
2533
2534 /**
2535 * Isomorphic variable storage.
2536 *
2537 * Uses LocalStorage in the browser and falls back to in-memory storage.
2538 *
2539 * @module storage
2540 */
2541
2542 /* c8 ignore start */
2543 class VarStoragePolyfill {
2544 constructor () {
2545 this.map = new Map()
2546 }
2547
2548 /**
2549 * @param {string} key
2550 * @param {any} newValue
2551 */
2552 setItem (key, newValue) {
2553 this.map.set(key, newValue)
2554 }
2555
2556 /**
2557 * @param {string} key
2558 */
2559 getItem (key) {
2560 return this.map.get(key)
2561 }
2562 }
2563 /* c8 ignore stop */
2564
2565 /**
2566 * @type {any}
2567 */
2568 let _localStorage = new VarStoragePolyfill()
2569 let usePolyfill = true
2570
2571 /* c8 ignore start */
2572 try {
2573 // if the same-origin rule is violated, accessing localStorage might thrown an error
2574 if (typeof localStorage !== 'undefined') {
2575 _localStorage = localStorage
2576 usePolyfill = false
2577 }
2578 } catch (e) { }
2579 /* c8 ignore stop */
2580
2581 /**
2582 * This is basically localStorage in browser, or a polyfill in nodejs
2583 */
2584 /* c8 ignore next */
2585 const varStorage = _localStorage
2586
2587 /**
2588 * A polyfill for `addEventListener('storage', event => {..})` that does nothing if the polyfill is being used.
2589 *
2590 * @param {function({ key: string, newValue: string, oldValue: string }): void} eventHandler
2591 * @function
2592 */
2593 /* c8 ignore next */
2594 const onChange = eventHandler => usePolyfill || addEventListener('storage', /** @type {any} */ (eventHandler))
2595
2596 /**
2597 * A polyfill for `removeEventListener('storage', event => {..})` that does nothing if the polyfill is being used.
2598 *
2599 * @param {function({ key: string, newValue: string, oldValue: string }): void} eventHandler
2600 * @function
2601 */
2602 /* c8 ignore next */
2603 const offChange = eventHandler => usePolyfill || removeEventListener('storage', /** @type {any} */ (eventHandler))
2604
2605 ;// CONCATENATED MODULE: ./node_modules/lib0/object.js
2606 /**
2607 * Utility functions for working with EcmaScript objects.
2608 *
2609 * @module object
2610 */
2611
2612 /**
2613 * @return {Object<string,any>} obj
2614 */
2615 const object_create = () => Object.create(null)
2616
2617 /**
2618 * Object.assign
2619 */
2620 const object_assign = Object.assign
2621
2622 /**
2623 * @param {Object<string,any>} obj
2624 */
2625 const keys = Object.keys
2626
2627 /**
2628 * @template V
2629 * @param {{[k:string]:V}} obj
2630 * @param {function(V,string):any} f
2631 */
2632 const forEach = (obj, f) => {
2633 for (const key in obj) {
2634 f(obj[key], key)
2635 }
2636 }
2637
2638 /**
2639 * @todo implement mapToArray & map
2640 *
2641 * @template R
2642 * @param {Object<string,any>} obj
2643 * @param {function(any,string):R} f
2644 * @return {Array<R>}
2645 */
2646 const object_map = (obj, f) => {
2647 const results = []
2648 for (const key in obj) {
2649 results.push(f(obj[key], key))
2650 }
2651 return results
2652 }
2653
2654 /**
2655 * @param {Object<string,any>} obj
2656 * @return {number}
2657 */
2658 const object_length = obj => keys(obj).length
2659
2660 /**
2661 * @param {Object<string,any>} obj
2662 * @param {function(any,string):boolean} f
2663 * @return {boolean}
2664 */
2665 const object_some = (obj, f) => {
2666 for (const key in obj) {
2667 if (f(obj[key], key)) {
2668 return true
2669 }
2670 }
2671 return false
2672 }
2673
2674 /**
2675 * @param {Object|undefined} obj
2676 */
2677 const isEmpty = obj => {
2678 // eslint-disable-next-line
2679 for (const _k in obj) {
2680 return false
2681 }
2682 return true
2683 }
2684
2685 /**
2686 * @param {Object<string,any>} obj
2687 * @param {function(any,string):boolean} f
2688 * @return {boolean}
2689 */
2690 const object_every = (obj, f) => {
2691 for (const key in obj) {
2692 if (!f(obj[key], key)) {
2693 return false
2694 }
2695 }
2696 return true
2697 }
2698
2699 /**
2700 * Calls `Object.prototype.hasOwnProperty`.
2701 *
2702 * @param {any} obj
2703 * @param {string|symbol} key
2704 * @return {boolean}
2705 */
2706 const hasProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key)
2707
2708 /**
2709 * @param {Object<string,any>} a
2710 * @param {Object<string,any>} b
2711 * @return {boolean}
2712 */
2713 const 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))
2714
2715 ;// CONCATENATED MODULE: ./node_modules/lib0/function.js
2716 /**
2717 * Common functions and function call helpers.
2718 *
2719 * @module function
2720 */
2721
2722
2723
2724
2725 /**
2726 * Calls all functions in `fs` with args. Only throws after all functions were called.
2727 *
2728 * @param {Array<function>} fs
2729 * @param {Array<any>} args
2730 */
2731 const callAll = (fs, args, i = 0) => {
2732 try {
2733 for (; i < fs.length; i++) {
2734 fs[i](...args)
2735 }
2736 } finally {
2737 if (i < fs.length) {
2738 callAll(fs, args, i + 1)
2739 }
2740 }
2741 }
2742
2743 const nop = () => {}
2744
2745 /**
2746 * @template T
2747 * @param {function():T} f
2748 * @return {T}
2749 */
2750 const apply = f => f()
2751
2752 /**
2753 * @template A
2754 *
2755 * @param {A} a
2756 * @return {A}
2757 */
2758 const id = a => a
2759
2760 /**
2761 * @template T
2762 *
2763 * @param {T} a
2764 * @param {T} b
2765 * @return {boolean}
2766 */
2767 const equalityStrict = (a, b) => a === b
2768
2769 /**
2770 * @template T
2771 *
2772 * @param {Array<T>|object} a
2773 * @param {Array<T>|object} b
2774 * @return {boolean}
2775 */
2776 const 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))))
2777
2778 /* c8 ignore start */
2779
2780 /**
2781 * @param {any} a
2782 * @param {any} b
2783 * @return {boolean}
2784 */
2785 const equalityDeep = (a, b) => {
2786 if (a == null || b == null) {
2787 return equalityStrict(a, b)
2788 }
2789 if (a.constructor !== b.constructor) {
2790 return false
2791 }
2792 if (a === b) {
2793 return true
2794 }
2795 switch (a.constructor) {
2796 case ArrayBuffer:
2797 a = new Uint8Array(a)
2798 b = new Uint8Array(b)
2799 // eslint-disable-next-line no-fallthrough
2800 case Uint8Array: {
2801 if (a.byteLength !== b.byteLength) {
2802 return false
2803 }
2804 for (let i = 0; i < a.length; i++) {
2805 if (a[i] !== b[i]) {
2806 return false
2807 }
2808 }
2809 break
2810 }
2811 case Set: {
2812 if (a.size !== b.size) {
2813 return false
2814 }
2815 for (const value of a) {
2816 if (!b.has(value)) {
2817 return false
2818 }
2819 }
2820 break
2821 }
2822 case Map: {
2823 if (a.size !== b.size) {
2824 return false
2825 }
2826 for (const key of a.keys()) {
2827 if (!b.has(key) || !equalityDeep(a.get(key), b.get(key))) {
2828 return false
2829 }
2830 }
2831 break
2832 }
2833 case Object:
2834 if (object_length(a) !== object_length(b)) {
2835 return false
2836 }
2837 for (const key in a) {
2838 if (!hasProperty(a, key) || !equalityDeep(a[key], b[key])) {
2839 return false
2840 }
2841 }
2842 break
2843 case Array:
2844 if (a.length !== b.length) {
2845 return false
2846 }
2847 for (let i = 0; i < a.length; i++) {
2848 if (!equalityDeep(a[i], b[i])) {
2849 return false
2850 }
2851 }
2852 break
2853 default:
2854 return false
2855 }
2856 return true
2857 }
2858
2859 /**
2860 * @template V
2861 * @template {V} OPTS
2862 *
2863 * @param {V} value
2864 * @param {Array<OPTS>} options
2865 */
2866 // @ts-ignore
2867 const isOneOf = (value, options) => options.includes(value)
2868 /* c8 ignore stop */
2869
2870 const function_isArray = isArray
2871
2872 /**
2873 * @param {any} s
2874 * @return {s is String}
2875 */
2876 const isString = (s) => s && s.constructor === String
2877
2878 /**
2879 * @param {any} n
2880 * @return {n is Number}
2881 */
2882 const isNumber = n => n != null && n.constructor === Number
2883
2884 /**
2885 * @template {abstract new (...args: any) => any} TYPE
2886 * @param {any} n
2887 * @param {TYPE} T
2888 * @return {n is InstanceType<TYPE>}
2889 */
2890 const is = (n, T) => n && n.constructor === T
2891
2892 /**
2893 * @template {abstract new (...args: any) => any} TYPE
2894 * @param {TYPE} T
2895 */
2896 const isTemplate = (T) =>
2897 /**
2898 * @param {any} n
2899 * @return {n is InstanceType<TYPE>}
2900 **/
2901 n => n && n.constructor === T
2902
2903 ;// CONCATENATED MODULE: ./node_modules/lib0/environment.js
2904 /**
2905 * Isomorphic module to work access the environment (query params, env variables).
2906 *
2907 * @module map
2908 */
2909
2910
2911
2912
2913
2914
2915
2916 /* c8 ignore next */
2917 // @ts-ignore
2918 const isNode = typeof process !== 'undefined' && process.release &&
2919 /node|io\.js/.test(process.release.name)
2920 /* c8 ignore next */
2921 const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && !isNode
2922 /* c8 ignore next 3 */
2923 const isMac = typeof navigator !== 'undefined'
2924 ? /Mac/.test(navigator.platform)
2925 : false
2926
2927 /**
2928 * @type {Map<string,string>}
2929 */
2930 let params
2931 const args = []
2932
2933 /* c8 ignore start */
2934 const computeParams = () => {
2935 if (params === undefined) {
2936 if (isNode) {
2937 params = create()
2938 const pargs = process.argv
2939 let currParamName = null
2940 for (let i = 0; i < pargs.length; i++) {
2941 const parg = pargs[i]
2942 if (parg[0] === '-') {
2943 if (currParamName !== null) {
2944 params.set(currParamName, '')
2945 }
2946 currParamName = parg
2947 } else {
2948 if (currParamName !== null) {
2949 params.set(currParamName, parg)
2950 currParamName = null
2951 } else {
2952 args.push(parg)
2953 }
2954 }
2955 }
2956 if (currParamName !== null) {
2957 params.set(currParamName, '')
2958 }
2959 // in ReactNative for example this would not be true (unless connected to the Remote Debugger)
2960 } else if (typeof location === 'object') {
2961 params = create(); // eslint-disable-next-line no-undef
2962 (location.search || '?').slice(1).split('&').forEach((kv) => {
2963 if (kv.length !== 0) {
2964 const [key, value] = kv.split('=')
2965 params.set(`--${fromCamelCase(key, '-')}`, value)
2966 params.set(`-${fromCamelCase(key, '-')}`, value)
2967 }
2968 })
2969 } else {
2970 params = create()
2971 }
2972 }
2973 return params
2974 }
2975 /* c8 ignore stop */
2976
2977 /**
2978 * @param {string} name
2979 * @return {boolean}
2980 */
2981 /* c8 ignore next */
2982 const hasParam = (name) => computeParams().has(name)
2983
2984 /**
2985 * @param {string} name
2986 * @param {string} defaultVal
2987 * @return {string}
2988 */
2989 /* c8 ignore next 2 */
2990 const getParam = (name, defaultVal) =>
2991 computeParams().get(name) || defaultVal
2992
2993 /**
2994 * @param {string} name
2995 * @return {string|null}
2996 */
2997 /* c8 ignore next 4 */
2998 const getVariable = (name) =>
2999 isNode
3000 ? undefinedToNull(process.env[name.toUpperCase()])
3001 : undefinedToNull(varStorage.getItem(name))
3002
3003 /**
3004 * @param {string} name
3005 * @return {string|null}
3006 */
3007 /* c8 ignore next 2 */
3008 const getConf = (name) =>
3009 computeParams().get('--' + name) || getVariable(name)
3010
3011 /**
3012 * @param {string} name
3013 * @return {boolean}
3014 */
3015 /* c8 ignore next 2 */
3016 const hasConf = (name) =>
3017 hasParam('--' + name) || getVariable(name) !== null
3018
3019 /* c8 ignore next */
3020 const production = hasConf('production')
3021
3022 /* c8 ignore next 2 */
3023 const forceColor = isNode &&
3024 isOneOf(process.env.FORCE_COLOR, ['true', '1', '2'])
3025
3026 /* c8 ignore start */
3027 const supportsColor = !hasParam('no-colors') &&
3028 (!isNode || process.stdout.isTTY || forceColor) && (
3029 !isNode || hasParam('color') || forceColor ||
3030 getVariable('COLORTERM') !== null ||
3031 (getVariable('TERM') || '').includes('color')
3032 )
3033 /* c8 ignore stop */
3034
3035 ;// CONCATENATED MODULE: ./node_modules/lib0/buffer.js
3036 /**
3037 * Utility functions to work with buffers (Uint8Array).
3038 *
3039 * @module buffer
3040 */
3041
3042
3043
3044
3045
3046
3047
3048
3049 /**
3050 * @param {number} len
3051 */
3052 const createUint8ArrayFromLen = len => new Uint8Array(len)
3053
3054 /**
3055 * Create Uint8Array with initial content from buffer
3056 *
3057 * @param {ArrayBuffer} buffer
3058 * @param {number} byteOffset
3059 * @param {number} length
3060 */
3061 const createUint8ArrayViewFromArrayBuffer = (buffer, byteOffset, length) => new Uint8Array(buffer, byteOffset, length)
3062
3063 /**
3064 * Create Uint8Array with initial content from buffer
3065 *
3066 * @param {ArrayBuffer} buffer
3067 */
3068 const createUint8ArrayFromArrayBuffer = buffer => new Uint8Array(buffer)
3069
3070 /* c8 ignore start */
3071 /**
3072 * @param {Uint8Array} bytes
3073 * @return {string}
3074 */
3075 const toBase64Browser = bytes => {
3076 let s = ''
3077 for (let i = 0; i < bytes.byteLength; i++) {
3078 s += fromCharCode(bytes[i])
3079 }
3080 // eslint-disable-next-line no-undef
3081 return btoa(s)
3082 }
3083 /* c8 ignore stop */
3084
3085 /**
3086 * @param {Uint8Array} bytes
3087 * @return {string}
3088 */
3089 const toBase64Node = bytes => Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64')
3090
3091 /* c8 ignore start */
3092 /**
3093 * @param {string} s
3094 * @return {Uint8Array}
3095 */
3096 const fromBase64Browser = s => {
3097 // eslint-disable-next-line no-undef
3098 const a = atob(s)
3099 const bytes = createUint8ArrayFromLen(a.length)
3100 for (let i = 0; i < a.length; i++) {
3101 bytes[i] = a.charCodeAt(i)
3102 }
3103 return bytes
3104 }
3105 /* c8 ignore stop */
3106
3107 /**
3108 * @param {string} s
3109 */
3110 const fromBase64Node = s => {
3111 const buf = Buffer.from(s, 'base64')
3112 return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)
3113 }
3114
3115 /* c8 ignore next */
3116 const toBase64 = isBrowser ? toBase64Browser : toBase64Node
3117
3118 /* c8 ignore next */
3119 const fromBase64 = isBrowser ? fromBase64Browser : fromBase64Node
3120
3121 /**
3122 * Base64 is always a more efficient choice. This exists for utility purposes only.
3123 *
3124 * @param {Uint8Array} buf
3125 */
3126 const toHexString = buf => array.map(buf, b => b.toString(16).padStart(2, '0')).join('')
3127
3128 /**
3129 * Note: This function expects that the hex doesn't start with 0x..
3130 *
3131 * @param {string} hex
3132 */
3133 const fromHexString = hex => {
3134 const hlen = hex.length
3135 const buf = new Uint8Array(math.ceil(hlen / 2))
3136 for (let i = 0; i < hlen; i += 2) {
3137 buf[buf.length - i / 2 - 1] = Number.parseInt(hex.slice(hlen - i - 2, hlen - i), 16)
3138 }
3139 return buf
3140 }
3141
3142 /**
3143 * Copy the content of an Uint8Array view to a new ArrayBuffer.
3144 *
3145 * @param {Uint8Array} uint8Array
3146 * @return {Uint8Array}
3147 */
3148 const copyUint8Array = uint8Array => {
3149 const newBuf = createUint8ArrayFromLen(uint8Array.byteLength)
3150 newBuf.set(uint8Array)
3151 return newBuf
3152 }
3153
3154 /**
3155 * Encode anything as a UInt8Array. It's a pun on typescripts's `any` type.
3156 * See encoding.writeAny for more information.
3157 *
3158 * @param {any} data
3159 * @return {Uint8Array}
3160 */
3161 const encodeAny = data => {
3162 const encoder = encoding.createEncoder()
3163 encoding.writeAny(encoder, data)
3164 return encoding.toUint8Array(encoder)
3165 }
3166
3167 /**
3168 * Decode an any-encoded value.
3169 *
3170 * @param {Uint8Array} buf
3171 * @return {any}
3172 */
3173 const decodeAny = buf => decoding.readAny(decoding.createDecoder(buf))
3174
3175 /**
3176 * Shift Byte Array {N} bits to the left. Does not expand byte array.
3177 *
3178 * @param {Uint8Array} bs
3179 * @param {number} N should be in the range of [0-7]
3180 */
3181 const shiftNBitsLeft = (bs, N) => {
3182 if (N === 0) return bs
3183 bs = new Uint8Array(bs)
3184 bs[0] <<= N
3185 for (let i = 1; i < bs.length; i++) {
3186 bs[i - 1] |= bs[i] >>> (8 - N)
3187 bs[i] <<= N
3188 }
3189 return bs
3190 }
3191
3192 ;// CONCATENATED MODULE: ./node_modules/lib0/binary.js
3193 /* eslint-env browser */
3194
3195 /**
3196 * Binary data constants.
3197 *
3198 * @module binary
3199 */
3200
3201 /**
3202 * n-th bit activated.
3203 *
3204 * @type {number}
3205 */
3206 const BIT1 = 1
3207 const BIT2 = 2
3208 const BIT3 = 4
3209 const BIT4 = 8
3210 const BIT5 = 16
3211 const BIT6 = 32
3212 const BIT7 = 64
3213 const BIT8 = 128
3214 const BIT9 = 256
3215 const BIT10 = 512
3216 const BIT11 = 1024
3217 const BIT12 = 2048
3218 const BIT13 = 4096
3219 const BIT14 = 8192
3220 const BIT15 = 16384
3221 const BIT16 = 32768
3222 const BIT17 = 65536
3223 const BIT18 = 1 << 17
3224 const BIT19 = 1 << 18
3225 const BIT20 = 1 << 19
3226 const BIT21 = 1 << 20
3227 const BIT22 = 1 << 21
3228 const BIT23 = 1 << 22
3229 const BIT24 = 1 << 23
3230 const BIT25 = 1 << 24
3231 const BIT26 = 1 << 25
3232 const BIT27 = 1 << 26
3233 const BIT28 = 1 << 27
3234 const BIT29 = 1 << 28
3235 const BIT30 = 1 << 29
3236 const BIT31 = 1 << 30
3237 const BIT32 = (/* unused pure expression or super */ null && (1 << 31))
3238
3239 /**
3240 * First n bits activated.
3241 *
3242 * @type {number}
3243 */
3244 const BITS0 = 0
3245 const BITS1 = 1
3246 const BITS2 = 3
3247 const BITS3 = 7
3248 const BITS4 = 15
3249 const BITS5 = 31
3250 const BITS6 = 63
3251 const BITS7 = 127
3252 const BITS8 = 255
3253 const BITS9 = 511
3254 const BITS10 = 1023
3255 const BITS11 = 2047
3256 const BITS12 = 4095
3257 const BITS13 = 8191
3258 const BITS14 = 16383
3259 const BITS15 = 32767
3260 const BITS16 = 65535
3261 const BITS17 = BIT18 - 1
3262 const BITS18 = BIT19 - 1
3263 const BITS19 = BIT20 - 1
3264 const BITS20 = BIT21 - 1
3265 const BITS21 = BIT22 - 1
3266 const BITS22 = BIT23 - 1
3267 const BITS23 = BIT24 - 1
3268 const BITS24 = BIT25 - 1
3269 const BITS25 = BIT26 - 1
3270 const BITS26 = BIT27 - 1
3271 const BITS27 = BIT28 - 1
3272 const BITS28 = BIT29 - 1
3273 const BITS29 = BIT30 - 1
3274 const BITS30 = BIT31 - 1
3275 /**
3276 * @type {number}
3277 */
3278 const BITS31 = 0x7FFFFFFF
3279 /**
3280 * @type {number}
3281 */
3282 const BITS32 = 0xFFFFFFFF
3283
3284 ;// CONCATENATED MODULE: ./node_modules/lib0/number.js
3285 /**
3286 * Utility helpers for working with numbers.
3287 *
3288 * @module number
3289 */
3290
3291
3292
3293
3294 const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER
3295 const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER
3296
3297 const LOWEST_INT32 = (/* unused pure expression or super */ null && (1 << 31))
3298 const HIGHEST_INT32 = BITS31
3299 const HIGHEST_UINT32 = BITS32
3300
3301 /* c8 ignore next */
3302 const isInteger = Number.isInteger || (num => typeof num === 'number' && isFinite(num) && floor(num) === num)
3303 const number_isNaN = Number.isNaN
3304 const number_parseInt = Number.parseInt
3305
3306 /**
3307 * Count the number of "1" bits in an unsigned 32bit number.
3308 *
3309 * Super fun bitcount algorithm by Brian Kernighan.
3310 *
3311 * @param {number} n
3312 */
3313 const countBits = n => {
3314 n &= binary.BITS32
3315 let count = 0
3316 while (n) {
3317 n &= (n - 1)
3318 count++
3319 }
3320 return count
3321 }
3322
3323 ;// CONCATENATED MODULE: ./node_modules/lib0/encoding.js
3324 /**
3325 * Efficient schema-less binary encoding with support for variable length encoding.
3326 *
3327 * Use [lib0/encoding] with [lib0/decoding]. Every encoding function has a corresponding decoding function.
3328 *
3329 * Encodes numbers in little-endian order (least to most significant byte order)
3330 * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
3331 * which is also used in Protocol Buffers.
3332 *
3333 * ```js
3334 * // encoding step
3335 * const encoder = encoding.createEncoder()
3336 * encoding.writeVarUint(encoder, 256)
3337 * encoding.writeVarString(encoder, 'Hello world!')
3338 * const buf = encoding.toUint8Array(encoder)
3339 * ```
3340 *
3341 * ```js
3342 * // decoding step
3343 * const decoder = decoding.createDecoder(buf)
3344 * decoding.readVarUint(decoder) // => 256
3345 * decoding.readVarString(decoder) // => 'Hello world!'
3346 * decoding.hasContent(decoder) // => false - all data is read
3347 * ```
3348 *
3349 * @module encoding
3350 */
3351
3352
3353
3354
3355
3356
3357
3358
3359 /**
3360 * A BinaryEncoder handles the encoding to an Uint8Array.
3361 */
3362 class Encoder {
3363 constructor () {
3364 this.cpos = 0
3365 this.cbuf = new Uint8Array(100)
3366 /**
3367 * @type {Array<Uint8Array>}
3368 */
3369 this.bufs = []
3370 }
3371 }
3372
3373 /**
3374 * @function
3375 * @return {Encoder}
3376 */
3377 const createEncoder = () => new Encoder()
3378
3379 /**
3380 * @param {function(Encoder):void} f
3381 */
3382 const encode = (f) => {
3383 const encoder = createEncoder()
3384 f(encoder)
3385 return toUint8Array(encoder)
3386 }
3387
3388 /**
3389 * The current length of the encoded data.
3390 *
3391 * @function
3392 * @param {Encoder} encoder
3393 * @return {number}
3394 */
3395 const encoding_length = encoder => {
3396 let len = encoder.cpos
3397 for (let i = 0; i < encoder.bufs.length; i++) {
3398 len += encoder.bufs[i].length
3399 }
3400 return len
3401 }
3402
3403 /**
3404 * Check whether encoder is empty.
3405 *
3406 * @function
3407 * @param {Encoder} encoder
3408 * @return {boolean}
3409 */
3410 const hasContent = encoder => encoder.cpos > 0 || encoder.bufs.length > 0
3411
3412 /**
3413 * Transform to Uint8Array.
3414 *
3415 * @function
3416 * @param {Encoder} encoder
3417 * @return {Uint8Array} The created ArrayBuffer.
3418 */
3419 const toUint8Array = encoder => {
3420 const uint8arr = new Uint8Array(encoding_length(encoder))
3421 let curPos = 0
3422 for (let i = 0; i < encoder.bufs.length; i++) {
3423 const d = encoder.bufs[i]
3424 uint8arr.set(d, curPos)
3425 curPos += d.length
3426 }
3427 uint8arr.set(createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos), curPos)
3428 return uint8arr
3429 }
3430
3431 /**
3432 * Verify that it is possible to write `len` bytes wtihout checking. If
3433 * necessary, a new Buffer with the required length is attached.
3434 *
3435 * @param {Encoder} encoder
3436 * @param {number} len
3437 */
3438 const verifyLen = (encoder, len) => {
3439 const bufferLen = encoder.cbuf.length
3440 if (bufferLen - encoder.cpos < len) {
3441 encoder.bufs.push(createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos))
3442 encoder.cbuf = new Uint8Array(max(bufferLen, len) * 2)
3443 encoder.cpos = 0
3444 }
3445 }
3446
3447 /**
3448 * Write one byte to the encoder.
3449 *
3450 * @function
3451 * @param {Encoder} encoder
3452 * @param {number} num The byte that is to be encoded.
3453 */
3454 const write = (encoder, num) => {
3455 const bufferLen = encoder.cbuf.length
3456 if (encoder.cpos === bufferLen) {
3457 encoder.bufs.push(encoder.cbuf)
3458 encoder.cbuf = new Uint8Array(bufferLen * 2)
3459 encoder.cpos = 0
3460 }
3461 encoder.cbuf[encoder.cpos++] = num
3462 }
3463
3464 /**
3465 * Write one byte at a specific position.
3466 * Position must already be written (i.e. encoder.length > pos)
3467 *
3468 * @function
3469 * @param {Encoder} encoder
3470 * @param {number} pos Position to which to write data
3471 * @param {number} num Unsigned 8-bit integer
3472 */
3473 const encoding_set = (encoder, pos, num) => {
3474 let buffer = null
3475 // iterate all buffers and adjust position
3476 for (let i = 0; i < encoder.bufs.length && buffer === null; i++) {
3477 const b = encoder.bufs[i]
3478 if (pos < b.length) {
3479 buffer = b // found buffer
3480 } else {
3481 pos -= b.length
3482 }
3483 }
3484 if (buffer === null) {
3485 // use current buffer
3486 buffer = encoder.cbuf
3487 }
3488 buffer[pos] = num
3489 }
3490
3491 /**
3492 * Write one byte as an unsigned integer.
3493 *
3494 * @function
3495 * @param {Encoder} encoder
3496 * @param {number} num The number that is to be encoded.
3497 */
3498 const writeUint8 = write
3499
3500 /**
3501 * Write one byte as an unsigned Integer at a specific location.
3502 *
3503 * @function
3504 * @param {Encoder} encoder
3505 * @param {number} pos The location where the data will be written.
3506 * @param {number} num The number that is to be encoded.
3507 */
3508 const setUint8 = (/* unused pure expression or super */ null && (encoding_set))
3509
3510 /**
3511 * Write two bytes as an unsigned integer.
3512 *
3513 * @function
3514 * @param {Encoder} encoder
3515 * @param {number} num The number that is to be encoded.
3516 */
3517 const writeUint16 = (encoder, num) => {
3518 write(encoder, num & binary.BITS8)
3519 write(encoder, (num >>> 8) & binary.BITS8)
3520 }
3521 /**
3522 * Write two bytes as an unsigned integer at a specific location.
3523 *
3524 * @function
3525 * @param {Encoder} encoder
3526 * @param {number} pos The location where the data will be written.
3527 * @param {number} num The number that is to be encoded.
3528 */
3529 const setUint16 = (encoder, pos, num) => {
3530 encoding_set(encoder, pos, num & binary.BITS8)
3531 encoding_set(encoder, pos + 1, (num >>> 8) & binary.BITS8)
3532 }
3533
3534 /**
3535 * Write two bytes as an unsigned integer
3536 *
3537 * @function
3538 * @param {Encoder} encoder
3539 * @param {number} num The number that is to be encoded.
3540 */
3541 const writeUint32 = (encoder, num) => {
3542 for (let i = 0; i < 4; i++) {
3543 write(encoder, num & binary.BITS8)
3544 num >>>= 8
3545 }
3546 }
3547
3548 /**
3549 * Write two bytes as an unsigned integer in big endian order.
3550 * (most significant byte first)
3551 *
3552 * @function
3553 * @param {Encoder} encoder
3554 * @param {number} num The number that is to be encoded.
3555 */
3556 const writeUint32BigEndian = (encoder, num) => {
3557 for (let i = 3; i >= 0; i--) {
3558 write(encoder, (num >>> (8 * i)) & binary.BITS8)
3559 }
3560 }
3561
3562 /**
3563 * Write two bytes as an unsigned integer at a specific location.
3564 *
3565 * @function
3566 * @param {Encoder} encoder
3567 * @param {number} pos The location where the data will be written.
3568 * @param {number} num The number that is to be encoded.
3569 */
3570 const setUint32 = (encoder, pos, num) => {
3571 for (let i = 0; i < 4; i++) {
3572 encoding_set(encoder, pos + i, num & binary.BITS8)
3573 num >>>= 8
3574 }
3575 }
3576
3577 /**
3578 * Write a variable length unsigned integer. Max encodable integer is 2^53.
3579 *
3580 * @function
3581 * @param {Encoder} encoder
3582 * @param {number} num The number that is to be encoded.
3583 */
3584 const writeVarUint = (encoder, num) => {
3585 while (num > BITS7) {
3586 write(encoder, BIT8 | (BITS7 & num))
3587 num = floor(num / 128) // shift >>> 7
3588 }
3589 write(encoder, BITS7 & num)
3590 }
3591
3592 /**
3593 * Write a variable length integer.
3594 *
3595 * We use the 7th bit instead for signaling that this is a negative number.
3596 *
3597 * @function
3598 * @param {Encoder} encoder
3599 * @param {number} num The number that is to be encoded.
3600 */
3601 const writeVarInt = (encoder, num) => {
3602 const isNegative = isNegativeZero(num)
3603 if (isNegative) {
3604 num = -num
3605 }
3606 // |- whether to continue reading |- whether is negative |- number
3607 write(encoder, (num > BITS6 ? BIT8 : 0) | (isNegative ? BIT7 : 0) | (BITS6 & num))
3608 num = floor(num / 64) // shift >>> 6
3609 // We don't need to consider the case of num === 0 so we can use a different
3610 // pattern here than above.
3611 while (num > 0) {
3612 write(encoder, (num > BITS7 ? BIT8 : 0) | (BITS7 & num))
3613 num = floor(num / 128) // shift >>> 7
3614 }
3615 }
3616
3617 /**
3618 * A cache to store strings temporarily
3619 */
3620 const _strBuffer = new Uint8Array(30000)
3621 const _maxStrBSize = _strBuffer.length / 3
3622
3623 /**
3624 * Write a variable length string.
3625 *
3626 * @function
3627 * @param {Encoder} encoder
3628 * @param {String} str The string that is to be encoded.
3629 */
3630 const _writeVarStringNative = (encoder, str) => {
3631 if (str.length < _maxStrBSize) {
3632 // We can encode the string into the existing buffer
3633 /* c8 ignore next */
3634 const written = utf8TextEncoder.encodeInto(str, _strBuffer).written || 0
3635 writeVarUint(encoder, written)
3636 for (let i = 0; i < written; i++) {
3637 write(encoder, _strBuffer[i])
3638 }
3639 } else {
3640 writeVarUint8Array(encoder, encodeUtf8(str))
3641 }
3642 }
3643
3644 /**
3645 * Write a variable length string.
3646 *
3647 * @function
3648 * @param {Encoder} encoder
3649 * @param {String} str The string that is to be encoded.
3650 */
3651 const _writeVarStringPolyfill = (encoder, str) => {
3652 const encodedString = unescape(encodeURIComponent(str))
3653 const len = encodedString.length
3654 writeVarUint(encoder, len)
3655 for (let i = 0; i < len; i++) {
3656 write(encoder, /** @type {number} */ (encodedString.codePointAt(i)))
3657 }
3658 }
3659
3660 /**
3661 * Write a variable length string.
3662 *
3663 * @function
3664 * @param {Encoder} encoder
3665 * @param {String} str The string that is to be encoded.
3666 */
3667 /* c8 ignore next */
3668 const writeVarString = (utf8TextEncoder && /** @type {any} */ (utf8TextEncoder).encodeInto) ? _writeVarStringNative : _writeVarStringPolyfill
3669
3670 /**
3671 * Write a string terminated by a special byte sequence. This is not very performant and is
3672 * generally discouraged. However, the resulting byte arrays are lexiographically ordered which
3673 * makes this a nice feature for databases.
3674 *
3675 * The string will be encoded using utf8 and then terminated and escaped using writeTerminatingUint8Array.
3676 *
3677 * @function
3678 * @param {Encoder} encoder
3679 * @param {String} str The string that is to be encoded.
3680 */
3681 const writeTerminatedString = (encoder, str) =>
3682 writeTerminatedUint8Array(encoder, string.encodeUtf8(str))
3683
3684 /**
3685 * Write a terminating Uint8Array. Note that this is not performant and is generally
3686 * discouraged. There are few situations when this is needed.
3687 *
3688 * We use 0x0 as a terminating character. 0x1 serves as an escape character for 0x0 and 0x1.
3689 *
3690 * Example: [0,1,2] is encoded to [1,0,1,1,2,0]. 0x0, and 0x1 needed to be escaped using 0x1. Then
3691 * the result is terminated using the 0x0 character.
3692 *
3693 * This is basically how many systems implement null terminated strings. However, we use an escape
3694 * character 0x1 to avoid issues and potenial attacks on our database (if this is used as a key
3695 * encoder for NoSql databases).
3696 *
3697 * @function
3698 * @param {Encoder} encoder
3699 * @param {Uint8Array} buf The string that is to be encoded.
3700 */
3701 const writeTerminatedUint8Array = (encoder, buf) => {
3702 for (let i = 0; i < buf.length; i++) {
3703 const b = buf[i]
3704 if (b === 0 || b === 1) {
3705 write(encoder, 1)
3706 }
3707 write(encoder, buf[i])
3708 }
3709 write(encoder, 0)
3710 }
3711
3712 /**
3713 * Write the content of another Encoder.
3714 *
3715 * @TODO: can be improved!
3716 * - Note: Should consider that when appending a lot of small Encoders, we should rather clone than referencing the old structure.
3717 * Encoders start with a rather big initial buffer.
3718 *
3719 * @function
3720 * @param {Encoder} encoder The enUint8Arr
3721 * @param {Encoder} append The BinaryEncoder to be written.
3722 */
3723 const writeBinaryEncoder = (encoder, append) => writeUint8Array(encoder, toUint8Array(append))
3724
3725 /**
3726 * Append fixed-length Uint8Array to the encoder.
3727 *
3728 * @function
3729 * @param {Encoder} encoder
3730 * @param {Uint8Array} uint8Array
3731 */
3732 const writeUint8Array = (encoder, uint8Array) => {
3733 const bufferLen = encoder.cbuf.length
3734 const cpos = encoder.cpos
3735 const leftCopyLen = min(bufferLen - cpos, uint8Array.length)
3736 const rightCopyLen = uint8Array.length - leftCopyLen
3737 encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos)
3738 encoder.cpos += leftCopyLen
3739 if (rightCopyLen > 0) {
3740 // Still something to write, write right half..
3741 // Append new buffer
3742 encoder.bufs.push(encoder.cbuf)
3743 // must have at least size of remaining buffer
3744 encoder.cbuf = new Uint8Array(max(bufferLen * 2, rightCopyLen))
3745 // copy array
3746 encoder.cbuf.set(uint8Array.subarray(leftCopyLen))
3747 encoder.cpos = rightCopyLen
3748 }
3749 }
3750
3751 /**
3752 * Append an Uint8Array to Encoder.
3753 *
3754 * @function
3755 * @param {Encoder} encoder
3756 * @param {Uint8Array} uint8Array
3757 */
3758 const writeVarUint8Array = (encoder, uint8Array) => {
3759 writeVarUint(encoder, uint8Array.byteLength)
3760 writeUint8Array(encoder, uint8Array)
3761 }
3762
3763 /**
3764 * Create an DataView of the next `len` bytes. Use it to write data after
3765 * calling this function.
3766 *
3767 * ```js
3768 * // write float32 using DataView
3769 * const dv = writeOnDataView(encoder, 4)
3770 * dv.setFloat32(0, 1.1)
3771 * // read float32 using DataView
3772 * const dv = readFromDataView(encoder, 4)
3773 * dv.getFloat32(0) // => 1.100000023841858 (leaving it to the reader to find out why this is the correct result)
3774 * ```
3775 *
3776 * @param {Encoder} encoder
3777 * @param {number} len
3778 * @return {DataView}
3779 */
3780 const writeOnDataView = (encoder, len) => {
3781 verifyLen(encoder, len)
3782 const dview = new DataView(encoder.cbuf.buffer, encoder.cpos, len)
3783 encoder.cpos += len
3784 return dview
3785 }
3786
3787 /**
3788 * @param {Encoder} encoder
3789 * @param {number} num
3790 */
3791 const writeFloat32 = (encoder, num) => writeOnDataView(encoder, 4).setFloat32(0, num, false)
3792
3793 /**
3794 * @param {Encoder} encoder
3795 * @param {number} num
3796 */
3797 const writeFloat64 = (encoder, num) => writeOnDataView(encoder, 8).setFloat64(0, num, false)
3798
3799 /**
3800 * @param {Encoder} encoder
3801 * @param {bigint} num
3802 */
3803 const writeBigInt64 = (encoder, num) => /** @type {any} */ (writeOnDataView(encoder, 8)).setBigInt64(0, num, false)
3804
3805 /**
3806 * @param {Encoder} encoder
3807 * @param {bigint} num
3808 */
3809 const writeBigUint64 = (encoder, num) => /** @type {any} */ (writeOnDataView(encoder, 8)).setBigUint64(0, num, false)
3810
3811 const floatTestBed = new DataView(new ArrayBuffer(4))
3812 /**
3813 * Check if a number can be encoded as a 32 bit float.
3814 *
3815 * @param {number} num
3816 * @return {boolean}
3817 */
3818 const isFloat32 = num => {
3819 floatTestBed.setFloat32(0, num)
3820 return floatTestBed.getFloat32(0) === num
3821 }
3822
3823 /**
3824 * Encode data with efficient binary format.
3825 *
3826 * Differences to JSON:
3827 * • Transforms data to a binary format (not to a string)
3828 * • Encodes undefined, NaN, and ArrayBuffer (these can't be represented in JSON)
3829 * • Numbers are efficiently encoded either as a variable length integer, as a
3830 * 32 bit float, as a 64 bit float, or as a 64 bit bigint.
3831 *
3832 * Encoding table:
3833 *
3834 * | Data Type | Prefix | Encoding Method | Comment |
3835 * | ------------------- | -------- | ------------------ | ------- |
3836 * | undefined | 127 | | Functions, symbol, and everything that cannot be identified is encoded as undefined |
3837 * | null | 126 | | |
3838 * | integer | 125 | writeVarInt | Only encodes 32 bit signed integers |
3839 * | float32 | 124 | writeFloat32 | |
3840 * | float64 | 123 | writeFloat64 | |
3841 * | bigint | 122 | writeBigInt64 | |
3842 * | boolean (false) | 121 | | True and false are different data types so we save the following byte |
3843 * | boolean (true) | 120 | | - 0b01111000 so the last bit determines whether true or false |
3844 * | string | 119 | writeVarString | |
3845 * | object<string,any> | 118 | custom | Writes {length} then {length} key-value pairs |
3846 * | array<any> | 117 | custom | Writes {length} then {length} json values |
3847 * | Uint8Array | 116 | writeVarUint8Array | We use Uint8Array for any kind of binary data |
3848 *
3849 * Reasons for the decreasing prefix:
3850 * We need the first bit for extendability (later we may want to encode the
3851 * prefix with writeVarUint). The remaining 7 bits are divided as follows:
3852 * [0-30] the beginning of the data range is used for custom purposes
3853 * (defined by the function that uses this library)
3854 * [31-127] the end of the data range is used for data encoding by
3855 * lib0/encoding.js
3856 *
3857 * @param {Encoder} encoder
3858 * @param {undefined|null|number|bigint|boolean|string|Object<string,any>|Array<any>|Uint8Array} data
3859 */
3860 const writeAny = (encoder, data) => {
3861 switch (typeof data) {
3862 case 'string':
3863 // TYPE 119: STRING
3864 write(encoder, 119)
3865 writeVarString(encoder, data)
3866 break
3867 case 'number':
3868 if (isInteger(data) && abs(data) <= BITS31) {
3869 // TYPE 125: INTEGER
3870 write(encoder, 125)
3871 writeVarInt(encoder, data)
3872 } else if (isFloat32(data)) {
3873 // TYPE 124: FLOAT32
3874 write(encoder, 124)
3875 writeFloat32(encoder, data)
3876 } else {
3877 // TYPE 123: FLOAT64
3878 write(encoder, 123)
3879 writeFloat64(encoder, data)
3880 }
3881 break
3882 case 'bigint':
3883 // TYPE 122: BigInt
3884 write(encoder, 122)
3885 writeBigInt64(encoder, data)
3886 break
3887 case 'object':
3888 if (data === null) {
3889 // TYPE 126: null
3890 write(encoder, 126)
3891 } else if (isArray(data)) {
3892 // TYPE 117: Array
3893 write(encoder, 117)
3894 writeVarUint(encoder, data.length)
3895 for (let i = 0; i < data.length; i++) {
3896 writeAny(encoder, data[i])
3897 }
3898 } else if (data instanceof Uint8Array) {
3899 // TYPE 116: ArrayBuffer
3900 write(encoder, 116)
3901 writeVarUint8Array(encoder, data)
3902 } else {
3903 // TYPE 118: Object
3904 write(encoder, 118)
3905 const keys = Object.keys(data)
3906 writeVarUint(encoder, keys.length)
3907 for (let i = 0; i < keys.length; i++) {
3908 const key = keys[i]
3909 writeVarString(encoder, key)
3910 writeAny(encoder, data[key])
3911 }
3912 }
3913 break
3914 case 'boolean':
3915 // TYPE 120/121: boolean (true/false)
3916 write(encoder, data ? 120 : 121)
3917 break
3918 default:
3919 // TYPE 127: undefined
3920 write(encoder, 127)
3921 }
3922 }
3923
3924 /**
3925 * Now come a few stateful encoder that have their own classes.
3926 */
3927
3928 /**
3929 * Basic Run Length Encoder - a basic compression implementation.
3930 *
3931 * 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.
3932 *
3933 * It was originally used for image compression. Cool .. article http://csbruce.com/cbm/transactor/pdfs/trans_v7_i06.pdf
3934 *
3935 * @note T must not be null!
3936 *
3937 * @template T
3938 */
3939 class RleEncoder extends Encoder {
3940 /**
3941 * @param {function(Encoder, T):void} writer
3942 */
3943 constructor (writer) {
3944 super()
3945 /**
3946 * The writer
3947 */
3948 this.w = writer
3949 /**
3950 * Current state
3951 * @type {T|null}
3952 */
3953 this.s = null
3954 this.count = 0
3955 }
3956
3957 /**
3958 * @param {T} v
3959 */
3960 write (v) {
3961 if (this.s === v) {
3962 this.count++
3963 } else {
3964 if (this.count > 0) {
3965 // flush counter, unless this is the first value (count = 0)
3966 writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw
3967 }
3968 this.count = 1
3969 // write first value
3970 this.w(this, v)
3971 this.s = v
3972 }
3973 }
3974 }
3975
3976 /**
3977 * Basic diff decoder using variable length encoding.
3978 *
3979 * Encodes the values [3, 1100, 1101, 1050, 0] to [3, 1097, 1, -51, -1050] using writeVarInt.
3980 */
3981 class IntDiffEncoder extends (/* unused pure expression or super */ null && (Encoder)) {
3982 /**
3983 * @param {number} start
3984 */
3985 constructor (start) {
3986 super()
3987 /**
3988 * Current state
3989 * @type {number}
3990 */
3991 this.s = start
3992 }
3993
3994 /**
3995 * @param {number} v
3996 */
3997 write (v) {
3998 writeVarInt(this, v - this.s)
3999 this.s = v
4000 }
4001 }
4002
4003 /**
4004 * A combination of IntDiffEncoder and RleEncoder.
4005 *
4006 * Basically first writes the IntDiffEncoder and then counts duplicate diffs using RleEncoding.
4007 *
4008 * 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])
4009 */
4010 class RleIntDiffEncoder extends (/* unused pure expression or super */ null && (Encoder)) {
4011 /**
4012 * @param {number} start
4013 */
4014 constructor (start) {
4015 super()
4016 /**
4017 * Current state
4018 * @type {number}
4019 */
4020 this.s = start
4021 this.count = 0
4022 }
4023
4024 /**
4025 * @param {number} v
4026 */
4027 write (v) {
4028 if (this.s === v && this.count > 0) {
4029 this.count++
4030 } else {
4031 if (this.count > 0) {
4032 // flush counter, unless this is the first value (count = 0)
4033 writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw
4034 }
4035 this.count = 1
4036 // write first value
4037 writeVarInt(this, v - this.s)
4038 this.s = v
4039 }
4040 }
4041 }
4042
4043 /**
4044 * @param {UintOptRleEncoder} encoder
4045 */
4046 const flushUintOptRleEncoder = encoder => {
4047 if (encoder.count > 0) {
4048 // flush counter, unless this is the first value (count = 0)
4049 // case 1: just a single value. set sign to positive
4050 // case 2: write several values. set sign to negative to indicate that there is a length coming
4051 writeVarInt(encoder.encoder, encoder.count === 1 ? encoder.s : -encoder.s)
4052 if (encoder.count > 1) {
4053 writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw
4054 }
4055 }
4056 }
4057
4058 /**
4059 * Optimized Rle encoder that does not suffer from the mentioned problem of the basic Rle encoder.
4060 *
4061 * Internally uses VarInt encoder to write unsigned integers. If the input occurs multiple times, we write
4062 * write it as a negative number. The UintOptRleDecoder then understands that it needs to read a count.
4063 *
4064 * Encodes [1,2,3,3,3] as [1,2,-3,3] (once 1, once 2, three times 3)
4065 */
4066 class UintOptRleEncoder {
4067 constructor () {
4068 this.encoder = new Encoder()
4069 /**
4070 * @type {number}
4071 */
4072 this.s = 0
4073 this.count = 0
4074 }
4075
4076 /**
4077 * @param {number} v
4078 */
4079 write (v) {
4080 if (this.s === v) {
4081 this.count++
4082 } else {
4083 flushUintOptRleEncoder(this)
4084 this.count = 1
4085 this.s = v
4086 }
4087 }
4088
4089 toUint8Array () {
4090 flushUintOptRleEncoder(this)
4091 return toUint8Array(this.encoder)
4092 }
4093 }
4094
4095 /**
4096 * Increasing Uint Optimized RLE Encoder
4097 *
4098 * The RLE encoder counts the number of same occurences of the same value.
4099 * The IncUintOptRle encoder counts if the value increases.
4100 * I.e. 7, 8, 9, 10 will be encoded as [-7, 4]. 1, 3, 5 will be encoded
4101 * as [1, 3, 5].
4102 */
4103 class IncUintOptRleEncoder {
4104 constructor () {
4105 this.encoder = new Encoder()
4106 /**
4107 * @type {number}
4108 */
4109 this.s = 0
4110 this.count = 0
4111 }
4112
4113 /**
4114 * @param {number} v
4115 */
4116 write (v) {
4117 if (this.s + this.count === v) {
4118 this.count++
4119 } else {
4120 flushUintOptRleEncoder(this)
4121 this.count = 1
4122 this.s = v
4123 }
4124 }
4125
4126 toUint8Array () {
4127 flushUintOptRleEncoder(this)
4128 return toUint8Array(this.encoder)
4129 }
4130 }
4131
4132 /**
4133 * @param {IntDiffOptRleEncoder} encoder
4134 */
4135 const flushIntDiffOptRleEncoder = encoder => {
4136 if (encoder.count > 0) {
4137 // 31 bit making up the diff | wether to write the counter
4138 // const encodedDiff = encoder.diff << 1 | (encoder.count === 1 ? 0 : 1)
4139 const encodedDiff = encoder.diff * 2 + (encoder.count === 1 ? 0 : 1)
4140 // flush counter, unless this is the first value (count = 0)
4141 // case 1: just a single value. set first bit to positive
4142 // case 2: write several values. set first bit to negative to indicate that there is a length coming
4143 writeVarInt(encoder.encoder, encodedDiff)
4144 if (encoder.count > 1) {
4145 writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw
4146 }
4147 }
4148 }
4149
4150 /**
4151 * A combination of the IntDiffEncoder and the UintOptRleEncoder.
4152 *
4153 * The count approach is similar to the UintDiffOptRleEncoder, but instead of using the negative bitflag, it encodes
4154 * in the LSB whether a count is to be read. Therefore this Encoder only supports 31 bit integers!
4155 *
4156 * Encodes [1, 2, 3, 2] as [3, 1, 6, -1] (more specifically [(1 << 1) | 1, (3 << 0) | 0, -1])
4157 *
4158 * Internally uses variable length encoding. Contrary to normal UintVar encoding, the first byte contains:
4159 * * 1 bit that denotes whether the next value is a count (LSB)
4160 * * 1 bit that denotes whether this value is negative (MSB - 1)
4161 * * 1 bit that denotes whether to continue reading the variable length integer (MSB)
4162 *
4163 * Therefore, only five bits remain to encode diff ranges.
4164 *
4165 * Use this Encoder only when appropriate. In most cases, this is probably a bad idea.
4166 */
4167 class IntDiffOptRleEncoder {
4168 constructor () {
4169 this.encoder = new Encoder()
4170 /**
4171 * @type {number}
4172 */
4173 this.s = 0
4174 this.count = 0
4175 this.diff = 0
4176 }
4177
4178 /**
4179 * @param {number} v
4180 */
4181 write (v) {
4182 if (this.diff === v - this.s) {
4183 this.s = v
4184 this.count++
4185 } else {
4186 flushIntDiffOptRleEncoder(this)
4187 this.count = 1
4188 this.diff = v - this.s
4189 this.s = v
4190 }
4191 }
4192
4193 toUint8Array () {
4194 flushIntDiffOptRleEncoder(this)
4195 return toUint8Array(this.encoder)
4196 }
4197 }
4198
4199 /**
4200 * Optimized String Encoder.
4201 *
4202 * 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.
4203 * 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?).
4204 *
4205 * This string encoder solves the above problem. All strings are concatenated and written as a single string using a single encoding call.
4206 *
4207 * The lengths are encoded using a UintOptRleEncoder.
4208 */
4209 class StringEncoder {
4210 constructor () {
4211 /**
4212 * @type {Array<string>}
4213 */
4214 this.sarr = []
4215 this.s = ''
4216 this.lensE = new UintOptRleEncoder()
4217 }
4218
4219 /**
4220 * @param {string} string
4221 */
4222 write (string) {
4223 this.s += string
4224 if (this.s.length > 19) {
4225 this.sarr.push(this.s)
4226 this.s = ''
4227 }
4228 this.lensE.write(string.length)
4229 }
4230
4231 toUint8Array () {
4232 const encoder = new Encoder()
4233 this.sarr.push(this.s)
4234 this.s = ''
4235 writeVarString(encoder, this.sarr.join(''))
4236 writeUint8Array(encoder, this.lensE.toUint8Array())
4237 return toUint8Array(encoder)
4238 }
4239 }
4240
4241 ;// CONCATENATED MODULE: ./node_modules/lib0/error.js
4242 /**
4243 * Error helpers.
4244 *
4245 * @module error
4246 */
4247
4248 /**
4249 * @param {string} s
4250 * @return {Error}
4251 */
4252 /* c8 ignore next */
4253 const error_create = s => new Error(s)
4254
4255 /**
4256 * @throws {Error}
4257 * @return {never}
4258 */
4259 /* c8 ignore next 3 */
4260 const methodUnimplemented = () => {
4261 throw error_create('Method unimplemented')
4262 }
4263
4264 /**
4265 * @throws {Error}
4266 * @return {never}
4267 */
4268 /* c8 ignore next 3 */
4269 const unexpectedCase = () => {
4270 throw error_create('Unexpected case')
4271 }
4272
4273 ;// CONCATENATED MODULE: ./node_modules/lib0/decoding.js
4274 /**
4275 * Efficient schema-less binary decoding with support for variable length encoding.
4276 *
4277 * Use [lib0/decoding] with [lib0/encoding]. Every encoding function has a corresponding decoding function.
4278 *
4279 * Encodes numbers in little-endian order (least to most significant byte order)
4280 * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
4281 * which is also used in Protocol Buffers.
4282 *
4283 * ```js
4284 * // encoding step
4285 * const encoder = encoding.createEncoder()
4286 * encoding.writeVarUint(encoder, 256)
4287 * encoding.writeVarString(encoder, 'Hello world!')
4288 * const buf = encoding.toUint8Array(encoder)
4289 * ```
4290 *
4291 * ```js
4292 * // decoding step
4293 * const decoder = decoding.createDecoder(buf)
4294 * decoding.readVarUint(decoder) // => 256
4295 * decoding.readVarString(decoder) // => 'Hello world!'
4296 * decoding.hasContent(decoder) // => false - all data is read
4297 * ```
4298 *
4299 * @module decoding
4300 */
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310 const errorUnexpectedEndOfArray = error_create('Unexpected end of array')
4311 const errorIntegerOutOfRange = error_create('Integer out of Range')
4312
4313 /**
4314 * A Decoder handles the decoding of an Uint8Array.
4315 */
4316 class Decoder {
4317 /**
4318 * @param {Uint8Array} uint8Array Binary data to decode
4319 */
4320 constructor (uint8Array) {
4321 /**
4322 * Decoding target.
4323 *
4324 * @type {Uint8Array}
4325 */
4326 this.arr = uint8Array
4327 /**
4328 * Current decoding position.
4329 *
4330 * @type {number}
4331 */
4332 this.pos = 0
4333 }
4334 }
4335
4336 /**
4337 * @function
4338 * @param {Uint8Array} uint8Array
4339 * @return {Decoder}
4340 */
4341 const createDecoder = uint8Array => new Decoder(uint8Array)
4342
4343 /**
4344 * @function
4345 * @param {Decoder} decoder
4346 * @return {boolean}
4347 */
4348 const decoding_hasContent = decoder => decoder.pos !== decoder.arr.length
4349
4350 /**
4351 * Clone a decoder instance.
4352 * Optionally set a new position parameter.
4353 *
4354 * @function
4355 * @param {Decoder} decoder The decoder instance
4356 * @param {number} [newPos] Defaults to current position
4357 * @return {Decoder} A clone of `decoder`
4358 */
4359 const clone = (decoder, newPos = decoder.pos) => {
4360 const _decoder = createDecoder(decoder.arr)
4361 _decoder.pos = newPos
4362 return _decoder
4363 }
4364
4365 /**
4366 * Create an Uint8Array view of the next `len` bytes and advance the position by `len`.
4367 *
4368 * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
4369 * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
4370 *
4371 * @function
4372 * @param {Decoder} decoder The decoder instance
4373 * @param {number} len The length of bytes to read
4374 * @return {Uint8Array}
4375 */
4376 const readUint8Array = (decoder, len) => {
4377 const view = createUint8ArrayViewFromArrayBuffer(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len)
4378 decoder.pos += len
4379 return view
4380 }
4381
4382 /**
4383 * Read variable length Uint8Array.
4384 *
4385 * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
4386 * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
4387 *
4388 * @function
4389 * @param {Decoder} decoder
4390 * @return {Uint8Array}
4391 */
4392 const readVarUint8Array = decoder => readUint8Array(decoder, readVarUint(decoder))
4393
4394 /**
4395 * Read the rest of the content as an ArrayBuffer
4396 * @function
4397 * @param {Decoder} decoder
4398 * @return {Uint8Array}
4399 */
4400 const readTailAsUint8Array = decoder => readUint8Array(decoder, decoder.arr.length - decoder.pos)
4401
4402 /**
4403 * Skip one byte, jump to the next position.
4404 * @function
4405 * @param {Decoder} decoder The decoder instance
4406 * @return {number} The next position
4407 */
4408 const skip8 = decoder => decoder.pos++
4409
4410 /**
4411 * Read one byte as unsigned integer.
4412 * @function
4413 * @param {Decoder} decoder The decoder instance
4414 * @return {number} Unsigned 8-bit integer
4415 */
4416 const readUint8 = decoder => decoder.arr[decoder.pos++]
4417
4418 /**
4419 * Read 2 bytes as unsigned integer.
4420 *
4421 * @function
4422 * @param {Decoder} decoder
4423 * @return {number} An unsigned integer.
4424 */
4425 const readUint16 = decoder => {
4426 const uint =
4427 decoder.arr[decoder.pos] +
4428 (decoder.arr[decoder.pos + 1] << 8)
4429 decoder.pos += 2
4430 return uint
4431 }
4432
4433 /**
4434 * Read 4 bytes as unsigned integer.
4435 *
4436 * @function
4437 * @param {Decoder} decoder
4438 * @return {number} An unsigned integer.
4439 */
4440 const readUint32 = decoder => {
4441 const uint =
4442 (decoder.arr[decoder.pos] +
4443 (decoder.arr[decoder.pos + 1] << 8) +
4444 (decoder.arr[decoder.pos + 2] << 16) +
4445 (decoder.arr[decoder.pos + 3] << 24)) >>> 0
4446 decoder.pos += 4
4447 return uint
4448 }
4449
4450 /**
4451 * Read 4 bytes as unsigned integer in big endian order.
4452 * (most significant byte first)
4453 *
4454 * @function
4455 * @param {Decoder} decoder
4456 * @return {number} An unsigned integer.
4457 */
4458 const readUint32BigEndian = decoder => {
4459 const uint =
4460 (decoder.arr[decoder.pos + 3] +
4461 (decoder.arr[decoder.pos + 2] << 8) +
4462 (decoder.arr[decoder.pos + 1] << 16) +
4463 (decoder.arr[decoder.pos] << 24)) >>> 0
4464 decoder.pos += 4
4465 return uint
4466 }
4467
4468 /**
4469 * Look ahead without incrementing the position
4470 * to the next byte and read it as unsigned integer.
4471 *
4472 * @function
4473 * @param {Decoder} decoder
4474 * @return {number} An unsigned integer.
4475 */
4476 const peekUint8 = decoder => decoder.arr[decoder.pos]
4477
4478 /**
4479 * Look ahead without incrementing the position
4480 * to the next byte and read it as unsigned integer.
4481 *
4482 * @function
4483 * @param {Decoder} decoder
4484 * @return {number} An unsigned integer.
4485 */
4486 const peekUint16 = decoder =>
4487 decoder.arr[decoder.pos] +
4488 (decoder.arr[decoder.pos + 1] << 8)
4489
4490 /**
4491 * Look ahead without incrementing the position
4492 * to the next byte and read it as unsigned integer.
4493 *
4494 * @function
4495 * @param {Decoder} decoder
4496 * @return {number} An unsigned integer.
4497 */
4498 const peekUint32 = decoder => (
4499 decoder.arr[decoder.pos] +
4500 (decoder.arr[decoder.pos + 1] << 8) +
4501 (decoder.arr[decoder.pos + 2] << 16) +
4502 (decoder.arr[decoder.pos + 3] << 24)
4503 ) >>> 0
4504
4505 /**
4506 * Read unsigned integer (32bit) with variable length.
4507 * 1/8th of the storage is used as encoding overhead.
4508 * * numbers < 2^7 is stored in one bytlength
4509 * * numbers < 2^14 is stored in two bylength
4510 *
4511 * @function
4512 * @param {Decoder} decoder
4513 * @return {number} An unsigned integer.length
4514 */
4515 const readVarUint = decoder => {
4516 let num = 0
4517 let mult = 1
4518 const len = decoder.arr.length
4519 while (decoder.pos < len) {
4520 const r = decoder.arr[decoder.pos++]
4521 // num = num | ((r & binary.BITS7) << len)
4522 num = num + (r & BITS7) * mult // shift $r << (7*#iterations) and add it to num
4523 mult *= 128 // next iteration, shift 7 "more" to the left
4524 if (r < BIT8) {
4525 return num
4526 }
4527 /* c8 ignore start */
4528 if (num > MAX_SAFE_INTEGER) {
4529 throw errorIntegerOutOfRange
4530 }
4531 /* c8 ignore stop */
4532 }
4533 throw errorUnexpectedEndOfArray
4534 }
4535
4536 /**
4537 * Read signed integer (32bit) with variable length.
4538 * 1/8th of the storage is used as encoding overhead.
4539 * * numbers < 2^7 is stored in one bytlength
4540 * * numbers < 2^14 is stored in two bylength
4541 * @todo This should probably create the inverse ~num if number is negative - but this would be a breaking change.
4542 *
4543 * @function
4544 * @param {Decoder} decoder
4545 * @return {number} An unsigned integer.length
4546 */
4547 const readVarInt = decoder => {
4548 let r = decoder.arr[decoder.pos++]
4549 let num = r & BITS6
4550 let mult = 64
4551 const sign = (r & BIT7) > 0 ? -1 : 1
4552 if ((r & BIT8) === 0) {
4553 // don't continue reading
4554 return sign * num
4555 }
4556 const len = decoder.arr.length
4557 while (decoder.pos < len) {
4558 r = decoder.arr[decoder.pos++]
4559 // num = num | ((r & binary.BITS7) << len)
4560 num = num + (r & BITS7) * mult
4561 mult *= 128
4562 if (r < BIT8) {
4563 return sign * num
4564 }
4565 /* c8 ignore start */
4566 if (num > MAX_SAFE_INTEGER) {
4567 throw errorIntegerOutOfRange
4568 }
4569 /* c8 ignore stop */
4570 }
4571 throw errorUnexpectedEndOfArray
4572 }
4573
4574 /**
4575 * Look ahead and read varUint without incrementing position
4576 *
4577 * @function
4578 * @param {Decoder} decoder
4579 * @return {number}
4580 */
4581 const peekVarUint = decoder => {
4582 const pos = decoder.pos
4583 const s = readVarUint(decoder)
4584 decoder.pos = pos
4585 return s
4586 }
4587
4588 /**
4589 * Look ahead and read varUint without incrementing position
4590 *
4591 * @function
4592 * @param {Decoder} decoder
4593 * @return {number}
4594 */
4595 const peekVarInt = decoder => {
4596 const pos = decoder.pos
4597 const s = readVarInt(decoder)
4598 decoder.pos = pos
4599 return s
4600 }
4601
4602 /**
4603 * We don't test this function anymore as we use native decoding/encoding by default now.
4604 * Better not modify this anymore..
4605 *
4606 * Transforming utf8 to a string is pretty expensive. The code performs 10x better
4607 * when String.fromCodePoint is fed with all characters as arguments.
4608 * But most environments have a maximum number of arguments per functions.
4609 * For effiency reasons we apply a maximum of 10000 characters at once.
4610 *
4611 * @function
4612 * @param {Decoder} decoder
4613 * @return {String} The read String.
4614 */
4615 /* c8 ignore start */
4616 const _readVarStringPolyfill = decoder => {
4617 let remainingLen = readVarUint(decoder)
4618 if (remainingLen === 0) {
4619 return ''
4620 } else {
4621 let encodedString = String.fromCodePoint(readUint8(decoder)) // remember to decrease remainingLen
4622 if (--remainingLen < 100) { // do not create a Uint8Array for small strings
4623 while (remainingLen--) {
4624 encodedString += String.fromCodePoint(readUint8(decoder))
4625 }
4626 } else {
4627 while (remainingLen > 0) {
4628 const nextLen = remainingLen < 10000 ? remainingLen : 10000
4629 // this is dangerous, we create a fresh array view from the existing buffer
4630 const bytes = decoder.arr.subarray(decoder.pos, decoder.pos + nextLen)
4631 decoder.pos += nextLen
4632 // Starting with ES5.1 we can supply a generic array-like object as arguments
4633 encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes))
4634 remainingLen -= nextLen
4635 }
4636 }
4637 return decodeURIComponent(escape(encodedString))
4638 }
4639 }
4640 /* c8 ignore stop */
4641
4642 /**
4643 * @function
4644 * @param {Decoder} decoder
4645 * @return {String} The read String
4646 */
4647 const _readVarStringNative = decoder =>
4648 /** @type any */ (utf8TextDecoder).decode(readVarUint8Array(decoder))
4649
4650 /**
4651 * Read string of variable length
4652 * * varUint is used to store the length of the string
4653 *
4654 * @function
4655 * @param {Decoder} decoder
4656 * @return {String} The read String
4657 *
4658 */
4659 /* c8 ignore next */
4660 const readVarString = utf8TextDecoder ? _readVarStringNative : _readVarStringPolyfill
4661
4662 /**
4663 * @param {Decoder} decoder
4664 * @return {Uint8Array}
4665 */
4666 const readTerminatedUint8Array = decoder => {
4667 const encoder = encoding.createEncoder()
4668 let b
4669 while (true) {
4670 b = readUint8(decoder)
4671 if (b === 0) {
4672 return encoding.toUint8Array(encoder)
4673 }
4674 if (b === 1) {
4675 b = readUint8(decoder)
4676 }
4677 encoding.write(encoder, b)
4678 }
4679 }
4680
4681 /**
4682 * @param {Decoder} decoder
4683 * @return {string}
4684 */
4685 const readTerminatedString = decoder => string.decodeUtf8(readTerminatedUint8Array(decoder))
4686
4687 /**
4688 * Look ahead and read varString without incrementing position
4689 *
4690 * @function
4691 * @param {Decoder} decoder
4692 * @return {string}
4693 */
4694 const peekVarString = decoder => {
4695 const pos = decoder.pos
4696 const s = readVarString(decoder)
4697 decoder.pos = pos
4698 return s
4699 }
4700
4701 /**
4702 * @param {Decoder} decoder
4703 * @param {number} len
4704 * @return {DataView}
4705 */
4706 const readFromDataView = (decoder, len) => {
4707 const dv = new DataView(decoder.arr.buffer, decoder.arr.byteOffset + decoder.pos, len)
4708 decoder.pos += len
4709 return dv
4710 }
4711
4712 /**
4713 * @param {Decoder} decoder
4714 */
4715 const readFloat32 = decoder => readFromDataView(decoder, 4).getFloat32(0, false)
4716
4717 /**
4718 * @param {Decoder} decoder
4719 */
4720 const readFloat64 = decoder => readFromDataView(decoder, 8).getFloat64(0, false)
4721
4722 /**
4723 * @param {Decoder} decoder
4724 */
4725 const readBigInt64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigInt64(0, false)
4726
4727 /**
4728 * @param {Decoder} decoder
4729 */
4730 const readBigUint64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigUint64(0, false)
4731
4732 /**
4733 * @type {Array<function(Decoder):any>}
4734 */
4735 const readAnyLookupTable = [
4736 decoder => undefined, // CASE 127: undefined
4737 decoder => null, // CASE 126: null
4738 readVarInt, // CASE 125: integer
4739 readFloat32, // CASE 124: float32
4740 readFloat64, // CASE 123: float64
4741 readBigInt64, // CASE 122: bigint
4742 decoder => false, // CASE 121: boolean (false)
4743 decoder => true, // CASE 120: boolean (true)
4744 readVarString, // CASE 119: string
4745 decoder => { // CASE 118: object<string,any>
4746 const len = readVarUint(decoder)
4747 /**
4748 * @type {Object<string,any>}
4749 */
4750 const obj = {}
4751 for (let i = 0; i < len; i++) {
4752 const key = readVarString(decoder)
4753 obj[key] = readAny(decoder)
4754 }
4755 return obj
4756 },
4757 decoder => { // CASE 117: array<any>
4758 const len = readVarUint(decoder)
4759 const arr = []
4760 for (let i = 0; i < len; i++) {
4761 arr.push(readAny(decoder))
4762 }
4763 return arr
4764 },
4765 readVarUint8Array // CASE 116: Uint8Array
4766 ]
4767
4768 /**
4769 * @param {Decoder} decoder
4770 */
4771 const readAny = decoder => readAnyLookupTable[127 - readUint8(decoder)](decoder)
4772
4773 /**
4774 * T must not be null.
4775 *
4776 * @template T
4777 */
4778 class RleDecoder extends Decoder {
4779 /**
4780 * @param {Uint8Array} uint8Array
4781 * @param {function(Decoder):T} reader
4782 */
4783 constructor (uint8Array, reader) {
4784 super(uint8Array)
4785 /**
4786 * The reader
4787 */
4788 this.reader = reader
4789 /**
4790 * Current state
4791 * @type {T|null}
4792 */
4793 this.s = null
4794 this.count = 0
4795 }
4796
4797 read () {
4798 if (this.count === 0) {
4799 this.s = this.reader(this)
4800 if (decoding_hasContent(this)) {
4801 this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented
4802 } else {
4803 this.count = -1 // read the current value forever
4804 }
4805 }
4806 this.count--
4807 return /** @type {T} */ (this.s)
4808 }
4809 }
4810
4811 class IntDiffDecoder extends (/* unused pure expression or super */ null && (Decoder)) {
4812 /**
4813 * @param {Uint8Array} uint8Array
4814 * @param {number} start
4815 */
4816 constructor (uint8Array, start) {
4817 super(uint8Array)
4818 /**
4819 * Current state
4820 * @type {number}
4821 */
4822 this.s = start
4823 }
4824
4825 /**
4826 * @return {number}
4827 */
4828 read () {
4829 this.s += readVarInt(this)
4830 return this.s
4831 }
4832 }
4833
4834 class RleIntDiffDecoder extends (/* unused pure expression or super */ null && (Decoder)) {
4835 /**
4836 * @param {Uint8Array} uint8Array
4837 * @param {number} start
4838 */
4839 constructor (uint8Array, start) {
4840 super(uint8Array)
4841 /**
4842 * Current state
4843 * @type {number}
4844 */
4845 this.s = start
4846 this.count = 0
4847 }
4848
4849 /**
4850 * @return {number}
4851 */
4852 read () {
4853 if (this.count === 0) {
4854 this.s += readVarInt(this)
4855 if (decoding_hasContent(this)) {
4856 this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented
4857 } else {
4858 this.count = -1 // read the current value forever
4859 }
4860 }
4861 this.count--
4862 return /** @type {number} */ (this.s)
4863 }
4864 }
4865
4866 class UintOptRleDecoder extends Decoder {
4867 /**
4868 * @param {Uint8Array} uint8Array
4869 */
4870 constructor (uint8Array) {
4871 super(uint8Array)
4872 /**
4873 * @type {number}
4874 */
4875 this.s = 0
4876 this.count = 0
4877 }
4878
4879 read () {
4880 if (this.count === 0) {
4881 this.s = readVarInt(this)
4882 // if the sign is negative, we read the count too, otherwise count is 1
4883 const isNegative = isNegativeZero(this.s)
4884 this.count = 1
4885 if (isNegative) {
4886 this.s = -this.s
4887 this.count = readVarUint(this) + 2
4888 }
4889 }
4890 this.count--
4891 return /** @type {number} */ (this.s)
4892 }
4893 }
4894
4895 class IncUintOptRleDecoder extends (/* unused pure expression or super */ null && (Decoder)) {
4896 /**
4897 * @param {Uint8Array} uint8Array
4898 */
4899 constructor (uint8Array) {
4900 super(uint8Array)
4901 /**
4902 * @type {number}
4903 */
4904 this.s = 0
4905 this.count = 0
4906 }
4907
4908 read () {
4909 if (this.count === 0) {
4910 this.s = readVarInt(this)
4911 // if the sign is negative, we read the count too, otherwise count is 1
4912 const isNegative = math.isNegativeZero(this.s)
4913 this.count = 1
4914 if (isNegative) {
4915 this.s = -this.s
4916 this.count = readVarUint(this) + 2
4917 }
4918 }
4919 this.count--
4920 return /** @type {number} */ (this.s++)
4921 }
4922 }
4923
4924 class IntDiffOptRleDecoder extends Decoder {
4925 /**
4926 * @param {Uint8Array} uint8Array
4927 */
4928 constructor (uint8Array) {
4929 super(uint8Array)
4930 /**
4931 * @type {number}
4932 */
4933 this.s = 0
4934 this.count = 0
4935 this.diff = 0
4936 }
4937
4938 /**
4939 * @return {number}
4940 */
4941 read () {
4942 if (this.count === 0) {
4943 const diff = readVarInt(this)
4944 // if the first bit is set, we read more data
4945 const hasCount = diff & 1
4946 this.diff = floor(diff / 2) // shift >> 1
4947 this.count = 1
4948 if (hasCount) {
4949 this.count = readVarUint(this) + 2
4950 }
4951 }
4952 this.s += this.diff
4953 this.count--
4954 return this.s
4955 }
4956 }
4957
4958 class StringDecoder {
4959 /**
4960 * @param {Uint8Array} uint8Array
4961 */
4962 constructor (uint8Array) {
4963 this.decoder = new UintOptRleDecoder(uint8Array)
4964 this.str = readVarString(this.decoder)
4965 /**
4966 * @type {number}
4967 */
4968 this.spos = 0
4969 }
4970
4971 /**
4972 * @return {string}
4973 */
4974 read () {
4975 const end = this.spos + this.decoder.read()
4976 const res = this.str.slice(this.spos, end)
4977 this.spos = end
4978 return res
4979 }
4980 }
4981
4982 ;// CONCATENATED MODULE: ./node_modules/lib0/webcrypto.js
4983 /* eslint-env browser */
4984
4985 const subtle = crypto.subtle
4986 const webcrypto_getRandomValues = crypto.getRandomValues.bind(crypto)
4987
4988 ;// CONCATENATED MODULE: ./node_modules/lib0/random.js
4989 /**
4990 * Isomorphic module for true random numbers / buffers / uuids.
4991 *
4992 * Attention: falls back to Math.random if the browser does not support crypto.
4993 *
4994 * @module random
4995 */
4996
4997
4998
4999
5000
5001 const rand = Math.random
5002
5003 const uint32 = () => webcrypto_getRandomValues(new Uint32Array(1))[0]
5004
5005 const uint53 = () => {
5006 const arr = getRandomValues(new Uint32Array(8))
5007 return (arr[0] & binary.BITS21) * (binary.BITS32 + 1) + (arr[1] >>> 0)
5008 }
5009
5010 /**
5011 * @template T
5012 * @param {Array<T>} arr
5013 * @return {T}
5014 */
5015 const oneOf = arr => arr[math.floor(rand() * arr.length)]
5016
5017 // @ts-ignore
5018 const uuidv4Template = [1e7] + -1e3 + -4e3 + -8e3 + -1e11
5019
5020 /**
5021 * @return {string}
5022 */
5023 const uuidv4 = () => uuidv4Template.replace(/[018]/g, /** @param {number} c */ c =>
5024 (c ^ uint32() & 15 >> c / 4).toString(16)
5025 )
5026
5027 ;// CONCATENATED MODULE: ./node_modules/lib0/promise.js
5028 /**
5029 * Utility helpers to work with promises.
5030 *
5031 * @module promise
5032 */
5033
5034
5035
5036 /**
5037 * @template T
5038 * @callback PromiseResolve
5039 * @param {T|PromiseLike<T>} [result]
5040 */
5041
5042 /**
5043 * @template T
5044 * @param {function(PromiseResolve<T>,function(Error):void):any} f
5045 * @return {Promise<T>}
5046 */
5047 const promise_create = f => /** @type {Promise<T>} */ (new Promise(f))
5048
5049 /**
5050 * @param {function(function():void,function(Error):void):void} f
5051 * @return {Promise<void>}
5052 */
5053 const createEmpty = f => new Promise(f)
5054
5055 /**
5056 * `Promise.all` wait for all promises in the array to resolve and return the result
5057 * @template {unknown[] | []} PS
5058 *
5059 * @param {PS} ps
5060 * @return {Promise<{ -readonly [P in keyof PS]: Awaited<PS[P]> }>}
5061 */
5062 const promise_all = Promise.all.bind(Promise)
5063
5064 /**
5065 * @param {Error} [reason]
5066 * @return {Promise<never>}
5067 */
5068 const reject = reason => Promise.reject(reason)
5069
5070 /**
5071 * @template T
5072 * @param {T|void} res
5073 * @return {Promise<T|void>}
5074 */
5075 const resolve = res => Promise.resolve(res)
5076
5077 /**
5078 * @template T
5079 * @param {T} res
5080 * @return {Promise<T>}
5081 */
5082 const resolveWith = res => Promise.resolve(res)
5083
5084 /**
5085 * @todo Next version, reorder parameters: check, [timeout, [intervalResolution]]
5086 *
5087 * @param {number} timeout
5088 * @param {function():boolean} check
5089 * @param {number} [intervalResolution]
5090 * @return {Promise<void>}
5091 */
5092 const until = (timeout, check, intervalResolution = 10) => promise_create((resolve, reject) => {
5093 const startTime = time.getUnixTime()
5094 const hasTimeout = timeout > 0
5095 const untilInterval = () => {
5096 if (check()) {
5097 clearInterval(intervalHandle)
5098 resolve()
5099 } else if (hasTimeout) {
5100 /* c8 ignore else */
5101 if (time.getUnixTime() - startTime > timeout) {
5102 clearInterval(intervalHandle)
5103 reject(new Error('Timeout'))
5104 }
5105 }
5106 }
5107 const intervalHandle = setInterval(untilInterval, intervalResolution)
5108 })
5109
5110 /**
5111 * @param {number} timeout
5112 * @return {Promise<undefined>}
5113 */
5114 const wait = timeout => promise_create((resolve, reject) => setTimeout(resolve, timeout))
5115
5116 /**
5117 * Checks if an object is a promise using ducktyping.
5118 *
5119 * Promises are often polyfilled, so it makes sense to add some additional guarantees if the user of this
5120 * library has some insane environment where global Promise objects are overwritten.
5121 *
5122 * @param {any} p
5123 * @return {boolean}
5124 */
5125 const isPromise = p => p instanceof Promise || (p && p.then && p.catch && p.finally)
5126
5127 ;// CONCATENATED MODULE: ./node_modules/lib0/pair.js
5128 /**
5129 * Working with value pairs.
5130 *
5131 * @module pair
5132 */
5133
5134 /**
5135 * @template L,R
5136 */
5137 class Pair {
5138 /**
5139 * @param {L} left
5140 * @param {R} right
5141 */
5142 constructor (left, right) {
5143 this.left = left
5144 this.right = right
5145 }
5146 }
5147
5148 /**
5149 * @template L,R
5150 * @param {L} left
5151 * @param {R} right
5152 * @return {Pair<L,R>}
5153 */
5154 const pair_create = (left, right) => new Pair(left, right)
5155
5156 /**
5157 * @template L,R
5158 * @param {R} right
5159 * @param {L} left
5160 * @return {Pair<L,R>}
5161 */
5162 const createReversed = (right, left) => new Pair(left, right)
5163
5164 /**
5165 * @template L,R
5166 * @param {Array<Pair<L,R>>} arr
5167 * @param {function(L, R):any} f
5168 */
5169 const pair_forEach = (arr, f) => arr.forEach(p => f(p.left, p.right))
5170
5171 /**
5172 * @template L,R,X
5173 * @param {Array<Pair<L,R>>} arr
5174 * @param {function(L, R):X} f
5175 * @return {Array<X>}
5176 */
5177 const pair_map = (arr, f) => arr.map(p => f(p.left, p.right))
5178
5179 ;// CONCATENATED MODULE: ./node_modules/lib0/dom.js
5180 /* eslint-env browser */
5181
5182 /**
5183 * Utility module to work with the DOM.
5184 *
5185 * @module dom
5186 */
5187
5188
5189
5190
5191 /* c8 ignore start */
5192 /**
5193 * @type {Document}
5194 */
5195 const doc = /** @type {Document} */ (typeof document !== 'undefined' ? document : {})
5196
5197 /**
5198 * @param {string} name
5199 * @return {HTMLElement}
5200 */
5201 const createElement = name => doc.createElement(name)
5202
5203 /**
5204 * @return {DocumentFragment}
5205 */
5206 const createDocumentFragment = () => doc.createDocumentFragment()
5207
5208 /**
5209 * @param {string} text
5210 * @return {Text}
5211 */
5212 const createTextNode = text => doc.createTextNode(text)
5213
5214 const domParser = /** @type {DOMParser} */ (typeof DOMParser !== 'undefined' ? new DOMParser() : null)
5215
5216 /**
5217 * @param {HTMLElement} el
5218 * @param {string} name
5219 * @param {Object} opts
5220 */
5221 const emitCustomEvent = (el, name, opts) => el.dispatchEvent(new CustomEvent(name, opts))
5222
5223 /**
5224 * @param {Element} el
5225 * @param {Array<pair.Pair<string,string|boolean>>} attrs Array of key-value pairs
5226 * @return {Element}
5227 */
5228 const setAttributes = (el, attrs) => {
5229 pair.forEach(attrs, (key, value) => {
5230 if (value === false) {
5231 el.removeAttribute(key)
5232 } else if (value === true) {
5233 el.setAttribute(key, '')
5234 } else {
5235 // @ts-ignore
5236 el.setAttribute(key, value)
5237 }
5238 })
5239 return el
5240 }
5241
5242 /**
5243 * @param {Element} el
5244 * @param {Map<string, string>} attrs Array of key-value pairs
5245 * @return {Element}
5246 */
5247 const setAttributesMap = (el, attrs) => {
5248 attrs.forEach((value, key) => { el.setAttribute(key, value) })
5249 return el
5250 }
5251
5252 /**
5253 * @param {Array<Node>|HTMLCollection} children
5254 * @return {DocumentFragment}
5255 */
5256 const fragment = children => {
5257 const fragment = createDocumentFragment()
5258 for (let i = 0; i < children.length; i++) {
5259 appendChild(fragment, children[i])
5260 }
5261 return fragment
5262 }
5263
5264 /**
5265 * @param {Element} parent
5266 * @param {Array<Node>} nodes
5267 * @return {Element}
5268 */
5269 const append = (parent, nodes) => {
5270 appendChild(parent, fragment(nodes))
5271 return parent
5272 }
5273
5274 /**
5275 * @param {HTMLElement} el
5276 */
5277 const remove = el => el.remove()
5278
5279 /**
5280 * @param {EventTarget} el
5281 * @param {string} name
5282 * @param {EventListener} f
5283 */
5284 const dom_addEventListener = (el, name, f) => el.addEventListener(name, f)
5285
5286 /**
5287 * @param {EventTarget} el
5288 * @param {string} name
5289 * @param {EventListener} f
5290 */
5291 const dom_removeEventListener = (el, name, f) => el.removeEventListener(name, f)
5292
5293 /**
5294 * @param {Node} node
5295 * @param {Array<pair.Pair<string,EventListener>>} listeners
5296 * @return {Node}
5297 */
5298 const addEventListeners = (node, listeners) => {
5299 pair.forEach(listeners, (name, f) => dom_addEventListener(node, name, f))
5300 return node
5301 }
5302
5303 /**
5304 * @param {Node} node
5305 * @param {Array<pair.Pair<string,EventListener>>} listeners
5306 * @return {Node}
5307 */
5308 const removeEventListeners = (node, listeners) => {
5309 pair.forEach(listeners, (name, f) => dom_removeEventListener(node, name, f))
5310 return node
5311 }
5312
5313 /**
5314 * @param {string} name
5315 * @param {Array<pair.Pair<string,string>|pair.Pair<string,boolean>>} attrs Array of key-value pairs
5316 * @param {Array<Node>} children
5317 * @return {Element}
5318 */
5319 const dom_element = (name, attrs = [], children = []) =>
5320 append(setAttributes(createElement(name), attrs), children)
5321
5322 /**
5323 * @param {number} width
5324 * @param {number} height
5325 */
5326 const canvas = (width, height) => {
5327 const c = /** @type {HTMLCanvasElement} */ (createElement('canvas'))
5328 c.height = height
5329 c.width = width
5330 return c
5331 }
5332
5333 /**
5334 * @param {string} t
5335 * @return {Text}
5336 */
5337 const dom_text = (/* unused pure expression or super */ null && (createTextNode))
5338
5339 /**
5340 * @param {pair.Pair<string,string>} pair
5341 */
5342 const pairToStyleString = pair => `${pair.left}:${pair.right};`
5343
5344 /**
5345 * @param {Array<pair.Pair<string,string>>} pairs
5346 * @return {string}
5347 */
5348 const pairsToStyleString = pairs => pairs.map(pairToStyleString).join('')
5349
5350 /**
5351 * @param {Map<string,string>} m
5352 * @return {string}
5353 */
5354 const mapToStyleString = m => map_map(m, (value, key) => `${key}:${value};`).join('')
5355
5356 /**
5357 * @todo should always query on a dom element
5358 *
5359 * @param {HTMLElement|ShadowRoot} el
5360 * @param {string} query
5361 * @return {HTMLElement | null}
5362 */
5363 const querySelector = (el, query) => el.querySelector(query)
5364
5365 /**
5366 * @param {HTMLElement|ShadowRoot} el
5367 * @param {string} query
5368 * @return {NodeListOf<HTMLElement>}
5369 */
5370 const querySelectorAll = (el, query) => el.querySelectorAll(query)
5371
5372 /**
5373 * @param {string} id
5374 * @return {HTMLElement}
5375 */
5376 const getElementById = id => /** @type {HTMLElement} */ (doc.getElementById(id))
5377
5378 /**
5379 * @param {string} html
5380 * @return {HTMLElement}
5381 */
5382 const _parse = html => domParser.parseFromString(`<html><body>${html}</body></html>`, 'text/html').body
5383
5384 /**
5385 * @param {string} html
5386 * @return {DocumentFragment}
5387 */
5388 const parseFragment = html => fragment(/** @type {any} */ (_parse(html).childNodes))
5389
5390 /**
5391 * @param {string} html
5392 * @return {HTMLElement}
5393 */
5394 const parseElement = html => /** @type HTMLElement */ (_parse(html).firstElementChild)
5395
5396 /**
5397 * @param {HTMLElement} oldEl
5398 * @param {HTMLElement|DocumentFragment} newEl
5399 */
5400 const replaceWith = (oldEl, newEl) => oldEl.replaceWith(newEl)
5401
5402 /**
5403 * @param {HTMLElement} parent
5404 * @param {HTMLElement} el
5405 * @param {Node|null} ref
5406 * @return {HTMLElement}
5407 */
5408 const insertBefore = (parent, el, ref) => parent.insertBefore(el, ref)
5409
5410 /**
5411 * @param {Node} parent
5412 * @param {Node} child
5413 * @return {Node}
5414 */
5415 const appendChild = (parent, child) => parent.appendChild(child)
5416
5417 const ELEMENT_NODE = doc.ELEMENT_NODE
5418 const TEXT_NODE = doc.TEXT_NODE
5419 const CDATA_SECTION_NODE = doc.CDATA_SECTION_NODE
5420 const COMMENT_NODE = doc.COMMENT_NODE
5421 const DOCUMENT_NODE = doc.DOCUMENT_NODE
5422 const DOCUMENT_TYPE_NODE = doc.DOCUMENT_TYPE_NODE
5423 const DOCUMENT_FRAGMENT_NODE = doc.DOCUMENT_FRAGMENT_NODE
5424
5425 /**
5426 * @param {any} node
5427 * @param {number} type
5428 */
5429 const checkNodeType = (node, type) => node.nodeType === type
5430
5431 /**
5432 * @param {Node} parent
5433 * @param {HTMLElement} child
5434 */
5435 const isParentOf = (parent, child) => {
5436 let p = child.parentNode
5437 while (p && p !== parent) {
5438 p = p.parentNode
5439 }
5440 return p === parent
5441 }
5442 /* c8 ignore stop */
5443
5444 ;// CONCATENATED MODULE: ./node_modules/lib0/symbol.js
5445 /**
5446 * Utility module to work with EcmaScript Symbols.
5447 *
5448 * @module symbol
5449 */
5450
5451 /**
5452 * Return fresh symbol.
5453 *
5454 * @return {Symbol}
5455 */
5456 const symbol_create = Symbol
5457
5458 /**
5459 * @param {any} s
5460 * @return {boolean}
5461 */
5462 const isSymbol = s => typeof s === 'symbol'
5463
5464 ;// CONCATENATED MODULE: ./node_modules/lib0/time.js
5465 /**
5466 * Utility module to work with time.
5467 *
5468 * @module time
5469 */
5470
5471
5472
5473
5474 /**
5475 * Return current time.
5476 *
5477 * @return {Date}
5478 */
5479 const getDate = () => new Date()
5480
5481 /**
5482 * Return current unix time.
5483 *
5484 * @return {number}
5485 */
5486 const getUnixTime = Date.now
5487
5488 /**
5489 * Transform time (in ms) to a human readable format. E.g. 1100 => 1.1s. 60s => 1min. .001 => 10μs.
5490 *
5491 * @param {number} d duration in milliseconds
5492 * @return {string} humanized approximation of time
5493 */
5494 const humanizeDuration = d => {
5495 if (d < 60000) {
5496 const p = metric.prefix(d, -1)
5497 return math.round(p.n * 100) / 100 + p.prefix + 's'
5498 }
5499 d = math.floor(d / 1000)
5500 const seconds = d % 60
5501 const minutes = math.floor(d / 60) % 60
5502 const hours = math.floor(d / 3600) % 24
5503 const days = math.floor(d / 86400)
5504 if (days > 0) {
5505 return days + 'd' + ((hours > 0 || minutes > 30) ? ' ' + (minutes > 30 ? hours + 1 : hours) + 'h' : '')
5506 }
5507 if (hours > 0) {
5508 /* c8 ignore next */
5509 return hours + 'h' + ((minutes > 0 || seconds > 30) ? ' ' + (seconds > 30 ? minutes + 1 : minutes) + 'min' : '')
5510 }
5511 return minutes + 'min' + (seconds > 0 ? ' ' + seconds + 's' : '')
5512 }
5513
5514 ;// CONCATENATED MODULE: ./node_modules/lib0/logging.common.js
5515
5516
5517
5518
5519
5520 const BOLD = symbol_create()
5521 const UNBOLD = symbol_create()
5522 const BLUE = symbol_create()
5523 const GREY = symbol_create()
5524 const GREEN = symbol_create()
5525 const RED = symbol_create()
5526 const PURPLE = symbol_create()
5527 const ORANGE = symbol_create()
5528 const UNCOLOR = symbol_create()
5529
5530 /* c8 ignore start */
5531 /**
5532 * @param {Array<string|Symbol|Object|number>} args
5533 * @return {Array<string|object|number>}
5534 */
5535 const computeNoColorLoggingArgs = args => {
5536 const strBuilder = []
5537 const logArgs = []
5538 // try with formatting until we find something unsupported
5539 let i = 0
5540 for (; i < args.length; i++) {
5541 const arg = args[i]
5542 if (arg.constructor === String || arg.constructor === Number) {
5543 strBuilder.push(arg)
5544 } else if (arg.constructor === Object) {
5545 logArgs.push(JSON.stringify(arg))
5546 }
5547 }
5548 return logArgs
5549 }
5550 /* c8 ignore stop */
5551
5552 const loggingColors = [GREEN, PURPLE, ORANGE, BLUE]
5553 let nextColor = 0
5554 let lastLoggingTime = getUnixTime()
5555
5556 /* c8 ignore start */
5557 /**
5558 * @param {function(...any):void} _print
5559 * @param {string} moduleName
5560 * @return {function(...any):void}
5561 */
5562 const createModuleLogger = (_print, moduleName) => {
5563 const color = loggingColors[nextColor]
5564 const debugRegexVar = getVariable('log')
5565 const doLogging = debugRegexVar !== null &&
5566 (debugRegexVar === '*' || debugRegexVar === 'true' ||
5567 new RegExp(debugRegexVar, 'gi').test(moduleName))
5568 nextColor = (nextColor + 1) % loggingColors.length
5569 moduleName += ': '
5570 return !doLogging
5571 ? nop
5572 : (...args) => {
5573 const timeNow = getUnixTime()
5574 const timeDiff = timeNow - lastLoggingTime
5575 lastLoggingTime = timeNow
5576 _print(
5577 color,
5578 moduleName,
5579 UNCOLOR,
5580 ...args.map((arg) =>
5581 (typeof arg === 'string' || typeof arg === 'symbol')
5582 ? arg
5583 : JSON.stringify(arg)
5584 ),
5585 color,
5586 ' +' + timeDiff + 'ms'
5587 )
5588 }
5589 }
5590 /* c8 ignore stop */
5591
5592 ;// CONCATENATED MODULE: ./node_modules/lib0/logging.js
5593 /**
5594 * Isomorphic logging module with support for colors!
5595 *
5596 * @module logging
5597 */
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611 /**
5612 * @type {Object<Symbol,pair.Pair<string,string>>}
5613 */
5614 const _browserStyleMap = {
5615 [BOLD]: pair_create('font-weight', 'bold'),
5616 [UNBOLD]: pair_create('font-weight', 'normal'),
5617 [BLUE]: pair_create('color', 'blue'),
5618 [GREEN]: pair_create('color', 'green'),
5619 [GREY]: pair_create('color', 'grey'),
5620 [RED]: pair_create('color', 'red'),
5621 [PURPLE]: pair_create('color', 'purple'),
5622 [ORANGE]: pair_create('color', 'orange'), // not well supported in chrome when debugging node with inspector - TODO: deprecate
5623 [UNCOLOR]: pair_create('color', 'black')
5624 }
5625
5626 /**
5627 * @param {Array<string|Symbol|Object|number>} args
5628 * @return {Array<string|object|number>}
5629 */
5630 /* c8 ignore start */
5631 const computeBrowserLoggingArgs = (args) => {
5632 const strBuilder = []
5633 const styles = []
5634 const currentStyle = create()
5635 /**
5636 * @type {Array<string|Object|number>}
5637 */
5638 let logArgs = []
5639 // try with formatting until we find something unsupported
5640 let i = 0
5641 for (; i < args.length; i++) {
5642 const arg = args[i]
5643 // @ts-ignore
5644 const style = _browserStyleMap[arg]
5645 if (style !== undefined) {
5646 currentStyle.set(style.left, style.right)
5647 } else {
5648 if (arg.constructor === String || arg.constructor === Number) {
5649 const style = mapToStyleString(currentStyle)
5650 if (i > 0 || style.length > 0) {
5651 strBuilder.push('%c' + arg)
5652 styles.push(style)
5653 } else {
5654 strBuilder.push(arg)
5655 }
5656 } else {
5657 break
5658 }
5659 }
5660 }
5661 if (i > 0) {
5662 // create logArgs with what we have so far
5663 logArgs = styles
5664 logArgs.unshift(strBuilder.join(''))
5665 }
5666 // append the rest
5667 for (; i < args.length; i++) {
5668 const arg = args[i]
5669 if (!(arg instanceof Symbol)) {
5670 logArgs.push(arg)
5671 }
5672 }
5673 return logArgs
5674 }
5675 /* c8 ignore stop */
5676
5677 /* c8 ignore start */
5678 const computeLoggingArgs = supportsColor
5679 ? computeBrowserLoggingArgs
5680 : computeNoColorLoggingArgs
5681 /* c8 ignore stop */
5682
5683 /**
5684 * @param {Array<string|Symbol|Object|number>} args
5685 */
5686 const print = (...args) => {
5687 console.log(...computeLoggingArgs(args))
5688 /* c8 ignore next */
5689 vconsoles.forEach((vc) => vc.print(args))
5690 }
5691
5692 /* c8 ignore start */
5693 /**
5694 * @param {Array<string|Symbol|Object|number>} args
5695 */
5696 const warn = (...args) => {
5697 console.warn(...computeLoggingArgs(args))
5698 args.unshift(common.ORANGE)
5699 vconsoles.forEach((vc) => vc.print(args))
5700 }
5701 /* c8 ignore stop */
5702
5703 /**
5704 * @param {Error} err
5705 */
5706 /* c8 ignore start */
5707 const printError = (err) => {
5708 console.error(err)
5709 vconsoles.forEach((vc) => vc.printError(err))
5710 }
5711 /* c8 ignore stop */
5712
5713 /**
5714 * @param {string} url image location
5715 * @param {number} height height of the image in pixel
5716 */
5717 /* c8 ignore start */
5718 const printImg = (url, height) => {
5719 if (env.isBrowser) {
5720 console.log(
5721 '%c ',
5722 `font-size: ${height}px; background-size: contain; background-repeat: no-repeat; background-image: url(${url})`
5723 )
5724 // console.log('%c ', `font-size: ${height}x; background: url(${url}) no-repeat;`)
5725 }
5726 vconsoles.forEach((vc) => vc.printImg(url, height))
5727 }
5728 /* c8 ignore stop */
5729
5730 /**
5731 * @param {string} base64
5732 * @param {number} height
5733 */
5734 /* c8 ignore next 2 */
5735 const printImgBase64 = (base64, height) =>
5736 printImg(`data:image/gif;base64,${base64}`, height)
5737
5738 /**
5739 * @param {Array<string|Symbol|Object|number>} args
5740 */
5741 const group = (...args) => {
5742 console.group(...computeLoggingArgs(args))
5743 /* c8 ignore next */
5744 vconsoles.forEach((vc) => vc.group(args))
5745 }
5746
5747 /**
5748 * @param {Array<string|Symbol|Object|number>} args
5749 */
5750 const groupCollapsed = (...args) => {
5751 console.groupCollapsed(...computeLoggingArgs(args))
5752 /* c8 ignore next */
5753 vconsoles.forEach((vc) => vc.groupCollapsed(args))
5754 }
5755
5756 const groupEnd = () => {
5757 console.groupEnd()
5758 /* c8 ignore next */
5759 vconsoles.forEach((vc) => vc.groupEnd())
5760 }
5761
5762 /**
5763 * @param {function():Node} createNode
5764 */
5765 /* c8 ignore next 2 */
5766 const printDom = (createNode) =>
5767 vconsoles.forEach((vc) => vc.printDom(createNode()))
5768
5769 /**
5770 * @param {HTMLCanvasElement} canvas
5771 * @param {number} height
5772 */
5773 /* c8 ignore next 2 */
5774 const printCanvas = (canvas, height) =>
5775 printImg(canvas.toDataURL(), height)
5776
5777 const vconsoles = set_create()
5778
5779 /**
5780 * @param {Array<string|Symbol|Object|number>} args
5781 * @return {Array<Element>}
5782 */
5783 /* c8 ignore start */
5784 const _computeLineSpans = (args) => {
5785 const spans = []
5786 const currentStyle = new Map()
5787 // try with formatting until we find something unsupported
5788 let i = 0
5789 for (; i < args.length; i++) {
5790 const arg = args[i]
5791 // @ts-ignore
5792 const style = _browserStyleMap[arg]
5793 if (style !== undefined) {
5794 currentStyle.set(style.left, style.right)
5795 } else {
5796 if (arg.constructor === String || arg.constructor === Number) {
5797 // @ts-ignore
5798 const span = dom.element('span', [
5799 pair.create('style', dom.mapToStyleString(currentStyle))
5800 ], [dom.text(arg.toString())])
5801 if (span.innerHTML === '') {
5802 span.innerHTML = '&nbsp;'
5803 }
5804 spans.push(span)
5805 } else {
5806 break
5807 }
5808 }
5809 }
5810 // append the rest
5811 for (; i < args.length; i++) {
5812 let content = args[i]
5813 if (!(content instanceof Symbol)) {
5814 if (content.constructor !== String && content.constructor !== Number) {
5815 content = ' ' + json.stringify(content) + ' '
5816 }
5817 spans.push(
5818 dom.element('span', [], [dom.text(/** @type {string} */ (content))])
5819 )
5820 }
5821 }
5822 return spans
5823 }
5824 /* c8 ignore stop */
5825
5826 const lineStyle =
5827 'font-family:monospace;border-bottom:1px solid #e2e2e2;padding:2px;'
5828
5829 /* c8 ignore start */
5830 class VConsole {
5831 /**
5832 * @param {Element} dom
5833 */
5834 constructor (dom) {
5835 this.dom = dom
5836 /**
5837 * @type {Element}
5838 */
5839 this.ccontainer = this.dom
5840 this.depth = 0
5841 vconsoles.add(this)
5842 }
5843
5844 /**
5845 * @param {Array<string|Symbol|Object|number>} args
5846 * @param {boolean} collapsed
5847 */
5848 group (args, collapsed = false) {
5849 eventloop.enqueue(() => {
5850 const triangleDown = dom.element('span', [
5851 pair.create('hidden', collapsed),
5852 pair.create('style', 'color:grey;font-size:120%;')
5853 ], [dom.text('▼')])
5854 const triangleRight = dom.element('span', [
5855 pair.create('hidden', !collapsed),
5856 pair.create('style', 'color:grey;font-size:125%;')
5857 ], [dom.text('▶')])
5858 const content = dom.element(
5859 'div',
5860 [pair.create(
5861 'style',
5862 `${lineStyle};padding-left:${this.depth * 10}px`
5863 )],
5864 [triangleDown, triangleRight, dom.text(' ')].concat(
5865 _computeLineSpans(args)
5866 )
5867 )
5868 const nextContainer = dom.element('div', [
5869 pair.create('hidden', collapsed)
5870 ])
5871 const nextLine = dom.element('div', [], [content, nextContainer])
5872 dom.append(this.ccontainer, [nextLine])
5873 this.ccontainer = nextContainer
5874 this.depth++
5875 // when header is clicked, collapse/uncollapse container
5876 dom.addEventListener(content, 'click', (_event) => {
5877 nextContainer.toggleAttribute('hidden')
5878 triangleDown.toggleAttribute('hidden')
5879 triangleRight.toggleAttribute('hidden')
5880 })
5881 })
5882 }
5883
5884 /**
5885 * @param {Array<string|Symbol|Object|number>} args
5886 */
5887 groupCollapsed (args) {
5888 this.group(args, true)
5889 }
5890
5891 groupEnd () {
5892 eventloop.enqueue(() => {
5893 if (this.depth > 0) {
5894 this.depth--
5895 // @ts-ignore
5896 this.ccontainer = this.ccontainer.parentElement.parentElement
5897 }
5898 })
5899 }
5900
5901 /**
5902 * @param {Array<string|Symbol|Object|number>} args
5903 */
5904 print (args) {
5905 eventloop.enqueue(() => {
5906 dom.append(this.ccontainer, [
5907 dom.element('div', [
5908 pair.create(
5909 'style',
5910 `${lineStyle};padding-left:${this.depth * 10}px`
5911 )
5912 ], _computeLineSpans(args))
5913 ])
5914 })
5915 }
5916
5917 /**
5918 * @param {Error} err
5919 */
5920 printError (err) {
5921 this.print([common.RED, common.BOLD, err.toString()])
5922 }
5923
5924 /**
5925 * @param {string} url
5926 * @param {number} height
5927 */
5928 printImg (url, height) {
5929 eventloop.enqueue(() => {
5930 dom.append(this.ccontainer, [
5931 dom.element('img', [
5932 pair.create('src', url),
5933 pair.create('height', `${math.round(height * 1.5)}px`)
5934 ])
5935 ])
5936 })
5937 }
5938
5939 /**
5940 * @param {Node} node
5941 */
5942 printDom (node) {
5943 eventloop.enqueue(() => {
5944 dom.append(this.ccontainer, [node])
5945 })
5946 }
5947
5948 destroy () {
5949 eventloop.enqueue(() => {
5950 vconsoles.delete(this)
5951 })
5952 }
5953 }
5954 /* c8 ignore stop */
5955
5956 /**
5957 * @param {Element} dom
5958 */
5959 /* c8 ignore next */
5960 const createVConsole = (dom) => new VConsole(dom)
5961
5962 /**
5963 * @param {string} moduleName
5964 * @return {function(...any):void}
5965 */
5966 const logging_createModuleLogger = (moduleName) => createModuleLogger(print, moduleName)
5967
5968 ;// CONCATENATED MODULE: ./node_modules/lib0/iterator.js
5969 /**
5970 * Utility module to create and manipulate Iterators.
5971 *
5972 * @module iterator
5973 */
5974
5975 /**
5976 * @template T,R
5977 * @param {Iterator<T>} iterator
5978 * @param {function(T):R} f
5979 * @return {IterableIterator<R>}
5980 */
5981 const mapIterator = (iterator, f) => ({
5982 [Symbol.iterator] () {
5983 return this
5984 },
5985 // @ts-ignore
5986 next () {
5987 const r = iterator.next()
5988 return { value: r.done ? undefined : f(r.value), done: r.done }
5989 }
5990 })
5991
5992 /**
5993 * @template T
5994 * @param {function():IteratorResult<T>} next
5995 * @return {IterableIterator<T>}
5996 */
5997 const createIterator = next => ({
5998 /**
5999 * @return {IterableIterator<T>}
6000 */
6001 [Symbol.iterator] () {
6002 return this
6003 },
6004 // @ts-ignore
6005 next
6006 })
6007
6008 /**
6009 * @template T
6010 * @param {Iterator<T>} iterator
6011 * @param {function(T):boolean} filter
6012 */
6013 const iteratorFilter = (iterator, filter) => createIterator(() => {
6014 let res
6015 do {
6016 res = iterator.next()
6017 } while (!res.done && !filter(res.value))
6018 return res
6019 })
6020
6021 /**
6022 * @template T,M
6023 * @param {Iterator<T>} iterator
6024 * @param {function(T):M} fmap
6025 */
6026 const iteratorMap = (iterator, fmap) => createIterator(() => {
6027 const { done, value } = iterator.next()
6028 return { done, value: done ? undefined : fmap(value) }
6029 })
6030
6031 ;// CONCATENATED MODULE: ./node_modules/yjs/dist/yjs.mjs
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052 /**
6053 * This is an abstract interface that all Connectors should implement to keep them interchangeable.
6054 *
6055 * @note This interface is experimental and it is not advised to actually inherit this class.
6056 * It just serves as typing information.
6057 *
6058 * @extends {Observable<any>}
6059 */
6060 class AbstractConnector extends (/* unused pure expression or super */ null && (Observable)) {
6061 /**
6062 * @param {Doc} ydoc
6063 * @param {any} awareness
6064 */
6065 constructor (ydoc, awareness) {
6066 super();
6067 this.doc = ydoc;
6068 this.awareness = awareness;
6069 }
6070 }
6071
6072 class DeleteItem {
6073 /**
6074 * @param {number} clock
6075 * @param {number} len
6076 */
6077 constructor (clock, len) {
6078 /**
6079 * @type {number}
6080 */
6081 this.clock = clock;
6082 /**
6083 * @type {number}
6084 */
6085 this.len = len;
6086 }
6087 }
6088
6089 /**
6090 * We no longer maintain a DeleteStore. DeleteSet is a temporary object that is created when needed.
6091 * - When created in a transaction, it must only be accessed after sorting, and merging
6092 * - This DeleteSet is send to other clients
6093 * - We do not create a DeleteSet when we send a sync message. The DeleteSet message is created directly from StructStore
6094 * - We read a DeleteSet as part of a sync/update message. In this case the DeleteSet is already sorted and merged.
6095 */
6096 class DeleteSet {
6097 constructor () {
6098 /**
6099 * @type {Map<number,Array<DeleteItem>>}
6100 */
6101 this.clients = new Map();
6102 }
6103 }
6104
6105 /**
6106 * Iterate over all structs that the DeleteSet gc's.
6107 *
6108 * @param {Transaction} transaction
6109 * @param {DeleteSet} ds
6110 * @param {function(GC|Item):void} f
6111 *
6112 * @function
6113 */
6114 const iterateDeletedStructs = (transaction, ds, f) =>
6115 ds.clients.forEach((deletes, clientid) => {
6116 const structs = /** @type {Array<GC|Item>} */ (transaction.doc.store.clients.get(clientid));
6117 for (let i = 0; i < deletes.length; i++) {
6118 const del = deletes[i];
6119 iterateStructs(transaction, structs, del.clock, del.len, f);
6120 }
6121 });
6122
6123 /**
6124 * @param {Array<DeleteItem>} dis
6125 * @param {number} clock
6126 * @return {number|null}
6127 *
6128 * @private
6129 * @function
6130 */
6131 const findIndexDS = (dis, clock) => {
6132 let left = 0;
6133 let right = dis.length - 1;
6134 while (left <= right) {
6135 const midindex = floor((left + right) / 2);
6136 const mid = dis[midindex];
6137 const midclock = mid.clock;
6138 if (midclock <= clock) {
6139 if (clock < midclock + mid.len) {
6140 return midindex
6141 }
6142 left = midindex + 1;
6143 } else {
6144 right = midindex - 1;
6145 }
6146 }
6147 return null
6148 };
6149
6150 /**
6151 * @param {DeleteSet} ds
6152 * @param {ID} id
6153 * @return {boolean}
6154 *
6155 * @private
6156 * @function
6157 */
6158 const isDeleted = (ds, id) => {
6159 const dis = ds.clients.get(id.client);
6160 return dis !== undefined && findIndexDS(dis, id.clock) !== null
6161 };
6162
6163 /**
6164 * @param {DeleteSet} ds
6165 *
6166 * @private
6167 * @function
6168 */
6169 const sortAndMergeDeleteSet = ds => {
6170 ds.clients.forEach(dels => {
6171 dels.sort((a, b) => a.clock - b.clock);
6172 // merge items without filtering or splicing the array
6173 // i is the current pointer
6174 // j refers to the current insert position for the pointed item
6175 // try to merge dels[i] into dels[j-1] or set dels[j]=dels[i]
6176 let i, j;
6177 for (i = 1, j = 1; i < dels.length; i++) {
6178 const left = dels[j - 1];
6179 const right = dels[i];
6180 if (left.clock + left.len >= right.clock) {
6181 left.len = max(left.len, right.clock + right.len - left.clock);
6182 } else {
6183 if (j < i) {
6184 dels[j] = right;
6185 }
6186 j++;
6187 }
6188 }
6189 dels.length = j;
6190 });
6191 };
6192
6193 /**
6194 * @param {Array<DeleteSet>} dss
6195 * @return {DeleteSet} A fresh DeleteSet
6196 */
6197 const mergeDeleteSets = dss => {
6198 const merged = new DeleteSet();
6199 for (let dssI = 0; dssI < dss.length; dssI++) {
6200 dss[dssI].clients.forEach((delsLeft, client) => {
6201 if (!merged.clients.has(client)) {
6202 // Write all missing keys from current ds and all following.
6203 // If merged already contains `client` current ds has already been added.
6204 /**
6205 * @type {Array<DeleteItem>}
6206 */
6207 const dels = delsLeft.slice();
6208 for (let i = dssI + 1; i < dss.length; i++) {
6209 appendTo(dels, dss[i].clients.get(client) || []);
6210 }
6211 merged.clients.set(client, dels);
6212 }
6213 });
6214 }
6215 sortAndMergeDeleteSet(merged);
6216 return merged
6217 };
6218
6219 /**
6220 * @param {DeleteSet} ds
6221 * @param {number} client
6222 * @param {number} clock
6223 * @param {number} length
6224 *
6225 * @private
6226 * @function
6227 */
6228 const addToDeleteSet = (ds, client, clock, length) => {
6229 setIfUndefined(ds.clients, client, () => /** @type {Array<DeleteItem>} */ ([])).push(new DeleteItem(clock, length));
6230 };
6231
6232 const createDeleteSet = () => new DeleteSet();
6233
6234 /**
6235 * @param {StructStore} ss
6236 * @return {DeleteSet} Merged and sorted DeleteSet
6237 *
6238 * @private
6239 * @function
6240 */
6241 const createDeleteSetFromStructStore = ss => {
6242 const ds = createDeleteSet();
6243 ss.clients.forEach((structs, client) => {
6244 /**
6245 * @type {Array<DeleteItem>}
6246 */
6247 const dsitems = [];
6248 for (let i = 0; i < structs.length; i++) {
6249 const struct = structs[i];
6250 if (struct.deleted) {
6251 const clock = struct.id.clock;
6252 let len = struct.length;
6253 if (i + 1 < structs.length) {
6254 for (let next = structs[i + 1]; i + 1 < structs.length && next.deleted; next = structs[++i + 1]) {
6255 len += next.length;
6256 }
6257 }
6258 dsitems.push(new DeleteItem(clock, len));
6259 }
6260 }
6261 if (dsitems.length > 0) {
6262 ds.clients.set(client, dsitems);
6263 }
6264 });
6265 return ds
6266 };
6267
6268 /**
6269 * @param {DSEncoderV1 | DSEncoderV2} encoder
6270 * @param {DeleteSet} ds
6271 *
6272 * @private
6273 * @function
6274 */
6275 const writeDeleteSet = (encoder, ds) => {
6276 writeVarUint(encoder.restEncoder, ds.clients.size);
6277
6278 // Ensure that the delete set is written in a deterministic order
6279 array_from(ds.clients.entries())
6280 .sort((a, b) => b[0] - a[0])
6281 .forEach(([client, dsitems]) => {
6282 encoder.resetDsCurVal();
6283 writeVarUint(encoder.restEncoder, client);
6284 const len = dsitems.length;
6285 writeVarUint(encoder.restEncoder, len);
6286 for (let i = 0; i < len; i++) {
6287 const item = dsitems[i];
6288 encoder.writeDsClock(item.clock);
6289 encoder.writeDsLen(item.len);
6290 }
6291 });
6292 };
6293
6294 /**
6295 * @param {DSDecoderV1 | DSDecoderV2} decoder
6296 * @return {DeleteSet}
6297 *
6298 * @private
6299 * @function
6300 */
6301 const readDeleteSet = decoder => {
6302 const ds = new DeleteSet();
6303 const numClients = readVarUint(decoder.restDecoder);
6304 for (let i = 0; i < numClients; i++) {
6305 decoder.resetDsCurVal();
6306 const client = readVarUint(decoder.restDecoder);
6307 const numberOfDeletes = readVarUint(decoder.restDecoder);
6308 if (numberOfDeletes > 0) {
6309 const dsField = setIfUndefined(ds.clients, client, () => /** @type {Array<DeleteItem>} */ ([]));
6310 for (let i = 0; i < numberOfDeletes; i++) {
6311 dsField.push(new DeleteItem(decoder.readDsClock(), decoder.readDsLen()));
6312 }
6313 }
6314 }
6315 return ds
6316 };
6317
6318 /**
6319 * @todo YDecoder also contains references to String and other Decoders. Would make sense to exchange YDecoder.toUint8Array for YDecoder.DsToUint8Array()..
6320 */
6321
6322 /**
6323 * @param {DSDecoderV1 | DSDecoderV2} decoder
6324 * @param {Transaction} transaction
6325 * @param {StructStore} store
6326 * @return {Uint8Array|null} Returns a v2 update containing all deletes that couldn't be applied yet; or null if all deletes were applied successfully.
6327 *
6328 * @private
6329 * @function
6330 */
6331 const readAndApplyDeleteSet = (decoder, transaction, store) => {
6332 const unappliedDS = new DeleteSet();
6333 const numClients = readVarUint(decoder.restDecoder);
6334 for (let i = 0; i < numClients; i++) {
6335 decoder.resetDsCurVal();
6336 const client = readVarUint(decoder.restDecoder);
6337 const numberOfDeletes = readVarUint(decoder.restDecoder);
6338 const structs = store.clients.get(client) || [];
6339 const state = getState(store, client);
6340 for (let i = 0; i < numberOfDeletes; i++) {
6341 const clock = decoder.readDsClock();
6342 const clockEnd = clock + decoder.readDsLen();
6343 if (clock < state) {
6344 if (state < clockEnd) {
6345 addToDeleteSet(unappliedDS, client, state, clockEnd - state);
6346 }
6347 let index = findIndexSS(structs, clock);
6348 /**
6349 * We can ignore the case of GC and Delete structs, because we are going to skip them
6350 * @type {Item}
6351 */
6352 // @ts-ignore
6353 let struct = structs[index];
6354 // split the first item if necessary
6355 if (!struct.deleted && struct.id.clock < clock) {
6356 structs.splice(index + 1, 0, splitItem(transaction, struct, clock - struct.id.clock));
6357 index++; // increase we now want to use the next struct
6358 }
6359 while (index < structs.length) {
6360 // @ts-ignore
6361 struct = structs[index++];
6362 if (struct.id.clock < clockEnd) {
6363 if (!struct.deleted) {
6364 if (clockEnd < struct.id.clock + struct.length) {
6365 structs.splice(index, 0, splitItem(transaction, struct, clockEnd - struct.id.clock));
6366 }
6367 struct.delete(transaction);
6368 }
6369 } else {
6370 break
6371 }
6372 }
6373 } else {
6374 addToDeleteSet(unappliedDS, client, clock, clockEnd - clock);
6375 }
6376 }
6377 }
6378 if (unappliedDS.clients.size > 0) {
6379 const ds = new UpdateEncoderV2();
6380 writeVarUint(ds.restEncoder, 0); // encode 0 structs
6381 writeDeleteSet(ds, unappliedDS);
6382 return ds.toUint8Array()
6383 }
6384 return null
6385 };
6386
6387 /**
6388 * @param {DeleteSet} ds1
6389 * @param {DeleteSet} ds2
6390 */
6391 const equalDeleteSets = (ds1, ds2) => {
6392 if (ds1.clients.size !== ds2.clients.size) return false
6393 for (const [client, deleteItems1] of ds1.clients.entries()) {
6394 const deleteItems2 = /** @type {Array<import('../internals.js').DeleteItem>} */ (ds2.clients.get(client));
6395 if (deleteItems2 === undefined || deleteItems1.length !== deleteItems2.length) return false
6396 for (let i = 0; i < deleteItems1.length; i++) {
6397 const di1 = deleteItems1[i];
6398 const di2 = deleteItems2[i];
6399 if (di1.clock !== di2.clock || di1.len !== di2.len) {
6400 return false
6401 }
6402 }
6403 }
6404 return true
6405 };
6406
6407 /**
6408 * @module Y
6409 */
6410
6411 const generateNewClientId = uint32;
6412
6413 /**
6414 * @typedef {Object} DocOpts
6415 * @property {boolean} [DocOpts.gc=true] Disable garbage collection (default: gc=true)
6416 * @property {function(Item):boolean} [DocOpts.gcFilter] Will be called before an Item is garbage collected. Return false to keep the Item.
6417 * @property {string} [DocOpts.guid] Define a globally unique identifier for this document
6418 * @property {string | null} [DocOpts.collectionid] Associate this document with a collection. This only plays a role if your provider has a concept of collection.
6419 * @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.
6420 * @property {boolean} [DocOpts.autoLoad] If a subdocument, automatically load document. If this is a subdocument, remote peers will load the document as well automatically.
6421 * @property {boolean} [DocOpts.shouldLoad] Whether the document should be synced by the provider now. This is toggled to true when you call ydoc.load()
6422 */
6423
6424 /**
6425 * A Yjs instance handles the state of shared data.
6426 * @extends Observable<string>
6427 */
6428 class Doc extends observable_Observable {
6429 /**
6430 * @param {DocOpts} opts configuration
6431 */
6432 constructor ({ guid = uuidv4(), collectionid = null, gc = true, gcFilter = () => true, meta = null, autoLoad = false, shouldLoad = true } = {}) {
6433 super();
6434 this.gc = gc;
6435 this.gcFilter = gcFilter;
6436 this.clientID = generateNewClientId();
6437 this.guid = guid;
6438 this.collectionid = collectionid;
6439 /**
6440 * @type {Map<string, AbstractType<YEvent<any>>>}
6441 */
6442 this.share = new Map();
6443 this.store = new StructStore();
6444 /**
6445 * @type {Transaction | null}
6446 */
6447 this._transaction = null;
6448 /**
6449 * @type {Array<Transaction>}
6450 */
6451 this._transactionCleanups = [];
6452 /**
6453 * @type {Set<Doc>}
6454 */
6455 this.subdocs = new Set();
6456 /**
6457 * If this document is a subdocument - a document integrated into another document - then _item is defined.
6458 * @type {Item?}
6459 */
6460 this._item = null;
6461 this.shouldLoad = shouldLoad;
6462 this.autoLoad = autoLoad;
6463 this.meta = meta;
6464 /**
6465 * This is set to true when the persistence provider loaded the document from the database or when the `sync` event fires.
6466 * 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.
6467 *
6468 * @type {boolean}
6469 */
6470 this.isLoaded = false;
6471 /**
6472 * This is set to true when the connection provider has successfully synced with a backend.
6473 * Note that when using peer-to-peer providers this event may not provide very useful.
6474 * Also note that not all providers implement this feature. Provider authors are encouraged to fire
6475 * the `sync` event when the doc has been synced (with `true` as a parameter) or if connection is
6476 * lost (with false as a parameter).
6477 */
6478 this.isSynced = false;
6479 /**
6480 * Promise that resolves once the document has been loaded from a presistence provider.
6481 */
6482 this.whenLoaded = promise_create(resolve => {
6483 this.on('load', () => {
6484 this.isLoaded = true;
6485 resolve(this);
6486 });
6487 });
6488 const provideSyncedPromise = () => promise_create(resolve => {
6489 /**
6490 * @param {boolean} isSynced
6491 */
6492 const eventHandler = (isSynced) => {
6493 if (isSynced === undefined || isSynced === true) {
6494 this.off('sync', eventHandler);
6495 resolve();
6496 }
6497 };
6498 this.on('sync', eventHandler);
6499 });
6500 this.on('sync', isSynced => {
6501 if (isSynced === false && this.isSynced) {
6502 this.whenSynced = provideSyncedPromise();
6503 }
6504 this.isSynced = isSynced === undefined || isSynced === true;
6505 if (!this.isLoaded) {
6506 this.emit('load', []);
6507 }
6508 });
6509 /**
6510 * Promise that resolves once the document has been synced with a backend.
6511 * This promise is recreated when the connection is lost.
6512 * Note the documentation about the `isSynced` property.
6513 */
6514 this.whenSynced = provideSyncedPromise();
6515 }
6516
6517 /**
6518 * Notify the parent document that you request to load data into this subdocument (if it is a subdocument).
6519 *
6520 * `load()` might be used in the future to request any provider to load the most current data.
6521 *
6522 * It is safe to call `load()` multiple times.
6523 */
6524 load () {
6525 const item = this._item;
6526 if (item !== null && !this.shouldLoad) {
6527 transact(/** @type {any} */ (item.parent).doc, transaction => {
6528 transaction.subdocsLoaded.add(this);
6529 }, null, true);
6530 }
6531 this.shouldLoad = true;
6532 }
6533
6534 getSubdocs () {
6535 return this.subdocs
6536 }
6537
6538 getSubdocGuids () {
6539 return new Set(array_from(this.subdocs).map(doc => doc.guid))
6540 }
6541
6542 /**
6543 * Changes that happen inside of a transaction are bundled. This means that
6544 * the observer fires _after_ the transaction is finished and that all changes
6545 * that happened inside of the transaction are sent as one message to the
6546 * other peers.
6547 *
6548 * @template T
6549 * @param {function(Transaction):T} f The function that should be executed as a transaction
6550 * @param {any} [origin] Origin of who started the transaction. Will be stored on transaction.origin
6551 * @return T
6552 *
6553 * @public
6554 */
6555 transact (f, origin = null) {
6556 return transact(this, f, origin)
6557 }
6558
6559 /**
6560 * Define a shared data type.
6561 *
6562 * Multiple calls of `y.get(name, TypeConstructor)` yield the same result
6563 * and do not overwrite each other. I.e.
6564 * `y.define(name, Y.Array) === y.define(name, Y.Array)`
6565 *
6566 * After this method is called, the type is also available on `y.share.get(name)`.
6567 *
6568 * *Best Practices:*
6569 * Define all types right after the Yjs instance is created and store them in a separate object.
6570 * Also use the typed methods `getText(name)`, `getArray(name)`, ..
6571 *
6572 * @example
6573 * const y = new Y(..)
6574 * const appState = {
6575 * document: y.getText('document')
6576 * comments: y.getArray('comments')
6577 * }
6578 *
6579 * @param {string} name
6580 * @param {Function} TypeConstructor The constructor of the type definition. E.g. Y.Text, Y.Array, Y.Map, ...
6581 * @return {AbstractType<any>} The created type. Constructed with TypeConstructor
6582 *
6583 * @public
6584 */
6585 get (name, TypeConstructor = AbstractType) {
6586 const type = setIfUndefined(this.share, name, () => {
6587 // @ts-ignore
6588 const t = new TypeConstructor();
6589 t._integrate(this, null);
6590 return t
6591 });
6592 const Constr = type.constructor;
6593 if (TypeConstructor !== AbstractType && Constr !== TypeConstructor) {
6594 if (Constr === AbstractType) {
6595 // @ts-ignore
6596 const t = new TypeConstructor();
6597 t._map = type._map;
6598 type._map.forEach(/** @param {Item?} n */ n => {
6599 for (; n !== null; n = n.left) {
6600 // @ts-ignore
6601 n.parent = t;
6602 }
6603 });
6604 t._start = type._start;
6605 for (let n = t._start; n !== null; n = n.right) {
6606 n.parent = t;
6607 }
6608 t._length = type._length;
6609 this.share.set(name, t);
6610 t._integrate(this, null);
6611 return t
6612 } else {
6613 throw new Error(`Type with the name ${name} has already been defined with a different constructor`)
6614 }
6615 }
6616 return type
6617 }
6618
6619 /**
6620 * @template T
6621 * @param {string} [name]
6622 * @return {YArray<T>}
6623 *
6624 * @public
6625 */
6626 getArray (name = '') {
6627 // @ts-ignore
6628 return this.get(name, YArray)
6629 }
6630
6631 /**
6632 * @param {string} [name]
6633 * @return {YText}
6634 *
6635 * @public
6636 */
6637 getText (name = '') {
6638 // @ts-ignore
6639 return this.get(name, YText)
6640 }
6641
6642 /**
6643 * @template T
6644 * @param {string} [name]
6645 * @return {YMap<T>}
6646 *
6647 * @public
6648 */
6649 getMap (name = '') {
6650 // @ts-ignore
6651 return this.get(name, YMap)
6652 }
6653
6654 /**
6655 * @param {string} [name]
6656 * @return {YXmlFragment}
6657 *
6658 * @public
6659 */
6660 getXmlFragment (name = '') {
6661 // @ts-ignore
6662 return this.get(name, YXmlFragment)
6663 }
6664
6665 /**
6666 * Converts the entire document into a js object, recursively traversing each yjs type
6667 * Doesn't log types that have not been defined (using ydoc.getType(..)).
6668 *
6669 * @deprecated Do not use this method and rather call toJSON directly on the shared types.
6670 *
6671 * @return {Object<string, any>}
6672 */
6673 toJSON () {
6674 /**
6675 * @type {Object<string, any>}
6676 */
6677 const doc = {};
6678
6679 this.share.forEach((value, key) => {
6680 doc[key] = value.toJSON();
6681 });
6682
6683 return doc
6684 }
6685
6686 /**
6687 * Emit `destroy` event and unregister all event handlers.
6688 */
6689 destroy () {
6690 array_from(this.subdocs).forEach(subdoc => subdoc.destroy());
6691 const item = this._item;
6692 if (item !== null) {
6693 this._item = null;
6694 const content = /** @type {ContentDoc} */ (item.content);
6695 content.doc = new Doc({ guid: this.guid, ...content.opts, shouldLoad: false });
6696 content.doc._item = item;
6697 transact(/** @type {any} */ (item).parent.doc, transaction => {
6698 const doc = content.doc;
6699 if (!item.deleted) {
6700 transaction.subdocsAdded.add(doc);
6701 }
6702 transaction.subdocsRemoved.add(this);
6703 }, null, true);
6704 }
6705 this.emit('destroyed', [true]);
6706 this.emit('destroy', [this]);
6707 super.destroy();
6708 }
6709
6710 /**
6711 * @param {string} eventName
6712 * @param {function(...any):any} f
6713 */
6714 on (eventName, f) {
6715 super.on(eventName, f);
6716 }
6717
6718 /**
6719 * @param {string} eventName
6720 * @param {function} f
6721 */
6722 off (eventName, f) {
6723 super.off(eventName, f);
6724 }
6725 }
6726
6727 class DSDecoderV1 {
6728 /**
6729 * @param {decoding.Decoder} decoder
6730 */
6731 constructor (decoder) {
6732 this.restDecoder = decoder;
6733 }
6734
6735 resetDsCurVal () {
6736 // nop
6737 }
6738
6739 /**
6740 * @return {number}
6741 */
6742 readDsClock () {
6743 return readVarUint(this.restDecoder)
6744 }
6745
6746 /**
6747 * @return {number}
6748 */
6749 readDsLen () {
6750 return readVarUint(this.restDecoder)
6751 }
6752 }
6753
6754 class UpdateDecoderV1 extends DSDecoderV1 {
6755 /**
6756 * @return {ID}
6757 */
6758 readLeftID () {
6759 return createID(readVarUint(this.restDecoder), readVarUint(this.restDecoder))
6760 }
6761
6762 /**
6763 * @return {ID}
6764 */
6765 readRightID () {
6766 return createID(readVarUint(this.restDecoder), readVarUint(this.restDecoder))
6767 }
6768
6769 /**
6770 * Read the next client id.
6771 * Use this in favor of readID whenever possible to reduce the number of objects created.
6772 */
6773 readClient () {
6774 return readVarUint(this.restDecoder)
6775 }
6776
6777 /**
6778 * @return {number} info An unsigned 8-bit integer
6779 */
6780 readInfo () {
6781 return readUint8(this.restDecoder)
6782 }
6783
6784 /**
6785 * @return {string}
6786 */
6787 readString () {
6788 return readVarString(this.restDecoder)
6789 }
6790
6791 /**
6792 * @return {boolean} isKey
6793 */
6794 readParentInfo () {
6795 return readVarUint(this.restDecoder) === 1
6796 }
6797
6798 /**
6799 * @return {number} info An unsigned 8-bit integer
6800 */
6801 readTypeRef () {
6802 return readVarUint(this.restDecoder)
6803 }
6804
6805 /**
6806 * Write len of a struct - well suited for Opt RLE encoder.
6807 *
6808 * @return {number} len
6809 */
6810 readLen () {
6811 return readVarUint(this.restDecoder)
6812 }
6813
6814 /**
6815 * @return {any}
6816 */
6817 readAny () {
6818 return readAny(this.restDecoder)
6819 }
6820
6821 /**
6822 * @return {Uint8Array}
6823 */
6824 readBuf () {
6825 return copyUint8Array(readVarUint8Array(this.restDecoder))
6826 }
6827
6828 /**
6829 * Legacy implementation uses JSON parse. We use any-decoding in v2.
6830 *
6831 * @return {any}
6832 */
6833 readJSON () {
6834 return JSON.parse(readVarString(this.restDecoder))
6835 }
6836
6837 /**
6838 * @return {string}
6839 */
6840 readKey () {
6841 return readVarString(this.restDecoder)
6842 }
6843 }
6844
6845 class DSDecoderV2 {
6846 /**
6847 * @param {decoding.Decoder} decoder
6848 */
6849 constructor (decoder) {
6850 /**
6851 * @private
6852 */
6853 this.dsCurrVal = 0;
6854 this.restDecoder = decoder;
6855 }
6856
6857 resetDsCurVal () {
6858 this.dsCurrVal = 0;
6859 }
6860
6861 /**
6862 * @return {number}
6863 */
6864 readDsClock () {
6865 this.dsCurrVal += readVarUint(this.restDecoder);
6866 return this.dsCurrVal
6867 }
6868
6869 /**
6870 * @return {number}
6871 */
6872 readDsLen () {
6873 const diff = readVarUint(this.restDecoder) + 1;
6874 this.dsCurrVal += diff;
6875 return diff
6876 }
6877 }
6878
6879 class UpdateDecoderV2 extends DSDecoderV2 {
6880 /**
6881 * @param {decoding.Decoder} decoder
6882 */
6883 constructor (decoder) {
6884 super(decoder);
6885 /**
6886 * List of cached keys. If the keys[id] does not exist, we read a new key
6887 * from stringEncoder and push it to keys.
6888 *
6889 * @type {Array<string>}
6890 */
6891 this.keys = [];
6892 readVarUint(decoder); // read feature flag - currently unused
6893 this.keyClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder));
6894 this.clientDecoder = new UintOptRleDecoder(readVarUint8Array(decoder));
6895 this.leftClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder));
6896 this.rightClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder));
6897 this.infoDecoder = new RleDecoder(readVarUint8Array(decoder), readUint8);
6898 this.stringDecoder = new StringDecoder(readVarUint8Array(decoder));
6899 this.parentInfoDecoder = new RleDecoder(readVarUint8Array(decoder), readUint8);
6900 this.typeRefDecoder = new UintOptRleDecoder(readVarUint8Array(decoder));
6901 this.lenDecoder = new UintOptRleDecoder(readVarUint8Array(decoder));
6902 }
6903
6904 /**
6905 * @return {ID}
6906 */
6907 readLeftID () {
6908 return new ID(this.clientDecoder.read(), this.leftClockDecoder.read())
6909 }
6910
6911 /**
6912 * @return {ID}
6913 */
6914 readRightID () {
6915 return new ID(this.clientDecoder.read(), this.rightClockDecoder.read())
6916 }
6917
6918 /**
6919 * Read the next client id.
6920 * Use this in favor of readID whenever possible to reduce the number of objects created.
6921 */
6922 readClient () {
6923 return this.clientDecoder.read()
6924 }
6925
6926 /**
6927 * @return {number} info An unsigned 8-bit integer
6928 */
6929 readInfo () {
6930 return /** @type {number} */ (this.infoDecoder.read())
6931 }
6932
6933 /**
6934 * @return {string}
6935 */
6936 readString () {
6937 return this.stringDecoder.read()
6938 }
6939
6940 /**
6941 * @return {boolean}
6942 */
6943 readParentInfo () {
6944 return this.parentInfoDecoder.read() === 1
6945 }
6946
6947 /**
6948 * @return {number} An unsigned 8-bit integer
6949 */
6950 readTypeRef () {
6951 return this.typeRefDecoder.read()
6952 }
6953
6954 /**
6955 * Write len of a struct - well suited for Opt RLE encoder.
6956 *
6957 * @return {number}
6958 */
6959 readLen () {
6960 return this.lenDecoder.read()
6961 }
6962
6963 /**
6964 * @return {any}
6965 */
6966 readAny () {
6967 return readAny(this.restDecoder)
6968 }
6969
6970 /**
6971 * @return {Uint8Array}
6972 */
6973 readBuf () {
6974 return readVarUint8Array(this.restDecoder)
6975 }
6976
6977 /**
6978 * This is mainly here for legacy purposes.
6979 *
6980 * 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.
6981 *
6982 * @return {any}
6983 */
6984 readJSON () {
6985 return readAny(this.restDecoder)
6986 }
6987
6988 /**
6989 * @return {string}
6990 */
6991 readKey () {
6992 const keyClock = this.keyClockDecoder.read();
6993 if (keyClock < this.keys.length) {
6994 return this.keys[keyClock]
6995 } else {
6996 const key = this.stringDecoder.read();
6997 this.keys.push(key);
6998 return key
6999 }
7000 }
7001 }
7002
7003 class DSEncoderV1 {
7004 constructor () {
7005 this.restEncoder = createEncoder();
7006 }
7007
7008 toUint8Array () {
7009 return toUint8Array(this.restEncoder)
7010 }
7011
7012 resetDsCurVal () {
7013 // nop
7014 }
7015
7016 /**
7017 * @param {number} clock
7018 */
7019 writeDsClock (clock) {
7020 writeVarUint(this.restEncoder, clock);
7021 }
7022
7023 /**
7024 * @param {number} len
7025 */
7026 writeDsLen (len) {
7027 writeVarUint(this.restEncoder, len);
7028 }
7029 }
7030
7031 class UpdateEncoderV1 extends DSEncoderV1 {
7032 /**
7033 * @param {ID} id
7034 */
7035 writeLeftID (id) {
7036 writeVarUint(this.restEncoder, id.client);
7037 writeVarUint(this.restEncoder, id.clock);
7038 }
7039
7040 /**
7041 * @param {ID} id
7042 */
7043 writeRightID (id) {
7044 writeVarUint(this.restEncoder, id.client);
7045 writeVarUint(this.restEncoder, id.clock);
7046 }
7047
7048 /**
7049 * Use writeClient and writeClock instead of writeID if possible.
7050 * @param {number} client
7051 */
7052 writeClient (client) {
7053 writeVarUint(this.restEncoder, client);
7054 }
7055
7056 /**
7057 * @param {number} info An unsigned 8-bit integer
7058 */
7059 writeInfo (info) {
7060 writeUint8(this.restEncoder, info);
7061 }
7062
7063 /**
7064 * @param {string} s
7065 */
7066 writeString (s) {
7067 writeVarString(this.restEncoder, s);
7068 }
7069
7070 /**
7071 * @param {boolean} isYKey
7072 */
7073 writeParentInfo (isYKey) {
7074 writeVarUint(this.restEncoder, isYKey ? 1 : 0);
7075 }
7076
7077 /**
7078 * @param {number} info An unsigned 8-bit integer
7079 */
7080 writeTypeRef (info) {
7081 writeVarUint(this.restEncoder, info);
7082 }
7083
7084 /**
7085 * Write len of a struct - well suited for Opt RLE encoder.
7086 *
7087 * @param {number} len
7088 */
7089 writeLen (len) {
7090 writeVarUint(this.restEncoder, len);
7091 }
7092
7093 /**
7094 * @param {any} any
7095 */
7096 writeAny (any) {
7097 writeAny(this.restEncoder, any);
7098 }
7099
7100 /**
7101 * @param {Uint8Array} buf
7102 */
7103 writeBuf (buf) {
7104 writeVarUint8Array(this.restEncoder, buf);
7105 }
7106
7107 /**
7108 * @param {any} embed
7109 */
7110 writeJSON (embed) {
7111 writeVarString(this.restEncoder, JSON.stringify(embed));
7112 }
7113
7114 /**
7115 * @param {string} key
7116 */
7117 writeKey (key) {
7118 writeVarString(this.restEncoder, key);
7119 }
7120 }
7121
7122 class DSEncoderV2 {
7123 constructor () {
7124 this.restEncoder = createEncoder(); // encodes all the rest / non-optimized
7125 this.dsCurrVal = 0;
7126 }
7127
7128 toUint8Array () {
7129 return toUint8Array(this.restEncoder)
7130 }
7131
7132 resetDsCurVal () {
7133 this.dsCurrVal = 0;
7134 }
7135
7136 /**
7137 * @param {number} clock
7138 */
7139 writeDsClock (clock) {
7140 const diff = clock - this.dsCurrVal;
7141 this.dsCurrVal = clock;
7142 writeVarUint(this.restEncoder, diff);
7143 }
7144
7145 /**
7146 * @param {number} len
7147 */
7148 writeDsLen (len) {
7149 if (len === 0) {
7150 unexpectedCase();
7151 }
7152 writeVarUint(this.restEncoder, len - 1);
7153 this.dsCurrVal += len;
7154 }
7155 }
7156
7157 class UpdateEncoderV2 extends DSEncoderV2 {
7158 constructor () {
7159 super();
7160 /**
7161 * @type {Map<string,number>}
7162 */
7163 this.keyMap = new Map();
7164 /**
7165 * Refers to the next uniqe key-identifier to me used.
7166 * See writeKey method for more information.
7167 *
7168 * @type {number}
7169 */
7170 this.keyClock = 0;
7171 this.keyClockEncoder = new IntDiffOptRleEncoder();
7172 this.clientEncoder = new UintOptRleEncoder();
7173 this.leftClockEncoder = new IntDiffOptRleEncoder();
7174 this.rightClockEncoder = new IntDiffOptRleEncoder();
7175 this.infoEncoder = new RleEncoder(writeUint8);
7176 this.stringEncoder = new StringEncoder();
7177 this.parentInfoEncoder = new RleEncoder(writeUint8);
7178 this.typeRefEncoder = new UintOptRleEncoder();
7179 this.lenEncoder = new UintOptRleEncoder();
7180 }
7181
7182 toUint8Array () {
7183 const encoder = createEncoder();
7184 writeVarUint(encoder, 0); // this is a feature flag that we might use in the future
7185 writeVarUint8Array(encoder, this.keyClockEncoder.toUint8Array());
7186 writeVarUint8Array(encoder, this.clientEncoder.toUint8Array());
7187 writeVarUint8Array(encoder, this.leftClockEncoder.toUint8Array());
7188 writeVarUint8Array(encoder, this.rightClockEncoder.toUint8Array());
7189 writeVarUint8Array(encoder, toUint8Array(this.infoEncoder));
7190 writeVarUint8Array(encoder, this.stringEncoder.toUint8Array());
7191 writeVarUint8Array(encoder, toUint8Array(this.parentInfoEncoder));
7192 writeVarUint8Array(encoder, this.typeRefEncoder.toUint8Array());
7193 writeVarUint8Array(encoder, this.lenEncoder.toUint8Array());
7194 // @note The rest encoder is appended! (note the missing var)
7195 writeUint8Array(encoder, toUint8Array(this.restEncoder));
7196 return toUint8Array(encoder)
7197 }
7198
7199 /**
7200 * @param {ID} id
7201 */
7202 writeLeftID (id) {
7203 this.clientEncoder.write(id.client);
7204 this.leftClockEncoder.write(id.clock);
7205 }
7206
7207 /**
7208 * @param {ID} id
7209 */
7210 writeRightID (id) {
7211 this.clientEncoder.write(id.client);
7212 this.rightClockEncoder.write(id.clock);
7213 }
7214
7215 /**
7216 * @param {number} client
7217 */
7218 writeClient (client) {
7219 this.clientEncoder.write(client);
7220 }
7221
7222 /**
7223 * @param {number} info An unsigned 8-bit integer
7224 */
7225 writeInfo (info) {
7226 this.infoEncoder.write(info);
7227 }
7228
7229 /**
7230 * @param {string} s
7231 */
7232 writeString (s) {
7233 this.stringEncoder.write(s);
7234 }
7235
7236 /**
7237 * @param {boolean} isYKey
7238 */
7239 writeParentInfo (isYKey) {
7240 this.parentInfoEncoder.write(isYKey ? 1 : 0);
7241 }
7242
7243 /**
7244 * @param {number} info An unsigned 8-bit integer
7245 */
7246 writeTypeRef (info) {
7247 this.typeRefEncoder.write(info);
7248 }
7249
7250 /**
7251 * Write len of a struct - well suited for Opt RLE encoder.
7252 *
7253 * @param {number} len
7254 */
7255 writeLen (len) {
7256 this.lenEncoder.write(len);
7257 }
7258
7259 /**
7260 * @param {any} any
7261 */
7262 writeAny (any) {
7263 writeAny(this.restEncoder, any);
7264 }
7265
7266 /**
7267 * @param {Uint8Array} buf
7268 */
7269 writeBuf (buf) {
7270 writeVarUint8Array(this.restEncoder, buf);
7271 }
7272
7273 /**
7274 * This is mainly here for legacy purposes.
7275 *
7276 * 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.
7277 *
7278 * @param {any} embed
7279 */
7280 writeJSON (embed) {
7281 writeAny(this.restEncoder, embed);
7282 }
7283
7284 /**
7285 * Property keys are often reused. For example, in y-prosemirror the key `bold` might
7286 * occur very often. For a 3d application, the key `position` might occur very often.
7287 *
7288 * We cache these keys in a Map and refer to them via a unique number.
7289 *
7290 * @param {string} key
7291 */
7292 writeKey (key) {
7293 const clock = this.keyMap.get(key);
7294 if (clock === undefined) {
7295 /**
7296 * @todo uncomment to introduce this feature finally
7297 *
7298 * Background. The ContentFormat object was always encoded using writeKey, but the decoder used to use readString.
7299 * Furthermore, I forgot to set the keyclock. So everything was working fine.
7300 *
7301 * However, this feature here is basically useless as it is not being used (it actually only consumes extra memory).
7302 *
7303 * I don't know yet how to reintroduce this feature..
7304 *
7305 * Older clients won't be able to read updates when we reintroduce this feature. So this should probably be done using a flag.
7306 *
7307 */
7308 // this.keyMap.set(key, this.keyClock)
7309 this.keyClockEncoder.write(this.keyClock++);
7310 this.stringEncoder.write(key);
7311 } else {
7312 this.keyClockEncoder.write(clock);
7313 }
7314 }
7315 }
7316
7317 /**
7318 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7319 * @param {Array<GC|Item>} structs All structs by `client`
7320 * @param {number} client
7321 * @param {number} clock write structs starting with `ID(client,clock)`
7322 *
7323 * @function
7324 */
7325 const writeStructs = (encoder, structs, client, clock) => {
7326 // write first id
7327 clock = max(clock, structs[0].id.clock); // make sure the first id exists
7328 const startNewStructs = findIndexSS(structs, clock);
7329 // write # encoded structs
7330 writeVarUint(encoder.restEncoder, structs.length - startNewStructs);
7331 encoder.writeClient(client);
7332 writeVarUint(encoder.restEncoder, clock);
7333 const firstStruct = structs[startNewStructs];
7334 // write first struct with an offset
7335 firstStruct.write(encoder, clock - firstStruct.id.clock);
7336 for (let i = startNewStructs + 1; i < structs.length; i++) {
7337 structs[i].write(encoder, 0);
7338 }
7339 };
7340
7341 /**
7342 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7343 * @param {StructStore} store
7344 * @param {Map<number,number>} _sm
7345 *
7346 * @private
7347 * @function
7348 */
7349 const writeClientsStructs = (encoder, store, _sm) => {
7350 // we filter all valid _sm entries into sm
7351 const sm = new Map();
7352 _sm.forEach((clock, client) => {
7353 // only write if new structs are available
7354 if (getState(store, client) > clock) {
7355 sm.set(client, clock);
7356 }
7357 });
7358 getStateVector(store).forEach((_clock, client) => {
7359 if (!_sm.has(client)) {
7360 sm.set(client, 0);
7361 }
7362 });
7363 // write # states that were updated
7364 writeVarUint(encoder.restEncoder, sm.size);
7365 // Write items with higher client ids first
7366 // This heavily improves the conflict algorithm.
7367 array_from(sm.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
7368 writeStructs(encoder, /** @type {Array<GC|Item>} */ (store.clients.get(client)), client, clock);
7369 });
7370 };
7371
7372 /**
7373 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder The decoder object to read data from.
7374 * @param {Doc} doc
7375 * @return {Map<number, { i: number, refs: Array<Item | GC> }>}
7376 *
7377 * @private
7378 * @function
7379 */
7380 const readClientsStructRefs = (decoder, doc) => {
7381 /**
7382 * @type {Map<number, { i: number, refs: Array<Item | GC> }>}
7383 */
7384 const clientRefs = create();
7385 const numOfStateUpdates = readVarUint(decoder.restDecoder);
7386 for (let i = 0; i < numOfStateUpdates; i++) {
7387 const numberOfStructs = readVarUint(decoder.restDecoder);
7388 /**
7389 * @type {Array<GC|Item>}
7390 */
7391 const refs = new Array(numberOfStructs);
7392 const client = decoder.readClient();
7393 let clock = readVarUint(decoder.restDecoder);
7394 // const start = performance.now()
7395 clientRefs.set(client, { i: 0, refs });
7396 for (let i = 0; i < numberOfStructs; i++) {
7397 const info = decoder.readInfo();
7398 switch (BITS5 & info) {
7399 case 0: { // GC
7400 const len = decoder.readLen();
7401 refs[i] = new GC(createID(client, clock), len);
7402 clock += len;
7403 break
7404 }
7405 case 10: { // Skip Struct (nothing to apply)
7406 // @todo we could reduce the amount of checks by adding Skip struct to clientRefs so we know that something is missing.
7407 const len = readVarUint(decoder.restDecoder);
7408 refs[i] = new Skip(createID(client, clock), len);
7409 clock += len;
7410 break
7411 }
7412 default: { // Item with content
7413 /**
7414 * The optimized implementation doesn't use any variables because inlining variables is faster.
7415 * Below a non-optimized version is shown that implements the basic algorithm with
7416 * a few comments
7417 */
7418 const cantCopyParentInfo = (info & (BIT7 | BIT8)) === 0;
7419 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
7420 // and we read the next string as parentYKey.
7421 // It indicates how we store/retrieve parent from `y.share`
7422 // @type {string|null}
7423 const struct = new Item(
7424 createID(client, clock),
7425 null, // leftd
7426 (info & BIT8) === BIT8 ? decoder.readLeftID() : null, // origin
7427 null, // right
7428 (info & BIT7) === BIT7 ? decoder.readRightID() : null, // right origin
7429 cantCopyParentInfo ? (decoder.readParentInfo() ? doc.get(decoder.readString()) : decoder.readLeftID()) : null, // parent
7430 cantCopyParentInfo && (info & BIT6) === BIT6 ? decoder.readString() : null, // parentSub
7431 readItemContent(decoder, info) // item content
7432 );
7433 /* A non-optimized implementation of the above algorithm:
7434
7435 // The item that was originally to the left of this item.
7436 const origin = (info & binary.BIT8) === binary.BIT8 ? decoder.readLeftID() : null
7437 // The item that was originally to the right of this item.
7438 const rightOrigin = (info & binary.BIT7) === binary.BIT7 ? decoder.readRightID() : null
7439 const cantCopyParentInfo = (info & (binary.BIT7 | binary.BIT8)) === 0
7440 const hasParentYKey = cantCopyParentInfo ? decoder.readParentInfo() : false
7441 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
7442 // and we read the next string as parentYKey.
7443 // It indicates how we store/retrieve parent from `y.share`
7444 // @type {string|null}
7445 const parentYKey = cantCopyParentInfo && hasParentYKey ? decoder.readString() : null
7446
7447 const struct = new Item(
7448 createID(client, clock),
7449 null, // leftd
7450 origin, // origin
7451 null, // right
7452 rightOrigin, // right origin
7453 cantCopyParentInfo && !hasParentYKey ? decoder.readLeftID() : (parentYKey !== null ? doc.get(parentYKey) : null), // parent
7454 cantCopyParentInfo && (info & binary.BIT6) === binary.BIT6 ? decoder.readString() : null, // parentSub
7455 readItemContent(decoder, info) // item content
7456 )
7457 */
7458 refs[i] = struct;
7459 clock += struct.length;
7460 }
7461 }
7462 }
7463 // console.log('time to read: ', performance.now() - start) // @todo remove
7464 }
7465 return clientRefs
7466 };
7467
7468 /**
7469 * Resume computing structs generated by struct readers.
7470 *
7471 * While there is something to do, we integrate structs in this order
7472 * 1. top element on stack, if stack is not empty
7473 * 2. next element from current struct reader (if empty, use next struct reader)
7474 *
7475 * If struct causally depends on another struct (ref.missing), we put next reader of
7476 * `ref.id.client` on top of stack.
7477 *
7478 * At some point we find a struct that has no causal dependencies,
7479 * then we start emptying the stack.
7480 *
7481 * It is not possible to have circles: i.e. struct1 (from client1) depends on struct2 (from client2)
7482 * depends on struct3 (from client1). Therefore the max stack size is eqaul to `structReaders.length`.
7483 *
7484 * This method is implemented in a way so that we can resume computation if this update
7485 * causally depends on another update.
7486 *
7487 * @param {Transaction} transaction
7488 * @param {StructStore} store
7489 * @param {Map<number, { i: number, refs: (GC | Item)[] }>} clientsStructRefs
7490 * @return { null | { update: Uint8Array, missing: Map<number,number> } }
7491 *
7492 * @private
7493 * @function
7494 */
7495 const integrateStructs = (transaction, store, clientsStructRefs) => {
7496 /**
7497 * @type {Array<Item | GC>}
7498 */
7499 const stack = [];
7500 // 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.
7501 let clientsStructRefsIds = array_from(clientsStructRefs.keys()).sort((a, b) => a - b);
7502 if (clientsStructRefsIds.length === 0) {
7503 return null
7504 }
7505 const getNextStructTarget = () => {
7506 if (clientsStructRefsIds.length === 0) {
7507 return null
7508 }
7509 let nextStructsTarget = /** @type {{i:number,refs:Array<GC|Item>}} */ (clientsStructRefs.get(clientsStructRefsIds[clientsStructRefsIds.length - 1]));
7510 while (nextStructsTarget.refs.length === nextStructsTarget.i) {
7511 clientsStructRefsIds.pop();
7512 if (clientsStructRefsIds.length > 0) {
7513 nextStructsTarget = /** @type {{i:number,refs:Array<GC|Item>}} */ (clientsStructRefs.get(clientsStructRefsIds[clientsStructRefsIds.length - 1]));
7514 } else {
7515 return null
7516 }
7517 }
7518 return nextStructsTarget
7519 };
7520 let curStructsTarget = getNextStructTarget();
7521 if (curStructsTarget === null && stack.length === 0) {
7522 return null
7523 }
7524
7525 /**
7526 * @type {StructStore}
7527 */
7528 const restStructs = new StructStore();
7529 const missingSV = new Map();
7530 /**
7531 * @param {number} client
7532 * @param {number} clock
7533 */
7534 const updateMissingSv = (client, clock) => {
7535 const mclock = missingSV.get(client);
7536 if (mclock == null || mclock > clock) {
7537 missingSV.set(client, clock);
7538 }
7539 };
7540 /**
7541 * @type {GC|Item}
7542 */
7543 let stackHead = /** @type {any} */ (curStructsTarget).refs[/** @type {any} */ (curStructsTarget).i++];
7544 // caching the state because it is used very often
7545 const state = new Map();
7546
7547 const addStackToRestSS = () => {
7548 for (const item of stack) {
7549 const client = item.id.client;
7550 const unapplicableItems = clientsStructRefs.get(client);
7551 if (unapplicableItems) {
7552 // decrement because we weren't able to apply previous operation
7553 unapplicableItems.i--;
7554 restStructs.clients.set(client, unapplicableItems.refs.slice(unapplicableItems.i));
7555 clientsStructRefs.delete(client);
7556 unapplicableItems.i = 0;
7557 unapplicableItems.refs = [];
7558 } else {
7559 // item was the last item on clientsStructRefs and the field was already cleared. Add item to restStructs and continue
7560 restStructs.clients.set(client, [item]);
7561 }
7562 // remove client from clientsStructRefsIds to prevent users from applying the same update again
7563 clientsStructRefsIds = clientsStructRefsIds.filter(c => c !== client);
7564 }
7565 stack.length = 0;
7566 };
7567
7568 // iterate over all struct readers until we are done
7569 while (true) {
7570 if (stackHead.constructor !== Skip) {
7571 const localClock = setIfUndefined(state, stackHead.id.client, () => getState(store, stackHead.id.client));
7572 const offset = localClock - stackHead.id.clock;
7573 if (offset < 0) {
7574 // update from the same client is missing
7575 stack.push(stackHead);
7576 updateMissingSv(stackHead.id.client, stackHead.id.clock - 1);
7577 // hid a dead wall, add all items from stack to restSS
7578 addStackToRestSS();
7579 } else {
7580 const missing = stackHead.getMissing(transaction, store);
7581 if (missing !== null) {
7582 stack.push(stackHead);
7583 // get the struct reader that has the missing struct
7584 /**
7585 * @type {{ refs: Array<GC|Item>, i: number }}
7586 */
7587 const structRefs = clientsStructRefs.get(/** @type {number} */ (missing)) || { refs: [], i: 0 };
7588 if (structRefs.refs.length === structRefs.i) {
7589 // This update message causally depends on another update message that doesn't exist yet
7590 updateMissingSv(/** @type {number} */ (missing), getState(store, missing));
7591 addStackToRestSS();
7592 } else {
7593 stackHead = structRefs.refs[structRefs.i++];
7594 continue
7595 }
7596 } else if (offset === 0 || offset < stackHead.length) {
7597 // all fine, apply the stackhead
7598 stackHead.integrate(transaction, offset);
7599 state.set(stackHead.id.client, stackHead.id.clock + stackHead.length);
7600 }
7601 }
7602 }
7603 // iterate to next stackHead
7604 if (stack.length > 0) {
7605 stackHead = /** @type {GC|Item} */ (stack.pop());
7606 } else if (curStructsTarget !== null && curStructsTarget.i < curStructsTarget.refs.length) {
7607 stackHead = /** @type {GC|Item} */ (curStructsTarget.refs[curStructsTarget.i++]);
7608 } else {
7609 curStructsTarget = getNextStructTarget();
7610 if (curStructsTarget === null) {
7611 // we are done!
7612 break
7613 } else {
7614 stackHead = /** @type {GC|Item} */ (curStructsTarget.refs[curStructsTarget.i++]);
7615 }
7616 }
7617 }
7618 if (restStructs.clients.size > 0) {
7619 const encoder = new UpdateEncoderV2();
7620 writeClientsStructs(encoder, restStructs, new Map());
7621 // write empty deleteset
7622 // writeDeleteSet(encoder, new DeleteSet())
7623 writeVarUint(encoder.restEncoder, 0); // => no need for an extra function call, just write 0 deletes
7624 return { missing: missingSV, update: encoder.toUint8Array() }
7625 }
7626 return null
7627 };
7628
7629 /**
7630 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7631 * @param {Transaction} transaction
7632 *
7633 * @private
7634 * @function
7635 */
7636 const writeStructsFromTransaction = (encoder, transaction) => writeClientsStructs(encoder, transaction.doc.store, transaction.beforeState);
7637
7638 /**
7639 * Read and apply a document update.
7640 *
7641 * This function has the same effect as `applyUpdate` but accepts an decoder.
7642 *
7643 * @param {decoding.Decoder} decoder
7644 * @param {Doc} ydoc
7645 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7646 * @param {UpdateDecoderV1 | UpdateDecoderV2} [structDecoder]
7647 *
7648 * @function
7649 */
7650 const readUpdateV2 = (decoder, ydoc, transactionOrigin, structDecoder = new UpdateDecoderV2(decoder)) =>
7651 transact(ydoc, transaction => {
7652 // force that transaction.local is set to non-local
7653 transaction.local = false;
7654 let retry = false;
7655 const doc = transaction.doc;
7656 const store = doc.store;
7657 // let start = performance.now()
7658 const ss = readClientsStructRefs(structDecoder, doc);
7659 // console.log('time to read structs: ', performance.now() - start) // @todo remove
7660 // start = performance.now()
7661 // console.log('time to merge: ', performance.now() - start) // @todo remove
7662 // start = performance.now()
7663 const restStructs = integrateStructs(transaction, store, ss);
7664 const pending = store.pendingStructs;
7665 if (pending) {
7666 // check if we can apply something
7667 for (const [client, clock] of pending.missing) {
7668 if (clock < getState(store, client)) {
7669 retry = true;
7670 break
7671 }
7672 }
7673 if (restStructs) {
7674 // merge restStructs into store.pending
7675 for (const [client, clock] of restStructs.missing) {
7676 const mclock = pending.missing.get(client);
7677 if (mclock == null || mclock > clock) {
7678 pending.missing.set(client, clock);
7679 }
7680 }
7681 pending.update = mergeUpdatesV2([pending.update, restStructs.update]);
7682 }
7683 } else {
7684 store.pendingStructs = restStructs;
7685 }
7686 // console.log('time to integrate: ', performance.now() - start) // @todo remove
7687 // start = performance.now()
7688 const dsRest = readAndApplyDeleteSet(structDecoder, transaction, store);
7689 if (store.pendingDs) {
7690 // @todo we could make a lower-bound state-vector check as we do above
7691 const pendingDSUpdate = new UpdateDecoderV2(createDecoder(store.pendingDs));
7692 readVarUint(pendingDSUpdate.restDecoder); // read 0 structs, because we only encode deletes in pendingdsupdate
7693 const dsRest2 = readAndApplyDeleteSet(pendingDSUpdate, transaction, store);
7694 if (dsRest && dsRest2) {
7695 // case 1: ds1 != null && ds2 != null
7696 store.pendingDs = mergeUpdatesV2([dsRest, dsRest2]);
7697 } else {
7698 // case 2: ds1 != null
7699 // case 3: ds2 != null
7700 // case 4: ds1 == null && ds2 == null
7701 store.pendingDs = dsRest || dsRest2;
7702 }
7703 } else {
7704 // Either dsRest == null && pendingDs == null OR dsRest != null
7705 store.pendingDs = dsRest;
7706 }
7707 // console.log('time to cleanup: ', performance.now() - start) // @todo remove
7708 // start = performance.now()
7709
7710 // console.log('time to resume delete readers: ', performance.now() - start) // @todo remove
7711 // start = performance.now()
7712 if (retry) {
7713 const update = /** @type {{update: Uint8Array}} */ (store.pendingStructs).update;
7714 store.pendingStructs = null;
7715 applyUpdateV2(transaction.doc, update);
7716 }
7717 }, transactionOrigin, false);
7718
7719 /**
7720 * Read and apply a document update.
7721 *
7722 * This function has the same effect as `applyUpdate` but accepts an decoder.
7723 *
7724 * @param {decoding.Decoder} decoder
7725 * @param {Doc} ydoc
7726 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7727 *
7728 * @function
7729 */
7730 const readUpdate = (decoder, ydoc, transactionOrigin) => readUpdateV2(decoder, ydoc, transactionOrigin, new UpdateDecoderV1(decoder));
7731
7732 /**
7733 * Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`.
7734 *
7735 * This function has the same effect as `readUpdate` but accepts an Uint8Array instead of a Decoder.
7736 *
7737 * @param {Doc} ydoc
7738 * @param {Uint8Array} update
7739 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7740 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
7741 *
7742 * @function
7743 */
7744 const applyUpdateV2 = (ydoc, update, transactionOrigin, YDecoder = UpdateDecoderV2) => {
7745 const decoder = createDecoder(update);
7746 readUpdateV2(decoder, ydoc, transactionOrigin, new YDecoder(decoder));
7747 };
7748
7749 /**
7750 * Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`.
7751 *
7752 * This function has the same effect as `readUpdate` but accepts an Uint8Array instead of a Decoder.
7753 *
7754 * @param {Doc} ydoc
7755 * @param {Uint8Array} update
7756 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7757 *
7758 * @function
7759 */
7760 const applyUpdate = (ydoc, update, transactionOrigin) => applyUpdateV2(ydoc, update, transactionOrigin, UpdateDecoderV1);
7761
7762 /**
7763 * Write all the document as a single update message. If you specify the state of the remote client (`targetStateVector`) it will
7764 * only write the operations that are missing.
7765 *
7766 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7767 * @param {Doc} doc
7768 * @param {Map<number,number>} [targetStateVector] The state of the target that receives the update. Leave empty to write all known structs
7769 *
7770 * @function
7771 */
7772 const writeStateAsUpdate = (encoder, doc, targetStateVector = new Map()) => {
7773 writeClientsStructs(encoder, doc.store, targetStateVector);
7774 writeDeleteSet(encoder, createDeleteSetFromStructStore(doc.store));
7775 };
7776
7777 /**
7778 * 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
7779 * only write the operations that are missing.
7780 *
7781 * Use `writeStateAsUpdate` instead if you are working with lib0/encoding.js#Encoder
7782 *
7783 * @param {Doc} doc
7784 * @param {Uint8Array} [encodedTargetStateVector] The state of the target that receives the update. Leave empty to write all known structs
7785 * @param {UpdateEncoderV1 | UpdateEncoderV2} [encoder]
7786 * @return {Uint8Array}
7787 *
7788 * @function
7789 */
7790 const encodeStateAsUpdateV2 = (doc, encodedTargetStateVector = new Uint8Array([0]), encoder = new UpdateEncoderV2()) => {
7791 const targetStateVector = decodeStateVector(encodedTargetStateVector);
7792 writeStateAsUpdate(encoder, doc, targetStateVector);
7793 const updates = [encoder.toUint8Array()];
7794 // also add the pending updates (if there are any)
7795 if (doc.store.pendingDs) {
7796 updates.push(doc.store.pendingDs);
7797 }
7798 if (doc.store.pendingStructs) {
7799 updates.push(diffUpdateV2(doc.store.pendingStructs.update, encodedTargetStateVector));
7800 }
7801 if (updates.length > 1) {
7802 if (encoder.constructor === UpdateEncoderV1) {
7803 return mergeUpdates(updates.map((update, i) => i === 0 ? update : convertUpdateFormatV2ToV1(update)))
7804 } else if (encoder.constructor === UpdateEncoderV2) {
7805 return mergeUpdatesV2(updates)
7806 }
7807 }
7808 return updates[0]
7809 };
7810
7811 /**
7812 * 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
7813 * only write the operations that are missing.
7814 *
7815 * Use `writeStateAsUpdate` instead if you are working with lib0/encoding.js#Encoder
7816 *
7817 * @param {Doc} doc
7818 * @param {Uint8Array} [encodedTargetStateVector] The state of the target that receives the update. Leave empty to write all known structs
7819 * @return {Uint8Array}
7820 *
7821 * @function
7822 */
7823 const encodeStateAsUpdate = (doc, encodedTargetStateVector) => encodeStateAsUpdateV2(doc, encodedTargetStateVector, new UpdateEncoderV1());
7824
7825 /**
7826 * Read state vector from Decoder and return as Map
7827 *
7828 * @param {DSDecoderV1 | DSDecoderV2} decoder
7829 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client.
7830 *
7831 * @function
7832 */
7833 const readStateVector = decoder => {
7834 const ss = new Map();
7835 const ssLength = readVarUint(decoder.restDecoder);
7836 for (let i = 0; i < ssLength; i++) {
7837 const client = readVarUint(decoder.restDecoder);
7838 const clock = readVarUint(decoder.restDecoder);
7839 ss.set(client, clock);
7840 }
7841 return ss
7842 };
7843
7844 /**
7845 * Read decodedState and return State as Map.
7846 *
7847 * @param {Uint8Array} decodedState
7848 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client.
7849 *
7850 * @function
7851 */
7852 // export const decodeStateVectorV2 = decodedState => readStateVector(new DSDecoderV2(decoding.createDecoder(decodedState)))
7853
7854 /**
7855 * Read decodedState and return State as Map.
7856 *
7857 * @param {Uint8Array} decodedState
7858 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client.
7859 *
7860 * @function
7861 */
7862 const decodeStateVector = decodedState => readStateVector(new DSDecoderV1(createDecoder(decodedState)));
7863
7864 /**
7865 * @param {DSEncoderV1 | DSEncoderV2} encoder
7866 * @param {Map<number,number>} sv
7867 * @function
7868 */
7869 const writeStateVector = (encoder, sv) => {
7870 writeVarUint(encoder.restEncoder, sv.size);
7871 array_from(sv.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
7872 writeVarUint(encoder.restEncoder, client); // @todo use a special client decoder that is based on mapping
7873 writeVarUint(encoder.restEncoder, clock);
7874 });
7875 return encoder
7876 };
7877
7878 /**
7879 * @param {DSEncoderV1 | DSEncoderV2} encoder
7880 * @param {Doc} doc
7881 *
7882 * @function
7883 */
7884 const writeDocumentStateVector = (encoder, doc) => writeStateVector(encoder, getStateVector(doc.store));
7885
7886 /**
7887 * Encode State as Uint8Array.
7888 *
7889 * @param {Doc|Map<number,number>} doc
7890 * @param {DSEncoderV1 | DSEncoderV2} [encoder]
7891 * @return {Uint8Array}
7892 *
7893 * @function
7894 */
7895 const encodeStateVectorV2 = (doc, encoder = new DSEncoderV2()) => {
7896 if (doc instanceof Map) {
7897 writeStateVector(encoder, doc);
7898 } else {
7899 writeDocumentStateVector(encoder, doc);
7900 }
7901 return encoder.toUint8Array()
7902 };
7903
7904 /**
7905 * Encode State as Uint8Array.
7906 *
7907 * @param {Doc|Map<number,number>} doc
7908 * @return {Uint8Array}
7909 *
7910 * @function
7911 */
7912 const encodeStateVector = doc => encodeStateVectorV2(doc, new DSEncoderV1());
7913
7914 /**
7915 * General event handler implementation.
7916 *
7917 * @template ARG0, ARG1
7918 *
7919 * @private
7920 */
7921 class EventHandler {
7922 constructor () {
7923 /**
7924 * @type {Array<function(ARG0, ARG1):void>}
7925 */
7926 this.l = [];
7927 }
7928 }
7929
7930 /**
7931 * @template ARG0,ARG1
7932 * @returns {EventHandler<ARG0,ARG1>}
7933 *
7934 * @private
7935 * @function
7936 */
7937 const createEventHandler = () => new EventHandler();
7938
7939 /**
7940 * Adds an event listener that is called when
7941 * {@link EventHandler#callEventListeners} is called.
7942 *
7943 * @template ARG0,ARG1
7944 * @param {EventHandler<ARG0,ARG1>} eventHandler
7945 * @param {function(ARG0,ARG1):void} f The event handler.
7946 *
7947 * @private
7948 * @function
7949 */
7950 const addEventHandlerListener = (eventHandler, f) =>
7951 eventHandler.l.push(f);
7952
7953 /**
7954 * Removes an event listener.
7955 *
7956 * @template ARG0,ARG1
7957 * @param {EventHandler<ARG0,ARG1>} eventHandler
7958 * @param {function(ARG0,ARG1):void} f The event handler that was added with
7959 * {@link EventHandler#addEventListener}
7960 *
7961 * @private
7962 * @function
7963 */
7964 const removeEventHandlerListener = (eventHandler, f) => {
7965 const l = eventHandler.l;
7966 const len = l.length;
7967 eventHandler.l = l.filter(g => f !== g);
7968 if (len === eventHandler.l.length) {
7969 console.error('[yjs] Tried to remove event handler that doesn\'t exist.');
7970 }
7971 };
7972
7973 /**
7974 * Call all event listeners that were added via
7975 * {@link EventHandler#addEventListener}.
7976 *
7977 * @template ARG0,ARG1
7978 * @param {EventHandler<ARG0,ARG1>} eventHandler
7979 * @param {ARG0} arg0
7980 * @param {ARG1} arg1
7981 *
7982 * @private
7983 * @function
7984 */
7985 const callEventHandlerListeners = (eventHandler, arg0, arg1) =>
7986 callAll(eventHandler.l, [arg0, arg1]);
7987
7988 class ID {
7989 /**
7990 * @param {number} client client id
7991 * @param {number} clock unique per client id, continuous number
7992 */
7993 constructor (client, clock) {
7994 /**
7995 * Client id
7996 * @type {number}
7997 */
7998 this.client = client;
7999 /**
8000 * unique per client id, continuous number
8001 * @type {number}
8002 */
8003 this.clock = clock;
8004 }
8005 }
8006
8007 /**
8008 * @param {ID | null} a
8009 * @param {ID | null} b
8010 * @return {boolean}
8011 *
8012 * @function
8013 */
8014 const compareIDs = (a, b) => a === b || (a !== null && b !== null && a.client === b.client && a.clock === b.clock);
8015
8016 /**
8017 * @param {number} client
8018 * @param {number} clock
8019 *
8020 * @private
8021 * @function
8022 */
8023 const createID = (client, clock) => new ID(client, clock);
8024
8025 /**
8026 * @param {encoding.Encoder} encoder
8027 * @param {ID} id
8028 *
8029 * @private
8030 * @function
8031 */
8032 const writeID = (encoder, id) => {
8033 encoding.writeVarUint(encoder, id.client);
8034 encoding.writeVarUint(encoder, id.clock);
8035 };
8036
8037 /**
8038 * Read ID.
8039 * * If first varUint read is 0xFFFFFF a RootID is returned.
8040 * * Otherwise an ID is returned
8041 *
8042 * @param {decoding.Decoder} decoder
8043 * @return {ID}
8044 *
8045 * @private
8046 * @function
8047 */
8048 const readID = decoder =>
8049 createID(decoding.readVarUint(decoder), decoding.readVarUint(decoder));
8050
8051 /**
8052 * The top types are mapped from y.share.get(keyname) => type.
8053 * `type` does not store any information about the `keyname`.
8054 * This function finds the correct `keyname` for `type` and throws otherwise.
8055 *
8056 * @param {AbstractType<any>} type
8057 * @return {string}
8058 *
8059 * @private
8060 * @function
8061 */
8062 const findRootTypeKey = type => {
8063 // @ts-ignore _y must be defined, otherwise unexpected case
8064 for (const [key, value] of type.doc.share.entries()) {
8065 if (value === type) {
8066 return key
8067 }
8068 }
8069 throw unexpectedCase()
8070 };
8071
8072 /**
8073 * Check if `parent` is a parent of `child`.
8074 *
8075 * @param {AbstractType<any>} parent
8076 * @param {Item|null} child
8077 * @return {Boolean} Whether `parent` is a parent of `child`.
8078 *
8079 * @private
8080 * @function
8081 */
8082 const yjs_isParentOf = (parent, child) => {
8083 while (child !== null) {
8084 if (child.parent === parent) {
8085 return true
8086 }
8087 child = /** @type {AbstractType<any>} */ (child.parent)._item;
8088 }
8089 return false
8090 };
8091
8092 /**
8093 * Convenient helper to log type information.
8094 *
8095 * Do not use in productive systems as the output can be immense!
8096 *
8097 * @param {AbstractType<any>} type
8098 */
8099 const logType = type => {
8100 const res = [];
8101 let n = type._start;
8102 while (n) {
8103 res.push(n);
8104 n = n.right;
8105 }
8106 console.log('Children: ', res);
8107 console.log('Children content: ', res.filter(m => !m.deleted).map(m => m.content));
8108 };
8109
8110 class PermanentUserData {
8111 /**
8112 * @param {Doc} doc
8113 * @param {YMap<any>} [storeType]
8114 */
8115 constructor (doc, storeType = doc.getMap('users')) {
8116 /**
8117 * @type {Map<string,DeleteSet>}
8118 */
8119 const dss = new Map();
8120 this.yusers = storeType;
8121 this.doc = doc;
8122 /**
8123 * Maps from clientid to userDescription
8124 *
8125 * @type {Map<number,string>}
8126 */
8127 this.clients = new Map();
8128 this.dss = dss;
8129 /**
8130 * @param {YMap<any>} user
8131 * @param {string} userDescription
8132 */
8133 const initUser = (user, userDescription) => {
8134 /**
8135 * @type {YArray<Uint8Array>}
8136 */
8137 const ds = user.get('ds');
8138 const ids = user.get('ids');
8139 const addClientId = /** @param {number} clientid */ clientid => this.clients.set(clientid, userDescription);
8140 ds.observe(/** @param {YArrayEvent<any>} event */ event => {
8141 event.changes.added.forEach(item => {
8142 item.content.getContent().forEach(encodedDs => {
8143 if (encodedDs instanceof Uint8Array) {
8144 this.dss.set(userDescription, mergeDeleteSets([this.dss.get(userDescription) || createDeleteSet(), readDeleteSet(new DSDecoderV1(decoding.createDecoder(encodedDs)))]));
8145 }
8146 });
8147 });
8148 });
8149 this.dss.set(userDescription, mergeDeleteSets(ds.map(encodedDs => readDeleteSet(new DSDecoderV1(decoding.createDecoder(encodedDs))))));
8150 ids.observe(/** @param {YArrayEvent<any>} event */ event =>
8151 event.changes.added.forEach(item => item.content.getContent().forEach(addClientId))
8152 );
8153 ids.forEach(addClientId);
8154 };
8155 // observe users
8156 storeType.observe(event => {
8157 event.keysChanged.forEach(userDescription =>
8158 initUser(storeType.get(userDescription), userDescription)
8159 );
8160 });
8161 // add intial data
8162 storeType.forEach(initUser);
8163 }
8164
8165 /**
8166 * @param {Doc} doc
8167 * @param {number} clientid
8168 * @param {string} userDescription
8169 * @param {Object} conf
8170 * @param {function(Transaction, DeleteSet):boolean} [conf.filter]
8171 */
8172 setUserMapping (doc, clientid, userDescription, { filter = () => true } = {}) {
8173 const users = this.yusers;
8174 let user = users.get(userDescription);
8175 if (!user) {
8176 user = new YMap();
8177 user.set('ids', new YArray());
8178 user.set('ds', new YArray());
8179 users.set(userDescription, user);
8180 }
8181 user.get('ids').push([clientid]);
8182 users.observe(_event => {
8183 setTimeout(() => {
8184 const userOverwrite = users.get(userDescription);
8185 if (userOverwrite !== user) {
8186 // user was overwritten, port all data over to the next user object
8187 // @todo Experiment with Y.Sets here
8188 user = userOverwrite;
8189 // @todo iterate over old type
8190 this.clients.forEach((_userDescription, clientid) => {
8191 if (userDescription === _userDescription) {
8192 user.get('ids').push([clientid]);
8193 }
8194 });
8195 const encoder = new DSEncoderV1();
8196 const ds = this.dss.get(userDescription);
8197 if (ds) {
8198 writeDeleteSet(encoder, ds);
8199 user.get('ds').push([encoder.toUint8Array()]);
8200 }
8201 }
8202 }, 0);
8203 });
8204 doc.on('afterTransaction', /** @param {Transaction} transaction */ transaction => {
8205 setTimeout(() => {
8206 const yds = user.get('ds');
8207 const ds = transaction.deleteSet;
8208 if (transaction.local && ds.clients.size > 0 && filter(transaction, ds)) {
8209 const encoder = new DSEncoderV1();
8210 writeDeleteSet(encoder, ds);
8211 yds.push([encoder.toUint8Array()]);
8212 }
8213 });
8214 });
8215 }
8216
8217 /**
8218 * @param {number} clientid
8219 * @return {any}
8220 */
8221 getUserByClientId (clientid) {
8222 return this.clients.get(clientid) || null
8223 }
8224
8225 /**
8226 * @param {ID} id
8227 * @return {string | null}
8228 */
8229 getUserByDeletedId (id) {
8230 for (const [userDescription, ds] of this.dss.entries()) {
8231 if (isDeleted(ds, id)) {
8232 return userDescription
8233 }
8234 }
8235 return null
8236 }
8237 }
8238
8239 /**
8240 * A relative position is based on the Yjs model and is not affected by document changes.
8241 * E.g. If you place a relative position before a certain character, it will always point to this character.
8242 * If you place a relative position at the end of a type, it will always point to the end of the type.
8243 *
8244 * A numeric position is often unsuited for user selections, because it does not change when content is inserted
8245 * before or after.
8246 *
8247 * ```Insert(0, 'x')('a|bc') = 'xa|bc'``` Where | is the relative position.
8248 *
8249 * One of the properties must be defined.
8250 *
8251 * @example
8252 * // Current cursor position is at position 10
8253 * const relativePosition = createRelativePositionFromIndex(yText, 10)
8254 * // modify yText
8255 * yText.insert(0, 'abc')
8256 * yText.delete(3, 10)
8257 * // Compute the cursor position
8258 * const absolutePosition = createAbsolutePositionFromRelativePosition(y, relativePosition)
8259 * absolutePosition.type === yText // => true
8260 * console.log('cursor location is ' + absolutePosition.index) // => cursor location is 3
8261 *
8262 */
8263 class RelativePosition {
8264 /**
8265 * @param {ID|null} type
8266 * @param {string|null} tname
8267 * @param {ID|null} item
8268 * @param {number} assoc
8269 */
8270 constructor (type, tname, item, assoc = 0) {
8271 /**
8272 * @type {ID|null}
8273 */
8274 this.type = type;
8275 /**
8276 * @type {string|null}
8277 */
8278 this.tname = tname;
8279 /**
8280 * @type {ID | null}
8281 */
8282 this.item = item;
8283 /**
8284 * A relative position is associated to a specific character. By default
8285 * assoc >= 0, the relative position is associated to the character
8286 * after the meant position.
8287 * I.e. position 1 in 'ab' is associated to character 'b'.
8288 *
8289 * If assoc < 0, then the relative position is associated to the caharacter
8290 * before the meant position.
8291 *
8292 * @type {number}
8293 */
8294 this.assoc = assoc;
8295 }
8296 }
8297
8298 /**
8299 * @param {RelativePosition} rpos
8300 * @return {any}
8301 */
8302 const relativePositionToJSON = rpos => {
8303 const json = {};
8304 if (rpos.type) {
8305 json.type = rpos.type;
8306 }
8307 if (rpos.tname) {
8308 json.tname = rpos.tname;
8309 }
8310 if (rpos.item) {
8311 json.item = rpos.item;
8312 }
8313 if (rpos.assoc != null) {
8314 json.assoc = rpos.assoc;
8315 }
8316 return json
8317 };
8318
8319 /**
8320 * @param {any} json
8321 * @return {RelativePosition}
8322 *
8323 * @function
8324 */
8325 const 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);
8326
8327 class AbsolutePosition {
8328 /**
8329 * @param {AbstractType<any>} type
8330 * @param {number} index
8331 * @param {number} [assoc]
8332 */
8333 constructor (type, index, assoc = 0) {
8334 /**
8335 * @type {AbstractType<any>}
8336 */
8337 this.type = type;
8338 /**
8339 * @type {number}
8340 */
8341 this.index = index;
8342 this.assoc = assoc;
8343 }
8344 }
8345
8346 /**
8347 * @param {AbstractType<any>} type
8348 * @param {number} index
8349 * @param {number} [assoc]
8350 *
8351 * @function
8352 */
8353 const createAbsolutePosition = (type, index, assoc = 0) => new AbsolutePosition(type, index, assoc);
8354
8355 /**
8356 * @param {AbstractType<any>} type
8357 * @param {ID|null} item
8358 * @param {number} [assoc]
8359 *
8360 * @function
8361 */
8362 const createRelativePosition = (type, item, assoc) => {
8363 let typeid = null;
8364 let tname = null;
8365 if (type._item === null) {
8366 tname = findRootTypeKey(type);
8367 } else {
8368 typeid = createID(type._item.id.client, type._item.id.clock);
8369 }
8370 return new RelativePosition(typeid, tname, item, assoc)
8371 };
8372
8373 /**
8374 * Create a relativePosition based on a absolute position.
8375 *
8376 * @param {AbstractType<any>} type The base type (e.g. YText or YArray).
8377 * @param {number} index The absolute position.
8378 * @param {number} [assoc]
8379 * @return {RelativePosition}
8380 *
8381 * @function
8382 */
8383 const createRelativePositionFromTypeIndex = (type, index, assoc = 0) => {
8384 let t = type._start;
8385 if (assoc < 0) {
8386 // associated to the left character or the beginning of a type, increment index if possible.
8387 if (index === 0) {
8388 return createRelativePosition(type, null, assoc)
8389 }
8390 index--;
8391 }
8392 while (t !== null) {
8393 if (!t.deleted && t.countable) {
8394 if (t.length > index) {
8395 // case 1: found position somewhere in the linked list
8396 return createRelativePosition(type, createID(t.id.client, t.id.clock + index), assoc)
8397 }
8398 index -= t.length;
8399 }
8400 if (t.right === null && assoc < 0) {
8401 // left-associated position, return last available id
8402 return createRelativePosition(type, t.lastId, assoc)
8403 }
8404 t = t.right;
8405 }
8406 return createRelativePosition(type, null, assoc)
8407 };
8408
8409 /**
8410 * @param {encoding.Encoder} encoder
8411 * @param {RelativePosition} rpos
8412 *
8413 * @function
8414 */
8415 const writeRelativePosition = (encoder, rpos) => {
8416 const { type, tname, item, assoc } = rpos;
8417 if (item !== null) {
8418 encoding.writeVarUint(encoder, 0);
8419 writeID(encoder, item);
8420 } else if (tname !== null) {
8421 // case 2: found position at the end of the list and type is stored in y.share
8422 encoding.writeUint8(encoder, 1);
8423 encoding.writeVarString(encoder, tname);
8424 } else if (type !== null) {
8425 // case 3: found position at the end of the list and type is attached to an item
8426 encoding.writeUint8(encoder, 2);
8427 writeID(encoder, type);
8428 } else {
8429 throw error.unexpectedCase()
8430 }
8431 encoding.writeVarInt(encoder, assoc);
8432 return encoder
8433 };
8434
8435 /**
8436 * @param {RelativePosition} rpos
8437 * @return {Uint8Array}
8438 */
8439 const encodeRelativePosition = rpos => {
8440 const encoder = encoding.createEncoder();
8441 writeRelativePosition(encoder, rpos);
8442 return encoding.toUint8Array(encoder)
8443 };
8444
8445 /**
8446 * @param {decoding.Decoder} decoder
8447 * @return {RelativePosition}
8448 *
8449 * @function
8450 */
8451 const readRelativePosition = decoder => {
8452 let type = null;
8453 let tname = null;
8454 let itemID = null;
8455 switch (decoding.readVarUint(decoder)) {
8456 case 0:
8457 // case 1: found position somewhere in the linked list
8458 itemID = readID(decoder);
8459 break
8460 case 1:
8461 // case 2: found position at the end of the list and type is stored in y.share
8462 tname = decoding.readVarString(decoder);
8463 break
8464 case 2: {
8465 // case 3: found position at the end of the list and type is attached to an item
8466 type = readID(decoder);
8467 }
8468 }
8469 const assoc = decoding.hasContent(decoder) ? decoding.readVarInt(decoder) : 0;
8470 return new RelativePosition(type, tname, itemID, assoc)
8471 };
8472
8473 /**
8474 * @param {Uint8Array} uint8Array
8475 * @return {RelativePosition}
8476 */
8477 const decodeRelativePosition = uint8Array => readRelativePosition(decoding.createDecoder(uint8Array));
8478
8479 /**
8480 * @param {RelativePosition} rpos
8481 * @param {Doc} doc
8482 * @return {AbsolutePosition|null}
8483 *
8484 * @function
8485 */
8486 const createAbsolutePositionFromRelativePosition = (rpos, doc) => {
8487 const store = doc.store;
8488 const rightID = rpos.item;
8489 const typeID = rpos.type;
8490 const tname = rpos.tname;
8491 const assoc = rpos.assoc;
8492 let type = null;
8493 let index = 0;
8494 if (rightID !== null) {
8495 if (getState(store, rightID.client) <= rightID.clock) {
8496 return null
8497 }
8498 const res = followRedone(store, rightID);
8499 const right = res.item;
8500 if (!(right instanceof Item)) {
8501 return null
8502 }
8503 type = /** @type {AbstractType<any>} */ (right.parent);
8504 if (type._item === null || !type._item.deleted) {
8505 index = (right.deleted || !right.countable) ? 0 : (res.diff + (assoc >= 0 ? 0 : 1)); // adjust position based on left association if necessary
8506 let n = right.left;
8507 while (n !== null) {
8508 if (!n.deleted && n.countable) {
8509 index += n.length;
8510 }
8511 n = n.left;
8512 }
8513 }
8514 } else {
8515 if (tname !== null) {
8516 type = doc.get(tname);
8517 } else if (typeID !== null) {
8518 if (getState(store, typeID.client) <= typeID.clock) {
8519 // type does not exist yet
8520 return null
8521 }
8522 const { item } = followRedone(store, typeID);
8523 if (item instanceof Item && item.content instanceof ContentType) {
8524 type = item.content.type;
8525 } else {
8526 // struct is garbage collected
8527 return null
8528 }
8529 } else {
8530 throw error.unexpectedCase()
8531 }
8532 if (assoc >= 0) {
8533 index = type._length;
8534 } else {
8535 index = 0;
8536 }
8537 }
8538 return createAbsolutePosition(type, index, rpos.assoc)
8539 };
8540
8541 /**
8542 * @param {RelativePosition|null} a
8543 * @param {RelativePosition|null} b
8544 * @return {boolean}
8545 *
8546 * @function
8547 */
8548 const compareRelativePositions = (a, b) => a === b || (
8549 a !== null && b !== null && a.tname === b.tname && compareIDs(a.item, b.item) && compareIDs(a.type, b.type) && a.assoc === b.assoc
8550 );
8551
8552 class Snapshot {
8553 /**
8554 * @param {DeleteSet} ds
8555 * @param {Map<number,number>} sv state map
8556 */
8557 constructor (ds, sv) {
8558 /**
8559 * @type {DeleteSet}
8560 */
8561 this.ds = ds;
8562 /**
8563 * State Map
8564 * @type {Map<number,number>}
8565 */
8566 this.sv = sv;
8567 }
8568 }
8569
8570 /**
8571 * @param {Snapshot} snap1
8572 * @param {Snapshot} snap2
8573 * @return {boolean}
8574 */
8575 const equalSnapshots = (snap1, snap2) => {
8576 const ds1 = snap1.ds.clients;
8577 const ds2 = snap2.ds.clients;
8578 const sv1 = snap1.sv;
8579 const sv2 = snap2.sv;
8580 if (sv1.size !== sv2.size || ds1.size !== ds2.size) {
8581 return false
8582 }
8583 for (const [key, value] of sv1.entries()) {
8584 if (sv2.get(key) !== value) {
8585 return false
8586 }
8587 }
8588 for (const [client, dsitems1] of ds1.entries()) {
8589 const dsitems2 = ds2.get(client) || [];
8590 if (dsitems1.length !== dsitems2.length) {
8591 return false
8592 }
8593 for (let i = 0; i < dsitems1.length; i++) {
8594 const dsitem1 = dsitems1[i];
8595 const dsitem2 = dsitems2[i];
8596 if (dsitem1.clock !== dsitem2.clock || dsitem1.len !== dsitem2.len) {
8597 return false
8598 }
8599 }
8600 }
8601 return true
8602 };
8603
8604 /**
8605 * @param {Snapshot} snapshot
8606 * @param {DSEncoderV1 | DSEncoderV2} [encoder]
8607 * @return {Uint8Array}
8608 */
8609 const encodeSnapshotV2 = (snapshot, encoder = new DSEncoderV2()) => {
8610 writeDeleteSet(encoder, snapshot.ds);
8611 writeStateVector(encoder, snapshot.sv);
8612 return encoder.toUint8Array()
8613 };
8614
8615 /**
8616 * @param {Snapshot} snapshot
8617 * @return {Uint8Array}
8618 */
8619 const encodeSnapshot = snapshot => encodeSnapshotV2(snapshot, new DSEncoderV1());
8620
8621 /**
8622 * @param {Uint8Array} buf
8623 * @param {DSDecoderV1 | DSDecoderV2} [decoder]
8624 * @return {Snapshot}
8625 */
8626 const decodeSnapshotV2 = (buf, decoder = new DSDecoderV2(decoding.createDecoder(buf))) => {
8627 return new Snapshot(readDeleteSet(decoder), readStateVector(decoder))
8628 };
8629
8630 /**
8631 * @param {Uint8Array} buf
8632 * @return {Snapshot}
8633 */
8634 const decodeSnapshot = buf => decodeSnapshotV2(buf, new DSDecoderV1(decoding.createDecoder(buf)));
8635
8636 /**
8637 * @param {DeleteSet} ds
8638 * @param {Map<number,number>} sm
8639 * @return {Snapshot}
8640 */
8641 const createSnapshot = (ds, sm) => new Snapshot(ds, sm);
8642
8643 const emptySnapshot = createSnapshot(createDeleteSet(), new Map());
8644
8645 /**
8646 * @param {Doc} doc
8647 * @return {Snapshot}
8648 */
8649 const snapshot = doc => createSnapshot(createDeleteSetFromStructStore(doc.store), getStateVector(doc.store));
8650
8651 /**
8652 * @param {Item} item
8653 * @param {Snapshot|undefined} snapshot
8654 *
8655 * @protected
8656 * @function
8657 */
8658 const isVisible = (item, snapshot) => snapshot === undefined
8659 ? !item.deleted
8660 : snapshot.sv.has(item.id.client) && (snapshot.sv.get(item.id.client) || 0) > item.id.clock && !isDeleted(snapshot.ds, item.id);
8661
8662 /**
8663 * @param {Transaction} transaction
8664 * @param {Snapshot} snapshot
8665 */
8666 const splitSnapshotAffectedStructs = (transaction, snapshot) => {
8667 const meta = setIfUndefined(transaction.meta, splitSnapshotAffectedStructs, set_create);
8668 const store = transaction.doc.store;
8669 // check if we already split for this snapshot
8670 if (!meta.has(snapshot)) {
8671 snapshot.sv.forEach((clock, client) => {
8672 if (clock < getState(store, client)) {
8673 getItemCleanStart(transaction, createID(client, clock));
8674 }
8675 });
8676 iterateDeletedStructs(transaction, snapshot.ds, _item => {});
8677 meta.add(snapshot);
8678 }
8679 };
8680
8681 /**
8682 * @example
8683 * const ydoc = new Y.Doc({ gc: false })
8684 * ydoc.getText().insert(0, 'world!')
8685 * const snapshot = Y.snapshot(ydoc)
8686 * ydoc.getText().insert(0, 'hello ')
8687 * const restored = Y.createDocFromSnapshot(ydoc, snapshot)
8688 * assert(restored.getText().toString() === 'world!')
8689 *
8690 * @param {Doc} originDoc
8691 * @param {Snapshot} snapshot
8692 * @param {Doc} [newDoc] Optionally, you may define the Yjs document that receives the data from originDoc
8693 * @return {Doc}
8694 */
8695 const createDocFromSnapshot = (originDoc, snapshot, newDoc = new Doc()) => {
8696 if (originDoc.gc) {
8697 // we should not try to restore a GC-ed document, because some of the restored items might have their content deleted
8698 throw new Error('Garbage-collection must be disabled in `originDoc`!')
8699 }
8700 const { sv, ds } = snapshot;
8701
8702 const encoder = new UpdateEncoderV2();
8703 originDoc.transact(transaction => {
8704 let size = 0;
8705 sv.forEach(clock => {
8706 if (clock > 0) {
8707 size++;
8708 }
8709 });
8710 encoding.writeVarUint(encoder.restEncoder, size);
8711 // splitting the structs before writing them to the encoder
8712 for (const [client, clock] of sv) {
8713 if (clock === 0) {
8714 continue
8715 }
8716 if (clock < getState(originDoc.store, client)) {
8717 getItemCleanStart(transaction, createID(client, clock));
8718 }
8719 const structs = originDoc.store.clients.get(client) || [];
8720 const lastStructIndex = findIndexSS(structs, clock - 1);
8721 // write # encoded structs
8722 encoding.writeVarUint(encoder.restEncoder, lastStructIndex + 1);
8723 encoder.writeClient(client);
8724 // first clock written is 0
8725 encoding.writeVarUint(encoder.restEncoder, 0);
8726 for (let i = 0; i <= lastStructIndex; i++) {
8727 structs[i].write(encoder, 0);
8728 }
8729 }
8730 writeDeleteSet(encoder, ds);
8731 });
8732
8733 applyUpdateV2(newDoc, encoder.toUint8Array(), 'snapshot');
8734 return newDoc
8735 };
8736
8737 /**
8738 * @param {Snapshot} snapshot
8739 * @param {Uint8Array} update
8740 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
8741 */
8742 const snapshotContainsUpdateV2 = (snapshot, update, YDecoder = UpdateDecoderV2) => {
8743 const updateDecoder = new YDecoder(decoding.createDecoder(update));
8744 const lazyDecoder = new LazyStructReader(updateDecoder, false);
8745 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
8746 if ((snapshot.sv.get(curr.id.client) || 0) < curr.id.clock + curr.length) {
8747 return false
8748 }
8749 }
8750 const mergedDS = mergeDeleteSets([snapshot.ds, readDeleteSet(updateDecoder)]);
8751 return equalDeleteSets(snapshot.ds, mergedDS)
8752 };
8753
8754 /**
8755 * @param {Snapshot} snapshot
8756 * @param {Uint8Array} update
8757 */
8758 const snapshotContainsUpdate = (snapshot, update) => snapshotContainsUpdateV2(snapshot, update, UpdateDecoderV1);
8759
8760 class StructStore {
8761 constructor () {
8762 /**
8763 * @type {Map<number,Array<GC|Item>>}
8764 */
8765 this.clients = new Map();
8766 /**
8767 * @type {null | { missing: Map<number, number>, update: Uint8Array }}
8768 */
8769 this.pendingStructs = null;
8770 /**
8771 * @type {null | Uint8Array}
8772 */
8773 this.pendingDs = null;
8774 }
8775 }
8776
8777 /**
8778 * Return the states as a Map<client,clock>.
8779 * Note that clock refers to the next expected clock id.
8780 *
8781 * @param {StructStore} store
8782 * @return {Map<number,number>}
8783 *
8784 * @public
8785 * @function
8786 */
8787 const getStateVector = store => {
8788 const sm = new Map();
8789 store.clients.forEach((structs, client) => {
8790 const struct = structs[structs.length - 1];
8791 sm.set(client, struct.id.clock + struct.length);
8792 });
8793 return sm
8794 };
8795
8796 /**
8797 * @param {StructStore} store
8798 * @param {number} client
8799 * @return {number}
8800 *
8801 * @public
8802 * @function
8803 */
8804 const getState = (store, client) => {
8805 const structs = store.clients.get(client);
8806 if (structs === undefined) {
8807 return 0
8808 }
8809 const lastStruct = structs[structs.length - 1];
8810 return lastStruct.id.clock + lastStruct.length
8811 };
8812
8813 /**
8814 * @param {StructStore} store
8815 * @param {GC|Item} struct
8816 *
8817 * @private
8818 * @function
8819 */
8820 const addStruct = (store, struct) => {
8821 let structs = store.clients.get(struct.id.client);
8822 if (structs === undefined) {
8823 structs = [];
8824 store.clients.set(struct.id.client, structs);
8825 } else {
8826 const lastStruct = structs[structs.length - 1];
8827 if (lastStruct.id.clock + lastStruct.length !== struct.id.clock) {
8828 throw unexpectedCase()
8829 }
8830 }
8831 structs.push(struct);
8832 };
8833
8834 /**
8835 * Perform a binary search on a sorted array
8836 * @param {Array<Item|GC>} structs
8837 * @param {number} clock
8838 * @return {number}
8839 *
8840 * @private
8841 * @function
8842 */
8843 const findIndexSS = (structs, clock) => {
8844 let left = 0;
8845 let right = structs.length - 1;
8846 let mid = structs[right];
8847 let midclock = mid.id.clock;
8848 if (midclock === clock) {
8849 return right
8850 }
8851 // @todo does it even make sense to pivot the search?
8852 // If a good split misses, it might actually increase the time to find the correct item.
8853 // Currently, the only advantage is that search with pivoting might find the item on the first try.
8854 let midindex = floor((clock / (midclock + mid.length - 1)) * right); // pivoting the search
8855 while (left <= right) {
8856 mid = structs[midindex];
8857 midclock = mid.id.clock;
8858 if (midclock <= clock) {
8859 if (clock < midclock + mid.length) {
8860 return midindex
8861 }
8862 left = midindex + 1;
8863 } else {
8864 right = midindex - 1;
8865 }
8866 midindex = floor((left + right) / 2);
8867 }
8868 // Always check state before looking for a struct in StructStore
8869 // Therefore the case of not finding a struct is unexpected
8870 throw unexpectedCase()
8871 };
8872
8873 /**
8874 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8875 *
8876 * @param {StructStore} store
8877 * @param {ID} id
8878 * @return {GC|Item}
8879 *
8880 * @private
8881 * @function
8882 */
8883 const find = (store, id) => {
8884 /**
8885 * @type {Array<GC|Item>}
8886 */
8887 // @ts-ignore
8888 const structs = store.clients.get(id.client);
8889 return structs[findIndexSS(structs, id.clock)]
8890 };
8891
8892 /**
8893 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8894 * @private
8895 * @function
8896 */
8897 const getItem = /** @type {function(StructStore,ID):Item} */ (find);
8898
8899 /**
8900 * @param {Transaction} transaction
8901 * @param {Array<Item|GC>} structs
8902 * @param {number} clock
8903 */
8904 const findIndexCleanStart = (transaction, structs, clock) => {
8905 const index = findIndexSS(structs, clock);
8906 const struct = structs[index];
8907 if (struct.id.clock < clock && struct instanceof Item) {
8908 structs.splice(index + 1, 0, splitItem(transaction, struct, clock - struct.id.clock));
8909 return index + 1
8910 }
8911 return index
8912 };
8913
8914 /**
8915 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8916 *
8917 * @param {Transaction} transaction
8918 * @param {ID} id
8919 * @return {Item}
8920 *
8921 * @private
8922 * @function
8923 */
8924 const getItemCleanStart = (transaction, id) => {
8925 const structs = /** @type {Array<Item>} */ (transaction.doc.store.clients.get(id.client));
8926 return structs[findIndexCleanStart(transaction, structs, id.clock)]
8927 };
8928
8929 /**
8930 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8931 *
8932 * @param {Transaction} transaction
8933 * @param {StructStore} store
8934 * @param {ID} id
8935 * @return {Item}
8936 *
8937 * @private
8938 * @function
8939 */
8940 const getItemCleanEnd = (transaction, store, id) => {
8941 /**
8942 * @type {Array<Item>}
8943 */
8944 // @ts-ignore
8945 const structs = store.clients.get(id.client);
8946 const index = findIndexSS(structs, id.clock);
8947 const struct = structs[index];
8948 if (id.clock !== struct.id.clock + struct.length - 1 && struct.constructor !== GC) {
8949 structs.splice(index + 1, 0, splitItem(transaction, struct, id.clock - struct.id.clock + 1));
8950 }
8951 return struct
8952 };
8953
8954 /**
8955 * Replace `item` with `newitem` in store
8956 * @param {StructStore} store
8957 * @param {GC|Item} struct
8958 * @param {GC|Item} newStruct
8959 *
8960 * @private
8961 * @function
8962 */
8963 const replaceStruct = (store, struct, newStruct) => {
8964 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(struct.id.client));
8965 structs[findIndexSS(structs, struct.id.clock)] = newStruct;
8966 };
8967
8968 /**
8969 * Iterate over a range of structs
8970 *
8971 * @param {Transaction} transaction
8972 * @param {Array<Item|GC>} structs
8973 * @param {number} clockStart Inclusive start
8974 * @param {number} len
8975 * @param {function(GC|Item):void} f
8976 *
8977 * @function
8978 */
8979 const iterateStructs = (transaction, structs, clockStart, len, f) => {
8980 if (len === 0) {
8981 return
8982 }
8983 const clockEnd = clockStart + len;
8984 let index = findIndexCleanStart(transaction, structs, clockStart);
8985 let struct;
8986 do {
8987 struct = structs[index++];
8988 if (clockEnd < struct.id.clock + struct.length) {
8989 findIndexCleanStart(transaction, structs, clockEnd);
8990 }
8991 f(struct);
8992 } while (index < structs.length && structs[index].id.clock < clockEnd)
8993 };
8994
8995 /**
8996 * A transaction is created for every change on the Yjs model. It is possible
8997 * to bundle changes on the Yjs model in a single transaction to
8998 * minimize the number on messages sent and the number of observer calls.
8999 * If possible the user of this library should bundle as many changes as
9000 * possible. Here is an example to illustrate the advantages of bundling:
9001 *
9002 * @example
9003 * const map = y.define('map', YMap)
9004 * // Log content when change is triggered
9005 * map.observe(() => {
9006 * console.log('change triggered')
9007 * })
9008 * // Each change on the map type triggers a log message:
9009 * map.set('a', 0) // => "change triggered"
9010 * map.set('b', 0) // => "change triggered"
9011 * // When put in a transaction, it will trigger the log after the transaction:
9012 * y.transact(() => {
9013 * map.set('a', 1)
9014 * map.set('b', 1)
9015 * }) // => "change triggered"
9016 *
9017 * @public
9018 */
9019 class Transaction {
9020 /**
9021 * @param {Doc} doc
9022 * @param {any} origin
9023 * @param {boolean} local
9024 */
9025 constructor (doc, origin, local) {
9026 /**
9027 * The Yjs instance.
9028 * @type {Doc}
9029 */
9030 this.doc = doc;
9031 /**
9032 * Describes the set of deleted items by ids
9033 * @type {DeleteSet}
9034 */
9035 this.deleteSet = new DeleteSet();
9036 /**
9037 * Holds the state before the transaction started.
9038 * @type {Map<Number,Number>}
9039 */
9040 this.beforeState = getStateVector(doc.store);
9041 /**
9042 * Holds the state after the transaction.
9043 * @type {Map<Number,Number>}
9044 */
9045 this.afterState = new Map();
9046 /**
9047 * All types that were directly modified (property added or child
9048 * inserted/deleted). New types are not included in this Set.
9049 * Maps from type to parentSubs (`item.parentSub = null` for YArray)
9050 * @type {Map<AbstractType<YEvent<any>>,Set<String|null>>}
9051 */
9052 this.changed = new Map();
9053 /**
9054 * Stores the events for the types that observe also child elements.
9055 * It is mainly used by `observeDeep`.
9056 * @type {Map<AbstractType<YEvent<any>>,Array<YEvent<any>>>}
9057 */
9058 this.changedParentTypes = new Map();
9059 /**
9060 * @type {Array<AbstractStruct>}
9061 */
9062 this._mergeStructs = [];
9063 /**
9064 * @type {any}
9065 */
9066 this.origin = origin;
9067 /**
9068 * Stores meta information on the transaction
9069 * @type {Map<any,any>}
9070 */
9071 this.meta = new Map();
9072 /**
9073 * Whether this change originates from this doc.
9074 * @type {boolean}
9075 */
9076 this.local = local;
9077 /**
9078 * @type {Set<Doc>}
9079 */
9080 this.subdocsAdded = new Set();
9081 /**
9082 * @type {Set<Doc>}
9083 */
9084 this.subdocsRemoved = new Set();
9085 /**
9086 * @type {Set<Doc>}
9087 */
9088 this.subdocsLoaded = new Set();
9089 /**
9090 * @type {boolean}
9091 */
9092 this._needFormattingCleanup = false;
9093 }
9094 }
9095
9096 /**
9097 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
9098 * @param {Transaction} transaction
9099 * @return {boolean} Whether data was written.
9100 */
9101 const writeUpdateMessageFromTransaction = (encoder, transaction) => {
9102 if (transaction.deleteSet.clients.size === 0 && !any(transaction.afterState, (clock, client) => transaction.beforeState.get(client) !== clock)) {
9103 return false
9104 }
9105 sortAndMergeDeleteSet(transaction.deleteSet);
9106 writeStructsFromTransaction(encoder, transaction);
9107 writeDeleteSet(encoder, transaction.deleteSet);
9108 return true
9109 };
9110
9111 /**
9112 * If `type.parent` was added in current transaction, `type` technically
9113 * did not change, it was just added and we should not fire events for `type`.
9114 *
9115 * @param {Transaction} transaction
9116 * @param {AbstractType<YEvent<any>>} type
9117 * @param {string|null} parentSub
9118 */
9119 const addChangedTypeToTransaction = (transaction, type, parentSub) => {
9120 const item = type._item;
9121 if (item === null || (item.id.clock < (transaction.beforeState.get(item.id.client) || 0) && !item.deleted)) {
9122 setIfUndefined(transaction.changed, type, set_create).add(parentSub);
9123 }
9124 };
9125
9126 /**
9127 * @param {Array<AbstractStruct>} structs
9128 * @param {number} pos
9129 * @return {number} # of merged structs
9130 */
9131 const tryToMergeWithLefts = (structs, pos) => {
9132 let right = structs[pos];
9133 let left = structs[pos - 1];
9134 let i = pos;
9135 for (; i > 0; right = left, left = structs[--i - 1]) {
9136 if (left.deleted === right.deleted && left.constructor === right.constructor) {
9137 if (left.mergeWith(right)) {
9138 if (right instanceof Item && right.parentSub !== null && /** @type {AbstractType<any>} */ (right.parent)._map.get(right.parentSub) === right) {
9139 /** @type {AbstractType<any>} */ (right.parent)._map.set(right.parentSub, /** @type {Item} */ (left));
9140 }
9141 continue
9142 }
9143 }
9144 break
9145 }
9146 const merged = pos - i;
9147 if (merged) {
9148 // remove all merged structs from the array
9149 structs.splice(pos + 1 - merged, merged);
9150 }
9151 return merged
9152 };
9153
9154 /**
9155 * @param {DeleteSet} ds
9156 * @param {StructStore} store
9157 * @param {function(Item):boolean} gcFilter
9158 */
9159 const tryGcDeleteSet = (ds, store, gcFilter) => {
9160 for (const [client, deleteItems] of ds.clients.entries()) {
9161 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9162 for (let di = deleteItems.length - 1; di >= 0; di--) {
9163 const deleteItem = deleteItems[di];
9164 const endDeleteItemClock = deleteItem.clock + deleteItem.len;
9165 for (
9166 let si = findIndexSS(structs, deleteItem.clock), struct = structs[si];
9167 si < structs.length && struct.id.clock < endDeleteItemClock;
9168 struct = structs[++si]
9169 ) {
9170 const struct = structs[si];
9171 if (deleteItem.clock + deleteItem.len <= struct.id.clock) {
9172 break
9173 }
9174 if (struct instanceof Item && struct.deleted && !struct.keep && gcFilter(struct)) {
9175 struct.gc(store, false);
9176 }
9177 }
9178 }
9179 }
9180 };
9181
9182 /**
9183 * @param {DeleteSet} ds
9184 * @param {StructStore} store
9185 */
9186 const tryMergeDeleteSet = (ds, store) => {
9187 // try to merge deleted / gc'd items
9188 // merge from right to left for better efficiecy and so we don't miss any merge targets
9189 ds.clients.forEach((deleteItems, client) => {
9190 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9191 for (let di = deleteItems.length - 1; di >= 0; di--) {
9192 const deleteItem = deleteItems[di];
9193 // start with merging the item next to the last deleted item
9194 const mostRightIndexToCheck = min(structs.length - 1, 1 + findIndexSS(structs, deleteItem.clock + deleteItem.len - 1));
9195 for (
9196 let si = mostRightIndexToCheck, struct = structs[si];
9197 si > 0 && struct.id.clock >= deleteItem.clock;
9198 struct = structs[si]
9199 ) {
9200 si -= 1 + tryToMergeWithLefts(structs, si);
9201 }
9202 }
9203 });
9204 };
9205
9206 /**
9207 * @param {DeleteSet} ds
9208 * @param {StructStore} store
9209 * @param {function(Item):boolean} gcFilter
9210 */
9211 const tryGc = (ds, store, gcFilter) => {
9212 tryGcDeleteSet(ds, store, gcFilter);
9213 tryMergeDeleteSet(ds, store);
9214 };
9215
9216 /**
9217 * @param {Array<Transaction>} transactionCleanups
9218 * @param {number} i
9219 */
9220 const cleanupTransactions = (transactionCleanups, i) => {
9221 if (i < transactionCleanups.length) {
9222 const transaction = transactionCleanups[i];
9223 const doc = transaction.doc;
9224 const store = doc.store;
9225 const ds = transaction.deleteSet;
9226 const mergeStructs = transaction._mergeStructs;
9227 try {
9228 sortAndMergeDeleteSet(ds);
9229 transaction.afterState = getStateVector(transaction.doc.store);
9230 doc.emit('beforeObserverCalls', [transaction, doc]);
9231 /**
9232 * An array of event callbacks.
9233 *
9234 * Each callback is called even if the other ones throw errors.
9235 *
9236 * @type {Array<function():void>}
9237 */
9238 const fs = [];
9239 // observe events on changed types
9240 transaction.changed.forEach((subs, itemtype) =>
9241 fs.push(() => {
9242 if (itemtype._item === null || !itemtype._item.deleted) {
9243 itemtype._callObserver(transaction, subs);
9244 }
9245 })
9246 );
9247 fs.push(() => {
9248 // deep observe events
9249 transaction.changedParentTypes.forEach((events, type) => {
9250 // We need to think about the possibility that the user transforms the
9251 // Y.Doc in the event.
9252 if (type._dEH.l.length > 0 && (type._item === null || !type._item.deleted)) {
9253 events = events
9254 .filter(event =>
9255 event.target._item === null || !event.target._item.deleted
9256 );
9257 events
9258 .forEach(event => {
9259 event.currentTarget = type;
9260 // path is relative to the current target
9261 event._path = null;
9262 });
9263 // sort events by path length so that top-level events are fired first.
9264 events
9265 .sort((event1, event2) => event1.path.length - event2.path.length);
9266 // We don't need to check for events.length
9267 // because we know it has at least one element
9268 callEventHandlerListeners(type._dEH, events, transaction);
9269 }
9270 });
9271 });
9272 fs.push(() => doc.emit('afterTransaction', [transaction, doc]));
9273 callAll(fs, []);
9274 if (transaction._needFormattingCleanup) {
9275 cleanupYTextAfterTransaction(transaction);
9276 }
9277 } finally {
9278 // Replace deleted items with ItemDeleted / GC.
9279 // This is where content is actually remove from the Yjs Doc.
9280 if (doc.gc) {
9281 tryGcDeleteSet(ds, store, doc.gcFilter);
9282 }
9283 tryMergeDeleteSet(ds, store);
9284
9285 // on all affected store.clients props, try to merge
9286 transaction.afterState.forEach((clock, client) => {
9287 const beforeClock = transaction.beforeState.get(client) || 0;
9288 if (beforeClock !== clock) {
9289 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9290 // we iterate from right to left so we can safely remove entries
9291 const firstChangePos = max(findIndexSS(structs, beforeClock), 1);
9292 for (let i = structs.length - 1; i >= firstChangePos;) {
9293 i -= 1 + tryToMergeWithLefts(structs, i);
9294 }
9295 }
9296 });
9297 // try to merge mergeStructs
9298 // @todo: it makes more sense to transform mergeStructs to a DS, sort it, and merge from right to left
9299 // but at the moment DS does not handle duplicates
9300 for (let i = mergeStructs.length - 1; i >= 0; i--) {
9301 const { client, clock } = mergeStructs[i].id;
9302 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9303 const replacedStructPos = findIndexSS(structs, clock);
9304 if (replacedStructPos + 1 < structs.length) {
9305 if (tryToMergeWithLefts(structs, replacedStructPos + 1) > 1) {
9306 continue // no need to perform next check, both are already merged
9307 }
9308 }
9309 if (replacedStructPos > 0) {
9310 tryToMergeWithLefts(structs, replacedStructPos);
9311 }
9312 }
9313 if (!transaction.local && transaction.afterState.get(doc.clientID) !== transaction.beforeState.get(doc.clientID)) {
9314 print(ORANGE, BOLD, '[yjs] ', UNBOLD, RED, 'Changed the client-id because another client seems to be using it.');
9315 doc.clientID = generateNewClientId();
9316 }
9317 // @todo Merge all the transactions into one and provide send the data as a single update message
9318 doc.emit('afterTransactionCleanup', [transaction, doc]);
9319 if (doc._observers.has('update')) {
9320 const encoder = new UpdateEncoderV1();
9321 const hasContent = writeUpdateMessageFromTransaction(encoder, transaction);
9322 if (hasContent) {
9323 doc.emit('update', [encoder.toUint8Array(), transaction.origin, doc, transaction]);
9324 }
9325 }
9326 if (doc._observers.has('updateV2')) {
9327 const encoder = new UpdateEncoderV2();
9328 const hasContent = writeUpdateMessageFromTransaction(encoder, transaction);
9329 if (hasContent) {
9330 doc.emit('updateV2', [encoder.toUint8Array(), transaction.origin, doc, transaction]);
9331 }
9332 }
9333 const { subdocsAdded, subdocsLoaded, subdocsRemoved } = transaction;
9334 if (subdocsAdded.size > 0 || subdocsRemoved.size > 0 || subdocsLoaded.size > 0) {
9335 subdocsAdded.forEach(subdoc => {
9336 subdoc.clientID = doc.clientID;
9337 if (subdoc.collectionid == null) {
9338 subdoc.collectionid = doc.collectionid;
9339 }
9340 doc.subdocs.add(subdoc);
9341 });
9342 subdocsRemoved.forEach(subdoc => doc.subdocs.delete(subdoc));
9343 doc.emit('subdocs', [{ loaded: subdocsLoaded, added: subdocsAdded, removed: subdocsRemoved }, doc, transaction]);
9344 subdocsRemoved.forEach(subdoc => subdoc.destroy());
9345 }
9346
9347 if (transactionCleanups.length <= i + 1) {
9348 doc._transactionCleanups = [];
9349 doc.emit('afterAllTransactions', [doc, transactionCleanups]);
9350 } else {
9351 cleanupTransactions(transactionCleanups, i + 1);
9352 }
9353 }
9354 }
9355 };
9356
9357 /**
9358 * Implements the functionality of `y.transact(()=>{..})`
9359 *
9360 * @template T
9361 * @param {Doc} doc
9362 * @param {function(Transaction):T} f
9363 * @param {any} [origin=true]
9364 * @return {T}
9365 *
9366 * @function
9367 */
9368 const transact = (doc, f, origin = null, local = true) => {
9369 const transactionCleanups = doc._transactionCleanups;
9370 let initialCall = false;
9371 /**
9372 * @type {any}
9373 */
9374 let result = null;
9375 if (doc._transaction === null) {
9376 initialCall = true;
9377 doc._transaction = new Transaction(doc, origin, local);
9378 transactionCleanups.push(doc._transaction);
9379 if (transactionCleanups.length === 1) {
9380 doc.emit('beforeAllTransactions', [doc]);
9381 }
9382 doc.emit('beforeTransaction', [doc._transaction, doc]);
9383 }
9384 try {
9385 result = f(doc._transaction);
9386 } finally {
9387 if (initialCall) {
9388 const finishCleanup = doc._transaction === transactionCleanups[0];
9389 doc._transaction = null;
9390 if (finishCleanup) {
9391 // The first transaction ended, now process observer calls.
9392 // Observer call may create new transactions for which we need to call the observers and do cleanup.
9393 // We don't want to nest these calls, so we execute these calls one after
9394 // another.
9395 // Also we need to ensure that all cleanups are called, even if the
9396 // observes throw errors.
9397 // This file is full of hacky try {} finally {} blocks to ensure that an
9398 // event can throw errors and also that the cleanup is called.
9399 cleanupTransactions(transactionCleanups, 0);
9400 }
9401 }
9402 }
9403 return result
9404 };
9405
9406 class StackItem {
9407 /**
9408 * @param {DeleteSet} deletions
9409 * @param {DeleteSet} insertions
9410 */
9411 constructor (deletions, insertions) {
9412 this.insertions = insertions;
9413 this.deletions = deletions;
9414 /**
9415 * Use this to save and restore metadata like selection range
9416 */
9417 this.meta = new Map();
9418 }
9419 }
9420 /**
9421 * @param {Transaction} tr
9422 * @param {UndoManager} um
9423 * @param {StackItem} stackItem
9424 */
9425 const clearUndoManagerStackItem = (tr, um, stackItem) => {
9426 iterateDeletedStructs(tr, stackItem.deletions, item => {
9427 if (item instanceof Item && um.scope.some(type => yjs_isParentOf(type, item))) {
9428 keepItem(item, false);
9429 }
9430 });
9431 };
9432
9433 /**
9434 * @param {UndoManager} undoManager
9435 * @param {Array<StackItem>} stack
9436 * @param {string} eventType
9437 * @return {StackItem?}
9438 */
9439 const popStackItem = (undoManager, stack, eventType) => {
9440 /**
9441 * Whether a change happened
9442 * @type {StackItem?}
9443 */
9444 let result = null;
9445 /**
9446 * Keep a reference to the transaction so we can fire the event with the changedParentTypes
9447 * @type {any}
9448 */
9449 let _tr = null;
9450 const doc = undoManager.doc;
9451 const scope = undoManager.scope;
9452 transact(doc, transaction => {
9453 while (stack.length > 0 && result === null) {
9454 const store = doc.store;
9455 const stackItem = /** @type {StackItem} */ (stack.pop());
9456 /**
9457 * @type {Set<Item>}
9458 */
9459 const itemsToRedo = new Set();
9460 /**
9461 * @type {Array<Item>}
9462 */
9463 const itemsToDelete = [];
9464 let performedChange = false;
9465 iterateDeletedStructs(transaction, stackItem.insertions, struct => {
9466 if (struct instanceof Item) {
9467 if (struct.redone !== null) {
9468 let { item, diff } = followRedone(store, struct.id);
9469 if (diff > 0) {
9470 item = getItemCleanStart(transaction, createID(item.id.client, item.id.clock + diff));
9471 }
9472 struct = item;
9473 }
9474 if (!struct.deleted && scope.some(type => yjs_isParentOf(type, /** @type {Item} */ (struct)))) {
9475 itemsToDelete.push(struct);
9476 }
9477 }
9478 });
9479 iterateDeletedStructs(transaction, stackItem.deletions, struct => {
9480 if (
9481 struct instanceof Item &&
9482 scope.some(type => yjs_isParentOf(type, struct)) &&
9483 // Never redo structs in stackItem.insertions because they were created and deleted in the same capture interval.
9484 !isDeleted(stackItem.insertions, struct.id)
9485 ) {
9486 itemsToRedo.add(struct);
9487 }
9488 });
9489 itemsToRedo.forEach(struct => {
9490 performedChange = redoItem(transaction, struct, itemsToRedo, stackItem.insertions, undoManager.ignoreRemoteMapChanges, undoManager) !== null || performedChange;
9491 });
9492 // We want to delete in reverse order so that children are deleted before
9493 // parents, so we have more information available when items are filtered.
9494 for (let i = itemsToDelete.length - 1; i >= 0; i--) {
9495 const item = itemsToDelete[i];
9496 if (undoManager.deleteFilter(item)) {
9497 item.delete(transaction);
9498 performedChange = true;
9499 }
9500 }
9501 result = performedChange ? stackItem : null;
9502 }
9503 transaction.changed.forEach((subProps, type) => {
9504 // destroy search marker if necessary
9505 if (subProps.has(null) && type._searchMarker) {
9506 type._searchMarker.length = 0;
9507 }
9508 });
9509 _tr = transaction;
9510 }, undoManager);
9511 if (result != null) {
9512 const changedParentTypes = _tr.changedParentTypes;
9513 undoManager.emit('stack-item-popped', [{ stackItem: result, type: eventType, changedParentTypes }, undoManager]);
9514 }
9515 return result
9516 };
9517
9518 /**
9519 * @typedef {Object} UndoManagerOptions
9520 * @property {number} [UndoManagerOptions.captureTimeout=500]
9521 * @property {function(Transaction):boolean} [UndoManagerOptions.captureTransaction] Do not capture changes of a Transaction if result false.
9522 * @property {function(Item):boolean} [UndoManagerOptions.deleteFilter=()=>true] Sometimes
9523 * it is necessary to filter what an Undo/Redo operation can delete. If this
9524 * filter returns false, the type/item won't be deleted even it is in the
9525 * undo/redo scope.
9526 * @property {Set<any>} [UndoManagerOptions.trackedOrigins=new Set([null])]
9527 * @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..).
9528 * @property {Doc} [doc] The document that this UndoManager operates on. Only needed if typeScope is empty.
9529 */
9530
9531 /**
9532 * Fires 'stack-item-added' event when a stack item was added to either the undo- or
9533 * the redo-stack. You may store additional stack information via the
9534 * metadata property on `event.stackItem.meta` (it is a `Map` of metadata properties).
9535 * Fires 'stack-item-popped' event when a stack item was popped from either the
9536 * undo- or the redo-stack. You may restore the saved stack information from `event.stackItem.meta`.
9537 *
9538 * @extends {Observable<'stack-item-added'|'stack-item-popped'|'stack-cleared'|'stack-item-updated'>}
9539 */
9540 class UndoManager extends (/* unused pure expression or super */ null && (Observable)) {
9541 /**
9542 * @param {AbstractType<any>|Array<AbstractType<any>>} typeScope Accepts either a single type, or an array of types
9543 * @param {UndoManagerOptions} options
9544 */
9545 constructor (typeScope, {
9546 captureTimeout = 500,
9547 captureTransaction = _tr => true,
9548 deleteFilter = () => true,
9549 trackedOrigins = new Set([null]),
9550 ignoreRemoteMapChanges = false,
9551 doc = /** @type {Doc} */ (array.isArray(typeScope) ? typeScope[0].doc : typeScope.doc)
9552 } = {}) {
9553 super();
9554 /**
9555 * @type {Array<AbstractType<any>>}
9556 */
9557 this.scope = [];
9558 this.addToScope(typeScope);
9559 this.deleteFilter = deleteFilter;
9560 trackedOrigins.add(this);
9561 this.trackedOrigins = trackedOrigins;
9562 this.captureTransaction = captureTransaction;
9563 /**
9564 * @type {Array<StackItem>}
9565 */
9566 this.undoStack = [];
9567 /**
9568 * @type {Array<StackItem>}
9569 */
9570 this.redoStack = [];
9571 /**
9572 * Whether the client is currently undoing (calling UndoManager.undo)
9573 *
9574 * @type {boolean}
9575 */
9576 this.undoing = false;
9577 this.redoing = false;
9578 this.doc = doc;
9579 this.lastChange = 0;
9580 this.ignoreRemoteMapChanges = ignoreRemoteMapChanges;
9581 this.captureTimeout = captureTimeout;
9582 /**
9583 * @param {Transaction} transaction
9584 */
9585 this.afterTransactionHandler = transaction => {
9586 // Only track certain transactions
9587 if (
9588 !this.captureTransaction(transaction) ||
9589 !this.scope.some(type => transaction.changedParentTypes.has(type)) ||
9590 (!this.trackedOrigins.has(transaction.origin) && (!transaction.origin || !this.trackedOrigins.has(transaction.origin.constructor)))
9591 ) {
9592 return
9593 }
9594 const undoing = this.undoing;
9595 const redoing = this.redoing;
9596 const stack = undoing ? this.redoStack : this.undoStack;
9597 if (undoing) {
9598 this.stopCapturing(); // next undo should not be appended to last stack item
9599 } else if (!redoing) {
9600 // neither undoing nor redoing: delete redoStack
9601 this.clear(false, true);
9602 }
9603 const insertions = new DeleteSet();
9604 transaction.afterState.forEach((endClock, client) => {
9605 const startClock = transaction.beforeState.get(client) || 0;
9606 const len = endClock - startClock;
9607 if (len > 0) {
9608 addToDeleteSet(insertions, client, startClock, len);
9609 }
9610 });
9611 const now = time.getUnixTime();
9612 let didAdd = false;
9613 if (this.lastChange > 0 && now - this.lastChange < this.captureTimeout && stack.length > 0 && !undoing && !redoing) {
9614 // append change to last stack op
9615 const lastOp = stack[stack.length - 1];
9616 lastOp.deletions = mergeDeleteSets([lastOp.deletions, transaction.deleteSet]);
9617 lastOp.insertions = mergeDeleteSets([lastOp.insertions, insertions]);
9618 } else {
9619 // create a new stack op
9620 stack.push(new StackItem(transaction.deleteSet, insertions));
9621 didAdd = true;
9622 }
9623 if (!undoing && !redoing) {
9624 this.lastChange = now;
9625 }
9626 // make sure that deleted structs are not gc'd
9627 iterateDeletedStructs(transaction, transaction.deleteSet, /** @param {Item|GC} item */ item => {
9628 if (item instanceof Item && this.scope.some(type => yjs_isParentOf(type, item))) {
9629 keepItem(item, true);
9630 }
9631 });
9632 const changeEvent = [{ stackItem: stack[stack.length - 1], origin: transaction.origin, type: undoing ? 'redo' : 'undo', changedParentTypes: transaction.changedParentTypes }, this];
9633 if (didAdd) {
9634 this.emit('stack-item-added', changeEvent);
9635 } else {
9636 this.emit('stack-item-updated', changeEvent);
9637 }
9638 };
9639 this.doc.on('afterTransaction', this.afterTransactionHandler);
9640 this.doc.on('destroy', () => {
9641 this.destroy();
9642 });
9643 }
9644
9645 /**
9646 * @param {Array<AbstractType<any>> | AbstractType<any>} ytypes
9647 */
9648 addToScope (ytypes) {
9649 ytypes = array.isArray(ytypes) ? ytypes : [ytypes];
9650 ytypes.forEach(ytype => {
9651 if (this.scope.every(yt => yt !== ytype)) {
9652 this.scope.push(ytype);
9653 }
9654 });
9655 }
9656
9657 /**
9658 * @param {any} origin
9659 */
9660 addTrackedOrigin (origin) {
9661 this.trackedOrigins.add(origin);
9662 }
9663
9664 /**
9665 * @param {any} origin
9666 */
9667 removeTrackedOrigin (origin) {
9668 this.trackedOrigins.delete(origin);
9669 }
9670
9671 clear (clearUndoStack = true, clearRedoStack = true) {
9672 if ((clearUndoStack && this.canUndo()) || (clearRedoStack && this.canRedo())) {
9673 this.doc.transact(tr => {
9674 if (clearUndoStack) {
9675 this.undoStack.forEach(item => clearUndoManagerStackItem(tr, this, item));
9676 this.undoStack = [];
9677 }
9678 if (clearRedoStack) {
9679 this.redoStack.forEach(item => clearUndoManagerStackItem(tr, this, item));
9680 this.redoStack = [];
9681 }
9682 this.emit('stack-cleared', [{ undoStackCleared: clearUndoStack, redoStackCleared: clearRedoStack }]);
9683 });
9684 }
9685 }
9686
9687 /**
9688 * UndoManager merges Undo-StackItem if they are created within time-gap
9689 * smaller than `options.captureTimeout`. Call `um.stopCapturing()` so that the next
9690 * StackItem won't be merged.
9691 *
9692 *
9693 * @example
9694 * // without stopCapturing
9695 * ytext.insert(0, 'a')
9696 * ytext.insert(1, 'b')
9697 * um.undo()
9698 * ytext.toString() // => '' (note that 'ab' was removed)
9699 * // with stopCapturing
9700 * ytext.insert(0, 'a')
9701 * um.stopCapturing()
9702 * ytext.insert(0, 'b')
9703 * um.undo()
9704 * ytext.toString() // => 'a' (note that only 'b' was removed)
9705 *
9706 */
9707 stopCapturing () {
9708 this.lastChange = 0;
9709 }
9710
9711 /**
9712 * Undo last changes on type.
9713 *
9714 * @return {StackItem?} Returns StackItem if a change was applied
9715 */
9716 undo () {
9717 this.undoing = true;
9718 let res;
9719 try {
9720 res = popStackItem(this, this.undoStack, 'undo');
9721 } finally {
9722 this.undoing = false;
9723 }
9724 return res
9725 }
9726
9727 /**
9728 * Redo last undo operation.
9729 *
9730 * @return {StackItem?} Returns StackItem if a change was applied
9731 */
9732 redo () {
9733 this.redoing = true;
9734 let res;
9735 try {
9736 res = popStackItem(this, this.redoStack, 'redo');
9737 } finally {
9738 this.redoing = false;
9739 }
9740 return res
9741 }
9742
9743 /**
9744 * Are undo steps available?
9745 *
9746 * @return {boolean} `true` if undo is possible
9747 */
9748 canUndo () {
9749 return this.undoStack.length > 0
9750 }
9751
9752 /**
9753 * Are redo steps available?
9754 *
9755 * @return {boolean} `true` if redo is possible
9756 */
9757 canRedo () {
9758 return this.redoStack.length > 0
9759 }
9760
9761 destroy () {
9762 this.trackedOrigins.delete(this);
9763 this.doc.off('afterTransaction', this.afterTransactionHandler);
9764 super.destroy();
9765 }
9766 }
9767
9768 /**
9769 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
9770 */
9771 function * lazyStructReaderGenerator (decoder) {
9772 const numOfStateUpdates = readVarUint(decoder.restDecoder);
9773 for (let i = 0; i < numOfStateUpdates; i++) {
9774 const numberOfStructs = readVarUint(decoder.restDecoder);
9775 const client = decoder.readClient();
9776 let clock = readVarUint(decoder.restDecoder);
9777 for (let i = 0; i < numberOfStructs; i++) {
9778 const info = decoder.readInfo();
9779 // @todo use switch instead of ifs
9780 if (info === 10) {
9781 const len = readVarUint(decoder.restDecoder);
9782 yield new Skip(createID(client, clock), len);
9783 clock += len;
9784 } else if ((BITS5 & info) !== 0) {
9785 const cantCopyParentInfo = (info & (BIT7 | BIT8)) === 0;
9786 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
9787 // and we read the next string as parentYKey.
9788 // It indicates how we store/retrieve parent from `y.share`
9789 // @type {string|null}
9790 const struct = new Item(
9791 createID(client, clock),
9792 null, // left
9793 (info & BIT8) === BIT8 ? decoder.readLeftID() : null, // origin
9794 null, // right
9795 (info & BIT7) === BIT7 ? decoder.readRightID() : null, // right origin
9796 // @ts-ignore Force writing a string here.
9797 cantCopyParentInfo ? (decoder.readParentInfo() ? decoder.readString() : decoder.readLeftID()) : null, // parent
9798 cantCopyParentInfo && (info & BIT6) === BIT6 ? decoder.readString() : null, // parentSub
9799 readItemContent(decoder, info) // item content
9800 );
9801 yield struct;
9802 clock += struct.length;
9803 } else {
9804 const len = decoder.readLen();
9805 yield new GC(createID(client, clock), len);
9806 clock += len;
9807 }
9808 }
9809 }
9810 }
9811
9812 class LazyStructReader {
9813 /**
9814 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
9815 * @param {boolean} filterSkips
9816 */
9817 constructor (decoder, filterSkips) {
9818 this.gen = lazyStructReaderGenerator(decoder);
9819 /**
9820 * @type {null | Item | Skip | GC}
9821 */
9822 this.curr = null;
9823 this.done = false;
9824 this.filterSkips = filterSkips;
9825 this.next();
9826 }
9827
9828 /**
9829 * @return {Item | GC | Skip |null}
9830 */
9831 next () {
9832 // ignore "Skip" structs
9833 do {
9834 this.curr = this.gen.next().value || null;
9835 } while (this.filterSkips && this.curr !== null && this.curr.constructor === Skip)
9836 return this.curr
9837 }
9838 }
9839
9840 /**
9841 * @param {Uint8Array} update
9842 *
9843 */
9844 const logUpdate = update => logUpdateV2(update, UpdateDecoderV1);
9845
9846 /**
9847 * @param {Uint8Array} update
9848 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
9849 *
9850 */
9851 const logUpdateV2 = (update, YDecoder = UpdateDecoderV2) => {
9852 const structs = [];
9853 const updateDecoder = new YDecoder(decoding.createDecoder(update));
9854 const lazyDecoder = new LazyStructReader(updateDecoder, false);
9855 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
9856 structs.push(curr);
9857 }
9858 logging.print('Structs: ', structs);
9859 const ds = readDeleteSet(updateDecoder);
9860 logging.print('DeleteSet: ', ds);
9861 };
9862
9863 /**
9864 * @param {Uint8Array} update
9865 *
9866 */
9867 const decodeUpdate = (update) => decodeUpdateV2(update, UpdateDecoderV1);
9868
9869 /**
9870 * @param {Uint8Array} update
9871 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
9872 *
9873 */
9874 const decodeUpdateV2 = (update, YDecoder = UpdateDecoderV2) => {
9875 const structs = [];
9876 const updateDecoder = new YDecoder(decoding.createDecoder(update));
9877 const lazyDecoder = new LazyStructReader(updateDecoder, false);
9878 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
9879 structs.push(curr);
9880 }
9881 return {
9882 structs,
9883 ds: readDeleteSet(updateDecoder)
9884 }
9885 };
9886
9887 class LazyStructWriter {
9888 /**
9889 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
9890 */
9891 constructor (encoder) {
9892 this.currClient = 0;
9893 this.startClock = 0;
9894 this.written = 0;
9895 this.encoder = encoder;
9896 /**
9897 * We want to write operations lazily, but also we need to know beforehand how many operations we want to write for each client.
9898 *
9899 * This kind of meta-information (#clients, #structs-per-client-written) is written to the restEncoder.
9900 *
9901 * We fragment the restEncoder and store a slice of it per-client until we know how many clients there are.
9902 * When we flush (toUint8Array) we write the restEncoder using the fragments and the meta-information.
9903 *
9904 * @type {Array<{ written: number, restEncoder: Uint8Array }>}
9905 */
9906 this.clientStructs = [];
9907 }
9908 }
9909
9910 /**
9911 * @param {Array<Uint8Array>} updates
9912 * @return {Uint8Array}
9913 */
9914 const mergeUpdates = updates => mergeUpdatesV2(updates, UpdateDecoderV1, UpdateEncoderV1);
9915
9916 /**
9917 * @param {Uint8Array} update
9918 * @param {typeof DSEncoderV1 | typeof DSEncoderV2} YEncoder
9919 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} YDecoder
9920 * @return {Uint8Array}
9921 */
9922 const encodeStateVectorFromUpdateV2 = (update, YEncoder = DSEncoderV2, YDecoder = UpdateDecoderV2) => {
9923 const encoder = new YEncoder();
9924 const updateDecoder = new LazyStructReader(new YDecoder(decoding.createDecoder(update)), false);
9925 let curr = updateDecoder.curr;
9926 if (curr !== null) {
9927 let size = 0;
9928 let currClient = curr.id.client;
9929 let stopCounting = curr.id.clock !== 0; // must start at 0
9930 let currClock = stopCounting ? 0 : curr.id.clock + curr.length;
9931 for (; curr !== null; curr = updateDecoder.next()) {
9932 if (currClient !== curr.id.client) {
9933 if (currClock !== 0) {
9934 size++;
9935 // We found a new client
9936 // write what we have to the encoder
9937 encoding.writeVarUint(encoder.restEncoder, currClient);
9938 encoding.writeVarUint(encoder.restEncoder, currClock);
9939 }
9940 currClient = curr.id.client;
9941 currClock = 0;
9942 stopCounting = curr.id.clock !== 0;
9943 }
9944 // we ignore skips
9945 if (curr.constructor === Skip) {
9946 stopCounting = true;
9947 }
9948 if (!stopCounting) {
9949 currClock = curr.id.clock + curr.length;
9950 }
9951 }
9952 // write what we have
9953 if (currClock !== 0) {
9954 size++;
9955 encoding.writeVarUint(encoder.restEncoder, currClient);
9956 encoding.writeVarUint(encoder.restEncoder, currClock);
9957 }
9958 // prepend the size of the state vector
9959 const enc = encoding.createEncoder();
9960 encoding.writeVarUint(enc, size);
9961 encoding.writeBinaryEncoder(enc, encoder.restEncoder);
9962 encoder.restEncoder = enc;
9963 return encoder.toUint8Array()
9964 } else {
9965 encoding.writeVarUint(encoder.restEncoder, 0);
9966 return encoder.toUint8Array()
9967 }
9968 };
9969
9970 /**
9971 * @param {Uint8Array} update
9972 * @return {Uint8Array}
9973 */
9974 const encodeStateVectorFromUpdate = update => encodeStateVectorFromUpdateV2(update, DSEncoderV1, UpdateDecoderV1);
9975
9976 /**
9977 * @param {Uint8Array} update
9978 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} YDecoder
9979 * @return {{ from: Map<number,number>, to: Map<number,number> }}
9980 */
9981 const parseUpdateMetaV2 = (update, YDecoder = UpdateDecoderV2) => {
9982 /**
9983 * @type {Map<number, number>}
9984 */
9985 const from = new Map();
9986 /**
9987 * @type {Map<number, number>}
9988 */
9989 const to = new Map();
9990 const updateDecoder = new LazyStructReader(new YDecoder(decoding.createDecoder(update)), false);
9991 let curr = updateDecoder.curr;
9992 if (curr !== null) {
9993 let currClient = curr.id.client;
9994 let currClock = curr.id.clock;
9995 // write the beginning to `from`
9996 from.set(currClient, currClock);
9997 for (; curr !== null; curr = updateDecoder.next()) {
9998 if (currClient !== curr.id.client) {
9999 // We found a new client
10000 // write the end to `to`
10001 to.set(currClient, currClock);
10002 // write the beginning to `from`
10003 from.set(curr.id.client, curr.id.clock);
10004 // update currClient
10005 currClient = curr.id.client;
10006 }
10007 currClock = curr.id.clock + curr.length;
10008 }
10009 // write the end to `to`
10010 to.set(currClient, currClock);
10011 }
10012 return { from, to }
10013 };
10014
10015 /**
10016 * @param {Uint8Array} update
10017 * @return {{ from: Map<number,number>, to: Map<number,number> }}
10018 */
10019 const parseUpdateMeta = update => parseUpdateMetaV2(update, UpdateDecoderV1);
10020
10021 /**
10022 * This method is intended to slice any kind of struct and retrieve the right part.
10023 * It does not handle side-effects, so it should only be used by the lazy-encoder.
10024 *
10025 * @param {Item | GC | Skip} left
10026 * @param {number} diff
10027 * @return {Item | GC}
10028 */
10029 const sliceStruct = (left, diff) => {
10030 if (left.constructor === GC) {
10031 const { client, clock } = left.id;
10032 return new GC(createID(client, clock + diff), left.length - diff)
10033 } else if (left.constructor === Skip) {
10034 const { client, clock } = left.id;
10035 return new Skip(createID(client, clock + diff), left.length - diff)
10036 } else {
10037 const leftItem = /** @type {Item} */ (left);
10038 const { client, clock } = leftItem.id;
10039 return new Item(
10040 createID(client, clock + diff),
10041 null,
10042 createID(client, clock + diff - 1),
10043 null,
10044 leftItem.rightOrigin,
10045 leftItem.parent,
10046 leftItem.parentSub,
10047 leftItem.content.splice(diff)
10048 )
10049 }
10050 };
10051
10052 /**
10053 *
10054 * This function works similarly to `readUpdateV2`.
10055 *
10056 * @param {Array<Uint8Array>} updates
10057 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
10058 * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder]
10059 * @return {Uint8Array}
10060 */
10061 const mergeUpdatesV2 = (updates, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => {
10062 if (updates.length === 1) {
10063 return updates[0]
10064 }
10065 const updateDecoders = updates.map(update => new YDecoder(createDecoder(update)));
10066 let lazyStructDecoders = updateDecoders.map(decoder => new LazyStructReader(decoder, true));
10067
10068 /**
10069 * @todo we don't need offset because we always slice before
10070 * @type {null | { struct: Item | GC | Skip, offset: number }}
10071 */
10072 let currWrite = null;
10073
10074 const updateEncoder = new YEncoder();
10075 // write structs lazily
10076 const lazyStructEncoder = new LazyStructWriter(updateEncoder);
10077
10078 // Note: We need to ensure that all lazyStructDecoders are fully consumed
10079 // Note: Should merge document updates whenever possible - even from different updates
10080 // Note: Should handle that some operations cannot be applied yet ()
10081
10082 while (true) {
10083 // Write higher clients first ⇒ sort by clientID & clock and remove decoders without content
10084 lazyStructDecoders = lazyStructDecoders.filter(dec => dec.curr !== null);
10085 lazyStructDecoders.sort(
10086 /** @type {function(any,any):number} */ (dec1, dec2) => {
10087 if (dec1.curr.id.client === dec2.curr.id.client) {
10088 const clockDiff = dec1.curr.id.clock - dec2.curr.id.clock;
10089 if (clockDiff === 0) {
10090 // @todo remove references to skip since the structDecoders must filter Skips.
10091 return dec1.curr.constructor === dec2.curr.constructor
10092 ? 0
10093 : dec1.curr.constructor === Skip ? 1 : -1 // we are filtering skips anyway.
10094 } else {
10095 return clockDiff
10096 }
10097 } else {
10098 return dec2.curr.id.client - dec1.curr.id.client
10099 }
10100 }
10101 );
10102 if (lazyStructDecoders.length === 0) {
10103 break
10104 }
10105 const currDecoder = lazyStructDecoders[0];
10106 // write from currDecoder until the next operation is from another client or if filler-struct
10107 // then we need to reorder the decoders and find the next operation to write
10108 const firstClient = /** @type {Item | GC} */ (currDecoder.curr).id.client;
10109
10110 if (currWrite !== null) {
10111 let curr = /** @type {Item | GC | null} */ (currDecoder.curr);
10112 let iterated = false;
10113
10114 // iterate until we find something that we haven't written already
10115 // remember: first the high client-ids are written
10116 while (curr !== null && curr.id.clock + curr.length <= currWrite.struct.id.clock + currWrite.struct.length && curr.id.client >= currWrite.struct.id.client) {
10117 curr = currDecoder.next();
10118 iterated = true;
10119 }
10120 if (
10121 curr === null || // current decoder is empty
10122 curr.id.client !== firstClient || // check whether there is another decoder that has has updates from `firstClient`
10123 (iterated && curr.id.clock > currWrite.struct.id.clock + currWrite.struct.length) // the above while loop was used and we are potentially missing updates
10124 ) {
10125 continue
10126 }
10127
10128 if (firstClient !== currWrite.struct.id.client) {
10129 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10130 currWrite = { struct: curr, offset: 0 };
10131 currDecoder.next();
10132 } else {
10133 if (currWrite.struct.id.clock + currWrite.struct.length < curr.id.clock) {
10134 // @todo write currStruct & set currStruct = Skip(clock = currStruct.id.clock + currStruct.length, length = curr.id.clock - self.clock)
10135 if (currWrite.struct.constructor === Skip) {
10136 // extend existing skip
10137 currWrite.struct.length = curr.id.clock + curr.length - currWrite.struct.id.clock;
10138 } else {
10139 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10140 const diff = curr.id.clock - currWrite.struct.id.clock - currWrite.struct.length;
10141 /**
10142 * @type {Skip}
10143 */
10144 const struct = new Skip(createID(firstClient, currWrite.struct.id.clock + currWrite.struct.length), diff);
10145 currWrite = { struct, offset: 0 };
10146 }
10147 } else { // if (currWrite.struct.id.clock + currWrite.struct.length >= curr.id.clock) {
10148 const diff = currWrite.struct.id.clock + currWrite.struct.length - curr.id.clock;
10149 if (diff > 0) {
10150 if (currWrite.struct.constructor === Skip) {
10151 // prefer to slice Skip because the other struct might contain more information
10152 currWrite.struct.length -= diff;
10153 } else {
10154 curr = sliceStruct(curr, diff);
10155 }
10156 }
10157 if (!currWrite.struct.mergeWith(/** @type {any} */ (curr))) {
10158 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10159 currWrite = { struct: curr, offset: 0 };
10160 currDecoder.next();
10161 }
10162 }
10163 }
10164 } else {
10165 currWrite = { struct: /** @type {Item | GC} */ (currDecoder.curr), offset: 0 };
10166 currDecoder.next();
10167 }
10168 for (
10169 let next = currDecoder.curr;
10170 next !== null && next.id.client === firstClient && next.id.clock === currWrite.struct.id.clock + currWrite.struct.length && next.constructor !== Skip;
10171 next = currDecoder.next()
10172 ) {
10173 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10174 currWrite = { struct: next, offset: 0 };
10175 }
10176 }
10177 if (currWrite !== null) {
10178 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10179 currWrite = null;
10180 }
10181 finishLazyStructWriting(lazyStructEncoder);
10182
10183 const dss = updateDecoders.map(decoder => readDeleteSet(decoder));
10184 const ds = mergeDeleteSets(dss);
10185 writeDeleteSet(updateEncoder, ds);
10186 return updateEncoder.toUint8Array()
10187 };
10188
10189 /**
10190 * @param {Uint8Array} update
10191 * @param {Uint8Array} sv
10192 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
10193 * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder]
10194 */
10195 const diffUpdateV2 = (update, sv, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => {
10196 const state = decodeStateVector(sv);
10197 const encoder = new YEncoder();
10198 const lazyStructWriter = new LazyStructWriter(encoder);
10199 const decoder = new YDecoder(createDecoder(update));
10200 const reader = new LazyStructReader(decoder, false);
10201 while (reader.curr) {
10202 const curr = reader.curr;
10203 const currClient = curr.id.client;
10204 const svClock = state.get(currClient) || 0;
10205 if (reader.curr.constructor === Skip) {
10206 // the first written struct shouldn't be a skip
10207 reader.next();
10208 continue
10209 }
10210 if (curr.id.clock + curr.length > svClock) {
10211 writeStructToLazyStructWriter(lazyStructWriter, curr, max(svClock - curr.id.clock, 0));
10212 reader.next();
10213 while (reader.curr && reader.curr.id.client === currClient) {
10214 writeStructToLazyStructWriter(lazyStructWriter, reader.curr, 0);
10215 reader.next();
10216 }
10217 } else {
10218 // read until something new comes up
10219 while (reader.curr && reader.curr.id.client === currClient && reader.curr.id.clock + reader.curr.length <= svClock) {
10220 reader.next();
10221 }
10222 }
10223 }
10224 finishLazyStructWriting(lazyStructWriter);
10225 // write ds
10226 const ds = readDeleteSet(decoder);
10227 writeDeleteSet(encoder, ds);
10228 return encoder.toUint8Array()
10229 };
10230
10231 /**
10232 * @param {Uint8Array} update
10233 * @param {Uint8Array} sv
10234 */
10235 const diffUpdate = (update, sv) => diffUpdateV2(update, sv, UpdateDecoderV1, UpdateEncoderV1);
10236
10237 /**
10238 * @param {LazyStructWriter} lazyWriter
10239 */
10240 const flushLazyStructWriter = lazyWriter => {
10241 if (lazyWriter.written > 0) {
10242 lazyWriter.clientStructs.push({ written: lazyWriter.written, restEncoder: toUint8Array(lazyWriter.encoder.restEncoder) });
10243 lazyWriter.encoder.restEncoder = createEncoder();
10244 lazyWriter.written = 0;
10245 }
10246 };
10247
10248 /**
10249 * @param {LazyStructWriter} lazyWriter
10250 * @param {Item | GC} struct
10251 * @param {number} offset
10252 */
10253 const writeStructToLazyStructWriter = (lazyWriter, struct, offset) => {
10254 // flush curr if we start another client
10255 if (lazyWriter.written > 0 && lazyWriter.currClient !== struct.id.client) {
10256 flushLazyStructWriter(lazyWriter);
10257 }
10258 if (lazyWriter.written === 0) {
10259 lazyWriter.currClient = struct.id.client;
10260 // write next client
10261 lazyWriter.encoder.writeClient(struct.id.client);
10262 // write startClock
10263 writeVarUint(lazyWriter.encoder.restEncoder, struct.id.clock + offset);
10264 }
10265 struct.write(lazyWriter.encoder, offset);
10266 lazyWriter.written++;
10267 };
10268 /**
10269 * Call this function when we collected all parts and want to
10270 * put all the parts together. After calling this method,
10271 * you can continue using the UpdateEncoder.
10272 *
10273 * @param {LazyStructWriter} lazyWriter
10274 */
10275 const finishLazyStructWriting = (lazyWriter) => {
10276 flushLazyStructWriter(lazyWriter);
10277
10278 // this is a fresh encoder because we called flushCurr
10279 const restEncoder = lazyWriter.encoder.restEncoder;
10280
10281 /**
10282 * Now we put all the fragments together.
10283 * This works similarly to `writeClientsStructs`
10284 */
10285
10286 // write # states that were updated - i.e. the clients
10287 writeVarUint(restEncoder, lazyWriter.clientStructs.length);
10288
10289 for (let i = 0; i < lazyWriter.clientStructs.length; i++) {
10290 const partStructs = lazyWriter.clientStructs[i];
10291 /**
10292 * Works similarly to `writeStructs`
10293 */
10294 // write # encoded structs
10295 writeVarUint(restEncoder, partStructs.written);
10296 // write the rest of the fragment
10297 writeUint8Array(restEncoder, partStructs.restEncoder);
10298 }
10299 };
10300
10301 /**
10302 * @param {Uint8Array} update
10303 * @param {function(Item|GC|Skip):Item|GC|Skip} blockTransformer
10304 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} YDecoder
10305 * @param {typeof UpdateEncoderV2 | typeof UpdateEncoderV1 } YEncoder
10306 */
10307 const convertUpdateFormat = (update, blockTransformer, YDecoder, YEncoder) => {
10308 const updateDecoder = new YDecoder(createDecoder(update));
10309 const lazyDecoder = new LazyStructReader(updateDecoder, false);
10310 const updateEncoder = new YEncoder();
10311 const lazyWriter = new LazyStructWriter(updateEncoder);
10312 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
10313 writeStructToLazyStructWriter(lazyWriter, blockTransformer(curr), 0);
10314 }
10315 finishLazyStructWriting(lazyWriter);
10316 const ds = readDeleteSet(updateDecoder);
10317 writeDeleteSet(updateEncoder, ds);
10318 return updateEncoder.toUint8Array()
10319 };
10320
10321 /**
10322 * @typedef {Object} ObfuscatorOptions
10323 * @property {boolean} [ObfuscatorOptions.formatting=true]
10324 * @property {boolean} [ObfuscatorOptions.subdocs=true]
10325 * @property {boolean} [ObfuscatorOptions.yxml=true] Whether to obfuscate nodeName / hookName
10326 */
10327
10328 /**
10329 * @param {ObfuscatorOptions} obfuscator
10330 */
10331 const createObfuscator = ({ formatting = true, subdocs = true, yxml = true } = {}) => {
10332 let i = 0;
10333 const mapKeyCache = map.create();
10334 const nodeNameCache = map.create();
10335 const formattingKeyCache = map.create();
10336 const formattingValueCache = map.create();
10337 formattingValueCache.set(null, null); // end of a formatting range should always be the end of a formatting range
10338 /**
10339 * @param {Item|GC|Skip} block
10340 * @return {Item|GC|Skip}
10341 */
10342 return block => {
10343 switch (block.constructor) {
10344 case GC:
10345 case Skip:
10346 return block
10347 case Item: {
10348 const item = /** @type {Item} */ (block);
10349 const content = item.content;
10350 switch (content.constructor) {
10351 case ContentDeleted:
10352 break
10353 case ContentType: {
10354 if (yxml) {
10355 const type = /** @type {ContentType} */ (content).type;
10356 if (type instanceof YXmlElement) {
10357 type.nodeName = map.setIfUndefined(nodeNameCache, type.nodeName, () => 'node-' + i);
10358 }
10359 if (type instanceof YXmlHook) {
10360 type.hookName = map.setIfUndefined(nodeNameCache, type.hookName, () => 'hook-' + i);
10361 }
10362 }
10363 break
10364 }
10365 case ContentAny: {
10366 const c = /** @type {ContentAny} */ (content);
10367 c.arr = c.arr.map(() => i);
10368 break
10369 }
10370 case ContentBinary: {
10371 const c = /** @type {ContentBinary} */ (content);
10372 c.content = new Uint8Array([i]);
10373 break
10374 }
10375 case ContentDoc: {
10376 const c = /** @type {ContentDoc} */ (content);
10377 if (subdocs) {
10378 c.opts = {};
10379 c.doc.guid = i + '';
10380 }
10381 break
10382 }
10383 case ContentEmbed: {
10384 const c = /** @type {ContentEmbed} */ (content);
10385 c.embed = {};
10386 break
10387 }
10388 case ContentFormat: {
10389 const c = /** @type {ContentFormat} */ (content);
10390 if (formatting) {
10391 c.key = map.setIfUndefined(formattingKeyCache, c.key, () => i + '');
10392 c.value = map.setIfUndefined(formattingValueCache, c.value, () => ({ i }));
10393 }
10394 break
10395 }
10396 case ContentJSON: {
10397 const c = /** @type {ContentJSON} */ (content);
10398 c.arr = c.arr.map(() => i);
10399 break
10400 }
10401 case ContentString: {
10402 const c = /** @type {ContentString} */ (content);
10403 c.str = string.repeat((i % 10) + '', c.str.length);
10404 break
10405 }
10406 default:
10407 // unknown content type
10408 error.unexpectedCase();
10409 }
10410 if (item.parentSub) {
10411 item.parentSub = map.setIfUndefined(mapKeyCache, item.parentSub, () => i + '');
10412 }
10413 i++;
10414 return block
10415 }
10416 default:
10417 // unknown block-type
10418 error.unexpectedCase();
10419 }
10420 }
10421 };
10422
10423 /**
10424 * This function obfuscates the content of a Yjs update. This is useful to share
10425 * buggy Yjs documents while significantly limiting the possibility that a
10426 * developer can on the user. Note that it might still be possible to deduce
10427 * some information by analyzing the "structure" of the document or by analyzing
10428 * the typing behavior using the CRDT-related metadata that is still kept fully
10429 * intact.
10430 *
10431 * @param {Uint8Array} update
10432 * @param {ObfuscatorOptions} [opts]
10433 */
10434 const obfuscateUpdate = (update, opts) => convertUpdateFormat(update, createObfuscator(opts), UpdateDecoderV1, UpdateEncoderV1);
10435
10436 /**
10437 * @param {Uint8Array} update
10438 * @param {ObfuscatorOptions} [opts]
10439 */
10440 const obfuscateUpdateV2 = (update, opts) => convertUpdateFormat(update, createObfuscator(opts), UpdateDecoderV2, UpdateEncoderV2);
10441
10442 /**
10443 * @param {Uint8Array} update
10444 */
10445 const convertUpdateFormatV1ToV2 = update => convertUpdateFormat(update, f.id, UpdateDecoderV1, UpdateEncoderV2);
10446
10447 /**
10448 * @param {Uint8Array} update
10449 */
10450 const convertUpdateFormatV2ToV1 = update => convertUpdateFormat(update, id, UpdateDecoderV2, UpdateEncoderV1);
10451
10452 const errorComputeChanges = 'You must not compute changes after the event-handler fired.';
10453
10454 /**
10455 * @template {AbstractType<any>} T
10456 * YEvent describes the changes on a YType.
10457 */
10458 class YEvent {
10459 /**
10460 * @param {T} target The changed type.
10461 * @param {Transaction} transaction
10462 */
10463 constructor (target, transaction) {
10464 /**
10465 * The type on which this event was created on.
10466 * @type {T}
10467 */
10468 this.target = target;
10469 /**
10470 * The current target on which the observe callback is called.
10471 * @type {AbstractType<any>}
10472 */
10473 this.currentTarget = target;
10474 /**
10475 * The transaction that triggered this event.
10476 * @type {Transaction}
10477 */
10478 this.transaction = transaction;
10479 /**
10480 * @type {Object|null}
10481 */
10482 this._changes = null;
10483 /**
10484 * @type {null | Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>}
10485 */
10486 this._keys = null;
10487 /**
10488 * @type {null | Array<{ insert?: string | Array<any> | object | AbstractType<any>, retain?: number, delete?: number, attributes?: Object<string, any> }>}
10489 */
10490 this._delta = null;
10491 /**
10492 * @type {Array<string|number>|null}
10493 */
10494 this._path = null;
10495 }
10496
10497 /**
10498 * Computes the path from `y` to the changed type.
10499 *
10500 * @todo v14 should standardize on path: Array<{parent, index}> because that is easier to work with.
10501 *
10502 * The following property holds:
10503 * @example
10504 * let type = y
10505 * event.path.forEach(dir => {
10506 * type = type.get(dir)
10507 * })
10508 * type === event.target // => true
10509 */
10510 get path () {
10511 return this._path || (this._path = getPathTo(this.currentTarget, this.target))
10512 }
10513
10514 /**
10515 * Check if a struct is deleted by this event.
10516 *
10517 * In contrast to change.deleted, this method also returns true if the struct was added and then deleted.
10518 *
10519 * @param {AbstractStruct} struct
10520 * @return {boolean}
10521 */
10522 deletes (struct) {
10523 return isDeleted(this.transaction.deleteSet, struct.id)
10524 }
10525
10526 /**
10527 * @type {Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>}
10528 */
10529 get keys () {
10530 if (this._keys === null) {
10531 if (this.transaction.doc._transactionCleanups.length === 0) {
10532 throw error_create(errorComputeChanges)
10533 }
10534 const keys = new Map();
10535 const target = this.target;
10536 const changed = /** @type Set<string|null> */ (this.transaction.changed.get(target));
10537 changed.forEach(key => {
10538 if (key !== null) {
10539 const item = /** @type {Item} */ (target._map.get(key));
10540 /**
10541 * @type {'delete' | 'add' | 'update'}
10542 */
10543 let action;
10544 let oldValue;
10545 if (this.adds(item)) {
10546 let prev = item.left;
10547 while (prev !== null && this.adds(prev)) {
10548 prev = prev.left;
10549 }
10550 if (this.deletes(item)) {
10551 if (prev !== null && this.deletes(prev)) {
10552 action = 'delete';
10553 oldValue = last(prev.content.getContent());
10554 } else {
10555 return
10556 }
10557 } else {
10558 if (prev !== null && this.deletes(prev)) {
10559 action = 'update';
10560 oldValue = last(prev.content.getContent());
10561 } else {
10562 action = 'add';
10563 oldValue = undefined;
10564 }
10565 }
10566 } else {
10567 if (this.deletes(item)) {
10568 action = 'delete';
10569 oldValue = last(/** @type {Item} */ item.content.getContent());
10570 } else {
10571 return // nop
10572 }
10573 }
10574 keys.set(key, { action, oldValue });
10575 }
10576 });
10577 this._keys = keys;
10578 }
10579 return this._keys
10580 }
10581
10582 /**
10583 * This is a computed property. Note that this can only be safely computed during the
10584 * event call. Computing this property after other changes happened might result in
10585 * unexpected behavior (incorrect computation of deltas). A safe way to collect changes
10586 * is to store the `changes` or the `delta` object. Avoid storing the `transaction` object.
10587 *
10588 * @type {Array<{insert?: string | Array<any> | object | AbstractType<any>, retain?: number, delete?: number, attributes?: Object<string, any>}>}
10589 */
10590 get delta () {
10591 return this.changes.delta
10592 }
10593
10594 /**
10595 * Check if a struct is added by this event.
10596 *
10597 * In contrast to change.deleted, this method also returns true if the struct was added and then deleted.
10598 *
10599 * @param {AbstractStruct} struct
10600 * @return {boolean}
10601 */
10602 adds (struct) {
10603 return struct.id.clock >= (this.transaction.beforeState.get(struct.id.client) || 0)
10604 }
10605
10606 /**
10607 * This is a computed property. Note that this can only be safely computed during the
10608 * event call. Computing this property after other changes happened might result in
10609 * unexpected behavior (incorrect computation of deltas). A safe way to collect changes
10610 * is to store the `changes` or the `delta` object. Avoid storing the `transaction` object.
10611 *
10612 * @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}>}}
10613 */
10614 get changes () {
10615 let changes = this._changes;
10616 if (changes === null) {
10617 if (this.transaction.doc._transactionCleanups.length === 0) {
10618 throw error_create(errorComputeChanges)
10619 }
10620 const target = this.target;
10621 const added = set_create();
10622 const deleted = set_create();
10623 /**
10624 * @type {Array<{insert:Array<any>}|{delete:number}|{retain:number}>}
10625 */
10626 const delta = [];
10627 changes = {
10628 added,
10629 deleted,
10630 delta,
10631 keys: this.keys
10632 };
10633 const changed = /** @type Set<string|null> */ (this.transaction.changed.get(target));
10634 if (changed.has(null)) {
10635 /**
10636 * @type {any}
10637 */
10638 let lastOp = null;
10639 const packOp = () => {
10640 if (lastOp) {
10641 delta.push(lastOp);
10642 }
10643 };
10644 for (let item = target._start; item !== null; item = item.right) {
10645 if (item.deleted) {
10646 if (this.deletes(item) && !this.adds(item)) {
10647 if (lastOp === null || lastOp.delete === undefined) {
10648 packOp();
10649 lastOp = { delete: 0 };
10650 }
10651 lastOp.delete += item.length;
10652 deleted.add(item);
10653 } // else nop
10654 } else {
10655 if (this.adds(item)) {
10656 if (lastOp === null || lastOp.insert === undefined) {
10657 packOp();
10658 lastOp = { insert: [] };
10659 }
10660 lastOp.insert = lastOp.insert.concat(item.content.getContent());
10661 added.add(item);
10662 } else {
10663 if (lastOp === null || lastOp.retain === undefined) {
10664 packOp();
10665 lastOp = { retain: 0 };
10666 }
10667 lastOp.retain += item.length;
10668 }
10669 }
10670 }
10671 if (lastOp !== null && lastOp.retain === undefined) {
10672 packOp();
10673 }
10674 }
10675 this._changes = changes;
10676 }
10677 return /** @type {any} */ (changes)
10678 }
10679 }
10680
10681 /**
10682 * Compute the path from this type to the specified target.
10683 *
10684 * @example
10685 * // `child` should be accessible via `type.get(path[0]).get(path[1])..`
10686 * const path = type.getPathTo(child)
10687 * // assuming `type instanceof YArray`
10688 * console.log(path) // might look like => [2, 'key1']
10689 * child === type.get(path[0]).get(path[1])
10690 *
10691 * @param {AbstractType<any>} parent
10692 * @param {AbstractType<any>} child target
10693 * @return {Array<string|number>} Path to the target
10694 *
10695 * @private
10696 * @function
10697 */
10698 const getPathTo = (parent, child) => {
10699 const path = [];
10700 while (child._item !== null && child !== parent) {
10701 if (child._item.parentSub !== null) {
10702 // parent is map-ish
10703 path.unshift(child._item.parentSub);
10704 } else {
10705 // parent is array-ish
10706 let i = 0;
10707 let c = /** @type {AbstractType<any>} */ (child._item.parent)._start;
10708 while (c !== child._item && c !== null) {
10709 if (!c.deleted) {
10710 i++;
10711 }
10712 c = c.right;
10713 }
10714 path.unshift(i);
10715 }
10716 child = /** @type {AbstractType<any>} */ (child._item.parent);
10717 }
10718 return path
10719 };
10720
10721 const maxSearchMarker = 80;
10722
10723 /**
10724 * A unique timestamp that identifies each marker.
10725 *
10726 * Time is relative,.. this is more like an ever-increasing clock.
10727 *
10728 * @type {number}
10729 */
10730 let globalSearchMarkerTimestamp = 0;
10731
10732 class ArraySearchMarker {
10733 /**
10734 * @param {Item} p
10735 * @param {number} index
10736 */
10737 constructor (p, index) {
10738 p.marker = true;
10739 this.p = p;
10740 this.index = index;
10741 this.timestamp = globalSearchMarkerTimestamp++;
10742 }
10743 }
10744
10745 /**
10746 * @param {ArraySearchMarker} marker
10747 */
10748 const refreshMarkerTimestamp = marker => { marker.timestamp = globalSearchMarkerTimestamp++; };
10749
10750 /**
10751 * This is rather complex so this function is the only thing that should overwrite a marker
10752 *
10753 * @param {ArraySearchMarker} marker
10754 * @param {Item} p
10755 * @param {number} index
10756 */
10757 const overwriteMarker = (marker, p, index) => {
10758 marker.p.marker = false;
10759 marker.p = p;
10760 p.marker = true;
10761 marker.index = index;
10762 marker.timestamp = globalSearchMarkerTimestamp++;
10763 };
10764
10765 /**
10766 * @param {Array<ArraySearchMarker>} searchMarker
10767 * @param {Item} p
10768 * @param {number} index
10769 */
10770 const markPosition = (searchMarker, p, index) => {
10771 if (searchMarker.length >= maxSearchMarker) {
10772 // override oldest marker (we don't want to create more objects)
10773 const marker = searchMarker.reduce((a, b) => a.timestamp < b.timestamp ? a : b);
10774 overwriteMarker(marker, p, index);
10775 return marker
10776 } else {
10777 // create new marker
10778 const pm = new ArraySearchMarker(p, index);
10779 searchMarker.push(pm);
10780 return pm
10781 }
10782 };
10783
10784 /**
10785 * Search marker help us to find positions in the associative array faster.
10786 *
10787 * They speed up the process of finding a position without much bookkeeping.
10788 *
10789 * A maximum of `maxSearchMarker` objects are created.
10790 *
10791 * This function always returns a refreshed marker (updated timestamp)
10792 *
10793 * @param {AbstractType<any>} yarray
10794 * @param {number} index
10795 */
10796 const findMarker = (yarray, index) => {
10797 if (yarray._start === null || index === 0 || yarray._searchMarker === null) {
10798 return null
10799 }
10800 const marker = yarray._searchMarker.length === 0 ? null : yarray._searchMarker.reduce((a, b) => abs(index - a.index) < abs(index - b.index) ? a : b);
10801 let p = yarray._start;
10802 let pindex = 0;
10803 if (marker !== null) {
10804 p = marker.p;
10805 pindex = marker.index;
10806 refreshMarkerTimestamp(marker); // we used it, we might need to use it again
10807 }
10808 // iterate to right if possible
10809 while (p.right !== null && pindex < index) {
10810 if (!p.deleted && p.countable) {
10811 if (index < pindex + p.length) {
10812 break
10813 }
10814 pindex += p.length;
10815 }
10816 p = p.right;
10817 }
10818 // iterate to left if necessary (might be that pindex > index)
10819 while (p.left !== null && pindex > index) {
10820 p = p.left;
10821 if (!p.deleted && p.countable) {
10822 pindex -= p.length;
10823 }
10824 }
10825 // we want to make sure that p can't be merged with left, because that would screw up everything
10826 // in that cas just return what we have (it is most likely the best marker anyway)
10827 // iterate to left until p can't be merged with left
10828 while (p.left !== null && p.left.id.client === p.id.client && p.left.id.clock + p.left.length === p.id.clock) {
10829 p = p.left;
10830 if (!p.deleted && p.countable) {
10831 pindex -= p.length;
10832 }
10833 }
10834
10835 // @todo remove!
10836 // assure position
10837 // {
10838 // let start = yarray._start
10839 // let pos = 0
10840 // while (start !== p) {
10841 // if (!start.deleted && start.countable) {
10842 // pos += start.length
10843 // }
10844 // start = /** @type {Item} */ (start.right)
10845 // }
10846 // if (pos !== pindex) {
10847 // debugger
10848 // throw new Error('Gotcha position fail!')
10849 // }
10850 // }
10851 // if (marker) {
10852 // if (window.lengthes == null) {
10853 // window.lengthes = []
10854 // window.getLengthes = () => window.lengthes.sort((a, b) => a - b)
10855 // }
10856 // window.lengthes.push(marker.index - pindex)
10857 // console.log('distance', marker.index - pindex, 'len', p && p.parent.length)
10858 // }
10859 if (marker !== null && abs(marker.index - pindex) < /** @type {YText|YArray<any>} */ (p.parent).length / maxSearchMarker) {
10860 // adjust existing marker
10861 overwriteMarker(marker, p, pindex);
10862 return marker
10863 } else {
10864 // create new marker
10865 return markPosition(yarray._searchMarker, p, pindex)
10866 }
10867 };
10868
10869 /**
10870 * Update markers when a change happened.
10871 *
10872 * This should be called before doing a deletion!
10873 *
10874 * @param {Array<ArraySearchMarker>} searchMarker
10875 * @param {number} index
10876 * @param {number} len If insertion, len is positive. If deletion, len is negative.
10877 */
10878 const updateMarkerChanges = (searchMarker, index, len) => {
10879 for (let i = searchMarker.length - 1; i >= 0; i--) {
10880 const m = searchMarker[i];
10881 if (len > 0) {
10882 /**
10883 * @type {Item|null}
10884 */
10885 let p = m.p;
10886 p.marker = false;
10887 // Ideally we just want to do a simple position comparison, but this will only work if
10888 // search markers don't point to deleted items for formats.
10889 // Iterate marker to prev undeleted countable position so we know what to do when updating a position
10890 while (p && (p.deleted || !p.countable)) {
10891 p = p.left;
10892 if (p && !p.deleted && p.countable) {
10893 // adjust position. the loop should break now
10894 m.index -= p.length;
10895 }
10896 }
10897 if (p === null || p.marker === true) {
10898 // remove search marker if updated position is null or if position is already marked
10899 searchMarker.splice(i, 1);
10900 continue
10901 }
10902 m.p = p;
10903 p.marker = true;
10904 }
10905 if (index < m.index || (len > 0 && index === m.index)) { // a simple index <= m.index check would actually suffice
10906 m.index = max(index, m.index + len);
10907 }
10908 }
10909 };
10910
10911 /**
10912 * Accumulate all (list) children of a type and return them as an Array.
10913 *
10914 * @param {AbstractType<any>} t
10915 * @return {Array<Item>}
10916 */
10917 const getTypeChildren = t => {
10918 let s = t._start;
10919 const arr = [];
10920 while (s) {
10921 arr.push(s);
10922 s = s.right;
10923 }
10924 return arr
10925 };
10926
10927 /**
10928 * Call event listeners with an event. This will also add an event to all
10929 * parents (for `.observeDeep` handlers).
10930 *
10931 * @template EventType
10932 * @param {AbstractType<EventType>} type
10933 * @param {Transaction} transaction
10934 * @param {EventType} event
10935 */
10936 const callTypeObservers = (type, transaction, event) => {
10937 const changedType = type;
10938 const changedParentTypes = transaction.changedParentTypes;
10939 while (true) {
10940 // @ts-ignore
10941 setIfUndefined(changedParentTypes, type, () => []).push(event);
10942 if (type._item === null) {
10943 break
10944 }
10945 type = /** @type {AbstractType<any>} */ (type._item.parent);
10946 }
10947 callEventHandlerListeners(changedType._eH, event, transaction);
10948 };
10949
10950 /**
10951 * @template EventType
10952 * Abstract Yjs Type class
10953 */
10954 class AbstractType {
10955 constructor () {
10956 /**
10957 * @type {Item|null}
10958 */
10959 this._item = null;
10960 /**
10961 * @type {Map<string,Item>}
10962 */
10963 this._map = new Map();
10964 /**
10965 * @type {Item|null}
10966 */
10967 this._start = null;
10968 /**
10969 * @type {Doc|null}
10970 */
10971 this.doc = null;
10972 this._length = 0;
10973 /**
10974 * Event handlers
10975 * @type {EventHandler<EventType,Transaction>}
10976 */
10977 this._eH = createEventHandler();
10978 /**
10979 * Deep event handlers
10980 * @type {EventHandler<Array<YEvent<any>>,Transaction>}
10981 */
10982 this._dEH = createEventHandler();
10983 /**
10984 * @type {null | Array<ArraySearchMarker>}
10985 */
10986 this._searchMarker = null;
10987 }
10988
10989 /**
10990 * @return {AbstractType<any>|null}
10991 */
10992 get parent () {
10993 return this._item ? /** @type {AbstractType<any>} */ (this._item.parent) : null
10994 }
10995
10996 /**
10997 * Integrate this type into the Yjs instance.
10998 *
10999 * * Save this struct in the os
11000 * * This type is sent to other client
11001 * * Observer functions are fired
11002 *
11003 * @param {Doc} y The Yjs instance
11004 * @param {Item|null} item
11005 */
11006 _integrate (y, item) {
11007 this.doc = y;
11008 this._item = item;
11009 }
11010
11011 /**
11012 * @return {AbstractType<EventType>}
11013 */
11014 _copy () {
11015 throw methodUnimplemented()
11016 }
11017
11018 /**
11019 * @return {AbstractType<EventType>}
11020 */
11021 clone () {
11022 throw methodUnimplemented()
11023 }
11024
11025 /**
11026 * @param {UpdateEncoderV1 | UpdateEncoderV2} _encoder
11027 */
11028 _write (_encoder) { }
11029
11030 /**
11031 * The first non-deleted item
11032 */
11033 get _first () {
11034 let n = this._start;
11035 while (n !== null && n.deleted) {
11036 n = n.right;
11037 }
11038 return n
11039 }
11040
11041 /**
11042 * Creates YEvent and calls all type observers.
11043 * Must be implemented by each type.
11044 *
11045 * @param {Transaction} transaction
11046 * @param {Set<null|string>} _parentSubs Keys changed on this type. `null` if list was modified.
11047 */
11048 _callObserver (transaction, _parentSubs) {
11049 if (!transaction.local && this._searchMarker) {
11050 this._searchMarker.length = 0;
11051 }
11052 }
11053
11054 /**
11055 * Observe all events that are created on this type.
11056 *
11057 * @param {function(EventType, Transaction):void} f Observer function
11058 */
11059 observe (f) {
11060 addEventHandlerListener(this._eH, f);
11061 }
11062
11063 /**
11064 * Observe all events that are created by this type and its children.
11065 *
11066 * @param {function(Array<YEvent<any>>,Transaction):void} f Observer function
11067 */
11068 observeDeep (f) {
11069 addEventHandlerListener(this._dEH, f);
11070 }
11071
11072 /**
11073 * Unregister an observer function.
11074 *
11075 * @param {function(EventType,Transaction):void} f Observer function
11076 */
11077 unobserve (f) {
11078 removeEventHandlerListener(this._eH, f);
11079 }
11080
11081 /**
11082 * Unregister an observer function.
11083 *
11084 * @param {function(Array<YEvent<any>>,Transaction):void} f Observer function
11085 */
11086 unobserveDeep (f) {
11087 removeEventHandlerListener(this._dEH, f);
11088 }
11089
11090 /**
11091 * @abstract
11092 * @return {any}
11093 */
11094 toJSON () {}
11095 }
11096
11097 /**
11098 * @param {AbstractType<any>} type
11099 * @param {number} start
11100 * @param {number} end
11101 * @return {Array<any>}
11102 *
11103 * @private
11104 * @function
11105 */
11106 const typeListSlice = (type, start, end) => {
11107 if (start < 0) {
11108 start = type._length + start;
11109 }
11110 if (end < 0) {
11111 end = type._length + end;
11112 }
11113 let len = end - start;
11114 const cs = [];
11115 let n = type._start;
11116 while (n !== null && len > 0) {
11117 if (n.countable && !n.deleted) {
11118 const c = n.content.getContent();
11119 if (c.length <= start) {
11120 start -= c.length;
11121 } else {
11122 for (let i = start; i < c.length && len > 0; i++) {
11123 cs.push(c[i]);
11124 len--;
11125 }
11126 start = 0;
11127 }
11128 }
11129 n = n.right;
11130 }
11131 return cs
11132 };
11133
11134 /**
11135 * @param {AbstractType<any>} type
11136 * @return {Array<any>}
11137 *
11138 * @private
11139 * @function
11140 */
11141 const typeListToArray = type => {
11142 const cs = [];
11143 let n = type._start;
11144 while (n !== null) {
11145 if (n.countable && !n.deleted) {
11146 const c = n.content.getContent();
11147 for (let i = 0; i < c.length; i++) {
11148 cs.push(c[i]);
11149 }
11150 }
11151 n = n.right;
11152 }
11153 return cs
11154 };
11155
11156 /**
11157 * @param {AbstractType<any>} type
11158 * @param {Snapshot} snapshot
11159 * @return {Array<any>}
11160 *
11161 * @private
11162 * @function
11163 */
11164 const typeListToArraySnapshot = (type, snapshot) => {
11165 const cs = [];
11166 let n = type._start;
11167 while (n !== null) {
11168 if (n.countable && isVisible(n, snapshot)) {
11169 const c = n.content.getContent();
11170 for (let i = 0; i < c.length; i++) {
11171 cs.push(c[i]);
11172 }
11173 }
11174 n = n.right;
11175 }
11176 return cs
11177 };
11178
11179 /**
11180 * Executes a provided function on once on overy element of this YArray.
11181 *
11182 * @param {AbstractType<any>} type
11183 * @param {function(any,number,any):void} f A function to execute on every element of this YArray.
11184 *
11185 * @private
11186 * @function
11187 */
11188 const typeListForEach = (type, f) => {
11189 let index = 0;
11190 let n = type._start;
11191 while (n !== null) {
11192 if (n.countable && !n.deleted) {
11193 const c = n.content.getContent();
11194 for (let i = 0; i < c.length; i++) {
11195 f(c[i], index++, type);
11196 }
11197 }
11198 n = n.right;
11199 }
11200 };
11201
11202 /**
11203 * @template C,R
11204 * @param {AbstractType<any>} type
11205 * @param {function(C,number,AbstractType<any>):R} f
11206 * @return {Array<R>}
11207 *
11208 * @private
11209 * @function
11210 */
11211 const typeListMap = (type, f) => {
11212 /**
11213 * @type {Array<any>}
11214 */
11215 const result = [];
11216 typeListForEach(type, (c, i) => {
11217 result.push(f(c, i, type));
11218 });
11219 return result
11220 };
11221
11222 /**
11223 * @param {AbstractType<any>} type
11224 * @return {IterableIterator<any>}
11225 *
11226 * @private
11227 * @function
11228 */
11229 const typeListCreateIterator = type => {
11230 let n = type._start;
11231 /**
11232 * @type {Array<any>|null}
11233 */
11234 let currentContent = null;
11235 let currentContentIndex = 0;
11236 return {
11237 [Symbol.iterator] () {
11238 return this
11239 },
11240 next: () => {
11241 // find some content
11242 if (currentContent === null) {
11243 while (n !== null && n.deleted) {
11244 n = n.right;
11245 }
11246 // check if we reached the end, no need to check currentContent, because it does not exist
11247 if (n === null) {
11248 return {
11249 done: true,
11250 value: undefined
11251 }
11252 }
11253 // we found n, so we can set currentContent
11254 currentContent = n.content.getContent();
11255 currentContentIndex = 0;
11256 n = n.right; // we used the content of n, now iterate to next
11257 }
11258 const value = currentContent[currentContentIndex++];
11259 // check if we need to empty currentContent
11260 if (currentContent.length <= currentContentIndex) {
11261 currentContent = null;
11262 }
11263 return {
11264 done: false,
11265 value
11266 }
11267 }
11268 }
11269 };
11270
11271 /**
11272 * @param {AbstractType<any>} type
11273 * @param {number} index
11274 * @return {any}
11275 *
11276 * @private
11277 * @function
11278 */
11279 const typeListGet = (type, index) => {
11280 const marker = findMarker(type, index);
11281 let n = type._start;
11282 if (marker !== null) {
11283 n = marker.p;
11284 index -= marker.index;
11285 }
11286 for (; n !== null; n = n.right) {
11287 if (!n.deleted && n.countable) {
11288 if (index < n.length) {
11289 return n.content.getContent()[index]
11290 }
11291 index -= n.length;
11292 }
11293 }
11294 };
11295
11296 /**
11297 * @param {Transaction} transaction
11298 * @param {AbstractType<any>} parent
11299 * @param {Item?} referenceItem
11300 * @param {Array<Object<string,any>|Array<any>|boolean|number|null|string|Uint8Array>} content
11301 *
11302 * @private
11303 * @function
11304 */
11305 const typeListInsertGenericsAfter = (transaction, parent, referenceItem, content) => {
11306 let left = referenceItem;
11307 const doc = transaction.doc;
11308 const ownClientId = doc.clientID;
11309 const store = doc.store;
11310 const right = referenceItem === null ? parent._start : referenceItem.right;
11311 /**
11312 * @type {Array<Object|Array<any>|number|null>}
11313 */
11314 let jsonContent = [];
11315 const packJsonContent = () => {
11316 if (jsonContent.length > 0) {
11317 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentAny(jsonContent));
11318 left.integrate(transaction, 0);
11319 jsonContent = [];
11320 }
11321 };
11322 content.forEach(c => {
11323 if (c === null) {
11324 jsonContent.push(c);
11325 } else {
11326 switch (c.constructor) {
11327 case Number:
11328 case Object:
11329 case Boolean:
11330 case Array:
11331 case String:
11332 jsonContent.push(c);
11333 break
11334 default:
11335 packJsonContent();
11336 switch (c.constructor) {
11337 case Uint8Array:
11338 case ArrayBuffer:
11339 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))));
11340 left.integrate(transaction, 0);
11341 break
11342 case Doc:
11343 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentDoc(/** @type {Doc} */ (c)));
11344 left.integrate(transaction, 0);
11345 break
11346 default:
11347 if (c instanceof AbstractType) {
11348 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentType(c));
11349 left.integrate(transaction, 0);
11350 } else {
11351 throw new Error('Unexpected content type in insert operation')
11352 }
11353 }
11354 }
11355 }
11356 });
11357 packJsonContent();
11358 };
11359
11360 const lengthExceeded = error_create('Length exceeded!');
11361
11362 /**
11363 * @param {Transaction} transaction
11364 * @param {AbstractType<any>} parent
11365 * @param {number} index
11366 * @param {Array<Object<string,any>|Array<any>|number|null|string|Uint8Array>} content
11367 *
11368 * @private
11369 * @function
11370 */
11371 const typeListInsertGenerics = (transaction, parent, index, content) => {
11372 if (index > parent._length) {
11373 throw lengthExceeded
11374 }
11375 if (index === 0) {
11376 if (parent._searchMarker) {
11377 updateMarkerChanges(parent._searchMarker, index, content.length);
11378 }
11379 return typeListInsertGenericsAfter(transaction, parent, null, content)
11380 }
11381 const startIndex = index;
11382 const marker = findMarker(parent, index);
11383 let n = parent._start;
11384 if (marker !== null) {
11385 n = marker.p;
11386 index -= marker.index;
11387 // we need to iterate one to the left so that the algorithm works
11388 if (index === 0) {
11389 // @todo refactor this as it actually doesn't consider formats
11390 n = n.prev; // important! get the left undeleted item so that we can actually decrease index
11391 index += (n && n.countable && !n.deleted) ? n.length : 0;
11392 }
11393 }
11394 for (; n !== null; n = n.right) {
11395 if (!n.deleted && n.countable) {
11396 if (index <= n.length) {
11397 if (index < n.length) {
11398 // insert in-between
11399 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + index));
11400 }
11401 break
11402 }
11403 index -= n.length;
11404 }
11405 }
11406 if (parent._searchMarker) {
11407 updateMarkerChanges(parent._searchMarker, startIndex, content.length);
11408 }
11409 return typeListInsertGenericsAfter(transaction, parent, n, content)
11410 };
11411
11412 /**
11413 * Pushing content is special as we generally want to push after the last item. So we don't have to update
11414 * the serach marker.
11415 *
11416 * @param {Transaction} transaction
11417 * @param {AbstractType<any>} parent
11418 * @param {Array<Object<string,any>|Array<any>|number|null|string|Uint8Array>} content
11419 *
11420 * @private
11421 * @function
11422 */
11423 const typeListPushGenerics = (transaction, parent, content) => {
11424 // Use the marker with the highest index and iterate to the right.
11425 const marker = (parent._searchMarker || []).reduce((maxMarker, currMarker) => currMarker.index > maxMarker.index ? currMarker : maxMarker, { index: 0, p: parent._start });
11426 let n = marker.p;
11427 if (n) {
11428 while (n.right) {
11429 n = n.right;
11430 }
11431 }
11432 return typeListInsertGenericsAfter(transaction, parent, n, content)
11433 };
11434
11435 /**
11436 * @param {Transaction} transaction
11437 * @param {AbstractType<any>} parent
11438 * @param {number} index
11439 * @param {number} length
11440 *
11441 * @private
11442 * @function
11443 */
11444 const typeListDelete = (transaction, parent, index, length) => {
11445 if (length === 0) { return }
11446 const startIndex = index;
11447 const startLength = length;
11448 const marker = findMarker(parent, index);
11449 let n = parent._start;
11450 if (marker !== null) {
11451 n = marker.p;
11452 index -= marker.index;
11453 }
11454 // compute the first item to be deleted
11455 for (; n !== null && index > 0; n = n.right) {
11456 if (!n.deleted && n.countable) {
11457 if (index < n.length) {
11458 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + index));
11459 }
11460 index -= n.length;
11461 }
11462 }
11463 // delete all items until done
11464 while (length > 0 && n !== null) {
11465 if (!n.deleted) {
11466 if (length < n.length) {
11467 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + length));
11468 }
11469 n.delete(transaction);
11470 length -= n.length;
11471 }
11472 n = n.right;
11473 }
11474 if (length > 0) {
11475 throw lengthExceeded
11476 }
11477 if (parent._searchMarker) {
11478 updateMarkerChanges(parent._searchMarker, startIndex, -startLength + length /* in case we remove the above exception */);
11479 }
11480 };
11481
11482 /**
11483 * @param {Transaction} transaction
11484 * @param {AbstractType<any>} parent
11485 * @param {string} key
11486 *
11487 * @private
11488 * @function
11489 */
11490 const typeMapDelete = (transaction, parent, key) => {
11491 const c = parent._map.get(key);
11492 if (c !== undefined) {
11493 c.delete(transaction);
11494 }
11495 };
11496
11497 /**
11498 * @param {Transaction} transaction
11499 * @param {AbstractType<any>} parent
11500 * @param {string} key
11501 * @param {Object|number|null|Array<any>|string|Uint8Array|AbstractType<any>} value
11502 *
11503 * @private
11504 * @function
11505 */
11506 const typeMapSet = (transaction, parent, key, value) => {
11507 const left = parent._map.get(key) || null;
11508 const doc = transaction.doc;
11509 const ownClientId = doc.clientID;
11510 let content;
11511 if (value == null) {
11512 content = new ContentAny([value]);
11513 } else {
11514 switch (value.constructor) {
11515 case Number:
11516 case Object:
11517 case Boolean:
11518 case Array:
11519 case String:
11520 content = new ContentAny([value]);
11521 break
11522 case Uint8Array:
11523 content = new ContentBinary(/** @type {Uint8Array} */ (value));
11524 break
11525 case Doc:
11526 content = new ContentDoc(/** @type {Doc} */ (value));
11527 break
11528 default:
11529 if (value instanceof AbstractType) {
11530 content = new ContentType(value);
11531 } else {
11532 throw new Error('Unexpected content type')
11533 }
11534 }
11535 }
11536 new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, null, null, parent, key, content).integrate(transaction, 0);
11537 };
11538
11539 /**
11540 * @param {AbstractType<any>} parent
11541 * @param {string} key
11542 * @return {Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined}
11543 *
11544 * @private
11545 * @function
11546 */
11547 const typeMapGet = (parent, key) => {
11548 const val = parent._map.get(key);
11549 return val !== undefined && !val.deleted ? val.content.getContent()[val.length - 1] : undefined
11550 };
11551
11552 /**
11553 * @param {AbstractType<any>} parent
11554 * @return {Object<string,Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined>}
11555 *
11556 * @private
11557 * @function
11558 */
11559 const typeMapGetAll = (parent) => {
11560 /**
11561 * @type {Object<string,any>}
11562 */
11563 const res = {};
11564 parent._map.forEach((value, key) => {
11565 if (!value.deleted) {
11566 res[key] = value.content.getContent()[value.length - 1];
11567 }
11568 });
11569 return res
11570 };
11571
11572 /**
11573 * @param {AbstractType<any>} parent
11574 * @param {string} key
11575 * @return {boolean}
11576 *
11577 * @private
11578 * @function
11579 */
11580 const typeMapHas = (parent, key) => {
11581 const val = parent._map.get(key);
11582 return val !== undefined && !val.deleted
11583 };
11584
11585 /**
11586 * @param {AbstractType<any>} parent
11587 * @param {string} key
11588 * @param {Snapshot} snapshot
11589 * @return {Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined}
11590 *
11591 * @private
11592 * @function
11593 */
11594 const typeMapGetSnapshot = (parent, key, snapshot) => {
11595 let v = parent._map.get(key) || null;
11596 while (v !== null && (!snapshot.sv.has(v.id.client) || v.id.clock >= (snapshot.sv.get(v.id.client) || 0))) {
11597 v = v.left;
11598 }
11599 return v !== null && isVisible(v, snapshot) ? v.content.getContent()[v.length - 1] : undefined
11600 };
11601
11602 /**
11603 * @param {Map<string,Item>} map
11604 * @return {IterableIterator<Array<any>>}
11605 *
11606 * @private
11607 * @function
11608 */
11609 const createMapIterator = map => iteratorFilter(map.entries(), /** @param {any} entry */ entry => !entry[1].deleted);
11610
11611 /**
11612 * @module YArray
11613 */
11614
11615 /**
11616 * Event that describes the changes on a YArray
11617 * @template T
11618 * @extends YEvent<YArray<T>>
11619 */
11620 class YArrayEvent extends YEvent {
11621 /**
11622 * @param {YArray<T>} yarray The changed type
11623 * @param {Transaction} transaction The transaction object
11624 */
11625 constructor (yarray, transaction) {
11626 super(yarray, transaction);
11627 this._transaction = transaction;
11628 }
11629 }
11630
11631 /**
11632 * A shared Array implementation.
11633 * @template T
11634 * @extends AbstractType<YArrayEvent<T>>
11635 * @implements {Iterable<T>}
11636 */
11637 class YArray extends AbstractType {
11638 constructor () {
11639 super();
11640 /**
11641 * @type {Array<any>?}
11642 * @private
11643 */
11644 this._prelimContent = [];
11645 /**
11646 * @type {Array<ArraySearchMarker>}
11647 */
11648 this._searchMarker = [];
11649 }
11650
11651 /**
11652 * Construct a new YArray containing the specified items.
11653 * @template {Object<string,any>|Array<any>|number|null|string|Uint8Array} T
11654 * @param {Array<T>} items
11655 * @return {YArray<T>}
11656 */
11657 static from (items) {
11658 /**
11659 * @type {YArray<T>}
11660 */
11661 const a = new YArray();
11662 a.push(items);
11663 return a
11664 }
11665
11666 /**
11667 * Integrate this type into the Yjs instance.
11668 *
11669 * * Save this struct in the os
11670 * * This type is sent to other client
11671 * * Observer functions are fired
11672 *
11673 * @param {Doc} y The Yjs instance
11674 * @param {Item} item
11675 */
11676 _integrate (y, item) {
11677 super._integrate(y, item);
11678 this.insert(0, /** @type {Array<any>} */ (this._prelimContent));
11679 this._prelimContent = null;
11680 }
11681
11682 /**
11683 * @return {YArray<T>}
11684 */
11685 _copy () {
11686 return new YArray()
11687 }
11688
11689 /**
11690 * @return {YArray<T>}
11691 */
11692 clone () {
11693 /**
11694 * @type {YArray<T>}
11695 */
11696 const arr = new YArray();
11697 arr.insert(0, this.toArray().map(el =>
11698 el instanceof AbstractType ? /** @type {typeof el} */ (el.clone()) : el
11699 ));
11700 return arr
11701 }
11702
11703 get length () {
11704 return this._prelimContent === null ? this._length : this._prelimContent.length
11705 }
11706
11707 /**
11708 * Creates YArrayEvent and calls observers.
11709 *
11710 * @param {Transaction} transaction
11711 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
11712 */
11713 _callObserver (transaction, parentSubs) {
11714 super._callObserver(transaction, parentSubs);
11715 callTypeObservers(this, transaction, new YArrayEvent(this, transaction));
11716 }
11717
11718 /**
11719 * Inserts new content at an index.
11720 *
11721 * Important: This function expects an array of content. Not just a content
11722 * object. The reason for this "weirdness" is that inserting several elements
11723 * is very efficient when it is done as a single operation.
11724 *
11725 * @example
11726 * // Insert character 'a' at position 0
11727 * yarray.insert(0, ['a'])
11728 * // Insert numbers 1, 2 at position 1
11729 * yarray.insert(1, [1, 2])
11730 *
11731 * @param {number} index The index to insert content at.
11732 * @param {Array<T>} content The array of content
11733 */
11734 insert (index, content) {
11735 if (this.doc !== null) {
11736 transact(this.doc, transaction => {
11737 typeListInsertGenerics(transaction, this, index, /** @type {any} */ (content));
11738 });
11739 } else {
11740 /** @type {Array<any>} */ (this._prelimContent).splice(index, 0, ...content);
11741 }
11742 }
11743
11744 /**
11745 * Appends content to this YArray.
11746 *
11747 * @param {Array<T>} content Array of content to append.
11748 *
11749 * @todo Use the following implementation in all types.
11750 */
11751 push (content) {
11752 if (this.doc !== null) {
11753 transact(this.doc, transaction => {
11754 typeListPushGenerics(transaction, this, /** @type {any} */ (content));
11755 });
11756 } else {
11757 /** @type {Array<any>} */ (this._prelimContent).push(...content);
11758 }
11759 }
11760
11761 /**
11762 * Preppends content to this YArray.
11763 *
11764 * @param {Array<T>} content Array of content to preppend.
11765 */
11766 unshift (content) {
11767 this.insert(0, content);
11768 }
11769
11770 /**
11771 * Deletes elements starting from an index.
11772 *
11773 * @param {number} index Index at which to start deleting elements
11774 * @param {number} length The number of elements to remove. Defaults to 1.
11775 */
11776 delete (index, length = 1) {
11777 if (this.doc !== null) {
11778 transact(this.doc, transaction => {
11779 typeListDelete(transaction, this, index, length);
11780 });
11781 } else {
11782 /** @type {Array<any>} */ (this._prelimContent).splice(index, length);
11783 }
11784 }
11785
11786 /**
11787 * Returns the i-th element from a YArray.
11788 *
11789 * @param {number} index The index of the element to return from the YArray
11790 * @return {T}
11791 */
11792 get (index) {
11793 return typeListGet(this, index)
11794 }
11795
11796 /**
11797 * Transforms this YArray to a JavaScript Array.
11798 *
11799 * @return {Array<T>}
11800 */
11801 toArray () {
11802 return typeListToArray(this)
11803 }
11804
11805 /**
11806 * Transforms this YArray to a JavaScript Array.
11807 *
11808 * @param {number} [start]
11809 * @param {number} [end]
11810 * @return {Array<T>}
11811 */
11812 slice (start = 0, end = this.length) {
11813 return typeListSlice(this, start, end)
11814 }
11815
11816 /**
11817 * Transforms this Shared Type to a JSON object.
11818 *
11819 * @return {Array<any>}
11820 */
11821 toJSON () {
11822 return this.map(c => c instanceof AbstractType ? c.toJSON() : c)
11823 }
11824
11825 /**
11826 * Returns an Array with the result of calling a provided function on every
11827 * element of this YArray.
11828 *
11829 * @template M
11830 * @param {function(T,number,YArray<T>):M} f Function that produces an element of the new Array
11831 * @return {Array<M>} A new array with each element being the result of the
11832 * callback function
11833 */
11834 map (f) {
11835 return typeListMap(this, /** @type {any} */ (f))
11836 }
11837
11838 /**
11839 * Executes a provided function once on overy element of this YArray.
11840 *
11841 * @param {function(T,number,YArray<T>):void} f A function to execute on every element of this YArray.
11842 */
11843 forEach (f) {
11844 typeListForEach(this, f);
11845 }
11846
11847 /**
11848 * @return {IterableIterator<T>}
11849 */
11850 [Symbol.iterator] () {
11851 return typeListCreateIterator(this)
11852 }
11853
11854 /**
11855 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
11856 */
11857 _write (encoder) {
11858 encoder.writeTypeRef(YArrayRefID);
11859 }
11860 }
11861
11862 /**
11863 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
11864 *
11865 * @private
11866 * @function
11867 */
11868 const readYArray = _decoder => new YArray();
11869
11870 /**
11871 * @template T
11872 * @extends YEvent<YMap<T>>
11873 * Event that describes the changes on a YMap.
11874 */
11875 class YMapEvent extends YEvent {
11876 /**
11877 * @param {YMap<T>} ymap The YArray that changed.
11878 * @param {Transaction} transaction
11879 * @param {Set<any>} subs The keys that changed.
11880 */
11881 constructor (ymap, transaction, subs) {
11882 super(ymap, transaction);
11883 this.keysChanged = subs;
11884 }
11885 }
11886
11887 /**
11888 * @template MapType
11889 * A shared Map implementation.
11890 *
11891 * @extends AbstractType<YMapEvent<MapType>>
11892 * @implements {Iterable<MapType>}
11893 */
11894 class YMap extends AbstractType {
11895 /**
11896 *
11897 * @param {Iterable<readonly [string, any]>=} entries - an optional iterable to initialize the YMap
11898 */
11899 constructor (entries) {
11900 super();
11901 /**
11902 * @type {Map<string,any>?}
11903 * @private
11904 */
11905 this._prelimContent = null;
11906
11907 if (entries === undefined) {
11908 this._prelimContent = new Map();
11909 } else {
11910 this._prelimContent = new Map(entries);
11911 }
11912 }
11913
11914 /**
11915 * Integrate this type into the Yjs instance.
11916 *
11917 * * Save this struct in the os
11918 * * This type is sent to other client
11919 * * Observer functions are fired
11920 *
11921 * @param {Doc} y The Yjs instance
11922 * @param {Item} item
11923 */
11924 _integrate (y, item) {
11925 super._integrate(y, item)
11926 ;/** @type {Map<string, any>} */ (this._prelimContent).forEach((value, key) => {
11927 this.set(key, value);
11928 });
11929 this._prelimContent = null;
11930 }
11931
11932 /**
11933 * @return {YMap<MapType>}
11934 */
11935 _copy () {
11936 return new YMap()
11937 }
11938
11939 /**
11940 * @return {YMap<MapType>}
11941 */
11942 clone () {
11943 /**
11944 * @type {YMap<MapType>}
11945 */
11946 const map = new YMap();
11947 this.forEach((value, key) => {
11948 map.set(key, value instanceof AbstractType ? /** @type {typeof value} */ (value.clone()) : value);
11949 });
11950 return map
11951 }
11952
11953 /**
11954 * Creates YMapEvent and calls observers.
11955 *
11956 * @param {Transaction} transaction
11957 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
11958 */
11959 _callObserver (transaction, parentSubs) {
11960 callTypeObservers(this, transaction, new YMapEvent(this, transaction, parentSubs));
11961 }
11962
11963 /**
11964 * Transforms this Shared Type to a JSON object.
11965 *
11966 * @return {Object<string,any>}
11967 */
11968 toJSON () {
11969 /**
11970 * @type {Object<string,MapType>}
11971 */
11972 const map = {};
11973 this._map.forEach((item, key) => {
11974 if (!item.deleted) {
11975 const v = item.content.getContent()[item.length - 1];
11976 map[key] = v instanceof AbstractType ? v.toJSON() : v;
11977 }
11978 });
11979 return map
11980 }
11981
11982 /**
11983 * Returns the size of the YMap (count of key/value pairs)
11984 *
11985 * @return {number}
11986 */
11987 get size () {
11988 return [...createMapIterator(this._map)].length
11989 }
11990
11991 /**
11992 * Returns the keys for each element in the YMap Type.
11993 *
11994 * @return {IterableIterator<string>}
11995 */
11996 keys () {
11997 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => v[0])
11998 }
11999
12000 /**
12001 * Returns the values for each element in the YMap Type.
12002 *
12003 * @return {IterableIterator<any>}
12004 */
12005 values () {
12006 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => v[1].content.getContent()[v[1].length - 1])
12007 }
12008
12009 /**
12010 * Returns an Iterator of [key, value] pairs
12011 *
12012 * @return {IterableIterator<any>}
12013 */
12014 entries () {
12015 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => [v[0], v[1].content.getContent()[v[1].length - 1]])
12016 }
12017
12018 /**
12019 * Executes a provided function on once on every key-value pair.
12020 *
12021 * @param {function(MapType,string,YMap<MapType>):void} f A function to execute on every element of this YArray.
12022 */
12023 forEach (f) {
12024 this._map.forEach((item, key) => {
12025 if (!item.deleted) {
12026 f(item.content.getContent()[item.length - 1], key, this);
12027 }
12028 });
12029 }
12030
12031 /**
12032 * Returns an Iterator of [key, value] pairs
12033 *
12034 * @return {IterableIterator<any>}
12035 */
12036 [Symbol.iterator] () {
12037 return this.entries()
12038 }
12039
12040 /**
12041 * Remove a specified element from this YMap.
12042 *
12043 * @param {string} key The key of the element to remove.
12044 */
12045 delete (key) {
12046 if (this.doc !== null) {
12047 transact(this.doc, transaction => {
12048 typeMapDelete(transaction, this, key);
12049 });
12050 } else {
12051 /** @type {Map<string, any>} */ (this._prelimContent).delete(key);
12052 }
12053 }
12054
12055 /**
12056 * Adds or updates an element with a specified key and value.
12057 * @template {MapType} VAL
12058 *
12059 * @param {string} key The key of the element to add to this YMap
12060 * @param {VAL} value The value of the element to add
12061 * @return {VAL}
12062 */
12063 set (key, value) {
12064 if (this.doc !== null) {
12065 transact(this.doc, transaction => {
12066 typeMapSet(transaction, this, key, /** @type {any} */ (value));
12067 });
12068 } else {
12069 /** @type {Map<string, any>} */ (this._prelimContent).set(key, value);
12070 }
12071 return value
12072 }
12073
12074 /**
12075 * Returns a specified element from this YMap.
12076 *
12077 * @param {string} key
12078 * @return {MapType|undefined}
12079 */
12080 get (key) {
12081 return /** @type {any} */ (typeMapGet(this, key))
12082 }
12083
12084 /**
12085 * Returns a boolean indicating whether the specified key exists or not.
12086 *
12087 * @param {string} key The key to test.
12088 * @return {boolean}
12089 */
12090 has (key) {
12091 return typeMapHas(this, key)
12092 }
12093
12094 /**
12095 * Removes all elements from this YMap.
12096 */
12097 clear () {
12098 if (this.doc !== null) {
12099 transact(this.doc, transaction => {
12100 this.forEach(function (_value, key, map) {
12101 typeMapDelete(transaction, map, key);
12102 });
12103 });
12104 } else {
12105 /** @type {Map<string, any>} */ (this._prelimContent).clear();
12106 }
12107 }
12108
12109 /**
12110 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
12111 */
12112 _write (encoder) {
12113 encoder.writeTypeRef(YMapRefID);
12114 }
12115 }
12116
12117 /**
12118 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
12119 *
12120 * @private
12121 * @function
12122 */
12123 const readYMap = _decoder => new YMap();
12124
12125 /**
12126 * @param {any} a
12127 * @param {any} b
12128 * @return {boolean}
12129 */
12130 const equalAttrs = (a, b) => a === b || (typeof a === 'object' && typeof b === 'object' && a && b && object_equalFlat(a, b));
12131
12132 class ItemTextListPosition {
12133 /**
12134 * @param {Item|null} left
12135 * @param {Item|null} right
12136 * @param {number} index
12137 * @param {Map<string,any>} currentAttributes
12138 */
12139 constructor (left, right, index, currentAttributes) {
12140 this.left = left;
12141 this.right = right;
12142 this.index = index;
12143 this.currentAttributes = currentAttributes;
12144 }
12145
12146 /**
12147 * Only call this if you know that this.right is defined
12148 */
12149 forward () {
12150 if (this.right === null) {
12151 unexpectedCase();
12152 }
12153 switch (this.right.content.constructor) {
12154 case ContentFormat:
12155 if (!this.right.deleted) {
12156 updateCurrentAttributes(this.currentAttributes, /** @type {ContentFormat} */ (this.right.content));
12157 }
12158 break
12159 default:
12160 if (!this.right.deleted) {
12161 this.index += this.right.length;
12162 }
12163 break
12164 }
12165 this.left = this.right;
12166 this.right = this.right.right;
12167 }
12168 }
12169
12170 /**
12171 * @param {Transaction} transaction
12172 * @param {ItemTextListPosition} pos
12173 * @param {number} count steps to move forward
12174 * @return {ItemTextListPosition}
12175 *
12176 * @private
12177 * @function
12178 */
12179 const findNextPosition = (transaction, pos, count) => {
12180 while (pos.right !== null && count > 0) {
12181 switch (pos.right.content.constructor) {
12182 case ContentFormat:
12183 if (!pos.right.deleted) {
12184 updateCurrentAttributes(pos.currentAttributes, /** @type {ContentFormat} */ (pos.right.content));
12185 }
12186 break
12187 default:
12188 if (!pos.right.deleted) {
12189 if (count < pos.right.length) {
12190 // split right
12191 getItemCleanStart(transaction, createID(pos.right.id.client, pos.right.id.clock + count));
12192 }
12193 pos.index += pos.right.length;
12194 count -= pos.right.length;
12195 }
12196 break
12197 }
12198 pos.left = pos.right;
12199 pos.right = pos.right.right;
12200 // pos.forward() - we don't forward because that would halve the performance because we already do the checks above
12201 }
12202 return pos
12203 };
12204
12205 /**
12206 * @param {Transaction} transaction
12207 * @param {AbstractType<any>} parent
12208 * @param {number} index
12209 * @return {ItemTextListPosition}
12210 *
12211 * @private
12212 * @function
12213 */
12214 const findPosition = (transaction, parent, index) => {
12215 const currentAttributes = new Map();
12216 const marker = findMarker(parent, index);
12217 if (marker) {
12218 const pos = new ItemTextListPosition(marker.p.left, marker.p, marker.index, currentAttributes);
12219 return findNextPosition(transaction, pos, index - marker.index)
12220 } else {
12221 const pos = new ItemTextListPosition(null, parent._start, 0, currentAttributes);
12222 return findNextPosition(transaction, pos, index)
12223 }
12224 };
12225
12226 /**
12227 * Negate applied formats
12228 *
12229 * @param {Transaction} transaction
12230 * @param {AbstractType<any>} parent
12231 * @param {ItemTextListPosition} currPos
12232 * @param {Map<string,any>} negatedAttributes
12233 *
12234 * @private
12235 * @function
12236 */
12237 const insertNegatedAttributes = (transaction, parent, currPos, negatedAttributes) => {
12238 // check if we really need to remove attributes
12239 while (
12240 currPos.right !== null && (
12241 currPos.right.deleted === true || (
12242 currPos.right.content.constructor === ContentFormat &&
12243 equalAttrs(negatedAttributes.get(/** @type {ContentFormat} */ (currPos.right.content).key), /** @type {ContentFormat} */ (currPos.right.content).value)
12244 )
12245 )
12246 ) {
12247 if (!currPos.right.deleted) {
12248 negatedAttributes.delete(/** @type {ContentFormat} */ (currPos.right.content).key);
12249 }
12250 currPos.forward();
12251 }
12252 const doc = transaction.doc;
12253 const ownClientId = doc.clientID;
12254 negatedAttributes.forEach((val, key) => {
12255 const left = currPos.left;
12256 const right = currPos.right;
12257 const nextFormat = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentFormat(key, val));
12258 nextFormat.integrate(transaction, 0);
12259 currPos.right = nextFormat;
12260 currPos.forward();
12261 });
12262 };
12263
12264 /**
12265 * @param {Map<string,any>} currentAttributes
12266 * @param {ContentFormat} format
12267 *
12268 * @private
12269 * @function
12270 */
12271 const updateCurrentAttributes = (currentAttributes, format) => {
12272 const { key, value } = format;
12273 if (value === null) {
12274 currentAttributes.delete(key);
12275 } else {
12276 currentAttributes.set(key, value);
12277 }
12278 };
12279
12280 /**
12281 * @param {ItemTextListPosition} currPos
12282 * @param {Object<string,any>} attributes
12283 *
12284 * @private
12285 * @function
12286 */
12287 const minimizeAttributeChanges = (currPos, attributes) => {
12288 // go right while attributes[right.key] === right.value (or right is deleted)
12289 while (true) {
12290 if (currPos.right === null) {
12291 break
12292 } 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 {
12293 break
12294 }
12295 currPos.forward();
12296 }
12297 };
12298
12299 /**
12300 * @param {Transaction} transaction
12301 * @param {AbstractType<any>} parent
12302 * @param {ItemTextListPosition} currPos
12303 * @param {Object<string,any>} attributes
12304 * @return {Map<string,any>}
12305 *
12306 * @private
12307 * @function
12308 **/
12309 const insertAttributes = (transaction, parent, currPos, attributes) => {
12310 const doc = transaction.doc;
12311 const ownClientId = doc.clientID;
12312 const negatedAttributes = new Map();
12313 // insert format-start items
12314 for (const key in attributes) {
12315 const val = attributes[key];
12316 const currentVal = currPos.currentAttributes.get(key) || null;
12317 if (!equalAttrs(currentVal, val)) {
12318 // save negated attribute (set null if currentVal undefined)
12319 negatedAttributes.set(key, currentVal);
12320 const { left, right } = currPos;
12321 currPos.right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentFormat(key, val));
12322 currPos.right.integrate(transaction, 0);
12323 currPos.forward();
12324 }
12325 }
12326 return negatedAttributes
12327 };
12328
12329 /**
12330 * @param {Transaction} transaction
12331 * @param {AbstractType<any>} parent
12332 * @param {ItemTextListPosition} currPos
12333 * @param {string|object|AbstractType<any>} text
12334 * @param {Object<string,any>} attributes
12335 *
12336 * @private
12337 * @function
12338 **/
12339 const insertText = (transaction, parent, currPos, text, attributes) => {
12340 currPos.currentAttributes.forEach((_val, key) => {
12341 if (attributes[key] === undefined) {
12342 attributes[key] = null;
12343 }
12344 });
12345 const doc = transaction.doc;
12346 const ownClientId = doc.clientID;
12347 minimizeAttributeChanges(currPos, attributes);
12348 const negatedAttributes = insertAttributes(transaction, parent, currPos, attributes);
12349 // insert content
12350 const content = text.constructor === String ? new ContentString(/** @type {string} */ (text)) : (text instanceof AbstractType ? new ContentType(text) : new ContentEmbed(text));
12351 let { left, right, index } = currPos;
12352 if (parent._searchMarker) {
12353 updateMarkerChanges(parent._searchMarker, currPos.index, content.getLength());
12354 }
12355 right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, content);
12356 right.integrate(transaction, 0);
12357 currPos.right = right;
12358 currPos.index = index;
12359 currPos.forward();
12360 insertNegatedAttributes(transaction, parent, currPos, negatedAttributes);
12361 };
12362
12363 /**
12364 * @param {Transaction} transaction
12365 * @param {AbstractType<any>} parent
12366 * @param {ItemTextListPosition} currPos
12367 * @param {number} length
12368 * @param {Object<string,any>} attributes
12369 *
12370 * @private
12371 * @function
12372 */
12373 const formatText = (transaction, parent, currPos, length, attributes) => {
12374 const doc = transaction.doc;
12375 const ownClientId = doc.clientID;
12376 minimizeAttributeChanges(currPos, attributes);
12377 const negatedAttributes = insertAttributes(transaction, parent, currPos, attributes);
12378 // iterate until first non-format or null is found
12379 // delete all formats with attributes[format.key] != null
12380 // also check the attributes after the first non-format as we do not want to insert redundant negated attributes there
12381 // eslint-disable-next-line no-labels
12382 iterationLoop: while (
12383 currPos.right !== null &&
12384 (length > 0 ||
12385 (
12386 negatedAttributes.size > 0 &&
12387 (currPos.right.deleted || currPos.right.content.constructor === ContentFormat)
12388 )
12389 )
12390 ) {
12391 if (!currPos.right.deleted) {
12392 switch (currPos.right.content.constructor) {
12393 case ContentFormat: {
12394 const { key, value } = /** @type {ContentFormat} */ (currPos.right.content);
12395 const attr = attributes[key];
12396 if (attr !== undefined) {
12397 if (equalAttrs(attr, value)) {
12398 negatedAttributes.delete(key);
12399 } else {
12400 if (length === 0) {
12401 // no need to further extend negatedAttributes
12402 // eslint-disable-next-line no-labels
12403 break iterationLoop
12404 }
12405 negatedAttributes.set(key, value);
12406 }
12407 currPos.right.delete(transaction);
12408 } else {
12409 currPos.currentAttributes.set(key, value);
12410 }
12411 break
12412 }
12413 default:
12414 if (length < currPos.right.length) {
12415 getItemCleanStart(transaction, createID(currPos.right.id.client, currPos.right.id.clock + length));
12416 }
12417 length -= currPos.right.length;
12418 break
12419 }
12420 }
12421 currPos.forward();
12422 }
12423 // Quill just assumes that the editor starts with a newline and that it always
12424 // ends with a newline. We only insert that newline when a new newline is
12425 // inserted - i.e when length is bigger than type.length
12426 if (length > 0) {
12427 let newlines = '';
12428 for (; length > 0; length--) {
12429 newlines += '\n';
12430 }
12431 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));
12432 currPos.right.integrate(transaction, 0);
12433 currPos.forward();
12434 }
12435 insertNegatedAttributes(transaction, parent, currPos, negatedAttributes);
12436 };
12437
12438 /**
12439 * Call this function after string content has been deleted in order to
12440 * clean up formatting Items.
12441 *
12442 * @param {Transaction} transaction
12443 * @param {Item} start
12444 * @param {Item|null} curr exclusive end, automatically iterates to the next Content Item
12445 * @param {Map<string,any>} startAttributes
12446 * @param {Map<string,any>} currAttributes
12447 * @return {number} The amount of formatting Items deleted.
12448 *
12449 * @function
12450 */
12451 const cleanupFormattingGap = (transaction, start, curr, startAttributes, currAttributes) => {
12452 /**
12453 * @type {Item|null}
12454 */
12455 let end = start;
12456 /**
12457 * @type {Map<string,ContentFormat>}
12458 */
12459 const endFormats = create();
12460 while (end && (!end.countable || end.deleted)) {
12461 if (!end.deleted && end.content.constructor === ContentFormat) {
12462 const cf = /** @type {ContentFormat} */ (end.content);
12463 endFormats.set(cf.key, cf);
12464 }
12465 end = end.right;
12466 }
12467 let cleanups = 0;
12468 let reachedCurr = false;
12469 while (start !== end) {
12470 if (curr === start) {
12471 reachedCurr = true;
12472 }
12473 if (!start.deleted) {
12474 const content = start.content;
12475 switch (content.constructor) {
12476 case ContentFormat: {
12477 const { key, value } = /** @type {ContentFormat} */ (content);
12478 const startAttrValue = startAttributes.get(key) || null;
12479 if (endFormats.get(key) !== content || startAttrValue === value) {
12480 // Either this format is overwritten or it is not necessary because the attribute already existed.
12481 start.delete(transaction);
12482 cleanups++;
12483 if (!reachedCurr && (currAttributes.get(key) || null) === value && startAttrValue !== value) {
12484 if (startAttrValue === null) {
12485 currAttributes.delete(key);
12486 } else {
12487 currAttributes.set(key, startAttrValue);
12488 }
12489 }
12490 }
12491 if (!reachedCurr && !start.deleted) {
12492 updateCurrentAttributes(currAttributes, /** @type {ContentFormat} */ (content));
12493 }
12494 break
12495 }
12496 }
12497 }
12498 start = /** @type {Item} */ (start.right);
12499 }
12500 return cleanups
12501 };
12502
12503 /**
12504 * @param {Transaction} transaction
12505 * @param {Item | null} item
12506 */
12507 const cleanupContextlessFormattingGap = (transaction, item) => {
12508 // iterate until item.right is null or content
12509 while (item && item.right && (item.right.deleted || !item.right.countable)) {
12510 item = item.right;
12511 }
12512 const attrs = new Set();
12513 // iterate back until a content item is found
12514 while (item && (item.deleted || !item.countable)) {
12515 if (!item.deleted && item.content.constructor === ContentFormat) {
12516 const key = /** @type {ContentFormat} */ (item.content).key;
12517 if (attrs.has(key)) {
12518 item.delete(transaction);
12519 } else {
12520 attrs.add(key);
12521 }
12522 }
12523 item = item.left;
12524 }
12525 };
12526
12527 /**
12528 * This function is experimental and subject to change / be removed.
12529 *
12530 * Ideally, we don't need this function at all. Formatting attributes should be cleaned up
12531 * automatically after each change. This function iterates twice over the complete YText type
12532 * and removes unnecessary formatting attributes. This is also helpful for testing.
12533 *
12534 * This function won't be exported anymore as soon as there is confidence that the YText type works as intended.
12535 *
12536 * @param {YText} type
12537 * @return {number} How many formatting attributes have been cleaned up.
12538 */
12539 const cleanupYTextFormatting = type => {
12540 let res = 0;
12541 transact(/** @type {Doc} */ (type.doc), transaction => {
12542 let start = /** @type {Item} */ (type._start);
12543 let end = type._start;
12544 let startAttributes = create();
12545 const currentAttributes = copy(startAttributes);
12546 while (end) {
12547 if (end.deleted === false) {
12548 switch (end.content.constructor) {
12549 case ContentFormat:
12550 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (end.content));
12551 break
12552 default:
12553 res += cleanupFormattingGap(transaction, start, end, startAttributes, currentAttributes);
12554 startAttributes = copy(currentAttributes);
12555 start = end;
12556 break
12557 }
12558 }
12559 end = end.right;
12560 }
12561 });
12562 return res
12563 };
12564
12565 /**
12566 * This will be called by the transction once the event handlers are called to potentially cleanup
12567 * formatting attributes.
12568 *
12569 * @param {Transaction} transaction
12570 */
12571 const cleanupYTextAfterTransaction = transaction => {
12572 /**
12573 * @type {Set<YText>}
12574 */
12575 const needFullCleanup = new Set();
12576 // check if another formatting item was inserted
12577 const doc = transaction.doc;
12578 for (const [client, afterClock] of transaction.afterState.entries()) {
12579 const clock = transaction.beforeState.get(client) || 0;
12580 if (afterClock === clock) {
12581 continue
12582 }
12583 iterateStructs(transaction, /** @type {Array<Item|GC>} */ (doc.store.clients.get(client)), clock, afterClock, item => {
12584 if (
12585 !item.deleted && /** @type {Item} */ (item).content.constructor === ContentFormat && item.constructor !== GC
12586 ) {
12587 needFullCleanup.add(/** @type {any} */ (item).parent);
12588 }
12589 });
12590 }
12591 // cleanup in a new transaction
12592 transact(doc, (t) => {
12593 iterateDeletedStructs(transaction, transaction.deleteSet, item => {
12594 if (item instanceof GC || !(/** @type {YText} */ (item.parent)._hasFormatting) || needFullCleanup.has(/** @type {YText} */ (item.parent))) {
12595 return
12596 }
12597 const parent = /** @type {YText} */ (item.parent);
12598 if (item.content.constructor === ContentFormat) {
12599 needFullCleanup.add(parent);
12600 } else {
12601 // If no formatting attribute was inserted or deleted, we can make due with contextless
12602 // formatting cleanups.
12603 // Contextless: it is not necessary to compute currentAttributes for the affected position.
12604 cleanupContextlessFormattingGap(t, item);
12605 }
12606 });
12607 // If a formatting item was inserted, we simply clean the whole type.
12608 // We need to compute currentAttributes for the current position anyway.
12609 for (const yText of needFullCleanup) {
12610 cleanupYTextFormatting(yText);
12611 }
12612 });
12613 };
12614
12615 /**
12616 * @param {Transaction} transaction
12617 * @param {ItemTextListPosition} currPos
12618 * @param {number} length
12619 * @return {ItemTextListPosition}
12620 *
12621 * @private
12622 * @function
12623 */
12624 const deleteText = (transaction, currPos, length) => {
12625 const startLength = length;
12626 const startAttrs = copy(currPos.currentAttributes);
12627 const start = currPos.right;
12628 while (length > 0 && currPos.right !== null) {
12629 if (currPos.right.deleted === false) {
12630 switch (currPos.right.content.constructor) {
12631 case ContentType:
12632 case ContentEmbed:
12633 case ContentString:
12634 if (length < currPos.right.length) {
12635 getItemCleanStart(transaction, createID(currPos.right.id.client, currPos.right.id.clock + length));
12636 }
12637 length -= currPos.right.length;
12638 currPos.right.delete(transaction);
12639 break
12640 }
12641 }
12642 currPos.forward();
12643 }
12644 if (start) {
12645 cleanupFormattingGap(transaction, start, currPos.right, startAttrs, currPos.currentAttributes);
12646 }
12647 const parent = /** @type {AbstractType<any>} */ (/** @type {Item} */ (currPos.left || currPos.right).parent);
12648 if (parent._searchMarker) {
12649 updateMarkerChanges(parent._searchMarker, currPos.index, -startLength + length);
12650 }
12651 return currPos
12652 };
12653
12654 /**
12655 * The Quill Delta format represents changes on a text document with
12656 * formatting information. For mor information visit {@link https://quilljs.com/docs/delta/|Quill Delta}
12657 *
12658 * @example
12659 * {
12660 * ops: [
12661 * { insert: 'Gandalf', attributes: { bold: true } },
12662 * { insert: ' the ' },
12663 * { insert: 'Grey', attributes: { color: '#cccccc' } }
12664 * ]
12665 * }
12666 *
12667 */
12668
12669 /**
12670 * Attributes that can be assigned to a selection of text.
12671 *
12672 * @example
12673 * {
12674 * bold: true,
12675 * font-size: '40px'
12676 * }
12677 *
12678 * @typedef {Object} TextAttributes
12679 */
12680
12681 /**
12682 * @extends YEvent<YText>
12683 * Event that describes the changes on a YText type.
12684 */
12685 class YTextEvent extends YEvent {
12686 /**
12687 * @param {YText} ytext
12688 * @param {Transaction} transaction
12689 * @param {Set<any>} subs The keys that changed
12690 */
12691 constructor (ytext, transaction, subs) {
12692 super(ytext, transaction);
12693 /**
12694 * Whether the children changed.
12695 * @type {Boolean}
12696 * @private
12697 */
12698 this.childListChanged = false;
12699 /**
12700 * Set of all changed attributes.
12701 * @type {Set<string>}
12702 */
12703 this.keysChanged = new Set();
12704 subs.forEach((sub) => {
12705 if (sub === null) {
12706 this.childListChanged = true;
12707 } else {
12708 this.keysChanged.add(sub);
12709 }
12710 });
12711 }
12712
12713 /**
12714 * @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}>}}
12715 */
12716 get changes () {
12717 if (this._changes === null) {
12718 /**
12719 * @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}>}}
12720 */
12721 const changes = {
12722 keys: this.keys,
12723 delta: this.delta,
12724 added: new Set(),
12725 deleted: new Set()
12726 };
12727 this._changes = changes;
12728 }
12729 return /** @type {any} */ (this._changes)
12730 }
12731
12732 /**
12733 * Compute the changes in the delta format.
12734 * A {@link https://quilljs.com/docs/delta/|Quill Delta}) that represents the changes on the document.
12735 *
12736 * @type {Array<{insert?:string|object|AbstractType<any>, delete?:number, retain?:number, attributes?: Object<string,any>}>}
12737 *
12738 * @public
12739 */
12740 get delta () {
12741 if (this._delta === null) {
12742 const y = /** @type {Doc} */ (this.target.doc);
12743 /**
12744 * @type {Array<{insert?:string|object|AbstractType<any>, delete?:number, retain?:number, attributes?: Object<string,any>}>}
12745 */
12746 const delta = [];
12747 transact(y, transaction => {
12748 const currentAttributes = new Map(); // saves all current attributes for insert
12749 const oldAttributes = new Map();
12750 let item = this.target._start;
12751 /**
12752 * @type {string?}
12753 */
12754 let action = null;
12755 /**
12756 * @type {Object<string,any>}
12757 */
12758 const attributes = {}; // counts added or removed new attributes for retain
12759 /**
12760 * @type {string|object}
12761 */
12762 let insert = '';
12763 let retain = 0;
12764 let deleteLen = 0;
12765 const addOp = () => {
12766 if (action !== null) {
12767 /**
12768 * @type {any}
12769 */
12770 let op = null;
12771 switch (action) {
12772 case 'delete':
12773 if (deleteLen > 0) {
12774 op = { delete: deleteLen };
12775 }
12776 deleteLen = 0;
12777 break
12778 case 'insert':
12779 if (typeof insert === 'object' || insert.length > 0) {
12780 op = { insert };
12781 if (currentAttributes.size > 0) {
12782 op.attributes = {};
12783 currentAttributes.forEach((value, key) => {
12784 if (value !== null) {
12785 op.attributes[key] = value;
12786 }
12787 });
12788 }
12789 }
12790 insert = '';
12791 break
12792 case 'retain':
12793 if (retain > 0) {
12794 op = { retain };
12795 if (!isEmpty(attributes)) {
12796 op.attributes = object_assign({}, attributes);
12797 }
12798 }
12799 retain = 0;
12800 break
12801 }
12802 if (op) delta.push(op);
12803 action = null;
12804 }
12805 };
12806 while (item !== null) {
12807 switch (item.content.constructor) {
12808 case ContentType:
12809 case ContentEmbed:
12810 if (this.adds(item)) {
12811 if (!this.deletes(item)) {
12812 addOp();
12813 action = 'insert';
12814 insert = item.content.getContent()[0];
12815 addOp();
12816 }
12817 } else if (this.deletes(item)) {
12818 if (action !== 'delete') {
12819 addOp();
12820 action = 'delete';
12821 }
12822 deleteLen += 1;
12823 } else if (!item.deleted) {
12824 if (action !== 'retain') {
12825 addOp();
12826 action = 'retain';
12827 }
12828 retain += 1;
12829 }
12830 break
12831 case ContentString:
12832 if (this.adds(item)) {
12833 if (!this.deletes(item)) {
12834 if (action !== 'insert') {
12835 addOp();
12836 action = 'insert';
12837 }
12838 insert += /** @type {ContentString} */ (item.content).str;
12839 }
12840 } else if (this.deletes(item)) {
12841 if (action !== 'delete') {
12842 addOp();
12843 action = 'delete';
12844 }
12845 deleteLen += item.length;
12846 } else if (!item.deleted) {
12847 if (action !== 'retain') {
12848 addOp();
12849 action = 'retain';
12850 }
12851 retain += item.length;
12852 }
12853 break
12854 case ContentFormat: {
12855 const { key, value } = /** @type {ContentFormat} */ (item.content);
12856 if (this.adds(item)) {
12857 if (!this.deletes(item)) {
12858 const curVal = currentAttributes.get(key) || null;
12859 if (!equalAttrs(curVal, value)) {
12860 if (action === 'retain') {
12861 addOp();
12862 }
12863 if (equalAttrs(value, (oldAttributes.get(key) || null))) {
12864 delete attributes[key];
12865 } else {
12866 attributes[key] = value;
12867 }
12868 } else if (value !== null) {
12869 item.delete(transaction);
12870 }
12871 }
12872 } else if (this.deletes(item)) {
12873 oldAttributes.set(key, value);
12874 const curVal = currentAttributes.get(key) || null;
12875 if (!equalAttrs(curVal, value)) {
12876 if (action === 'retain') {
12877 addOp();
12878 }
12879 attributes[key] = curVal;
12880 }
12881 } else if (!item.deleted) {
12882 oldAttributes.set(key, value);
12883 const attr = attributes[key];
12884 if (attr !== undefined) {
12885 if (!equalAttrs(attr, value)) {
12886 if (action === 'retain') {
12887 addOp();
12888 }
12889 if (value === null) {
12890 delete attributes[key];
12891 } else {
12892 attributes[key] = value;
12893 }
12894 } else if (attr !== null) { // this will be cleaned up automatically by the contextless cleanup function
12895 item.delete(transaction);
12896 }
12897 }
12898 }
12899 if (!item.deleted) {
12900 if (action === 'insert') {
12901 addOp();
12902 }
12903 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (item.content));
12904 }
12905 break
12906 }
12907 }
12908 item = item.right;
12909 }
12910 addOp();
12911 while (delta.length > 0) {
12912 const lastOp = delta[delta.length - 1];
12913 if (lastOp.retain !== undefined && lastOp.attributes === undefined) {
12914 // retain delta's if they don't assign attributes
12915 delta.pop();
12916 } else {
12917 break
12918 }
12919 }
12920 });
12921 this._delta = delta;
12922 }
12923 return /** @type {any} */ (this._delta)
12924 }
12925 }
12926
12927 /**
12928 * Type that represents text with formatting information.
12929 *
12930 * This type replaces y-richtext as this implementation is able to handle
12931 * block formats (format information on a paragraph), embeds (complex elements
12932 * like pictures and videos), and text formats (**bold**, *italic*).
12933 *
12934 * @extends AbstractType<YTextEvent>
12935 */
12936 class YText extends AbstractType {
12937 /**
12938 * @param {String} [string] The initial value of the YText.
12939 */
12940 constructor (string) {
12941 super();
12942 /**
12943 * Array of pending operations on this type
12944 * @type {Array<function():void>?}
12945 */
12946 this._pending = string !== undefined ? [() => this.insert(0, string)] : [];
12947 /**
12948 * @type {Array<ArraySearchMarker>|null}
12949 */
12950 this._searchMarker = [];
12951 /**
12952 * Whether this YText contains formatting attributes.
12953 * This flag is updated when a formatting item is integrated (see ContentFormat.integrate)
12954 */
12955 this._hasFormatting = false;
12956 }
12957
12958 /**
12959 * Number of characters of this text type.
12960 *
12961 * @type {number}
12962 */
12963 get length () {
12964 return this._length
12965 }
12966
12967 /**
12968 * @param {Doc} y
12969 * @param {Item} item
12970 */
12971 _integrate (y, item) {
12972 super._integrate(y, item);
12973 try {
12974 /** @type {Array<function>} */ (this._pending).forEach(f => f());
12975 } catch (e) {
12976 console.error(e);
12977 }
12978 this._pending = null;
12979 }
12980
12981 _copy () {
12982 return new YText()
12983 }
12984
12985 /**
12986 * @return {YText}
12987 */
12988 clone () {
12989 const text = new YText();
12990 text.applyDelta(this.toDelta());
12991 return text
12992 }
12993
12994 /**
12995 * Creates YTextEvent and calls observers.
12996 *
12997 * @param {Transaction} transaction
12998 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
12999 */
13000 _callObserver (transaction, parentSubs) {
13001 super._callObserver(transaction, parentSubs);
13002 const event = new YTextEvent(this, transaction, parentSubs);
13003 callTypeObservers(this, transaction, event);
13004 // If a remote change happened, we try to cleanup potential formatting duplicates.
13005 if (!transaction.local && this._hasFormatting) {
13006 transaction._needFormattingCleanup = true;
13007 }
13008 }
13009
13010 /**
13011 * Returns the unformatted string representation of this YText type.
13012 *
13013 * @public
13014 */
13015 toString () {
13016 let str = '';
13017 /**
13018 * @type {Item|null}
13019 */
13020 let n = this._start;
13021 while (n !== null) {
13022 if (!n.deleted && n.countable && n.content.constructor === ContentString) {
13023 str += /** @type {ContentString} */ (n.content).str;
13024 }
13025 n = n.right;
13026 }
13027 return str
13028 }
13029
13030 /**
13031 * Returns the unformatted string representation of this YText type.
13032 *
13033 * @return {string}
13034 * @public
13035 */
13036 toJSON () {
13037 return this.toString()
13038 }
13039
13040 /**
13041 * Apply a {@link Delta} on this shared YText type.
13042 *
13043 * @param {any} delta The changes to apply on this element.
13044 * @param {object} opts
13045 * @param {boolean} [opts.sanitize] Sanitize input delta. Removes ending newlines if set to true.
13046 *
13047 *
13048 * @public
13049 */
13050 applyDelta (delta, { sanitize = true } = {}) {
13051 if (this.doc !== null) {
13052 transact(this.doc, transaction => {
13053 const currPos = new ItemTextListPosition(null, this._start, 0, new Map());
13054 for (let i = 0; i < delta.length; i++) {
13055 const op = delta[i];
13056 if (op.insert !== undefined) {
13057 // Quill assumes that the content starts with an empty paragraph.
13058 // Yjs/Y.Text assumes that it starts empty. We always hide that
13059 // there is a newline at the end of the content.
13060 // If we omit this step, clients will see a different number of
13061 // paragraphs, but nothing bad will happen.
13062 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;
13063 if (typeof ins !== 'string' || ins.length > 0) {
13064 insertText(transaction, this, currPos, ins, op.attributes || {});
13065 }
13066 } else if (op.retain !== undefined) {
13067 formatText(transaction, this, currPos, op.retain, op.attributes || {});
13068 } else if (op.delete !== undefined) {
13069 deleteText(transaction, currPos, op.delete);
13070 }
13071 }
13072 });
13073 } else {
13074 /** @type {Array<function>} */ (this._pending).push(() => this.applyDelta(delta));
13075 }
13076 }
13077
13078 /**
13079 * Returns the Delta representation of this YText type.
13080 *
13081 * @param {Snapshot} [snapshot]
13082 * @param {Snapshot} [prevSnapshot]
13083 * @param {function('removed' | 'added', ID):any} [computeYChange]
13084 * @return {any} The Delta representation of this type.
13085 *
13086 * @public
13087 */
13088 toDelta (snapshot, prevSnapshot, computeYChange) {
13089 /**
13090 * @type{Array<any>}
13091 */
13092 const ops = [];
13093 const currentAttributes = new Map();
13094 const doc = /** @type {Doc} */ (this.doc);
13095 let str = '';
13096 let n = this._start;
13097 function packStr () {
13098 if (str.length > 0) {
13099 // pack str with attributes to ops
13100 /**
13101 * @type {Object<string,any>}
13102 */
13103 const attributes = {};
13104 let addAttributes = false;
13105 currentAttributes.forEach((value, key) => {
13106 addAttributes = true;
13107 attributes[key] = value;
13108 });
13109 /**
13110 * @type {Object<string,any>}
13111 */
13112 const op = { insert: str };
13113 if (addAttributes) {
13114 op.attributes = attributes;
13115 }
13116 ops.push(op);
13117 str = '';
13118 }
13119 }
13120 const computeDelta = () => {
13121 while (n !== null) {
13122 if (isVisible(n, snapshot) || (prevSnapshot !== undefined && isVisible(n, prevSnapshot))) {
13123 switch (n.content.constructor) {
13124 case ContentString: {
13125 const cur = currentAttributes.get('ychange');
13126 if (snapshot !== undefined && !isVisible(n, snapshot)) {
13127 if (cur === undefined || cur.user !== n.id.client || cur.type !== 'removed') {
13128 packStr();
13129 currentAttributes.set('ychange', computeYChange ? computeYChange('removed', n.id) : { type: 'removed' });
13130 }
13131 } else if (prevSnapshot !== undefined && !isVisible(n, prevSnapshot)) {
13132 if (cur === undefined || cur.user !== n.id.client || cur.type !== 'added') {
13133 packStr();
13134 currentAttributes.set('ychange', computeYChange ? computeYChange('added', n.id) : { type: 'added' });
13135 }
13136 } else if (cur !== undefined) {
13137 packStr();
13138 currentAttributes.delete('ychange');
13139 }
13140 str += /** @type {ContentString} */ (n.content).str;
13141 break
13142 }
13143 case ContentType:
13144 case ContentEmbed: {
13145 packStr();
13146 /**
13147 * @type {Object<string,any>}
13148 */
13149 const op = {
13150 insert: n.content.getContent()[0]
13151 };
13152 if (currentAttributes.size > 0) {
13153 const attrs = /** @type {Object<string,any>} */ ({});
13154 op.attributes = attrs;
13155 currentAttributes.forEach((value, key) => {
13156 attrs[key] = value;
13157 });
13158 }
13159 ops.push(op);
13160 break
13161 }
13162 case ContentFormat:
13163 if (isVisible(n, snapshot)) {
13164 packStr();
13165 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (n.content));
13166 }
13167 break
13168 }
13169 }
13170 n = n.right;
13171 }
13172 packStr();
13173 };
13174 if (snapshot || prevSnapshot) {
13175 // snapshots are merged again after the transaction, so we need to keep the
13176 // transaction alive until we are done
13177 transact(doc, transaction => {
13178 if (snapshot) {
13179 splitSnapshotAffectedStructs(transaction, snapshot);
13180 }
13181 if (prevSnapshot) {
13182 splitSnapshotAffectedStructs(transaction, prevSnapshot);
13183 }
13184 computeDelta();
13185 }, 'cleanup');
13186 } else {
13187 computeDelta();
13188 }
13189 return ops
13190 }
13191
13192 /**
13193 * Insert text at a given index.
13194 *
13195 * @param {number} index The index at which to start inserting.
13196 * @param {String} text The text to insert at the specified position.
13197 * @param {TextAttributes} [attributes] Optionally define some formatting
13198 * information to apply on the inserted
13199 * Text.
13200 * @public
13201 */
13202 insert (index, text, attributes) {
13203 if (text.length <= 0) {
13204 return
13205 }
13206 const y = this.doc;
13207 if (y !== null) {
13208 transact(y, transaction => {
13209 const pos = findPosition(transaction, this, index);
13210 if (!attributes) {
13211 attributes = {};
13212 // @ts-ignore
13213 pos.currentAttributes.forEach((v, k) => { attributes[k] = v; });
13214 }
13215 insertText(transaction, this, pos, text, attributes);
13216 });
13217 } else {
13218 /** @type {Array<function>} */ (this._pending).push(() => this.insert(index, text, attributes));
13219 }
13220 }
13221
13222 /**
13223 * Inserts an embed at a index.
13224 *
13225 * @param {number} index The index to insert the embed at.
13226 * @param {Object | AbstractType<any>} embed The Object that represents the embed.
13227 * @param {TextAttributes} attributes Attribute information to apply on the
13228 * embed
13229 *
13230 * @public
13231 */
13232 insertEmbed (index, embed, attributes = {}) {
13233 const y = this.doc;
13234 if (y !== null) {
13235 transact(y, transaction => {
13236 const pos = findPosition(transaction, this, index);
13237 insertText(transaction, this, pos, embed, attributes);
13238 });
13239 } else {
13240 /** @type {Array<function>} */ (this._pending).push(() => this.insertEmbed(index, embed, attributes));
13241 }
13242 }
13243
13244 /**
13245 * Deletes text starting from an index.
13246 *
13247 * @param {number} index Index at which to start deleting.
13248 * @param {number} length The number of characters to remove. Defaults to 1.
13249 *
13250 * @public
13251 */
13252 delete (index, length) {
13253 if (length === 0) {
13254 return
13255 }
13256 const y = this.doc;
13257 if (y !== null) {
13258 transact(y, transaction => {
13259 deleteText(transaction, findPosition(transaction, this, index), length);
13260 });
13261 } else {
13262 /** @type {Array<function>} */ (this._pending).push(() => this.delete(index, length));
13263 }
13264 }
13265
13266 /**
13267 * Assigns properties to a range of text.
13268 *
13269 * @param {number} index The position where to start formatting.
13270 * @param {number} length The amount of characters to assign properties to.
13271 * @param {TextAttributes} attributes Attribute information to apply on the
13272 * text.
13273 *
13274 * @public
13275 */
13276 format (index, length, attributes) {
13277 if (length === 0) {
13278 return
13279 }
13280 const y = this.doc;
13281 if (y !== null) {
13282 transact(y, transaction => {
13283 const pos = findPosition(transaction, this, index);
13284 if (pos.right === null) {
13285 return
13286 }
13287 formatText(transaction, this, pos, length, attributes);
13288 });
13289 } else {
13290 /** @type {Array<function>} */ (this._pending).push(() => this.format(index, length, attributes));
13291 }
13292 }
13293
13294 /**
13295 * Removes an attribute.
13296 *
13297 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13298 *
13299 * @param {String} attributeName The attribute name that is to be removed.
13300 *
13301 * @public
13302 */
13303 removeAttribute (attributeName) {
13304 if (this.doc !== null) {
13305 transact(this.doc, transaction => {
13306 typeMapDelete(transaction, this, attributeName);
13307 });
13308 } else {
13309 /** @type {Array<function>} */ (this._pending).push(() => this.removeAttribute(attributeName));
13310 }
13311 }
13312
13313 /**
13314 * Sets or updates an attribute.
13315 *
13316 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13317 *
13318 * @param {String} attributeName The attribute name that is to be set.
13319 * @param {any} attributeValue The attribute value that is to be set.
13320 *
13321 * @public
13322 */
13323 setAttribute (attributeName, attributeValue) {
13324 if (this.doc !== null) {
13325 transact(this.doc, transaction => {
13326 typeMapSet(transaction, this, attributeName, attributeValue);
13327 });
13328 } else {
13329 /** @type {Array<function>} */ (this._pending).push(() => this.setAttribute(attributeName, attributeValue));
13330 }
13331 }
13332
13333 /**
13334 * Returns an attribute value that belongs to the attribute name.
13335 *
13336 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13337 *
13338 * @param {String} attributeName The attribute name that identifies the
13339 * queried value.
13340 * @return {any} The queried attribute value.
13341 *
13342 * @public
13343 */
13344 getAttribute (attributeName) {
13345 return /** @type {any} */ (typeMapGet(this, attributeName))
13346 }
13347
13348 /**
13349 * Returns all attribute name/value pairs in a JSON Object.
13350 *
13351 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13352 *
13353 * @return {Object<string, any>} A JSON Object that describes the attributes.
13354 *
13355 * @public
13356 */
13357 getAttributes () {
13358 return typeMapGetAll(this)
13359 }
13360
13361 /**
13362 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
13363 */
13364 _write (encoder) {
13365 encoder.writeTypeRef(YTextRefID);
13366 }
13367 }
13368
13369 /**
13370 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
13371 * @return {YText}
13372 *
13373 * @private
13374 * @function
13375 */
13376 const readYText = _decoder => new YText();
13377
13378 /**
13379 * @module YXml
13380 */
13381
13382 /**
13383 * Define the elements to which a set of CSS queries apply.
13384 * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors}
13385 *
13386 * @example
13387 * query = '.classSelector'
13388 * query = 'nodeSelector'
13389 * query = '#idSelector'
13390 *
13391 * @typedef {string} CSS_Selector
13392 */
13393
13394 /**
13395 * Dom filter function.
13396 *
13397 * @callback domFilter
13398 * @param {string} nodeName The nodeName of the element
13399 * @param {Map} attributes The map of attributes.
13400 * @return {boolean} Whether to include the Dom node in the YXmlElement.
13401 */
13402
13403 /**
13404 * Represents a subset of the nodes of a YXmlElement / YXmlFragment and a
13405 * position within them.
13406 *
13407 * Can be created with {@link YXmlFragment#createTreeWalker}
13408 *
13409 * @public
13410 * @implements {Iterable<YXmlElement|YXmlText|YXmlElement|YXmlHook>}
13411 */
13412 class YXmlTreeWalker {
13413 /**
13414 * @param {YXmlFragment | YXmlElement} root
13415 * @param {function(AbstractType<any>):boolean} [f]
13416 */
13417 constructor (root, f = () => true) {
13418 this._filter = f;
13419 this._root = root;
13420 /**
13421 * @type {Item}
13422 */
13423 this._currentNode = /** @type {Item} */ (root._start);
13424 this._firstCall = true;
13425 }
13426
13427 [Symbol.iterator] () {
13428 return this
13429 }
13430
13431 /**
13432 * Get the next node.
13433 *
13434 * @return {IteratorResult<YXmlElement|YXmlText|YXmlHook>} The next node.
13435 *
13436 * @public
13437 */
13438 next () {
13439 /**
13440 * @type {Item|null}
13441 */
13442 let n = this._currentNode;
13443 let type = n && n.content && /** @type {any} */ (n.content).type;
13444 if (n !== null && (!this._firstCall || n.deleted || !this._filter(type))) { // if first call, we check if we can use the first item
13445 do {
13446 type = /** @type {any} */ (n.content).type;
13447 if (!n.deleted && (type.constructor === YXmlElement || type.constructor === YXmlFragment) && type._start !== null) {
13448 // walk down in the tree
13449 n = type._start;
13450 } else {
13451 // walk right or up in the tree
13452 while (n !== null) {
13453 if (n.right !== null) {
13454 n = n.right;
13455 break
13456 } else if (n.parent === this._root) {
13457 n = null;
13458 } else {
13459 n = /** @type {AbstractType<any>} */ (n.parent)._item;
13460 }
13461 }
13462 }
13463 } while (n !== null && (n.deleted || !this._filter(/** @type {ContentType} */ (n.content).type)))
13464 }
13465 this._firstCall = false;
13466 if (n === null) {
13467 // @ts-ignore
13468 return { value: undefined, done: true }
13469 }
13470 this._currentNode = n;
13471 return { value: /** @type {any} */ (n.content).type, done: false }
13472 }
13473 }
13474
13475 /**
13476 * Represents a list of {@link YXmlElement}.and {@link YXmlText} types.
13477 * A YxmlFragment is similar to a {@link YXmlElement}, but it does not have a
13478 * nodeName and it does not have attributes. Though it can be bound to a DOM
13479 * element - in this case the attributes and the nodeName are not shared.
13480 *
13481 * @public
13482 * @extends AbstractType<YXmlEvent>
13483 */
13484 class YXmlFragment extends AbstractType {
13485 constructor () {
13486 super();
13487 /**
13488 * @type {Array<any>|null}
13489 */
13490 this._prelimContent = [];
13491 }
13492
13493 /**
13494 * @type {YXmlElement|YXmlText|null}
13495 */
13496 get firstChild () {
13497 const first = this._first;
13498 return first ? first.content.getContent()[0] : null
13499 }
13500
13501 /**
13502 * Integrate this type into the Yjs instance.
13503 *
13504 * * Save this struct in the os
13505 * * This type is sent to other client
13506 * * Observer functions are fired
13507 *
13508 * @param {Doc} y The Yjs instance
13509 * @param {Item} item
13510 */
13511 _integrate (y, item) {
13512 super._integrate(y, item);
13513 this.insert(0, /** @type {Array<any>} */ (this._prelimContent));
13514 this._prelimContent = null;
13515 }
13516
13517 _copy () {
13518 return new YXmlFragment()
13519 }
13520
13521 /**
13522 * @return {YXmlFragment}
13523 */
13524 clone () {
13525 const el = new YXmlFragment();
13526 // @ts-ignore
13527 el.insert(0, this.toArray().map(item => item instanceof AbstractType ? item.clone() : item));
13528 return el
13529 }
13530
13531 get length () {
13532 return this._prelimContent === null ? this._length : this._prelimContent.length
13533 }
13534
13535 /**
13536 * Create a subtree of childNodes.
13537 *
13538 * @example
13539 * const walker = elem.createTreeWalker(dom => dom.nodeName === 'div')
13540 * for (let node in walker) {
13541 * // `node` is a div node
13542 * nop(node)
13543 * }
13544 *
13545 * @param {function(AbstractType<any>):boolean} filter Function that is called on each child element and
13546 * returns a Boolean indicating whether the child
13547 * is to be included in the subtree.
13548 * @return {YXmlTreeWalker} A subtree and a position within it.
13549 *
13550 * @public
13551 */
13552 createTreeWalker (filter) {
13553 return new YXmlTreeWalker(this, filter)
13554 }
13555
13556 /**
13557 * Returns the first YXmlElement that matches the query.
13558 * Similar to DOM's {@link querySelector}.
13559 *
13560 * Query support:
13561 * - tagname
13562 * TODO:
13563 * - id
13564 * - attribute
13565 *
13566 * @param {CSS_Selector} query The query on the children.
13567 * @return {YXmlElement|YXmlText|YXmlHook|null} The first element that matches the query or null.
13568 *
13569 * @public
13570 */
13571 querySelector (query) {
13572 query = query.toUpperCase();
13573 // @ts-ignore
13574 const iterator = new YXmlTreeWalker(this, element => element.nodeName && element.nodeName.toUpperCase() === query);
13575 const next = iterator.next();
13576 if (next.done) {
13577 return null
13578 } else {
13579 return next.value
13580 }
13581 }
13582
13583 /**
13584 * Returns all YXmlElements that match the query.
13585 * Similar to Dom's {@link querySelectorAll}.
13586 *
13587 * @todo Does not yet support all queries. Currently only query by tagName.
13588 *
13589 * @param {CSS_Selector} query The query on the children
13590 * @return {Array<YXmlElement|YXmlText|YXmlHook|null>} The elements that match this query.
13591 *
13592 * @public
13593 */
13594 querySelectorAll (query) {
13595 query = query.toUpperCase();
13596 // @ts-ignore
13597 return array_from(new YXmlTreeWalker(this, element => element.nodeName && element.nodeName.toUpperCase() === query))
13598 }
13599
13600 /**
13601 * Creates YXmlEvent and calls observers.
13602 *
13603 * @param {Transaction} transaction
13604 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
13605 */
13606 _callObserver (transaction, parentSubs) {
13607 callTypeObservers(this, transaction, new YXmlEvent(this, parentSubs, transaction));
13608 }
13609
13610 /**
13611 * Get the string representation of all the children of this YXmlFragment.
13612 *
13613 * @return {string} The string representation of all children.
13614 */
13615 toString () {
13616 return typeListMap(this, xml => xml.toString()).join('')
13617 }
13618
13619 /**
13620 * @return {string}
13621 */
13622 toJSON () {
13623 return this.toString()
13624 }
13625
13626 /**
13627 * Creates a Dom Element that mirrors this YXmlElement.
13628 *
13629 * @param {Document} [_document=document] The document object (you must define
13630 * this when calling this method in
13631 * nodejs)
13632 * @param {Object<string, any>} [hooks={}] Optional property to customize how hooks
13633 * are presented in the DOM
13634 * @param {any} [binding] You should not set this property. This is
13635 * used if DomBinding wants to create a
13636 * association to the created DOM type.
13637 * @return {Node} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
13638 *
13639 * @public
13640 */
13641 toDOM (_document = document, hooks = {}, binding) {
13642 const fragment = _document.createDocumentFragment();
13643 if (binding !== undefined) {
13644 binding._createAssociation(fragment, this);
13645 }
13646 typeListForEach(this, xmlType => {
13647 fragment.insertBefore(xmlType.toDOM(_document, hooks, binding), null);
13648 });
13649 return fragment
13650 }
13651
13652 /**
13653 * Inserts new content at an index.
13654 *
13655 * @example
13656 * // Insert character 'a' at position 0
13657 * xml.insert(0, [new Y.XmlText('text')])
13658 *
13659 * @param {number} index The index to insert content at
13660 * @param {Array<YXmlElement|YXmlText>} content The array of content
13661 */
13662 insert (index, content) {
13663 if (this.doc !== null) {
13664 transact(this.doc, transaction => {
13665 typeListInsertGenerics(transaction, this, index, content);
13666 });
13667 } else {
13668 // @ts-ignore _prelimContent is defined because this is not yet integrated
13669 this._prelimContent.splice(index, 0, ...content);
13670 }
13671 }
13672
13673 /**
13674 * Inserts new content at an index.
13675 *
13676 * @example
13677 * // Insert character 'a' at position 0
13678 * xml.insert(0, [new Y.XmlText('text')])
13679 *
13680 * @param {null|Item|YXmlElement|YXmlText} ref The index to insert content at
13681 * @param {Array<YXmlElement|YXmlText>} content The array of content
13682 */
13683 insertAfter (ref, content) {
13684 if (this.doc !== null) {
13685 transact(this.doc, transaction => {
13686 const refItem = (ref && ref instanceof AbstractType) ? ref._item : ref;
13687 typeListInsertGenericsAfter(transaction, this, refItem, content);
13688 });
13689 } else {
13690 const pc = /** @type {Array<any>} */ (this._prelimContent);
13691 const index = ref === null ? 0 : pc.findIndex(el => el === ref) + 1;
13692 if (index === 0 && ref !== null) {
13693 throw error_create('Reference item not found')
13694 }
13695 pc.splice(index, 0, ...content);
13696 }
13697 }
13698
13699 /**
13700 * Deletes elements starting from an index.
13701 *
13702 * @param {number} index Index at which to start deleting elements
13703 * @param {number} [length=1] The number of elements to remove. Defaults to 1.
13704 */
13705 delete (index, length = 1) {
13706 if (this.doc !== null) {
13707 transact(this.doc, transaction => {
13708 typeListDelete(transaction, this, index, length);
13709 });
13710 } else {
13711 // @ts-ignore _prelimContent is defined because this is not yet integrated
13712 this._prelimContent.splice(index, length);
13713 }
13714 }
13715
13716 /**
13717 * Transforms this YArray to a JavaScript Array.
13718 *
13719 * @return {Array<YXmlElement|YXmlText|YXmlHook>}
13720 */
13721 toArray () {
13722 return typeListToArray(this)
13723 }
13724
13725 /**
13726 * Appends content to this YArray.
13727 *
13728 * @param {Array<YXmlElement|YXmlText>} content Array of content to append.
13729 */
13730 push (content) {
13731 this.insert(this.length, content);
13732 }
13733
13734 /**
13735 * Preppends content to this YArray.
13736 *
13737 * @param {Array<YXmlElement|YXmlText>} content Array of content to preppend.
13738 */
13739 unshift (content) {
13740 this.insert(0, content);
13741 }
13742
13743 /**
13744 * Returns the i-th element from a YArray.
13745 *
13746 * @param {number} index The index of the element to return from the YArray
13747 * @return {YXmlElement|YXmlText}
13748 */
13749 get (index) {
13750 return typeListGet(this, index)
13751 }
13752
13753 /**
13754 * Transforms this YArray to a JavaScript Array.
13755 *
13756 * @param {number} [start]
13757 * @param {number} [end]
13758 * @return {Array<YXmlElement|YXmlText>}
13759 */
13760 slice (start = 0, end = this.length) {
13761 return typeListSlice(this, start, end)
13762 }
13763
13764 /**
13765 * Executes a provided function on once on overy child element.
13766 *
13767 * @param {function(YXmlElement|YXmlText,number, typeof self):void} f A function to execute on every element of this YArray.
13768 */
13769 forEach (f) {
13770 typeListForEach(this, f);
13771 }
13772
13773 /**
13774 * Transform the properties of this type to binary and write it to an
13775 * BinaryEncoder.
13776 *
13777 * This is called when this Item is sent to a remote peer.
13778 *
13779 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
13780 */
13781 _write (encoder) {
13782 encoder.writeTypeRef(YXmlFragmentRefID);
13783 }
13784 }
13785
13786 /**
13787 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
13788 * @return {YXmlFragment}
13789 *
13790 * @private
13791 * @function
13792 */
13793 const readYXmlFragment = _decoder => new YXmlFragment();
13794
13795 /**
13796 * @typedef {Object|number|null|Array<any>|string|Uint8Array|AbstractType<any>} ValueTypes
13797 */
13798
13799 /**
13800 * An YXmlElement imitates the behavior of a
13801 * {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}.
13802 *
13803 * * An YXmlElement has attributes (key value pairs)
13804 * * An YXmlElement has childElements that must inherit from YXmlElement
13805 *
13806 * @template {{ [key: string]: ValueTypes }} [KV={ [key: string]: string }]
13807 */
13808 class YXmlElement extends YXmlFragment {
13809 constructor (nodeName = 'UNDEFINED') {
13810 super();
13811 this.nodeName = nodeName;
13812 /**
13813 * @type {Map<string, any>|null}
13814 */
13815 this._prelimAttrs = new Map();
13816 }
13817
13818 /**
13819 * @type {YXmlElement|YXmlText|null}
13820 */
13821 get nextSibling () {
13822 const n = this._item ? this._item.next : null;
13823 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
13824 }
13825
13826 /**
13827 * @type {YXmlElement|YXmlText|null}
13828 */
13829 get prevSibling () {
13830 const n = this._item ? this._item.prev : null;
13831 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
13832 }
13833
13834 /**
13835 * Integrate this type into the Yjs instance.
13836 *
13837 * * Save this struct in the os
13838 * * This type is sent to other client
13839 * * Observer functions are fired
13840 *
13841 * @param {Doc} y The Yjs instance
13842 * @param {Item} item
13843 */
13844 _integrate (y, item) {
13845 super._integrate(y, item)
13846 ;(/** @type {Map<string, any>} */ (this._prelimAttrs)).forEach((value, key) => {
13847 this.setAttribute(key, value);
13848 });
13849 this._prelimAttrs = null;
13850 }
13851
13852 /**
13853 * Creates an Item with the same effect as this Item (without position effect)
13854 *
13855 * @return {YXmlElement}
13856 */
13857 _copy () {
13858 return new YXmlElement(this.nodeName)
13859 }
13860
13861 /**
13862 * @return {YXmlElement<KV>}
13863 */
13864 clone () {
13865 /**
13866 * @type {YXmlElement<KV>}
13867 */
13868 const el = new YXmlElement(this.nodeName);
13869 const attrs = this.getAttributes();
13870 forEach(attrs, (value, key) => {
13871 if (typeof value === 'string') {
13872 el.setAttribute(key, value);
13873 }
13874 });
13875 // @ts-ignore
13876 el.insert(0, this.toArray().map(item => item instanceof AbstractType ? item.clone() : item));
13877 return el
13878 }
13879
13880 /**
13881 * Returns the XML serialization of this YXmlElement.
13882 * The attributes are ordered by attribute-name, so you can easily use this
13883 * method to compare YXmlElements
13884 *
13885 * @return {string} The string representation of this type.
13886 *
13887 * @public
13888 */
13889 toString () {
13890 const attrs = this.getAttributes();
13891 const stringBuilder = [];
13892 const keys = [];
13893 for (const key in attrs) {
13894 keys.push(key);
13895 }
13896 keys.sort();
13897 const keysLen = keys.length;
13898 for (let i = 0; i < keysLen; i++) {
13899 const key = keys[i];
13900 stringBuilder.push(key + '="' + attrs[key] + '"');
13901 }
13902 const nodeName = this.nodeName.toLocaleLowerCase();
13903 const attrsString = stringBuilder.length > 0 ? ' ' + stringBuilder.join(' ') : '';
13904 return `<${nodeName}${attrsString}>${super.toString()}</${nodeName}>`
13905 }
13906
13907 /**
13908 * Removes an attribute from this YXmlElement.
13909 *
13910 * @param {string} attributeName The attribute name that is to be removed.
13911 *
13912 * @public
13913 */
13914 removeAttribute (attributeName) {
13915 if (this.doc !== null) {
13916 transact(this.doc, transaction => {
13917 typeMapDelete(transaction, this, attributeName);
13918 });
13919 } else {
13920 /** @type {Map<string,any>} */ (this._prelimAttrs).delete(attributeName);
13921 }
13922 }
13923
13924 /**
13925 * Sets or updates an attribute.
13926 *
13927 * @template {keyof KV & string} KEY
13928 *
13929 * @param {KEY} attributeName The attribute name that is to be set.
13930 * @param {KV[KEY]} attributeValue The attribute value that is to be set.
13931 *
13932 * @public
13933 */
13934 setAttribute (attributeName, attributeValue) {
13935 if (this.doc !== null) {
13936 transact(this.doc, transaction => {
13937 typeMapSet(transaction, this, attributeName, attributeValue);
13938 });
13939 } else {
13940 /** @type {Map<string, any>} */ (this._prelimAttrs).set(attributeName, attributeValue);
13941 }
13942 }
13943
13944 /**
13945 * Returns an attribute value that belongs to the attribute name.
13946 *
13947 * @template {keyof KV & string} KEY
13948 *
13949 * @param {KEY} attributeName The attribute name that identifies the
13950 * queried value.
13951 * @return {KV[KEY]|undefined} The queried attribute value.
13952 *
13953 * @public
13954 */
13955 getAttribute (attributeName) {
13956 return /** @type {any} */ (typeMapGet(this, attributeName))
13957 }
13958
13959 /**
13960 * Returns whether an attribute exists
13961 *
13962 * @param {string} attributeName The attribute name to check for existence.
13963 * @return {boolean} whether the attribute exists.
13964 *
13965 * @public
13966 */
13967 hasAttribute (attributeName) {
13968 return /** @type {any} */ (typeMapHas(this, attributeName))
13969 }
13970
13971 /**
13972 * Returns all attribute name/value pairs in a JSON Object.
13973 *
13974 * @return {{ [Key in Extract<keyof KV,string>]?: KV[Key]}} A JSON Object that describes the attributes.
13975 *
13976 * @public
13977 */
13978 getAttributes () {
13979 return /** @type {any} */ (typeMapGetAll(this))
13980 }
13981
13982 /**
13983 * Creates a Dom Element that mirrors this YXmlElement.
13984 *
13985 * @param {Document} [_document=document] The document object (you must define
13986 * this when calling this method in
13987 * nodejs)
13988 * @param {Object<string, any>} [hooks={}] Optional property to customize how hooks
13989 * are presented in the DOM
13990 * @param {any} [binding] You should not set this property. This is
13991 * used if DomBinding wants to create a
13992 * association to the created DOM type.
13993 * @return {Node} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
13994 *
13995 * @public
13996 */
13997 toDOM (_document = document, hooks = {}, binding) {
13998 const dom = _document.createElement(this.nodeName);
13999 const attrs = this.getAttributes();
14000 for (const key in attrs) {
14001 const value = attrs[key];
14002 if (typeof value === 'string') {
14003 dom.setAttribute(key, value);
14004 }
14005 }
14006 typeListForEach(this, yxml => {
14007 dom.appendChild(yxml.toDOM(_document, hooks, binding));
14008 });
14009 if (binding !== undefined) {
14010 binding._createAssociation(dom, this);
14011 }
14012 return dom
14013 }
14014
14015 /**
14016 * Transform the properties of this type to binary and write it to an
14017 * BinaryEncoder.
14018 *
14019 * This is called when this Item is sent to a remote peer.
14020 *
14021 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
14022 */
14023 _write (encoder) {
14024 encoder.writeTypeRef(YXmlElementRefID);
14025 encoder.writeKey(this.nodeName);
14026 }
14027 }
14028
14029 /**
14030 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14031 * @return {YXmlElement}
14032 *
14033 * @function
14034 */
14035 const readYXmlElement = decoder => new YXmlElement(decoder.readKey());
14036
14037 /**
14038 * @extends YEvent<YXmlElement|YXmlText|YXmlFragment>
14039 * An Event that describes changes on a YXml Element or Yxml Fragment
14040 */
14041 class YXmlEvent extends YEvent {
14042 /**
14043 * @param {YXmlElement|YXmlText|YXmlFragment} target The target on which the event is created.
14044 * @param {Set<string|null>} subs The set of changed attributes. `null` is included if the
14045 * child list changed.
14046 * @param {Transaction} transaction The transaction instance with wich the
14047 * change was created.
14048 */
14049 constructor (target, subs, transaction) {
14050 super(target, transaction);
14051 /**
14052 * Whether the children changed.
14053 * @type {Boolean}
14054 * @private
14055 */
14056 this.childListChanged = false;
14057 /**
14058 * Set of all changed attributes.
14059 * @type {Set<string>}
14060 */
14061 this.attributesChanged = new Set();
14062 subs.forEach((sub) => {
14063 if (sub === null) {
14064 this.childListChanged = true;
14065 } else {
14066 this.attributesChanged.add(sub);
14067 }
14068 });
14069 }
14070 }
14071
14072 /**
14073 * You can manage binding to a custom type with YXmlHook.
14074 *
14075 * @extends {YMap<any>}
14076 */
14077 class YXmlHook extends YMap {
14078 /**
14079 * @param {string} hookName nodeName of the Dom Node.
14080 */
14081 constructor (hookName) {
14082 super();
14083 /**
14084 * @type {string}
14085 */
14086 this.hookName = hookName;
14087 }
14088
14089 /**
14090 * Creates an Item with the same effect as this Item (without position effect)
14091 */
14092 _copy () {
14093 return new YXmlHook(this.hookName)
14094 }
14095
14096 /**
14097 * @return {YXmlHook}
14098 */
14099 clone () {
14100 const el = new YXmlHook(this.hookName);
14101 this.forEach((value, key) => {
14102 el.set(key, value);
14103 });
14104 return el
14105 }
14106
14107 /**
14108 * Creates a Dom Element that mirrors this YXmlElement.
14109 *
14110 * @param {Document} [_document=document] The document object (you must define
14111 * this when calling this method in
14112 * nodejs)
14113 * @param {Object.<string, any>} [hooks] Optional property to customize how hooks
14114 * are presented in the DOM
14115 * @param {any} [binding] You should not set this property. This is
14116 * used if DomBinding wants to create a
14117 * association to the created DOM type
14118 * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
14119 *
14120 * @public
14121 */
14122 toDOM (_document = document, hooks = {}, binding) {
14123 const hook = hooks[this.hookName];
14124 let dom;
14125 if (hook !== undefined) {
14126 dom = hook.createDom(this);
14127 } else {
14128 dom = document.createElement(this.hookName);
14129 }
14130 dom.setAttribute('data-yjs-hook', this.hookName);
14131 if (binding !== undefined) {
14132 binding._createAssociation(dom, this);
14133 }
14134 return dom
14135 }
14136
14137 /**
14138 * Transform the properties of this type to binary and write it to an
14139 * BinaryEncoder.
14140 *
14141 * This is called when this Item is sent to a remote peer.
14142 *
14143 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
14144 */
14145 _write (encoder) {
14146 encoder.writeTypeRef(YXmlHookRefID);
14147 encoder.writeKey(this.hookName);
14148 }
14149 }
14150
14151 /**
14152 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14153 * @return {YXmlHook}
14154 *
14155 * @private
14156 * @function
14157 */
14158 const readYXmlHook = decoder =>
14159 new YXmlHook(decoder.readKey());
14160
14161 /**
14162 * Represents text in a Dom Element. In the future this type will also handle
14163 * simple formatting information like bold and italic.
14164 */
14165 class YXmlText extends YText {
14166 /**
14167 * @type {YXmlElement|YXmlText|null}
14168 */
14169 get nextSibling () {
14170 const n = this._item ? this._item.next : null;
14171 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
14172 }
14173
14174 /**
14175 * @type {YXmlElement|YXmlText|null}
14176 */
14177 get prevSibling () {
14178 const n = this._item ? this._item.prev : null;
14179 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
14180 }
14181
14182 _copy () {
14183 return new YXmlText()
14184 }
14185
14186 /**
14187 * @return {YXmlText}
14188 */
14189 clone () {
14190 const text = new YXmlText();
14191 text.applyDelta(this.toDelta());
14192 return text
14193 }
14194
14195 /**
14196 * Creates a Dom Element that mirrors this YXmlText.
14197 *
14198 * @param {Document} [_document=document] The document object (you must define
14199 * this when calling this method in
14200 * nodejs)
14201 * @param {Object<string, any>} [hooks] Optional property to customize how hooks
14202 * are presented in the DOM
14203 * @param {any} [binding] You should not set this property. This is
14204 * used if DomBinding wants to create a
14205 * association to the created DOM type.
14206 * @return {Text} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
14207 *
14208 * @public
14209 */
14210 toDOM (_document = document, hooks, binding) {
14211 const dom = _document.createTextNode(this.toString());
14212 if (binding !== undefined) {
14213 binding._createAssociation(dom, this);
14214 }
14215 return dom
14216 }
14217
14218 toString () {
14219 // @ts-ignore
14220 return this.toDelta().map(delta => {
14221 const nestedNodes = [];
14222 for (const nodeName in delta.attributes) {
14223 const attrs = [];
14224 for (const key in delta.attributes[nodeName]) {
14225 attrs.push({ key, value: delta.attributes[nodeName][key] });
14226 }
14227 // sort attributes to get a unique order
14228 attrs.sort((a, b) => a.key < b.key ? -1 : 1);
14229 nestedNodes.push({ nodeName, attrs });
14230 }
14231 // sort node order to get a unique order
14232 nestedNodes.sort((a, b) => a.nodeName < b.nodeName ? -1 : 1);
14233 // now convert to dom string
14234 let str = '';
14235 for (let i = 0; i < nestedNodes.length; i++) {
14236 const node = nestedNodes[i];
14237 str += `<${node.nodeName}`;
14238 for (let j = 0; j < node.attrs.length; j++) {
14239 const attr = node.attrs[j];
14240 str += ` ${attr.key}="${attr.value}"`;
14241 }
14242 str += '>';
14243 }
14244 str += delta.insert;
14245 for (let i = nestedNodes.length - 1; i >= 0; i--) {
14246 str += `</${nestedNodes[i].nodeName}>`;
14247 }
14248 return str
14249 }).join('')
14250 }
14251
14252 /**
14253 * @return {string}
14254 */
14255 toJSON () {
14256 return this.toString()
14257 }
14258
14259 /**
14260 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14261 */
14262 _write (encoder) {
14263 encoder.writeTypeRef(YXmlTextRefID);
14264 }
14265 }
14266
14267 /**
14268 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14269 * @return {YXmlText}
14270 *
14271 * @private
14272 * @function
14273 */
14274 const readYXmlText = decoder => new YXmlText();
14275
14276 class AbstractStruct {
14277 /**
14278 * @param {ID} id
14279 * @param {number} length
14280 */
14281 constructor (id, length) {
14282 this.id = id;
14283 this.length = length;
14284 }
14285
14286 /**
14287 * @type {boolean}
14288 */
14289 get deleted () {
14290 throw methodUnimplemented()
14291 }
14292
14293 /**
14294 * Merge this struct with the item to the right.
14295 * This method is already assuming that `this.id.clock + this.length === this.id.clock`.
14296 * Also this method does *not* remove right from StructStore!
14297 * @param {AbstractStruct} right
14298 * @return {boolean} wether this merged with right
14299 */
14300 mergeWith (right) {
14301 return false
14302 }
14303
14304 /**
14305 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
14306 * @param {number} offset
14307 * @param {number} encodingRef
14308 */
14309 write (encoder, offset, encodingRef) {
14310 throw methodUnimplemented()
14311 }
14312
14313 /**
14314 * @param {Transaction} transaction
14315 * @param {number} offset
14316 */
14317 integrate (transaction, offset) {
14318 throw methodUnimplemented()
14319 }
14320 }
14321
14322 const structGCRefNumber = 0;
14323
14324 /**
14325 * @private
14326 */
14327 class GC extends AbstractStruct {
14328 get deleted () {
14329 return true
14330 }
14331
14332 delete () {}
14333
14334 /**
14335 * @param {GC} right
14336 * @return {boolean}
14337 */
14338 mergeWith (right) {
14339 if (this.constructor !== right.constructor) {
14340 return false
14341 }
14342 this.length += right.length;
14343 return true
14344 }
14345
14346 /**
14347 * @param {Transaction} transaction
14348 * @param {number} offset
14349 */
14350 integrate (transaction, offset) {
14351 if (offset > 0) {
14352 this.id.clock += offset;
14353 this.length -= offset;
14354 }
14355 addStruct(transaction.doc.store, this);
14356 }
14357
14358 /**
14359 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14360 * @param {number} offset
14361 */
14362 write (encoder, offset) {
14363 encoder.writeInfo(structGCRefNumber);
14364 encoder.writeLen(this.length - offset);
14365 }
14366
14367 /**
14368 * @param {Transaction} transaction
14369 * @param {StructStore} store
14370 * @return {null | number}
14371 */
14372 getMissing (transaction, store) {
14373 return null
14374 }
14375 }
14376
14377 class ContentBinary {
14378 /**
14379 * @param {Uint8Array} content
14380 */
14381 constructor (content) {
14382 this.content = content;
14383 }
14384
14385 /**
14386 * @return {number}
14387 */
14388 getLength () {
14389 return 1
14390 }
14391
14392 /**
14393 * @return {Array<any>}
14394 */
14395 getContent () {
14396 return [this.content]
14397 }
14398
14399 /**
14400 * @return {boolean}
14401 */
14402 isCountable () {
14403 return true
14404 }
14405
14406 /**
14407 * @return {ContentBinary}
14408 */
14409 copy () {
14410 return new ContentBinary(this.content)
14411 }
14412
14413 /**
14414 * @param {number} offset
14415 * @return {ContentBinary}
14416 */
14417 splice (offset) {
14418 throw methodUnimplemented()
14419 }
14420
14421 /**
14422 * @param {ContentBinary} right
14423 * @return {boolean}
14424 */
14425 mergeWith (right) {
14426 return false
14427 }
14428
14429 /**
14430 * @param {Transaction} transaction
14431 * @param {Item} item
14432 */
14433 integrate (transaction, item) {}
14434 /**
14435 * @param {Transaction} transaction
14436 */
14437 delete (transaction) {}
14438 /**
14439 * @param {StructStore} store
14440 */
14441 gc (store) {}
14442 /**
14443 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14444 * @param {number} offset
14445 */
14446 write (encoder, offset) {
14447 encoder.writeBuf(this.content);
14448 }
14449
14450 /**
14451 * @return {number}
14452 */
14453 getRef () {
14454 return 3
14455 }
14456 }
14457
14458 /**
14459 * @param {UpdateDecoderV1 | UpdateDecoderV2 } decoder
14460 * @return {ContentBinary}
14461 */
14462 const readContentBinary = decoder => new ContentBinary(decoder.readBuf());
14463
14464 class ContentDeleted {
14465 /**
14466 * @param {number} len
14467 */
14468 constructor (len) {
14469 this.len = len;
14470 }
14471
14472 /**
14473 * @return {number}
14474 */
14475 getLength () {
14476 return this.len
14477 }
14478
14479 /**
14480 * @return {Array<any>}
14481 */
14482 getContent () {
14483 return []
14484 }
14485
14486 /**
14487 * @return {boolean}
14488 */
14489 isCountable () {
14490 return false
14491 }
14492
14493 /**
14494 * @return {ContentDeleted}
14495 */
14496 copy () {
14497 return new ContentDeleted(this.len)
14498 }
14499
14500 /**
14501 * @param {number} offset
14502 * @return {ContentDeleted}
14503 */
14504 splice (offset) {
14505 const right = new ContentDeleted(this.len - offset);
14506 this.len = offset;
14507 return right
14508 }
14509
14510 /**
14511 * @param {ContentDeleted} right
14512 * @return {boolean}
14513 */
14514 mergeWith (right) {
14515 this.len += right.len;
14516 return true
14517 }
14518
14519 /**
14520 * @param {Transaction} transaction
14521 * @param {Item} item
14522 */
14523 integrate (transaction, item) {
14524 addToDeleteSet(transaction.deleteSet, item.id.client, item.id.clock, this.len);
14525 item.markDeleted();
14526 }
14527
14528 /**
14529 * @param {Transaction} transaction
14530 */
14531 delete (transaction) {}
14532 /**
14533 * @param {StructStore} store
14534 */
14535 gc (store) {}
14536 /**
14537 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14538 * @param {number} offset
14539 */
14540 write (encoder, offset) {
14541 encoder.writeLen(this.len - offset);
14542 }
14543
14544 /**
14545 * @return {number}
14546 */
14547 getRef () {
14548 return 1
14549 }
14550 }
14551
14552 /**
14553 * @private
14554 *
14555 * @param {UpdateDecoderV1 | UpdateDecoderV2 } decoder
14556 * @return {ContentDeleted}
14557 */
14558 const readContentDeleted = decoder => new ContentDeleted(decoder.readLen());
14559
14560 /**
14561 * @param {string} guid
14562 * @param {Object<string, any>} opts
14563 */
14564 const createDocFromOpts = (guid, opts) => new Doc({ guid, ...opts, shouldLoad: opts.shouldLoad || opts.autoLoad || false });
14565
14566 /**
14567 * @private
14568 */
14569 class ContentDoc {
14570 /**
14571 * @param {Doc} doc
14572 */
14573 constructor (doc) {
14574 if (doc._item) {
14575 console.error('This document was already integrated as a sub-document. You should create a second instance instead with the same guid.');
14576 }
14577 /**
14578 * @type {Doc}
14579 */
14580 this.doc = doc;
14581 /**
14582 * @type {any}
14583 */
14584 const opts = {};
14585 this.opts = opts;
14586 if (!doc.gc) {
14587 opts.gc = false;
14588 }
14589 if (doc.autoLoad) {
14590 opts.autoLoad = true;
14591 }
14592 if (doc.meta !== null) {
14593 opts.meta = doc.meta;
14594 }
14595 }
14596
14597 /**
14598 * @return {number}
14599 */
14600 getLength () {
14601 return 1
14602 }
14603
14604 /**
14605 * @return {Array<any>}
14606 */
14607 getContent () {
14608 return [this.doc]
14609 }
14610
14611 /**
14612 * @return {boolean}
14613 */
14614 isCountable () {
14615 return true
14616 }
14617
14618 /**
14619 * @return {ContentDoc}
14620 */
14621 copy () {
14622 return new ContentDoc(createDocFromOpts(this.doc.guid, this.opts))
14623 }
14624
14625 /**
14626 * @param {number} offset
14627 * @return {ContentDoc}
14628 */
14629 splice (offset) {
14630 throw methodUnimplemented()
14631 }
14632
14633 /**
14634 * @param {ContentDoc} right
14635 * @return {boolean}
14636 */
14637 mergeWith (right) {
14638 return false
14639 }
14640
14641 /**
14642 * @param {Transaction} transaction
14643 * @param {Item} item
14644 */
14645 integrate (transaction, item) {
14646 // this needs to be reflected in doc.destroy as well
14647 this.doc._item = item;
14648 transaction.subdocsAdded.add(this.doc);
14649 if (this.doc.shouldLoad) {
14650 transaction.subdocsLoaded.add(this.doc);
14651 }
14652 }
14653
14654 /**
14655 * @param {Transaction} transaction
14656 */
14657 delete (transaction) {
14658 if (transaction.subdocsAdded.has(this.doc)) {
14659 transaction.subdocsAdded.delete(this.doc);
14660 } else {
14661 transaction.subdocsRemoved.add(this.doc);
14662 }
14663 }
14664
14665 /**
14666 * @param {StructStore} store
14667 */
14668 gc (store) { }
14669
14670 /**
14671 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14672 * @param {number} offset
14673 */
14674 write (encoder, offset) {
14675 encoder.writeString(this.doc.guid);
14676 encoder.writeAny(this.opts);
14677 }
14678
14679 /**
14680 * @return {number}
14681 */
14682 getRef () {
14683 return 9
14684 }
14685 }
14686
14687 /**
14688 * @private
14689 *
14690 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14691 * @return {ContentDoc}
14692 */
14693 const readContentDoc = decoder => new ContentDoc(createDocFromOpts(decoder.readString(), decoder.readAny()));
14694
14695 /**
14696 * @private
14697 */
14698 class ContentEmbed {
14699 /**
14700 * @param {Object} embed
14701 */
14702 constructor (embed) {
14703 this.embed = embed;
14704 }
14705
14706 /**
14707 * @return {number}
14708 */
14709 getLength () {
14710 return 1
14711 }
14712
14713 /**
14714 * @return {Array<any>}
14715 */
14716 getContent () {
14717 return [this.embed]
14718 }
14719
14720 /**
14721 * @return {boolean}
14722 */
14723 isCountable () {
14724 return true
14725 }
14726
14727 /**
14728 * @return {ContentEmbed}
14729 */
14730 copy () {
14731 return new ContentEmbed(this.embed)
14732 }
14733
14734 /**
14735 * @param {number} offset
14736 * @return {ContentEmbed}
14737 */
14738 splice (offset) {
14739 throw methodUnimplemented()
14740 }
14741
14742 /**
14743 * @param {ContentEmbed} right
14744 * @return {boolean}
14745 */
14746 mergeWith (right) {
14747 return false
14748 }
14749
14750 /**
14751 * @param {Transaction} transaction
14752 * @param {Item} item
14753 */
14754 integrate (transaction, item) {}
14755 /**
14756 * @param {Transaction} transaction
14757 */
14758 delete (transaction) {}
14759 /**
14760 * @param {StructStore} store
14761 */
14762 gc (store) {}
14763 /**
14764 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14765 * @param {number} offset
14766 */
14767 write (encoder, offset) {
14768 encoder.writeJSON(this.embed);
14769 }
14770
14771 /**
14772 * @return {number}
14773 */
14774 getRef () {
14775 return 5
14776 }
14777 }
14778
14779 /**
14780 * @private
14781 *
14782 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14783 * @return {ContentEmbed}
14784 */
14785 const readContentEmbed = decoder => new ContentEmbed(decoder.readJSON());
14786
14787 /**
14788 * @private
14789 */
14790 class ContentFormat {
14791 /**
14792 * @param {string} key
14793 * @param {Object} value
14794 */
14795 constructor (key, value) {
14796 this.key = key;
14797 this.value = value;
14798 }
14799
14800 /**
14801 * @return {number}
14802 */
14803 getLength () {
14804 return 1
14805 }
14806
14807 /**
14808 * @return {Array<any>}
14809 */
14810 getContent () {
14811 return []
14812 }
14813
14814 /**
14815 * @return {boolean}
14816 */
14817 isCountable () {
14818 return false
14819 }
14820
14821 /**
14822 * @return {ContentFormat}
14823 */
14824 copy () {
14825 return new ContentFormat(this.key, this.value)
14826 }
14827
14828 /**
14829 * @param {number} _offset
14830 * @return {ContentFormat}
14831 */
14832 splice (_offset) {
14833 throw methodUnimplemented()
14834 }
14835
14836 /**
14837 * @param {ContentFormat} _right
14838 * @return {boolean}
14839 */
14840 mergeWith (_right) {
14841 return false
14842 }
14843
14844 /**
14845 * @param {Transaction} _transaction
14846 * @param {Item} item
14847 */
14848 integrate (_transaction, item) {
14849 // @todo searchmarker are currently unsupported for rich text documents
14850 const p = /** @type {YText} */ (item.parent);
14851 p._searchMarker = null;
14852 p._hasFormatting = true;
14853 }
14854
14855 /**
14856 * @param {Transaction} transaction
14857 */
14858 delete (transaction) {}
14859 /**
14860 * @param {StructStore} store
14861 */
14862 gc (store) {}
14863 /**
14864 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14865 * @param {number} offset
14866 */
14867 write (encoder, offset) {
14868 encoder.writeKey(this.key);
14869 encoder.writeJSON(this.value);
14870 }
14871
14872 /**
14873 * @return {number}
14874 */
14875 getRef () {
14876 return 6
14877 }
14878 }
14879
14880 /**
14881 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14882 * @return {ContentFormat}
14883 */
14884 const readContentFormat = decoder => new ContentFormat(decoder.readKey(), decoder.readJSON());
14885
14886 /**
14887 * @private
14888 */
14889 class ContentJSON {
14890 /**
14891 * @param {Array<any>} arr
14892 */
14893 constructor (arr) {
14894 /**
14895 * @type {Array<any>}
14896 */
14897 this.arr = arr;
14898 }
14899
14900 /**
14901 * @return {number}
14902 */
14903 getLength () {
14904 return this.arr.length
14905 }
14906
14907 /**
14908 * @return {Array<any>}
14909 */
14910 getContent () {
14911 return this.arr
14912 }
14913
14914 /**
14915 * @return {boolean}
14916 */
14917 isCountable () {
14918 return true
14919 }
14920
14921 /**
14922 * @return {ContentJSON}
14923 */
14924 copy () {
14925 return new ContentJSON(this.arr)
14926 }
14927
14928 /**
14929 * @param {number} offset
14930 * @return {ContentJSON}
14931 */
14932 splice (offset) {
14933 const right = new ContentJSON(this.arr.slice(offset));
14934 this.arr = this.arr.slice(0, offset);
14935 return right
14936 }
14937
14938 /**
14939 * @param {ContentJSON} right
14940 * @return {boolean}
14941 */
14942 mergeWith (right) {
14943 this.arr = this.arr.concat(right.arr);
14944 return true
14945 }
14946
14947 /**
14948 * @param {Transaction} transaction
14949 * @param {Item} item
14950 */
14951 integrate (transaction, item) {}
14952 /**
14953 * @param {Transaction} transaction
14954 */
14955 delete (transaction) {}
14956 /**
14957 * @param {StructStore} store
14958 */
14959 gc (store) {}
14960 /**
14961 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14962 * @param {number} offset
14963 */
14964 write (encoder, offset) {
14965 const len = this.arr.length;
14966 encoder.writeLen(len - offset);
14967 for (let i = offset; i < len; i++) {
14968 const c = this.arr[i];
14969 encoder.writeString(c === undefined ? 'undefined' : JSON.stringify(c));
14970 }
14971 }
14972
14973 /**
14974 * @return {number}
14975 */
14976 getRef () {
14977 return 2
14978 }
14979 }
14980
14981 /**
14982 * @private
14983 *
14984 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14985 * @return {ContentJSON}
14986 */
14987 const readContentJSON = decoder => {
14988 const len = decoder.readLen();
14989 const cs = [];
14990 for (let i = 0; i < len; i++) {
14991 const c = decoder.readString();
14992 if (c === 'undefined') {
14993 cs.push(undefined);
14994 } else {
14995 cs.push(JSON.parse(c));
14996 }
14997 }
14998 return new ContentJSON(cs)
14999 };
15000
15001 class ContentAny {
15002 /**
15003 * @param {Array<any>} arr
15004 */
15005 constructor (arr) {
15006 /**
15007 * @type {Array<any>}
15008 */
15009 this.arr = arr;
15010 }
15011
15012 /**
15013 * @return {number}
15014 */
15015 getLength () {
15016 return this.arr.length
15017 }
15018
15019 /**
15020 * @return {Array<any>}
15021 */
15022 getContent () {
15023 return this.arr
15024 }
15025
15026 /**
15027 * @return {boolean}
15028 */
15029 isCountable () {
15030 return true
15031 }
15032
15033 /**
15034 * @return {ContentAny}
15035 */
15036 copy () {
15037 return new ContentAny(this.arr)
15038 }
15039
15040 /**
15041 * @param {number} offset
15042 * @return {ContentAny}
15043 */
15044 splice (offset) {
15045 const right = new ContentAny(this.arr.slice(offset));
15046 this.arr = this.arr.slice(0, offset);
15047 return right
15048 }
15049
15050 /**
15051 * @param {ContentAny} right
15052 * @return {boolean}
15053 */
15054 mergeWith (right) {
15055 this.arr = this.arr.concat(right.arr);
15056 return true
15057 }
15058
15059 /**
15060 * @param {Transaction} transaction
15061 * @param {Item} item
15062 */
15063 integrate (transaction, item) {}
15064 /**
15065 * @param {Transaction} transaction
15066 */
15067 delete (transaction) {}
15068 /**
15069 * @param {StructStore} store
15070 */
15071 gc (store) {}
15072 /**
15073 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
15074 * @param {number} offset
15075 */
15076 write (encoder, offset) {
15077 const len = this.arr.length;
15078 encoder.writeLen(len - offset);
15079 for (let i = offset; i < len; i++) {
15080 const c = this.arr[i];
15081 encoder.writeAny(c);
15082 }
15083 }
15084
15085 /**
15086 * @return {number}
15087 */
15088 getRef () {
15089 return 8
15090 }
15091 }
15092
15093 /**
15094 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
15095 * @return {ContentAny}
15096 */
15097 const readContentAny = decoder => {
15098 const len = decoder.readLen();
15099 const cs = [];
15100 for (let i = 0; i < len; i++) {
15101 cs.push(decoder.readAny());
15102 }
15103 return new ContentAny(cs)
15104 };
15105
15106 /**
15107 * @private
15108 */
15109 class ContentString {
15110 /**
15111 * @param {string} str
15112 */
15113 constructor (str) {
15114 /**
15115 * @type {string}
15116 */
15117 this.str = str;
15118 }
15119
15120 /**
15121 * @return {number}
15122 */
15123 getLength () {
15124 return this.str.length
15125 }
15126
15127 /**
15128 * @return {Array<any>}
15129 */
15130 getContent () {
15131 return this.str.split('')
15132 }
15133
15134 /**
15135 * @return {boolean}
15136 */
15137 isCountable () {
15138 return true
15139 }
15140
15141 /**
15142 * @return {ContentString}
15143 */
15144 copy () {
15145 return new ContentString(this.str)
15146 }
15147
15148 /**
15149 * @param {number} offset
15150 * @return {ContentString}
15151 */
15152 splice (offset) {
15153 const right = new ContentString(this.str.slice(offset));
15154 this.str = this.str.slice(0, offset);
15155
15156 // Prevent encoding invalid documents because of splitting of surrogate pairs: https://github.com/yjs/yjs/issues/248
15157 const firstCharCode = this.str.charCodeAt(offset - 1);
15158 if (firstCharCode >= 0xD800 && firstCharCode <= 0xDBFF) {
15159 // Last character of the left split is the start of a surrogate utf16/ucs2 pair.
15160 // We don't support splitting of surrogate pairs because this may lead to invalid documents.
15161 // Replace the invalid character with a unicode replacement character (� / U+FFFD)
15162 this.str = this.str.slice(0, offset - 1) + '�';
15163 // replace right as well
15164 right.str = '�' + right.str.slice(1);
15165 }
15166 return right
15167 }
15168
15169 /**
15170 * @param {ContentString} right
15171 * @return {boolean}
15172 */
15173 mergeWith (right) {
15174 this.str += right.str;
15175 return true
15176 }
15177
15178 /**
15179 * @param {Transaction} transaction
15180 * @param {Item} item
15181 */
15182 integrate (transaction, item) {}
15183 /**
15184 * @param {Transaction} transaction
15185 */
15186 delete (transaction) {}
15187 /**
15188 * @param {StructStore} store
15189 */
15190 gc (store) {}
15191 /**
15192 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
15193 * @param {number} offset
15194 */
15195 write (encoder, offset) {
15196 encoder.writeString(offset === 0 ? this.str : this.str.slice(offset));
15197 }
15198
15199 /**
15200 * @return {number}
15201 */
15202 getRef () {
15203 return 4
15204 }
15205 }
15206
15207 /**
15208 * @private
15209 *
15210 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
15211 * @return {ContentString}
15212 */
15213 const readContentString = decoder => new ContentString(decoder.readString());
15214
15215 /**
15216 * @type {Array<function(UpdateDecoderV1 | UpdateDecoderV2):AbstractType<any>>}
15217 * @private
15218 */
15219 const typeRefs = [
15220 readYArray,
15221 readYMap,
15222 readYText,
15223 readYXmlElement,
15224 readYXmlFragment,
15225 readYXmlHook,
15226 readYXmlText
15227 ];
15228
15229 const YArrayRefID = 0;
15230 const YMapRefID = 1;
15231 const YTextRefID = 2;
15232 const YXmlElementRefID = 3;
15233 const YXmlFragmentRefID = 4;
15234 const YXmlHookRefID = 5;
15235 const YXmlTextRefID = 6;
15236
15237 /**
15238 * @private
15239 */
15240 class ContentType {
15241 /**
15242 * @param {AbstractType<any>} type
15243 */
15244 constructor (type) {
15245 /**
15246 * @type {AbstractType<any>}
15247 */
15248 this.type = type;
15249 }
15250
15251 /**
15252 * @return {number}
15253 */
15254 getLength () {
15255 return 1
15256 }
15257
15258 /**
15259 * @return {Array<any>}
15260 */
15261 getContent () {
15262 return [this.type]
15263 }
15264
15265 /**
15266 * @return {boolean}
15267 */
15268 isCountable () {
15269 return true
15270 }
15271
15272 /**
15273 * @return {ContentType}
15274 */
15275 copy () {
15276 return new ContentType(this.type._copy())
15277 }
15278
15279 /**
15280 * @param {number} offset
15281 * @return {ContentType}
15282 */
15283 splice (offset) {
15284 throw methodUnimplemented()
15285 }
15286
15287 /**
15288 * @param {ContentType} right
15289 * @return {boolean}
15290 */
15291 mergeWith (right) {
15292 return false
15293 }
15294
15295 /**
15296 * @param {Transaction} transaction
15297 * @param {Item} item
15298 */
15299 integrate (transaction, item) {
15300 this.type._integrate(transaction.doc, item);
15301 }
15302
15303 /**
15304 * @param {Transaction} transaction
15305 */
15306 delete (transaction) {
15307 let item = this.type._start;
15308 while (item !== null) {
15309 if (!item.deleted) {
15310 item.delete(transaction);
15311 } else if (item.id.clock < (transaction.beforeState.get(item.id.client) || 0)) {
15312 // This will be gc'd later and we want to merge it if possible
15313 // We try to merge all deleted items after each transaction,
15314 // but we have no knowledge about that this needs to be merged
15315 // since it is not in transaction.ds. Hence we add it to transaction._mergeStructs
15316 transaction._mergeStructs.push(item);
15317 }
15318 item = item.right;
15319 }
15320 this.type._map.forEach(item => {
15321 if (!item.deleted) {
15322 item.delete(transaction);
15323 } else if (item.id.clock < (transaction.beforeState.get(item.id.client) || 0)) {
15324 // same as above
15325 transaction._mergeStructs.push(item);
15326 }
15327 });
15328 transaction.changed.delete(this.type);
15329 }
15330
15331 /**
15332 * @param {StructStore} store
15333 */
15334 gc (store) {
15335 let item = this.type._start;
15336 while (item !== null) {
15337 item.gc(store, true);
15338 item = item.right;
15339 }
15340 this.type._start = null;
15341 this.type._map.forEach(/** @param {Item | null} item */ (item) => {
15342 while (item !== null) {
15343 item.gc(store, true);
15344 item = item.left;
15345 }
15346 });
15347 this.type._map = new Map();
15348 }
15349
15350 /**
15351 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
15352 * @param {number} offset
15353 */
15354 write (encoder, offset) {
15355 this.type._write(encoder);
15356 }
15357
15358 /**
15359 * @return {number}
15360 */
15361 getRef () {
15362 return 7
15363 }
15364 }
15365
15366 /**
15367 * @private
15368 *
15369 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
15370 * @return {ContentType}
15371 */
15372 const readContentType = decoder => new ContentType(typeRefs[decoder.readTypeRef()](decoder));
15373
15374 /**
15375 * @todo This should return several items
15376 *
15377 * @param {StructStore} store
15378 * @param {ID} id
15379 * @return {{item:Item, diff:number}}
15380 */
15381 const followRedone = (store, id) => {
15382 /**
15383 * @type {ID|null}
15384 */
15385 let nextID = id;
15386 let diff = 0;
15387 let item;
15388 do {
15389 if (diff > 0) {
15390 nextID = createID(nextID.client, nextID.clock + diff);
15391 }
15392 item = getItem(store, nextID);
15393 diff = nextID.clock - item.id.clock;
15394 nextID = item.redone;
15395 } while (nextID !== null && item instanceof Item)
15396 return {
15397 item, diff
15398 }
15399 };
15400
15401 /**
15402 * Make sure that neither item nor any of its parents is ever deleted.
15403 *
15404 * This property does not persist when storing it into a database or when
15405 * sending it to other peers
15406 *
15407 * @param {Item|null} item
15408 * @param {boolean} keep
15409 */
15410 const keepItem = (item, keep) => {
15411 while (item !== null && item.keep !== keep) {
15412 item.keep = keep;
15413 item = /** @type {AbstractType<any>} */ (item.parent)._item;
15414 }
15415 };
15416
15417 /**
15418 * Split leftItem into two items
15419 * @param {Transaction} transaction
15420 * @param {Item} leftItem
15421 * @param {number} diff
15422 * @return {Item}
15423 *
15424 * @function
15425 * @private
15426 */
15427 const splitItem = (transaction, leftItem, diff) => {
15428 // create rightItem
15429 const { client, clock } = leftItem.id;
15430 const rightItem = new Item(
15431 createID(client, clock + diff),
15432 leftItem,
15433 createID(client, clock + diff - 1),
15434 leftItem.right,
15435 leftItem.rightOrigin,
15436 leftItem.parent,
15437 leftItem.parentSub,
15438 leftItem.content.splice(diff)
15439 );
15440 if (leftItem.deleted) {
15441 rightItem.markDeleted();
15442 }
15443 if (leftItem.keep) {
15444 rightItem.keep = true;
15445 }
15446 if (leftItem.redone !== null) {
15447 rightItem.redone = createID(leftItem.redone.client, leftItem.redone.clock + diff);
15448 }
15449 // update left (do not set leftItem.rightOrigin as it will lead to problems when syncing)
15450 leftItem.right = rightItem;
15451 // update right
15452 if (rightItem.right !== null) {
15453 rightItem.right.left = rightItem;
15454 }
15455 // right is more specific.
15456 transaction._mergeStructs.push(rightItem);
15457 // update parent._map
15458 if (rightItem.parentSub !== null && rightItem.right === null) {
15459 /** @type {AbstractType<any>} */ (rightItem.parent)._map.set(rightItem.parentSub, rightItem);
15460 }
15461 leftItem.length = diff;
15462 return rightItem
15463 };
15464
15465 /**
15466 * @param {Array<StackItem>} stack
15467 * @param {ID} id
15468 */
15469 const isDeletedByUndoStack = (stack, id) => array.some(stack, /** @param {StackItem} s */ s => isDeleted(s.deletions, id));
15470
15471 /**
15472 * Redoes the effect of this operation.
15473 *
15474 * @param {Transaction} transaction The Yjs instance.
15475 * @param {Item} item
15476 * @param {Set<Item>} redoitems
15477 * @param {DeleteSet} itemsToDelete
15478 * @param {boolean} ignoreRemoteMapChanges
15479 * @param {import('../utils/UndoManager.js').UndoManager} um
15480 *
15481 * @return {Item|null}
15482 *
15483 * @private
15484 */
15485 const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) => {
15486 const doc = transaction.doc;
15487 const store = doc.store;
15488 const ownClientID = doc.clientID;
15489 const redone = item.redone;
15490 if (redone !== null) {
15491 return getItemCleanStart(transaction, redone)
15492 }
15493 let parentItem = /** @type {AbstractType<any>} */ (item.parent)._item;
15494 /**
15495 * @type {Item|null}
15496 */
15497 let left = null;
15498 /**
15499 * @type {Item|null}
15500 */
15501 let right;
15502 // make sure that parent is redone
15503 if (parentItem !== null && parentItem.deleted === true) {
15504 // try to undo parent if it will be undone anyway
15505 if (parentItem.redone === null && (!redoitems.has(parentItem) || redoItem(transaction, parentItem, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) === null)) {
15506 return null
15507 }
15508 while (parentItem.redone !== null) {
15509 parentItem = getItemCleanStart(transaction, parentItem.redone);
15510 }
15511 }
15512 const parentType = parentItem === null ? /** @type {AbstractType<any>} */ (item.parent) : /** @type {ContentType} */ (parentItem.content).type;
15513
15514 if (item.parentSub === null) {
15515 // Is an array item. Insert at the old position
15516 left = item.left;
15517 right = item;
15518 // find next cloned_redo items
15519 while (left !== null) {
15520 /**
15521 * @type {Item|null}
15522 */
15523 let leftTrace = left;
15524 // trace redone until parent matches
15525 while (leftTrace !== null && /** @type {AbstractType<any>} */ (leftTrace.parent)._item !== parentItem) {
15526 leftTrace = leftTrace.redone === null ? null : getItemCleanStart(transaction, leftTrace.redone);
15527 }
15528 if (leftTrace !== null && /** @type {AbstractType<any>} */ (leftTrace.parent)._item === parentItem) {
15529 left = leftTrace;
15530 break
15531 }
15532 left = left.left;
15533 }
15534 while (right !== null) {
15535 /**
15536 * @type {Item|null}
15537 */
15538 let rightTrace = right;
15539 // trace redone until parent matches
15540 while (rightTrace !== null && /** @type {AbstractType<any>} */ (rightTrace.parent)._item !== parentItem) {
15541 rightTrace = rightTrace.redone === null ? null : getItemCleanStart(transaction, rightTrace.redone);
15542 }
15543 if (rightTrace !== null && /** @type {AbstractType<any>} */ (rightTrace.parent)._item === parentItem) {
15544 right = rightTrace;
15545 break
15546 }
15547 right = right.right;
15548 }
15549 } else {
15550 right = null;
15551 if (item.right && !ignoreRemoteMapChanges) {
15552 left = item;
15553 // Iterate right while right is in itemsToDelete
15554 // If it is intended to delete right while item is redone, we can expect that item should replace right.
15555 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))) {
15556 left = left.right;
15557 // follow redone
15558 while (left.redone) left = getItemCleanStart(transaction, left.redone);
15559 }
15560 if (left && left.right !== null) {
15561 // It is not possible to redo this item because it conflicts with a
15562 // change from another client
15563 return null
15564 }
15565 } else {
15566 left = parentType._map.get(item.parentSub) || null;
15567 }
15568 }
15569 const nextClock = getState(store, ownClientID);
15570 const nextId = createID(ownClientID, nextClock);
15571 const redoneItem = new Item(
15572 nextId,
15573 left, left && left.lastId,
15574 right, right && right.id,
15575 parentType,
15576 item.parentSub,
15577 item.content.copy()
15578 );
15579 item.redone = nextId;
15580 keepItem(redoneItem, true);
15581 redoneItem.integrate(transaction, 0);
15582 return redoneItem
15583 };
15584
15585 /**
15586 * Abstract class that represents any content.
15587 */
15588 class Item extends AbstractStruct {
15589 /**
15590 * @param {ID} id
15591 * @param {Item | null} left
15592 * @param {ID | null} origin
15593 * @param {Item | null} right
15594 * @param {ID | null} rightOrigin
15595 * @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.
15596 * @param {string | null} parentSub
15597 * @param {AbstractContent} content
15598 */
15599 constructor (id, left, origin, right, rightOrigin, parent, parentSub, content) {
15600 super(id, content.getLength());
15601 /**
15602 * The item that was originally to the left of this item.
15603 * @type {ID | null}
15604 */
15605 this.origin = origin;
15606 /**
15607 * The item that is currently to the left of this item.
15608 * @type {Item | null}
15609 */
15610 this.left = left;
15611 /**
15612 * The item that is currently to the right of this item.
15613 * @type {Item | null}
15614 */
15615 this.right = right;
15616 /**
15617 * The item that was originally to the right of this item.
15618 * @type {ID | null}
15619 */
15620 this.rightOrigin = rightOrigin;
15621 /**
15622 * @type {AbstractType<any>|ID|null}
15623 */
15624 this.parent = parent;
15625 /**
15626 * If the parent refers to this item with some kind of key (e.g. YMap, the
15627 * key is specified here. The key is then used to refer to the list in which
15628 * to insert this item. If `parentSub = null` type._start is the list in
15629 * which to insert to. Otherwise it is `parent._map`.
15630 * @type {String | null}
15631 */
15632 this.parentSub = parentSub;
15633 /**
15634 * If this type's effect is redone this type refers to the type that undid
15635 * this operation.
15636 * @type {ID | null}
15637 */
15638 this.redone = null;
15639 /**
15640 * @type {AbstractContent}
15641 */
15642 this.content = content;
15643 /**
15644 * bit1: keep
15645 * bit2: countable
15646 * bit3: deleted
15647 * bit4: mark - mark node as fast-search-marker
15648 * @type {number} byte
15649 */
15650 this.info = this.content.isCountable() ? BIT2 : 0;
15651 }
15652
15653 /**
15654 * This is used to mark the item as an indexed fast-search marker
15655 *
15656 * @type {boolean}
15657 */
15658 set marker (isMarked) {
15659 if (((this.info & BIT4) > 0) !== isMarked) {
15660 this.info ^= BIT4;
15661 }
15662 }
15663
15664 get marker () {
15665 return (this.info & BIT4) > 0
15666 }
15667
15668 /**
15669 * If true, do not garbage collect this Item.
15670 */
15671 get keep () {
15672 return (this.info & BIT1) > 0
15673 }
15674
15675 set keep (doKeep) {
15676 if (this.keep !== doKeep) {
15677 this.info ^= BIT1;
15678 }
15679 }
15680
15681 get countable () {
15682 return (this.info & BIT2) > 0
15683 }
15684
15685 /**
15686 * Whether this item was deleted or not.
15687 * @type {Boolean}
15688 */
15689 get deleted () {
15690 return (this.info & BIT3) > 0
15691 }
15692
15693 set deleted (doDelete) {
15694 if (this.deleted !== doDelete) {
15695 this.info ^= BIT3;
15696 }
15697 }
15698
15699 markDeleted () {
15700 this.info |= BIT3;
15701 }
15702
15703 /**
15704 * Return the creator clientID of the missing op or define missing items and return null.
15705 *
15706 * @param {Transaction} transaction
15707 * @param {StructStore} store
15708 * @return {null | number}
15709 */
15710 getMissing (transaction, store) {
15711 if (this.origin && this.origin.client !== this.id.client && this.origin.clock >= getState(store, this.origin.client)) {
15712 return this.origin.client
15713 }
15714 if (this.rightOrigin && this.rightOrigin.client !== this.id.client && this.rightOrigin.clock >= getState(store, this.rightOrigin.client)) {
15715 return this.rightOrigin.client
15716 }
15717 if (this.parent && this.parent.constructor === ID && this.id.client !== this.parent.client && this.parent.clock >= getState(store, this.parent.client)) {
15718 return this.parent.client
15719 }
15720
15721 // We have all missing ids, now find the items
15722
15723 if (this.origin) {
15724 this.left = getItemCleanEnd(transaction, store, this.origin);
15725 this.origin = this.left.lastId;
15726 }
15727 if (this.rightOrigin) {
15728 this.right = getItemCleanStart(transaction, this.rightOrigin);
15729 this.rightOrigin = this.right.id;
15730 }
15731 if ((this.left && this.left.constructor === GC) || (this.right && this.right.constructor === GC)) {
15732 this.parent = null;
15733 }
15734 // only set parent if this shouldn't be garbage collected
15735 if (!this.parent) {
15736 if (this.left && this.left.constructor === Item) {
15737 this.parent = this.left.parent;
15738 this.parentSub = this.left.parentSub;
15739 }
15740 if (this.right && this.right.constructor === Item) {
15741 this.parent = this.right.parent;
15742 this.parentSub = this.right.parentSub;
15743 }
15744 } else if (this.parent.constructor === ID) {
15745 const parentItem = getItem(store, this.parent);
15746 if (parentItem.constructor === GC) {
15747 this.parent = null;
15748 } else {
15749 this.parent = /** @type {ContentType} */ (parentItem.content).type;
15750 }
15751 }
15752 return null
15753 }
15754
15755 /**
15756 * @param {Transaction} transaction
15757 * @param {number} offset
15758 */
15759 integrate (transaction, offset) {
15760 if (offset > 0) {
15761 this.id.clock += offset;
15762 this.left = getItemCleanEnd(transaction, transaction.doc.store, createID(this.id.client, this.id.clock - 1));
15763 this.origin = this.left.lastId;
15764 this.content = this.content.splice(offset);
15765 this.length -= offset;
15766 }
15767
15768 if (this.parent) {
15769 if ((!this.left && (!this.right || this.right.left !== null)) || (this.left && this.left.right !== this.right)) {
15770 /**
15771 * @type {Item|null}
15772 */
15773 let left = this.left;
15774
15775 /**
15776 * @type {Item|null}
15777 */
15778 let o;
15779 // set o to the first conflicting item
15780 if (left !== null) {
15781 o = left.right;
15782 } else if (this.parentSub !== null) {
15783 o = /** @type {AbstractType<any>} */ (this.parent)._map.get(this.parentSub) || null;
15784 while (o !== null && o.left !== null) {
15785 o = o.left;
15786 }
15787 } else {
15788 o = /** @type {AbstractType<any>} */ (this.parent)._start;
15789 }
15790 // TODO: use something like DeleteSet here (a tree implementation would be best)
15791 // @todo use global set definitions
15792 /**
15793 * @type {Set<Item>}
15794 */
15795 const conflictingItems = new Set();
15796 /**
15797 * @type {Set<Item>}
15798 */
15799 const itemsBeforeOrigin = new Set();
15800 // Let c in conflictingItems, b in itemsBeforeOrigin
15801 // ***{origin}bbbb{this}{c,b}{c,b}{o}***
15802 // Note that conflictingItems is a subset of itemsBeforeOrigin
15803 while (o !== null && o !== this.right) {
15804 itemsBeforeOrigin.add(o);
15805 conflictingItems.add(o);
15806 if (compareIDs(this.origin, o.origin)) {
15807 // case 1
15808 if (o.id.client < this.id.client) {
15809 left = o;
15810 conflictingItems.clear();
15811 } else if (compareIDs(this.rightOrigin, o.rightOrigin)) {
15812 // this and o are conflicting and point to the same integration points. The id decides which item comes first.
15813 // Since this is to the left of o, we can break here
15814 break
15815 } // else, o might be integrated before an item that this conflicts with. If so, we will find it in the next iterations
15816 } 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.
15817 // case 2
15818 if (!conflictingItems.has(getItem(transaction.doc.store, o.origin))) {
15819 left = o;
15820 conflictingItems.clear();
15821 }
15822 } else {
15823 break
15824 }
15825 o = o.right;
15826 }
15827 this.left = left;
15828 }
15829 // reconnect left/right + update parent map/start if necessary
15830 if (this.left !== null) {
15831 const right = this.left.right;
15832 this.right = right;
15833 this.left.right = this;
15834 } else {
15835 let r;
15836 if (this.parentSub !== null) {
15837 r = /** @type {AbstractType<any>} */ (this.parent)._map.get(this.parentSub) || null;
15838 while (r !== null && r.left !== null) {
15839 r = r.left;
15840 }
15841 } else {
15842 r = /** @type {AbstractType<any>} */ (this.parent)._start
15843 ;/** @type {AbstractType<any>} */ (this.parent)._start = this;
15844 }
15845 this.right = r;
15846 }
15847 if (this.right !== null) {
15848 this.right.left = this;
15849 } else if (this.parentSub !== null) {
15850 // set as current parent value if right === null and this is parentSub
15851 /** @type {AbstractType<any>} */ (this.parent)._map.set(this.parentSub, this);
15852 if (this.left !== null) {
15853 // this is the current attribute value of parent. delete right
15854 this.left.delete(transaction);
15855 }
15856 }
15857 // adjust length of parent
15858 if (this.parentSub === null && this.countable && !this.deleted) {
15859 /** @type {AbstractType<any>} */ (this.parent)._length += this.length;
15860 }
15861 addStruct(transaction.doc.store, this);
15862 this.content.integrate(transaction, this);
15863 // add parent to transaction.changed
15864 addChangedTypeToTransaction(transaction, /** @type {AbstractType<any>} */ (this.parent), this.parentSub);
15865 if ((/** @type {AbstractType<any>} */ (this.parent)._item !== null && /** @type {AbstractType<any>} */ (this.parent)._item.deleted) || (this.parentSub !== null && this.right !== null)) {
15866 // delete if parent is deleted or if this is not the current attribute value of parent
15867 this.delete(transaction);
15868 }
15869 } else {
15870 // parent is not defined. Integrate GC struct instead
15871 new GC(this.id, this.length).integrate(transaction, 0);
15872 }
15873 }
15874
15875 /**
15876 * Returns the next non-deleted item
15877 */
15878 get next () {
15879 let n = this.right;
15880 while (n !== null && n.deleted) {
15881 n = n.right;
15882 }
15883 return n
15884 }
15885
15886 /**
15887 * Returns the previous non-deleted item
15888 */
15889 get prev () {
15890 let n = this.left;
15891 while (n !== null && n.deleted) {
15892 n = n.left;
15893 }
15894 return n
15895 }
15896
15897 /**
15898 * Computes the last content address of this Item.
15899 */
15900 get lastId () {
15901 // allocating ids is pretty costly because of the amount of ids created, so we try to reuse whenever possible
15902 return this.length === 1 ? this.id : createID(this.id.client, this.id.clock + this.length - 1)
15903 }
15904
15905 /**
15906 * Try to merge two items
15907 *
15908 * @param {Item} right
15909 * @return {boolean}
15910 */
15911 mergeWith (right) {
15912 if (
15913 this.constructor === right.constructor &&
15914 compareIDs(right.origin, this.lastId) &&
15915 this.right === right &&
15916 compareIDs(this.rightOrigin, right.rightOrigin) &&
15917 this.id.client === right.id.client &&
15918 this.id.clock + this.length === right.id.clock &&
15919 this.deleted === right.deleted &&
15920 this.redone === null &&
15921 right.redone === null &&
15922 this.content.constructor === right.content.constructor &&
15923 this.content.mergeWith(right.content)
15924 ) {
15925 const searchMarker = /** @type {AbstractType<any>} */ (this.parent)._searchMarker;
15926 if (searchMarker) {
15927 searchMarker.forEach(marker => {
15928 if (marker.p === right) {
15929 // right is going to be "forgotten" so we need to update the marker
15930 marker.p = this;
15931 // adjust marker index
15932 if (!this.deleted && this.countable) {
15933 marker.index -= this.length;
15934 }
15935 }
15936 });
15937 }
15938 if (right.keep) {
15939 this.keep = true;
15940 }
15941 this.right = right.right;
15942 if (this.right !== null) {
15943 this.right.left = this;
15944 }
15945 this.length += right.length;
15946 return true
15947 }
15948 return false
15949 }
15950
15951 /**
15952 * Mark this Item as deleted.
15953 *
15954 * @param {Transaction} transaction
15955 */
15956 delete (transaction) {
15957 if (!this.deleted) {
15958 const parent = /** @type {AbstractType<any>} */ (this.parent);
15959 // adjust the length of parent
15960 if (this.countable && this.parentSub === null) {
15961 parent._length -= this.length;
15962 }
15963 this.markDeleted();
15964 addToDeleteSet(transaction.deleteSet, this.id.client, this.id.clock, this.length);
15965 addChangedTypeToTransaction(transaction, parent, this.parentSub);
15966 this.content.delete(transaction);
15967 }
15968 }
15969
15970 /**
15971 * @param {StructStore} store
15972 * @param {boolean} parentGCd
15973 */
15974 gc (store, parentGCd) {
15975 if (!this.deleted) {
15976 throw unexpectedCase()
15977 }
15978 this.content.gc(store);
15979 if (parentGCd) {
15980 replaceStruct(store, this, new GC(this.id, this.length));
15981 } else {
15982 this.content = new ContentDeleted(this.length);
15983 }
15984 }
15985
15986 /**
15987 * Transform the properties of this type to binary and write it to an
15988 * BinaryEncoder.
15989 *
15990 * This is called when this Item is sent to a remote peer.
15991 *
15992 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
15993 * @param {number} offset
15994 */
15995 write (encoder, offset) {
15996 const origin = offset > 0 ? createID(this.id.client, this.id.clock + offset - 1) : this.origin;
15997 const rightOrigin = this.rightOrigin;
15998 const parentSub = this.parentSub;
15999 const info = (this.content.getRef() & BITS5) |
16000 (origin === null ? 0 : BIT8) | // origin is defined
16001 (rightOrigin === null ? 0 : BIT7) | // right origin is defined
16002 (parentSub === null ? 0 : BIT6); // parentSub is non-null
16003 encoder.writeInfo(info);
16004 if (origin !== null) {
16005 encoder.writeLeftID(origin);
16006 }
16007 if (rightOrigin !== null) {
16008 encoder.writeRightID(rightOrigin);
16009 }
16010 if (origin === null && rightOrigin === null) {
16011 const parent = /** @type {AbstractType<any>} */ (this.parent);
16012 if (parent._item !== undefined) {
16013 const parentItem = parent._item;
16014 if (parentItem === null) {
16015 // parent type on y._map
16016 // find the correct key
16017 const ykey = findRootTypeKey(parent);
16018 encoder.writeParentInfo(true); // write parentYKey
16019 encoder.writeString(ykey);
16020 } else {
16021 encoder.writeParentInfo(false); // write parent id
16022 encoder.writeLeftID(parentItem.id);
16023 }
16024 } else if (parent.constructor === String) { // this edge case was added by differential updates
16025 encoder.writeParentInfo(true); // write parentYKey
16026 encoder.writeString(parent);
16027 } else if (parent.constructor === ID) {
16028 encoder.writeParentInfo(false); // write parent id
16029 encoder.writeLeftID(parent);
16030 } else {
16031 unexpectedCase();
16032 }
16033 if (parentSub !== null) {
16034 encoder.writeString(parentSub);
16035 }
16036 }
16037 this.content.write(encoder, offset);
16038 }
16039 }
16040
16041 /**
16042 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
16043 * @param {number} info
16044 */
16045 const readItemContent = (decoder, info) => contentRefs[info & BITS5](decoder);
16046
16047 /**
16048 * A lookup map for reading Item content.
16049 *
16050 * @type {Array<function(UpdateDecoderV1 | UpdateDecoderV2):AbstractContent>}
16051 */
16052 const contentRefs = [
16053 () => { unexpectedCase(); }, // GC is not ItemContent
16054 readContentDeleted, // 1
16055 readContentJSON, // 2
16056 readContentBinary, // 3
16057 readContentString, // 4
16058 readContentEmbed, // 5
16059 readContentFormat, // 6
16060 readContentType, // 7
16061 readContentAny, // 8
16062 readContentDoc, // 9
16063 () => { unexpectedCase(); } // 10 - Skip is not ItemContent
16064 ];
16065
16066 const structSkipRefNumber = 10;
16067
16068 /**
16069 * @private
16070 */
16071 class Skip extends AbstractStruct {
16072 get deleted () {
16073 return true
16074 }
16075
16076 delete () {}
16077
16078 /**
16079 * @param {Skip} right
16080 * @return {boolean}
16081 */
16082 mergeWith (right) {
16083 if (this.constructor !== right.constructor) {
16084 return false
16085 }
16086 this.length += right.length;
16087 return true
16088 }
16089
16090 /**
16091 * @param {Transaction} transaction
16092 * @param {number} offset
16093 */
16094 integrate (transaction, offset) {
16095 // skip structs cannot be integrated
16096 unexpectedCase();
16097 }
16098
16099 /**
16100 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
16101 * @param {number} offset
16102 */
16103 write (encoder, offset) {
16104 encoder.writeInfo(structSkipRefNumber);
16105 // write as VarUint because Skips can't make use of predictable length-encoding
16106 writeVarUint(encoder.restEncoder, this.length - offset);
16107 }
16108
16109 /**
16110 * @param {Transaction} transaction
16111 * @param {StructStore} store
16112 * @return {null | number}
16113 */
16114 getMissing (transaction, store) {
16115 return null
16116 }
16117 }
16118
16119 /** eslint-env browser */
16120
16121 const glo = /** @type {any} */ (typeof globalThis !== 'undefined'
16122 ? globalThis
16123 : typeof window !== 'undefined'
16124 ? window
16125 // @ts-ignore
16126 : typeof global !== 'undefined' ? global : {});
16127
16128 const importIdentifier = '__ $YJS$ __';
16129
16130 if (glo[importIdentifier] === true) {
16131 /**
16132 * Dear reader of this message. Please take this seriously.
16133 *
16134 * If you see this message, make sure that you only import one version of Yjs. In many cases,
16135 * your package manager installs two versions of Yjs that are used by different packages within your project.
16136 * Another reason for this message is that some parts of your project use the commonjs version of Yjs
16137 * and others use the EcmaScript version of Yjs.
16138 *
16139 * This often leads to issues that are hard to debug. We often need to perform constructor checks,
16140 * e.g. `struct instanceof GC`. If you imported different versions of Yjs, it is impossible for us to
16141 * do the constructor checks anymore - which might break the CRDT algorithm.
16142 *
16143 * https://github.com/yjs/yjs/issues/438
16144 */
16145 console.error('Yjs was already imported. This breaks constructor checks and will lead to issues! - https://github.com/yjs/yjs/issues/438');
16146 }
16147 glo[importIdentifier] = true;
16148
16149
16150 //# sourceMappingURL=yjs.mjs.map
16151
16152 ;// CONCATENATED MODULE: ./packages/sync/build-module/provider.js
16153 /**
16154 * External dependencies
16155 */
16156 // @ts-ignore
16157
16158
16159 /** @typedef {import('./types').ObjectType} ObjectType */
16160 /** @typedef {import('./types').ObjectID} ObjectID */
16161 /** @typedef {import('./types').ObjectConfig} ObjectConfig */
16162 /** @typedef {import('./types').CRDTDoc} CRDTDoc */
16163 /** @typedef {import('./types').ConnectDoc} ConnectDoc */
16164 /** @typedef {import('./types').SyncProvider} SyncProvider */
16165
16166 /**
16167 * Create a sync provider.
16168 *
16169 * @param {ConnectDoc} connectLocal Connect the document to a local database.
16170 * @param {ConnectDoc} connectRemote Connect the document to a remote sync connection.
16171 * @return {SyncProvider} Sync provider.
16172 */
16173 const createSyncProvider = (connectLocal, connectRemote) => {
16174 /**
16175 * @type {Record<string,ObjectConfig>}
16176 */
16177 const config = {};
16178
16179 /**
16180 * @type {Record<string,Record<string,()=>void>>}
16181 */
16182 const listeners = {};
16183
16184 /**
16185 * @type {Record<string,Record<string,CRDTDoc>>}
16186 */
16187 const docs = {};
16188
16189 /**
16190 * Registeres an object type.
16191 *
16192 * @param {ObjectType} objectType Object type to register.
16193 * @param {ObjectConfig} objectConfig Object config.
16194 */
16195 function register(objectType, objectConfig) {
16196 config[objectType] = objectConfig;
16197 }
16198
16199 /**
16200 * Fetch data from local database or remote source.
16201 *
16202 * @param {ObjectType} objectType Object type to load.
16203 * @param {ObjectID} objectId Object ID to load.
16204 * @param {Function} handleChanges Callback to call when data changes.
16205 */
16206 async function bootstrap(objectType, objectId, handleChanges) {
16207 const doc = new Doc();
16208 docs[objectType] = docs[objectType] || {};
16209 docs[objectType][objectId] = doc;
16210 const updateHandler = () => {
16211 const data = config[objectType].fromCRDTDoc(doc);
16212 handleChanges(data);
16213 };
16214 doc.on('update', updateHandler);
16215
16216 // connect to locally saved database.
16217 const destroyLocalConnection = await connectLocal(objectId, objectType, doc);
16218
16219 // Once the database syncing is done, start the remote syncing
16220 if (connectRemote) {
16221 await connectRemote(objectId, objectType, doc);
16222 }
16223 const loadRemotely = config[objectType].fetch;
16224 if (loadRemotely) {
16225 loadRemotely(objectId).then(data => {
16226 doc.transact(() => {
16227 config[objectType].applyChangesToDoc(doc, data);
16228 });
16229 });
16230 }
16231 listeners[objectType] = listeners[objectType] || {};
16232 listeners[objectType][objectId] = () => {
16233 destroyLocalConnection();
16234 doc.off('update', updateHandler);
16235 };
16236 }
16237
16238 /**
16239 * Fetch data from local database or remote source.
16240 *
16241 * @param {ObjectType} objectType Object type to load.
16242 * @param {ObjectID} objectId Object ID to load.
16243 * @param {any} data Updates to make.
16244 */
16245 async function update(objectType, objectId, data) {
16246 const doc = docs[objectType][objectId];
16247 if (!doc) {
16248 throw 'Error doc ' + objectType + ' ' + objectId + ' not found';
16249 }
16250 doc.transact(() => {
16251 config[objectType].applyChangesToDoc(doc, data);
16252 });
16253 }
16254
16255 /**
16256 * Stop updating a document and discard it.
16257 *
16258 * @param {ObjectType} objectType Object type to load.
16259 * @param {ObjectID} objectId Object ID to load.
16260 */
16261 async function discard(objectType, objectId) {
16262 if (listeners?.[objectType]?.[objectId]) {
16263 listeners[objectType][objectId]();
16264 }
16265 }
16266 return {
16267 register,
16268 bootstrap,
16269 update,
16270 discard
16271 };
16272 };
16273
16274 ;// CONCATENATED MODULE: ./node_modules/lib0/indexeddb.js
16275 /* eslint-env browser */
16276
16277 /**
16278 * Helpers to work with IndexedDB.
16279 *
16280 * @module indexeddb
16281 */
16282
16283
16284
16285
16286 /* c8 ignore start */
16287
16288 /**
16289 * IDB Request to Promise transformer
16290 *
16291 * @param {IDBRequest} request
16292 * @return {Promise<any>}
16293 */
16294 const rtop = request => promise_create((resolve, reject) => {
16295 // @ts-ignore
16296 request.onerror = event => reject(new Error(event.target.error))
16297 // @ts-ignore
16298 request.onsuccess = event => resolve(event.target.result)
16299 })
16300
16301 /**
16302 * @param {string} name
16303 * @param {function(IDBDatabase):any} initDB Called when the database is first created
16304 * @return {Promise<IDBDatabase>}
16305 */
16306 const openDB = (name, initDB) => promise_create((resolve, reject) => {
16307 const request = indexedDB.open(name)
16308 /**
16309 * @param {any} event
16310 */
16311 request.onupgradeneeded = event => initDB(event.target.result)
16312 /**
16313 * @param {any} event
16314 */
16315 request.onerror = event => reject(error_create(event.target.error))
16316 /**
16317 * @param {any} event
16318 */
16319 request.onsuccess = event => {
16320 /**
16321 * @type {IDBDatabase}
16322 */
16323 const db = event.target.result
16324 db.onversionchange = () => { db.close() }
16325 if (typeof addEventListener !== 'undefined') {
16326 addEventListener('unload', () => db.close())
16327 }
16328 resolve(db)
16329 }
16330 })
16331
16332 /**
16333 * @param {string} name
16334 */
16335 const deleteDB = name => rtop(indexedDB.deleteDatabase(name))
16336
16337 /**
16338 * @param {IDBDatabase} db
16339 * @param {Array<Array<string>|Array<string|IDBObjectStoreParameters|undefined>>} definitions
16340 */
16341 const createStores = (db, definitions) => definitions.forEach(d =>
16342 // @ts-ignore
16343 db.createObjectStore.apply(db, d)
16344 )
16345
16346 /**
16347 * @param {IDBDatabase} db
16348 * @param {Array<string>} stores
16349 * @param {"readwrite"|"readonly"} [access]
16350 * @return {Array<IDBObjectStore>}
16351 */
16352 const indexeddb_transact = (db, stores, access = 'readwrite') => {
16353 const transaction = db.transaction(stores, access)
16354 return stores.map(store => getStore(transaction, store))
16355 }
16356
16357 /**
16358 * @param {IDBObjectStore} store
16359 * @param {IDBKeyRange} [range]
16360 * @return {Promise<number>}
16361 */
16362 const count = (store, range) =>
16363 rtop(store.count(range))
16364
16365 /**
16366 * @param {IDBObjectStore} store
16367 * @param {String | number | ArrayBuffer | Date | Array<any> } key
16368 * @return {Promise<String | number | ArrayBuffer | Date | Array<any>>}
16369 */
16370 const get = (store, key) =>
16371 rtop(store.get(key))
16372
16373 /**
16374 * @param {IDBObjectStore} store
16375 * @param {String | number | ArrayBuffer | Date | IDBKeyRange | Array<any> } key
16376 */
16377 const del = (store, key) =>
16378 rtop(store.delete(key))
16379
16380 /**
16381 * @param {IDBObjectStore} store
16382 * @param {String | number | ArrayBuffer | Date | boolean} item
16383 * @param {String | number | ArrayBuffer | Date | Array<any>} [key]
16384 */
16385 const put = (store, item, key) =>
16386 rtop(store.put(item, key))
16387
16388 /**
16389 * @param {IDBObjectStore} store
16390 * @param {String | number | ArrayBuffer | Date | boolean} item
16391 * @param {String | number | ArrayBuffer | Date | Array<any>} key
16392 * @return {Promise<any>}
16393 */
16394 const indexeddb_add = (store, item, key) =>
16395 rtop(store.add(item, key))
16396
16397 /**
16398 * @param {IDBObjectStore} store
16399 * @param {String | number | ArrayBuffer | Date} item
16400 * @return {Promise<number>} Returns the generated key
16401 */
16402 const addAutoKey = (store, item) =>
16403 rtop(store.add(item))
16404
16405 /**
16406 * @param {IDBObjectStore} store
16407 * @param {IDBKeyRange} [range]
16408 * @param {number} [limit]
16409 * @return {Promise<Array<any>>}
16410 */
16411 const getAll = (store, range, limit) =>
16412 rtop(store.getAll(range, limit))
16413
16414 /**
16415 * @param {IDBObjectStore} store
16416 * @param {IDBKeyRange} [range]
16417 * @param {number} [limit]
16418 * @return {Promise<Array<any>>}
16419 */
16420 const getAllKeys = (store, range, limit) =>
16421 rtop(store.getAllKeys(range, limit))
16422
16423 /**
16424 * @param {IDBObjectStore} store
16425 * @param {IDBKeyRange|null} query
16426 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction
16427 * @return {Promise<any>}
16428 */
16429 const queryFirst = (store, query, direction) => {
16430 /**
16431 * @type {any}
16432 */
16433 let first = null
16434 return iterateKeys(store, query, key => {
16435 first = key
16436 return false
16437 }, direction).then(() => first)
16438 }
16439
16440 /**
16441 * @param {IDBObjectStore} store
16442 * @param {IDBKeyRange?} [range]
16443 * @return {Promise<any>}
16444 */
16445 const getLastKey = (store, range = null) => queryFirst(store, range, 'prev')
16446
16447 /**
16448 * @param {IDBObjectStore} store
16449 * @param {IDBKeyRange?} [range]
16450 * @return {Promise<any>}
16451 */
16452 const getFirstKey = (store, range = null) => queryFirst(store, range, 'next')
16453
16454 /**
16455 * @typedef KeyValuePair
16456 * @type {Object}
16457 * @property {any} k key
16458 * @property {any} v Value
16459 */
16460
16461 /**
16462 * @param {IDBObjectStore} store
16463 * @param {IDBKeyRange} [range]
16464 * @param {number} [limit]
16465 * @return {Promise<Array<KeyValuePair>>}
16466 */
16467 const getAllKeysValues = (store, range, limit) =>
16468 // @ts-ignore
16469 promise.all([getAllKeys(store, range, limit), getAll(store, range, limit)]).then(([ks, vs]) => ks.map((k, i) => ({ k, v: vs[i] })))
16470
16471 /**
16472 * @param {any} request
16473 * @param {function(IDBCursorWithValue):void|boolean|Promise<void|boolean>} f
16474 * @return {Promise<void>}
16475 */
16476 const iterateOnRequest = (request, f) => promise_create((resolve, reject) => {
16477 request.onerror = reject
16478 /**
16479 * @param {any} event
16480 */
16481 request.onsuccess = async event => {
16482 const cursor = event.target.result
16483 if (cursor === null || (await f(cursor)) === false) {
16484 return resolve()
16485 }
16486 cursor.continue()
16487 }
16488 })
16489
16490 /**
16491 * Iterate on keys and values
16492 * @param {IDBObjectStore} store
16493 * @param {IDBKeyRange|null} keyrange
16494 * @param {function(any,any):void|boolean|Promise<void|boolean>} f Callback that receives (value, key)
16495 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction
16496 */
16497 const iterate = (store, keyrange, f, direction = 'next') =>
16498 iterateOnRequest(store.openCursor(keyrange, direction), cursor => f(cursor.value, cursor.key))
16499
16500 /**
16501 * Iterate on the keys (no values)
16502 *
16503 * @param {IDBObjectStore} store
16504 * @param {IDBKeyRange|null} keyrange
16505 * @param {function(any):void|boolean|Promise<void|boolean>} f callback that receives the key
16506 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction
16507 */
16508 const iterateKeys = (store, keyrange, f, direction = 'next') =>
16509 iterateOnRequest(store.openKeyCursor(keyrange, direction), cursor => f(cursor.key))
16510
16511 /**
16512 * Open store from transaction
16513 * @param {IDBTransaction} t
16514 * @param {String} store
16515 * @returns {IDBObjectStore}
16516 */
16517 const getStore = (t, store) => t.objectStore(store)
16518
16519 /**
16520 * @param {any} lower
16521 * @param {any} upper
16522 * @param {boolean} lowerOpen
16523 * @param {boolean} upperOpen
16524 */
16525 const createIDBKeyRangeBound = (lower, upper, lowerOpen, upperOpen) => IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen)
16526
16527 /**
16528 * @param {any} upper
16529 * @param {boolean} upperOpen
16530 */
16531 const createIDBKeyRangeUpperBound = (upper, upperOpen) => IDBKeyRange.upperBound(upper, upperOpen)
16532
16533 /**
16534 * @param {any} lower
16535 * @param {boolean} lowerOpen
16536 */
16537 const createIDBKeyRangeLowerBound = (lower, lowerOpen) => IDBKeyRange.lowerBound(lower, lowerOpen)
16538
16539 /* c8 ignore stop */
16540
16541 ;// CONCATENATED MODULE: ./node_modules/y-indexeddb/src/y-indexeddb.js
16542
16543
16544
16545
16546
16547 const customStoreName = 'custom'
16548 const updatesStoreName = 'updates'
16549
16550 const PREFERRED_TRIM_SIZE = 500
16551
16552 /**
16553 * @param {IndexeddbPersistence} idbPersistence
16554 * @param {function(IDBObjectStore):void} [beforeApplyUpdatesCallback]
16555 * @param {function(IDBObjectStore):void} [afterApplyUpdatesCallback]
16556 */
16557 const fetchUpdates = (idbPersistence, beforeApplyUpdatesCallback = () => {}, afterApplyUpdatesCallback = () => {}) => {
16558 const [updatesStore] = indexeddb_transact(/** @type {IDBDatabase} */ (idbPersistence.db), [updatesStoreName]) // , 'readonly')
16559 return getAll(updatesStore, createIDBKeyRangeLowerBound(idbPersistence._dbref, false)).then(updates => {
16560 if (!idbPersistence._destroyed) {
16561 beforeApplyUpdatesCallback(updatesStore)
16562 transact(idbPersistence.doc, () => {
16563 updates.forEach(val => applyUpdate(idbPersistence.doc, val))
16564 }, idbPersistence, false)
16565 afterApplyUpdatesCallback(updatesStore)
16566 }
16567 })
16568 .then(() => getLastKey(updatesStore).then(lastKey => { idbPersistence._dbref = lastKey + 1 }))
16569 .then(() => count(updatesStore).then(cnt => { idbPersistence._dbsize = cnt }))
16570 .then(() => updatesStore)
16571 }
16572
16573 /**
16574 * @param {IndexeddbPersistence} idbPersistence
16575 * @param {boolean} forceStore
16576 */
16577 const storeState = (idbPersistence, forceStore = true) =>
16578 fetchUpdates(idbPersistence)
16579 .then(updatesStore => {
16580 if (forceStore || idbPersistence._dbsize >= PREFERRED_TRIM_SIZE) {
16581 addAutoKey(updatesStore, encodeStateAsUpdate(idbPersistence.doc))
16582 .then(() => del(updatesStore, createIDBKeyRangeUpperBound(idbPersistence._dbref, true)))
16583 .then(() => count(updatesStore).then(cnt => { idbPersistence._dbsize = cnt }))
16584 }
16585 })
16586
16587 /**
16588 * @param {string} name
16589 */
16590 const clearDocument = name => idb.deleteDB(name)
16591
16592 /**
16593 * @extends Observable<string>
16594 */
16595 class IndexeddbPersistence extends observable_Observable {
16596 /**
16597 * @param {string} name
16598 * @param {Y.Doc} doc
16599 */
16600 constructor (name, doc) {
16601 super()
16602 this.doc = doc
16603 this.name = name
16604 this._dbref = 0
16605 this._dbsize = 0
16606 this._destroyed = false
16607 /**
16608 * @type {IDBDatabase|null}
16609 */
16610 this.db = null
16611 this.synced = false
16612 this._db = openDB(name, db =>
16613 createStores(db, [
16614 ['updates', { autoIncrement: true }],
16615 ['custom']
16616 ])
16617 )
16618 /**
16619 * @type {Promise<IndexeddbPersistence>}
16620 */
16621 this.whenSynced = promise_create(resolve => this.on('synced', () => resolve(this)))
16622
16623 this._db.then(db => {
16624 this.db = db
16625 /**
16626 * @param {IDBObjectStore} updatesStore
16627 */
16628 const beforeApplyUpdatesCallback = (updatesStore) => addAutoKey(updatesStore, encodeStateAsUpdate(doc))
16629 const afterApplyUpdatesCallback = () => {
16630 if (this._destroyed) return this
16631 this.synced = true
16632 this.emit('synced', [this])
16633 }
16634 fetchUpdates(this, beforeApplyUpdatesCallback, afterApplyUpdatesCallback)
16635 })
16636 /**
16637 * Timeout in ms untill data is merged and persisted in idb.
16638 */
16639 this._storeTimeout = 1000
16640 /**
16641 * @type {any}
16642 */
16643 this._storeTimeoutId = null
16644 /**
16645 * @param {Uint8Array} update
16646 * @param {any} origin
16647 */
16648 this._storeUpdate = (update, origin) => {
16649 if (this.db && origin !== this) {
16650 const [updatesStore] = indexeddb_transact(/** @type {IDBDatabase} */ (this.db), [updatesStoreName])
16651 addAutoKey(updatesStore, update)
16652 if (++this._dbsize >= PREFERRED_TRIM_SIZE) {
16653 // debounce store call
16654 if (this._storeTimeoutId !== null) {
16655 clearTimeout(this._storeTimeoutId)
16656 }
16657 this._storeTimeoutId = setTimeout(() => {
16658 storeState(this, false)
16659 this._storeTimeoutId = null
16660 }, this._storeTimeout)
16661 }
16662 }
16663 }
16664 doc.on('update', this._storeUpdate)
16665 this.destroy = this.destroy.bind(this)
16666 doc.on('destroy', this.destroy)
16667 }
16668
16669 destroy () {
16670 if (this._storeTimeoutId) {
16671 clearTimeout(this._storeTimeoutId)
16672 }
16673 this.doc.off('update', this._storeUpdate)
16674 this.doc.off('destroy', this.destroy)
16675 this._destroyed = true
16676 return this._db.then(db => {
16677 db.close()
16678 })
16679 }
16680
16681 /**
16682 * Destroys this instance and removes all data from indexeddb.
16683 *
16684 * @return {Promise<void>}
16685 */
16686 clearData () {
16687 return this.destroy().then(() => {
16688 deleteDB(this.name)
16689 })
16690 }
16691
16692 /**
16693 * @param {String | number | ArrayBuffer | Date} key
16694 * @return {Promise<String | number | ArrayBuffer | Date | any>}
16695 */
16696 get (key) {
16697 return this._db.then(db => {
16698 const [custom] = indexeddb_transact(db, [customStoreName], 'readonly')
16699 return get(custom, key)
16700 })
16701 }
16702
16703 /**
16704 * @param {String | number | ArrayBuffer | Date} key
16705 * @param {String | number | ArrayBuffer | Date} value
16706 * @return {Promise<String | number | ArrayBuffer | Date>}
16707 */
16708 set (key, value) {
16709 return this._db.then(db => {
16710 const [custom] = indexeddb_transact(db, [customStoreName])
16711 return put(custom, value, key)
16712 })
16713 }
16714
16715 /**
16716 * @param {String | number | ArrayBuffer | Date} key
16717 * @return {Promise<undefined>}
16718 */
16719 del (key) {
16720 return this._db.then(db => {
16721 const [custom] = indexeddb_transact(db, [customStoreName])
16722 return del(custom, key)
16723 })
16724 }
16725 }
16726
16727 ;// CONCATENATED MODULE: ./packages/sync/build-module/connect-indexdb.js
16728 /**
16729 * External dependencies
16730 */
16731 // @ts-ignore
16732
16733
16734 /** @typedef {import('./types').ObjectType} ObjectType */
16735 /** @typedef {import('./types').ObjectID} ObjectID */
16736 /** @typedef {import('./types').CRDTDoc} CRDTDoc */
16737 /** @typedef {import('./types').ConnectDoc} ConnectDoc */
16738 /** @typedef {import('./types').SyncProvider} SyncProvider */
16739
16740 /**
16741 * Connect function to the IndexedDB persistence provider.
16742 *
16743 * @param {ObjectID} objectId The object ID.
16744 * @param {ObjectType} objectType The object type.
16745 * @param {CRDTDoc} doc The CRDT document.
16746 *
16747 * @return {Promise<() => void>} Promise that resolves when the connection is established.
16748 */
16749 function connectIndexDb(objectId, objectType, doc) {
16750 const roomName = `${objectType}-${objectId}`;
16751 const provider = new IndexeddbPersistence(roomName, doc);
16752 return new Promise(resolve => {
16753 provider.on('synced', () => {
16754 resolve(() => provider.destroy());
16755 });
16756 });
16757 }
16758
16759 ;// CONCATENATED MODULE: ./node_modules/lib0/websocket.js
16760 /* eslint-env browser */
16761
16762 /**
16763 * Tiny websocket connection handler.
16764 *
16765 * Implements exponential backoff reconnects, ping/pong, and a nice event system using [lib0/observable].
16766 *
16767 * @module websocket
16768 */
16769
16770
16771
16772
16773
16774 const reconnectTimeoutBase = 1200
16775 const maxReconnectTimeout = 2500
16776 // @todo - this should depend on awareness.outdatedTime
16777 const messageReconnectTimeout = 30000
16778
16779 /**
16780 * @param {WebsocketClient} wsclient
16781 */
16782 const setupWS = (wsclient) => {
16783 if (wsclient.shouldConnect && wsclient.ws === null) {
16784 const websocket = new WebSocket(wsclient.url)
16785 const binaryType = wsclient.binaryType
16786 /**
16787 * @type {any}
16788 */
16789 let pingTimeout = null
16790 if (binaryType) {
16791 websocket.binaryType = binaryType
16792 }
16793 wsclient.ws = websocket
16794 wsclient.connecting = true
16795 wsclient.connected = false
16796 websocket.onmessage = event => {
16797 wsclient.lastMessageReceived = getUnixTime()
16798 const data = event.data
16799 const message = typeof data === 'string' ? JSON.parse(data) : data
16800 if (message && message.type === 'pong') {
16801 clearTimeout(pingTimeout)
16802 pingTimeout = setTimeout(sendPing, messageReconnectTimeout / 2)
16803 }
16804 wsclient.emit('message', [message, wsclient])
16805 }
16806 /**
16807 * @param {any} error
16808 */
16809 const onclose = error => {
16810 if (wsclient.ws !== null) {
16811 wsclient.ws = null
16812 wsclient.connecting = false
16813 if (wsclient.connected) {
16814 wsclient.connected = false
16815 wsclient.emit('disconnect', [{ type: 'disconnect', error }, wsclient])
16816 } else {
16817 wsclient.unsuccessfulReconnects++
16818 }
16819 // Start with no reconnect timeout and increase timeout by
16820 // log10(wsUnsuccessfulReconnects).
16821 // The idea is to increase reconnect timeout slowly and have no reconnect
16822 // timeout at the beginning (log(1) = 0)
16823 setTimeout(setupWS, min(log10(wsclient.unsuccessfulReconnects + 1) * reconnectTimeoutBase, maxReconnectTimeout), wsclient)
16824 }
16825 clearTimeout(pingTimeout)
16826 }
16827 const sendPing = () => {
16828 if (wsclient.ws === websocket) {
16829 wsclient.send({
16830 type: 'ping'
16831 })
16832 }
16833 }
16834 websocket.onclose = () => onclose(null)
16835 websocket.onerror = error => onclose(error)
16836 websocket.onopen = () => {
16837 wsclient.lastMessageReceived = getUnixTime()
16838 wsclient.connecting = false
16839 wsclient.connected = true
16840 wsclient.unsuccessfulReconnects = 0
16841 wsclient.emit('connect', [{ type: 'connect' }, wsclient])
16842 // set ping
16843 pingTimeout = setTimeout(sendPing, messageReconnectTimeout / 2)
16844 }
16845 }
16846 }
16847
16848 /**
16849 * @extends Observable<string>
16850 */
16851 class WebsocketClient extends observable_Observable {
16852 /**
16853 * @param {string} url
16854 * @param {object} opts
16855 * @param {'arraybuffer' | 'blob' | null} [opts.binaryType] Set `ws.binaryType`
16856 */
16857 constructor (url, { binaryType } = {}) {
16858 super()
16859 this.url = url
16860 /**
16861 * @type {WebSocket?}
16862 */
16863 this.ws = null
16864 this.binaryType = binaryType || null
16865 this.connected = false
16866 this.connecting = false
16867 this.unsuccessfulReconnects = 0
16868 this.lastMessageReceived = 0
16869 /**
16870 * Whether to connect to other peers or not
16871 * @type {boolean}
16872 */
16873 this.shouldConnect = true
16874 this._checkInterval = setInterval(() => {
16875 if (this.connected && messageReconnectTimeout < getUnixTime() - this.lastMessageReceived) {
16876 // no message received in a long time - not even your own awareness
16877 // updates (which are updated every 15 seconds)
16878 /** @type {WebSocket} */ (this.ws).close()
16879 }
16880 }, messageReconnectTimeout / 2)
16881 setupWS(this)
16882 }
16883
16884 /**
16885 * @param {any} message
16886 */
16887 send (message) {
16888 if (this.ws) {
16889 this.ws.send(JSON.stringify(message))
16890 }
16891 }
16892
16893 destroy () {
16894 clearInterval(this._checkInterval)
16895 this.disconnect()
16896 super.destroy()
16897 }
16898
16899 disconnect () {
16900 this.shouldConnect = false
16901 if (this.ws !== null) {
16902 this.ws.close()
16903 }
16904 }
16905
16906 connect () {
16907 this.shouldConnect = true
16908 if (!this.connected && this.ws === null) {
16909 setupWS(this)
16910 }
16911 }
16912 }
16913
16914 ;// CONCATENATED MODULE: ./node_modules/lib0/broadcastchannel.js
16915 /* eslint-env browser */
16916
16917 /**
16918 * Helpers for cross-tab communication using broadcastchannel with LocalStorage fallback.
16919 *
16920 * ```js
16921 * // In browser window A:
16922 * broadcastchannel.subscribe('my events', data => console.log(data))
16923 * broadcastchannel.publish('my events', 'Hello world!') // => A: 'Hello world!' fires synchronously in same tab
16924 *
16925 * // In browser window B:
16926 * broadcastchannel.publish('my events', 'hello from tab B') // => A: 'hello from tab B'
16927 * ```
16928 *
16929 * @module broadcastchannel
16930 */
16931
16932 // @todo before next major: use Uint8Array instead as buffer object
16933
16934
16935
16936
16937
16938
16939 /**
16940 * @typedef {Object} Channel
16941 * @property {Set<function(any, any):any>} Channel.subs
16942 * @property {any} Channel.bc
16943 */
16944
16945 /**
16946 * @type {Map<string, Channel>}
16947 */
16948 const channels = new Map()
16949
16950 /* c8 ignore start */
16951 class LocalStoragePolyfill {
16952 /**
16953 * @param {string} room
16954 */
16955 constructor (room) {
16956 this.room = room
16957 /**
16958 * @type {null|function({data:ArrayBuffer}):void}
16959 */
16960 this.onmessage = null
16961 /**
16962 * @param {any} e
16963 */
16964 this._onChange = e => e.key === room && this.onmessage !== null && this.onmessage({ data: fromBase64(e.newValue || '') })
16965 onChange(this._onChange)
16966 }
16967
16968 /**
16969 * @param {ArrayBuffer} buf
16970 */
16971 postMessage (buf) {
16972 varStorage.setItem(this.room, toBase64(createUint8ArrayFromArrayBuffer(buf)))
16973 }
16974
16975 close () {
16976 offChange(this._onChange)
16977 }
16978 }
16979 /* c8 ignore stop */
16980
16981 // Use BroadcastChannel or Polyfill
16982 /* c8 ignore next */
16983 const BC = typeof BroadcastChannel === 'undefined' ? LocalStoragePolyfill : BroadcastChannel
16984
16985 /**
16986 * @param {string} room
16987 * @return {Channel}
16988 */
16989 const getChannel = room =>
16990 setIfUndefined(channels, room, () => {
16991 const subs = set_create()
16992 const bc = new BC(room)
16993 /**
16994 * @param {{data:ArrayBuffer}} e
16995 */
16996 /* c8 ignore next */
16997 bc.onmessage = e => subs.forEach(sub => sub(e.data, 'broadcastchannel'))
16998 return {
16999 bc, subs
17000 }
17001 })
17002
17003 /**
17004 * Subscribe to global `publish` events.
17005 *
17006 * @function
17007 * @param {string} room
17008 * @param {function(any, any):any} f
17009 */
17010 const subscribe = (room, f) => {
17011 getChannel(room).subs.add(f)
17012 return f
17013 }
17014
17015 /**
17016 * Unsubscribe from `publish` global events.
17017 *
17018 * @function
17019 * @param {string} room
17020 * @param {function(any, any):any} f
17021 */
17022 const unsubscribe = (room, f) => {
17023 const channel = getChannel(room)
17024 const unsubscribed = channel.subs.delete(f)
17025 if (unsubscribed && channel.subs.size === 0) {
17026 channel.bc.close()
17027 channels.delete(room)
17028 }
17029 return unsubscribed
17030 }
17031
17032 /**
17033 * Publish data to all subscribers (including subscribers on this tab)
17034 *
17035 * @function
17036 * @param {string} room
17037 * @param {any} data
17038 * @param {any} [origin]
17039 */
17040 const publish = (room, data, origin = null) => {
17041 const c = getChannel(room)
17042 c.bc.postMessage(data)
17043 c.subs.forEach(sub => sub(data, origin))
17044 }
17045
17046 ;// CONCATENATED MODULE: ./node_modules/lib0/mutex.js
17047 /**
17048 * Mutual exclude for JavaScript.
17049 *
17050 * @module mutex
17051 */
17052
17053 /**
17054 * @callback mutex
17055 * @param {function():void} cb Only executed when this mutex is not in the current stack
17056 * @param {function():void} [elseCb] Executed when this mutex is in the current stack
17057 */
17058
17059 /**
17060 * Creates a mutual exclude function with the following property:
17061 *
17062 * ```js
17063 * const mutex = createMutex()
17064 * mutex(() => {
17065 * // This function is immediately executed
17066 * mutex(() => {
17067 * // This function is not executed, as the mutex is already active.
17068 * })
17069 * })
17070 * ```
17071 *
17072 * @return {mutex} A mutual exclude function
17073 * @public
17074 */
17075 const createMutex = () => {
17076 let token = true
17077 return (f, g) => {
17078 if (token) {
17079 token = false
17080 try {
17081 f()
17082 } finally {
17083 token = true
17084 }
17085 } else if (g !== undefined) {
17086 g()
17087 }
17088 }
17089 }
17090
17091 // EXTERNAL MODULE: ./node_modules/simple-peer/simplepeer.min.js
17092 var simplepeer_min = __webpack_require__(2248);
17093 var simplepeer_min_default = /*#__PURE__*/__webpack_require__.n(simplepeer_min);
17094 ;// CONCATENATED MODULE: ./node_modules/y-protocols/sync.js
17095 /**
17096 * @module sync-protocol
17097 */
17098
17099
17100
17101
17102
17103 /**
17104 * @typedef {Map<number, number>} StateMap
17105 */
17106
17107 /**
17108 * Core Yjs defines two message types:
17109 * • YjsSyncStep1: Includes the State Set of the sending client. When received, the client should reply with YjsSyncStep2.
17110 * • YjsSyncStep2: Includes all missing structs and the complete delete set. When received, the client is assured that it
17111 * received all information from the remote client.
17112 *
17113 * In a peer-to-peer network, you may want to introduce a SyncDone message type. Both parties should initiate the connection
17114 * with SyncStep1. When a client received SyncStep2, it should reply with SyncDone. When the local client received both
17115 * SyncStep2 and SyncDone, it is assured that it is synced to the remote client.
17116 *
17117 * In a client-server model, you want to handle this differently: The client should initiate the connection with SyncStep1.
17118 * When the server receives SyncStep1, it should reply with SyncStep2 immediately followed by SyncStep1. The client replies
17119 * with SyncStep2 when it receives SyncStep1. Optionally the server may send a SyncDone after it received SyncStep2, so the
17120 * client knows that the sync is finished. There are two reasons for this more elaborated sync model: 1. This protocol can
17121 * easily be implemented on top of http and websockets. 2. The server shoul only reply to requests, and not initiate them.
17122 * Therefore it is necesarry that the client initiates the sync.
17123 *
17124 * Construction of a message:
17125 * [messageType : varUint, message definition..]
17126 *
17127 * Note: A message does not include information about the room name. This must to be handled by the upper layer protocol!
17128 *
17129 * stringify[messageType] stringifies a message definition (messageType is already read from the bufffer)
17130 */
17131
17132 const messageYjsSyncStep1 = 0
17133 const messageYjsSyncStep2 = 1
17134 const messageYjsUpdate = 2
17135
17136 /**
17137 * Create a sync step 1 message based on the state of the current shared document.
17138 *
17139 * @param {encoding.Encoder} encoder
17140 * @param {Y.Doc} doc
17141 */
17142 const writeSyncStep1 = (encoder, doc) => {
17143 writeVarUint(encoder, messageYjsSyncStep1)
17144 const sv = encodeStateVector(doc)
17145 writeVarUint8Array(encoder, sv)
17146 }
17147
17148 /**
17149 * @param {encoding.Encoder} encoder
17150 * @param {Y.Doc} doc
17151 * @param {Uint8Array} [encodedStateVector]
17152 */
17153 const writeSyncStep2 = (encoder, doc, encodedStateVector) => {
17154 writeVarUint(encoder, messageYjsSyncStep2)
17155 writeVarUint8Array(encoder, encodeStateAsUpdate(doc, encodedStateVector))
17156 }
17157
17158 /**
17159 * Read SyncStep1 message and reply with SyncStep2.
17160 *
17161 * @param {decoding.Decoder} decoder The reply to the received message
17162 * @param {encoding.Encoder} encoder The received message
17163 * @param {Y.Doc} doc
17164 */
17165 const readSyncStep1 = (decoder, encoder, doc) =>
17166 writeSyncStep2(encoder, doc, readVarUint8Array(decoder))
17167
17168 /**
17169 * Read and apply Structs and then DeleteStore to a y instance.
17170 *
17171 * @param {decoding.Decoder} decoder
17172 * @param {Y.Doc} doc
17173 * @param {any} transactionOrigin
17174 */
17175 const readSyncStep2 = (decoder, doc, transactionOrigin) => {
17176 try {
17177 applyUpdate(doc, readVarUint8Array(decoder), transactionOrigin)
17178 } catch (error) {
17179 // This catches errors that are thrown by event handlers
17180 console.error('Caught error while handling a Yjs update', error)
17181 }
17182 }
17183
17184 /**
17185 * @param {encoding.Encoder} encoder
17186 * @param {Uint8Array} update
17187 */
17188 const writeUpdate = (encoder, update) => {
17189 writeVarUint(encoder, messageYjsUpdate)
17190 writeVarUint8Array(encoder, update)
17191 }
17192
17193 /**
17194 * Read and apply Structs and then DeleteStore to a y instance.
17195 *
17196 * @param {decoding.Decoder} decoder
17197 * @param {Y.Doc} doc
17198 * @param {any} transactionOrigin
17199 */
17200 const sync_readUpdate = readSyncStep2
17201
17202 /**
17203 * @param {decoding.Decoder} decoder A message received from another client
17204 * @param {encoding.Encoder} encoder The reply message. Will not be sent if empty.
17205 * @param {Y.Doc} doc
17206 * @param {any} transactionOrigin
17207 */
17208 const readSyncMessage = (decoder, encoder, doc, transactionOrigin) => {
17209 const messageType = readVarUint(decoder)
17210 switch (messageType) {
17211 case messageYjsSyncStep1:
17212 readSyncStep1(decoder, encoder, doc)
17213 break
17214 case messageYjsSyncStep2:
17215 readSyncStep2(decoder, doc, transactionOrigin)
17216 break
17217 case messageYjsUpdate:
17218 sync_readUpdate(decoder, doc, transactionOrigin)
17219 break
17220 default:
17221 throw new Error('Unknown message type')
17222 }
17223 return messageType
17224 }
17225
17226 ;// CONCATENATED MODULE: ./node_modules/y-protocols/awareness.js
17227 /**
17228 * @module awareness-protocol
17229 */
17230
17231
17232
17233
17234
17235
17236
17237 // eslint-disable-line
17238
17239 const outdatedTimeout = 30000
17240
17241 /**
17242 * @typedef {Object} MetaClientState
17243 * @property {number} MetaClientState.clock
17244 * @property {number} MetaClientState.lastUpdated unix timestamp
17245 */
17246
17247 /**
17248 * The Awareness class implements a simple shared state protocol that can be used for non-persistent data like awareness information
17249 * (cursor, username, status, ..). Each client can update its own local state and listen to state changes of
17250 * remote clients. Every client may set a state of a remote peer to `null` to mark the client as offline.
17251 *
17252 * Each client is identified by a unique client id (something we borrow from `doc.clientID`). A client can override
17253 * its own state by propagating a message with an increasing timestamp (`clock`). If such a message is received, it is
17254 * applied if the known state of that client is older than the new state (`clock < newClock`). If a client thinks that
17255 * a remote client is offline, it may propagate a message with
17256 * `{ clock: currentClientClock, state: null, client: remoteClient }`. If such a
17257 * message is received, and the known clock of that client equals the received clock, it will override the state with `null`.
17258 *
17259 * Before a client disconnects, it should propagate a `null` state with an updated clock.
17260 *
17261 * Awareness states must be updated every 30 seconds. Otherwise the Awareness instance will delete the client state.
17262 *
17263 * @extends {Observable<string>}
17264 */
17265 class Awareness extends observable_Observable {
17266 /**
17267 * @param {Y.Doc} doc
17268 */
17269 constructor (doc) {
17270 super()
17271 this.doc = doc
17272 /**
17273 * @type {number}
17274 */
17275 this.clientID = doc.clientID
17276 /**
17277 * Maps from client id to client state
17278 * @type {Map<number, Object<string, any>>}
17279 */
17280 this.states = new Map()
17281 /**
17282 * @type {Map<number, MetaClientState>}
17283 */
17284 this.meta = new Map()
17285 this._checkInterval = /** @type {any} */ (setInterval(() => {
17286 const now = getUnixTime()
17287 if (this.getLocalState() !== null && (outdatedTimeout / 2 <= now - /** @type {{lastUpdated:number}} */ (this.meta.get(this.clientID)).lastUpdated)) {
17288 // renew local clock
17289 this.setLocalState(this.getLocalState())
17290 }
17291 /**
17292 * @type {Array<number>}
17293 */
17294 const remove = []
17295 this.meta.forEach((meta, clientid) => {
17296 if (clientid !== this.clientID && outdatedTimeout <= now - meta.lastUpdated && this.states.has(clientid)) {
17297 remove.push(clientid)
17298 }
17299 })
17300 if (remove.length > 0) {
17301 removeAwarenessStates(this, remove, 'timeout')
17302 }
17303 }, floor(outdatedTimeout / 10)))
17304 doc.on('destroy', () => {
17305 this.destroy()
17306 })
17307 this.setLocalState({})
17308 }
17309
17310 destroy () {
17311 this.emit('destroy', [this])
17312 this.setLocalState(null)
17313 super.destroy()
17314 clearInterval(this._checkInterval)
17315 }
17316
17317 /**
17318 * @return {Object<string,any>|null}
17319 */
17320 getLocalState () {
17321 return this.states.get(this.clientID) || null
17322 }
17323
17324 /**
17325 * @param {Object<string,any>|null} state
17326 */
17327 setLocalState (state) {
17328 const clientID = this.clientID
17329 const currLocalMeta = this.meta.get(clientID)
17330 const clock = currLocalMeta === undefined ? 0 : currLocalMeta.clock + 1
17331 const prevState = this.states.get(clientID)
17332 if (state === null) {
17333 this.states.delete(clientID)
17334 } else {
17335 this.states.set(clientID, state)
17336 }
17337 this.meta.set(clientID, {
17338 clock,
17339 lastUpdated: getUnixTime()
17340 })
17341 const added = []
17342 const updated = []
17343 const filteredUpdated = []
17344 const removed = []
17345 if (state === null) {
17346 removed.push(clientID)
17347 } else if (prevState == null) {
17348 if (state != null) {
17349 added.push(clientID)
17350 }
17351 } else {
17352 updated.push(clientID)
17353 if (!equalityDeep(prevState, state)) {
17354 filteredUpdated.push(clientID)
17355 }
17356 }
17357 if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
17358 this.emit('change', [{ added, updated: filteredUpdated, removed }, 'local'])
17359 }
17360 this.emit('update', [{ added, updated, removed }, 'local'])
17361 }
17362
17363 /**
17364 * @param {string} field
17365 * @param {any} value
17366 */
17367 setLocalStateField (field, value) {
17368 const state = this.getLocalState()
17369 if (state !== null) {
17370 this.setLocalState({
17371 ...state,
17372 [field]: value
17373 })
17374 }
17375 }
17376
17377 /**
17378 * @return {Map<number,Object<string,any>>}
17379 */
17380 getStates () {
17381 return this.states
17382 }
17383 }
17384
17385 /**
17386 * Mark (remote) clients as inactive and remove them from the list of active peers.
17387 * This change will be propagated to remote clients.
17388 *
17389 * @param {Awareness} awareness
17390 * @param {Array<number>} clients
17391 * @param {any} origin
17392 */
17393 const removeAwarenessStates = (awareness, clients, origin) => {
17394 const removed = []
17395 for (let i = 0; i < clients.length; i++) {
17396 const clientID = clients[i]
17397 if (awareness.states.has(clientID)) {
17398 awareness.states.delete(clientID)
17399 if (clientID === awareness.clientID) {
17400 const curMeta = /** @type {MetaClientState} */ (awareness.meta.get(clientID))
17401 awareness.meta.set(clientID, {
17402 clock: curMeta.clock + 1,
17403 lastUpdated: getUnixTime()
17404 })
17405 }
17406 removed.push(clientID)
17407 }
17408 }
17409 if (removed.length > 0) {
17410 awareness.emit('change', [{ added: [], updated: [], removed }, origin])
17411 awareness.emit('update', [{ added: [], updated: [], removed }, origin])
17412 }
17413 }
17414
17415 /**
17416 * @param {Awareness} awareness
17417 * @param {Array<number>} clients
17418 * @return {Uint8Array}
17419 */
17420 const encodeAwarenessUpdate = (awareness, clients, states = awareness.states) => {
17421 const len = clients.length
17422 const encoder = createEncoder()
17423 writeVarUint(encoder, len)
17424 for (let i = 0; i < len; i++) {
17425 const clientID = clients[i]
17426 const state = states.get(clientID) || null
17427 const clock = /** @type {MetaClientState} */ (awareness.meta.get(clientID)).clock
17428 writeVarUint(encoder, clientID)
17429 writeVarUint(encoder, clock)
17430 writeVarString(encoder, JSON.stringify(state))
17431 }
17432 return toUint8Array(encoder)
17433 }
17434
17435 /**
17436 * Modify the content of an awareness update before re-encoding it to an awareness update.
17437 *
17438 * This might be useful when you have a central server that wants to ensure that clients
17439 * cant hijack somebody elses identity.
17440 *
17441 * @param {Uint8Array} update
17442 * @param {function(any):any} modify
17443 * @return {Uint8Array}
17444 */
17445 const modifyAwarenessUpdate = (update, modify) => {
17446 const decoder = decoding.createDecoder(update)
17447 const encoder = encoding.createEncoder()
17448 const len = decoding.readVarUint(decoder)
17449 encoding.writeVarUint(encoder, len)
17450 for (let i = 0; i < len; i++) {
17451 const clientID = decoding.readVarUint(decoder)
17452 const clock = decoding.readVarUint(decoder)
17453 const state = JSON.parse(decoding.readVarString(decoder))
17454 const modifiedState = modify(state)
17455 encoding.writeVarUint(encoder, clientID)
17456 encoding.writeVarUint(encoder, clock)
17457 encoding.writeVarString(encoder, JSON.stringify(modifiedState))
17458 }
17459 return encoding.toUint8Array(encoder)
17460 }
17461
17462 /**
17463 * @param {Awareness} awareness
17464 * @param {Uint8Array} update
17465 * @param {any} origin This will be added to the emitted change event
17466 */
17467 const applyAwarenessUpdate = (awareness, update, origin) => {
17468 const decoder = createDecoder(update)
17469 const timestamp = getUnixTime()
17470 const added = []
17471 const updated = []
17472 const filteredUpdated = []
17473 const removed = []
17474 const len = readVarUint(decoder)
17475 for (let i = 0; i < len; i++) {
17476 const clientID = readVarUint(decoder)
17477 let clock = readVarUint(decoder)
17478 const state = JSON.parse(readVarString(decoder))
17479 const clientMeta = awareness.meta.get(clientID)
17480 const prevState = awareness.states.get(clientID)
17481 const currClock = clientMeta === undefined ? 0 : clientMeta.clock
17482 if (currClock < clock || (currClock === clock && state === null && awareness.states.has(clientID))) {
17483 if (state === null) {
17484 // never let a remote client remove this local state
17485 if (clientID === awareness.clientID && awareness.getLocalState() != null) {
17486 // remote client removed the local state. Do not remote state. Broadcast a message indicating
17487 // that this client still exists by increasing the clock
17488 clock++
17489 } else {
17490 awareness.states.delete(clientID)
17491 }
17492 } else {
17493 awareness.states.set(clientID, state)
17494 }
17495 awareness.meta.set(clientID, {
17496 clock,
17497 lastUpdated: timestamp
17498 })
17499 if (clientMeta === undefined && state !== null) {
17500 added.push(clientID)
17501 } else if (clientMeta !== undefined && state === null) {
17502 removed.push(clientID)
17503 } else if (state !== null) {
17504 if (!equalityDeep(state, prevState)) {
17505 filteredUpdated.push(clientID)
17506 }
17507 updated.push(clientID)
17508 }
17509 }
17510 }
17511 if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
17512 awareness.emit('change', [{
17513 added, updated: filteredUpdated, removed
17514 }, origin])
17515 }
17516 if (added.length > 0 || updated.length > 0 || removed.length > 0) {
17517 awareness.emit('update', [{
17518 added, updated, removed
17519 }, origin])
17520 }
17521 }
17522
17523 ;// CONCATENATED MODULE: ./packages/sync/build-module/y-webrtc/crypto.js
17524 // File copied as is from the y-webrtc package.
17525 /* eslint-disable eslint-comments/disable-enable-pair */
17526 /* eslint-disable eslint-comments/no-unlimited-disable */
17527 /* eslint-disable */
17528 // @ts-nocheck
17529 /* eslint-env browser */
17530
17531
17532
17533
17534
17535
17536
17537 /**
17538 * @param {string} secret
17539 * @param {string} roomName
17540 * @return {PromiseLike<CryptoKey>}
17541 */
17542 const deriveKey = (secret, roomName) => {
17543 const secretBuffer = encodeUtf8(secret).buffer;
17544 const salt = encodeUtf8(roomName).buffer;
17545 return crypto.subtle.importKey('raw', secretBuffer, 'PBKDF2', false, ['deriveKey']).then(keyMaterial => crypto.subtle.deriveKey({
17546 name: 'PBKDF2',
17547 salt,
17548 iterations: 100000,
17549 hash: 'SHA-256'
17550 }, keyMaterial, {
17551 name: 'AES-GCM',
17552 length: 256
17553 }, true, ['encrypt', 'decrypt']));
17554 };
17555
17556 /**
17557 * @param {Uint8Array} data data to be encrypted
17558 * @param {CryptoKey?} key
17559 * @return {PromiseLike<Uint8Array>} encrypted, base64 encoded message
17560 */
17561 const encrypt = (data, key) => {
17562 if (!key) {
17563 return (/** @type {PromiseLike<Uint8Array>} */
17564 resolve(data)
17565 );
17566 }
17567 const iv = crypto.getRandomValues(new Uint8Array(12));
17568 return crypto.subtle.encrypt({
17569 name: 'AES-GCM',
17570 iv
17571 }, key, data).then(cipher => {
17572 const encryptedDataEncoder = createEncoder();
17573 writeVarString(encryptedDataEncoder, 'AES-GCM');
17574 writeVarUint8Array(encryptedDataEncoder, iv);
17575 writeVarUint8Array(encryptedDataEncoder, new Uint8Array(cipher));
17576 return toUint8Array(encryptedDataEncoder);
17577 });
17578 };
17579
17580 /**
17581 * @param {Object} data data to be encrypted
17582 * @param {CryptoKey?} key
17583 * @return {PromiseLike<Uint8Array>} encrypted data, if key is provided
17584 */
17585 const encryptJson = (data, key) => {
17586 const dataEncoder = createEncoder();
17587 writeAny(dataEncoder, data);
17588 return encrypt(toUint8Array(dataEncoder), key);
17589 };
17590
17591 /**
17592 * @param {Uint8Array} data
17593 * @param {CryptoKey?} key
17594 * @return {PromiseLike<Uint8Array>} decrypted buffer
17595 */
17596 const decrypt = (data, key) => {
17597 if (!key) {
17598 return (/** @type {PromiseLike<Uint8Array>} */
17599 resolve(data)
17600 );
17601 }
17602 const dataDecoder = createDecoder(data);
17603 const algorithm = readVarString(dataDecoder);
17604 if (algorithm !== 'AES-GCM') {
17605 reject(error_create('Unknown encryption algorithm'));
17606 }
17607 const iv = readVarUint8Array(dataDecoder);
17608 const cipher = readVarUint8Array(dataDecoder);
17609 return crypto.subtle.decrypt({
17610 name: 'AES-GCM',
17611 iv
17612 }, key, cipher).then(data => new Uint8Array(data));
17613 };
17614
17615 /**
17616 * @param {Uint8Array} data
17617 * @param {CryptoKey?} key
17618 * @return {PromiseLike<Object>} decrypted object
17619 */
17620 const decryptJson = (data, key) => decrypt(data, key).then(decryptedValue => readAny(createDecoder(new Uint8Array(decryptedValue))));
17621
17622 ;// CONCATENATED MODULE: ./packages/sync/build-module/y-webrtc/y-webrtc.js
17623 // File copied as is from the y-webrtc package with only exports
17624 // added to the following vars/functions: signalingConns,rooms, publishSignalingMessage, log.
17625 /* eslint-disable eslint-comments/disable-enable-pair */
17626 /* eslint-disable eslint-comments/no-unlimited-disable */
17627 /* eslint-disable */
17628 // @ts-nocheck
17629
17630
17631
17632
17633
17634
17635
17636
17637
17638
17639
17640
17641
17642
17643 // eslint-disable-line
17644
17645
17646
17647
17648 const y_webrtc_log = logging_createModuleLogger('y-webrtc');
17649 const messageSync = 0;
17650 const messageQueryAwareness = 3;
17651 const messageAwareness = 1;
17652 const messageBcPeerId = 4;
17653
17654 /**
17655 * @type {Map<string, SignalingConn>}
17656 */
17657 const signalingConns = new Map();
17658
17659 /**
17660 * @type {Map<string,Room>}
17661 */
17662 const rooms = new Map();
17663
17664 /**
17665 * @param {Room} room
17666 */
17667 const 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', [{
17677 synced
17678 }]);
17679 y_webrtc_log('synced ', BOLD, room.name, UNBOLD, ' with all peers');
17680 }
17681 };
17682
17683 /**
17684 * @param {Room} room
17685 * @param {Uint8Array} buf
17686 * @param {function} syncedCallback
17687 * @return {encoding.Encoder?}
17688 */
17689 const readMessage = (room, buf, syncedCallback) => {
17690 const decoder = createDecoder(buf);
17691 const encoder = createEncoder();
17692 const messageType = readVarUint(decoder);
17693 if (room === undefined) {
17694 return null;
17695 }
17696 const awareness = room.awareness;
17697 const doc = room.doc;
17698 let sendReply = false;
17699 switch (messageType) {
17700 case messageSync:
17701 {
17702 writeVarUint(encoder, messageSync);
17703 const syncMessageType = readSyncMessage(decoder, encoder, doc, room);
17704 if (syncMessageType === messageYjsSyncStep2 && !room.synced) {
17705 syncedCallback();
17706 }
17707 if (syncMessageType === messageYjsSyncStep1) {
17708 sendReply = true;
17709 }
17710 break;
17711 }
17712 case messageQueryAwareness:
17713 writeVarUint(encoder, messageAwareness);
17714 writeVarUint8Array(encoder, encodeAwarenessUpdate(awareness, Array.from(awareness.getStates().keys())));
17715 sendReply = true;
17716 break;
17717 case messageAwareness:
17718 applyAwarenessUpdate(awareness, readVarUint8Array(decoder), room);
17719 break;
17720 case messageBcPeerId:
17721 {
17722 const add = readUint8(decoder) === 1;
17723 const peerName = readVarString(decoder);
17724 if (peerName !== room.peerId && (room.bcConns.has(peerName) && !add || !room.bcConns.has(peerName) && add)) {
17725 const removed = [];
17726 const added = [];
17727 if (add) {
17728 room.bcConns.add(peerName);
17729 added.push(peerName);
17730 } else {
17731 room.bcConns.delete(peerName);
17732 removed.push(peerName);
17733 }
17734 room.provider.emit('peers', [{
17735 added,
17736 removed,
17737 webrtcPeers: Array.from(room.webrtcConns.keys()),
17738 bcPeers: Array.from(room.bcConns)
17739 }]);
17740 broadcastBcPeerId(room);
17741 }
17742 break;
17743 }
17744 default:
17745 console.error('Unable to compute message');
17746 return encoder;
17747 }
17748 if (!sendReply) {
17749 // nothing has been written, no answer created
17750 return null;
17751 }
17752 return encoder;
17753 };
17754
17755 /**
17756 * @param {WebrtcConn} peerConn
17757 * @param {Uint8Array} buf
17758 * @return {encoding.Encoder?}
17759 */
17760 const readPeerMessage = (peerConn, buf) => {
17761 const room = peerConn.room;
17762 y_webrtc_log('received message from ', BOLD, peerConn.remotePeerId, GREY, ' (', room.name, ')', UNBOLD, UNCOLOR);
17763 return readMessage(room, buf, () => {
17764 peerConn.synced = true;
17765 y_webrtc_log('synced ', BOLD, room.name, UNBOLD, ' with ', BOLD, peerConn.remotePeerId);
17766 checkIsSynced(room);
17767 });
17768 };
17769
17770 /**
17771 * @param {WebrtcConn} webrtcConn
17772 * @param {encoding.Encoder} encoder
17773 */
17774 const sendWebrtcConn = (webrtcConn, encoder) => {
17775 y_webrtc_log('send message to ', BOLD, webrtcConn.remotePeerId, UNBOLD, GREY, ' (', webrtcConn.room.name, ')', UNCOLOR);
17776 try {
17777 webrtcConn.peer.send(toUint8Array(encoder));
17778 } catch (e) {}
17779 };
17780
17781 /**
17782 * @param {Room} room
17783 * @param {Uint8Array} m
17784 */
17785 const broadcastWebrtcConn = (room, m) => {
17786 y_webrtc_log('broadcast message in ', BOLD, room.name, UNBOLD);
17787 room.webrtcConns.forEach(conn => {
17788 try {
17789 conn.peer.send(m);
17790 } catch (e) {}
17791 });
17792 };
17793 class WebrtcConn {
17794 /**
17795 * @param {SignalingConn} signalingConn
17796 * @param {boolean} initiator
17797 * @param {string} remotePeerId
17798 * @param {Room} room
17799 */
17800 constructor(signalingConn, initiator, remotePeerId, room) {
17801 y_webrtc_log('establishing connection to ', BOLD, remotePeerId);
17802 this.room = room;
17803 this.remotePeerId = remotePeerId;
17804 this.glareToken = undefined;
17805 this.closed = false;
17806 this.connected = false;
17807 this.synced = false;
17808 /**
17809 * @type {any}
17810 */
17811 this.peer = new (simplepeer_min_default())({
17812 initiator,
17813 ...room.provider.peerOpts
17814 });
17815 this.peer.on('signal', signal => {
17816 if (this.glareToken === undefined) {
17817 // add some randomness to the timestamp of the offer
17818 this.glareToken = Date.now() + Math.random();
17819 }
17820 publishSignalingMessage(signalingConn, room, {
17821 to: remotePeerId,
17822 from: room.peerId,
17823 type: 'signal',
17824 token: this.glareToken,
17825 signal
17826 });
17827 });
17828 this.peer.on('connect', () => {
17829 y_webrtc_log('connected to ', BOLD, remotePeerId);
17830 this.connected = true;
17831 // send sync step 1
17832 const provider = room.provider;
17833 const doc = provider.doc;
17834 const awareness = room.awareness;
17835 const encoder = createEncoder();
17836 writeVarUint(encoder, messageSync);
17837 writeSyncStep1(encoder, doc);
17838 sendWebrtcConn(this, encoder);
17839 const awarenessStates = awareness.getStates();
17840 if (awarenessStates.size > 0) {
17841 const encoder = createEncoder();
17842 writeVarUint(encoder, messageAwareness);
17843 writeVarUint8Array(encoder, encodeAwarenessUpdate(awareness, Array.from(awarenessStates.keys())));
17844 sendWebrtcConn(this, encoder);
17845 }
17846 });
17847 this.peer.on('close', () => {
17848 this.connected = false;
17849 this.closed = true;
17850 if (room.webrtcConns.has(this.remotePeerId)) {
17851 room.webrtcConns.delete(this.remotePeerId);
17852 room.provider.emit('peers', [{
17853 removed: [this.remotePeerId],
17854 added: [],
17855 webrtcPeers: Array.from(room.webrtcConns.keys()),
17856 bcPeers: Array.from(room.bcConns)
17857 }]);
17858 }
17859 checkIsSynced(room);
17860 this.peer.destroy();
17861 y_webrtc_log('closed connection to ', BOLD, remotePeerId);
17862 announceSignalingInfo(room);
17863 });
17864 this.peer.on('error', err => {
17865 y_webrtc_log('Error in connection to ', BOLD, remotePeerId, ': ', err);
17866 announceSignalingInfo(room);
17867 });
17868 this.peer.on('data', data => {
17869 const answer = readPeerMessage(this, data);
17870 if (answer !== null) {
17871 sendWebrtcConn(this, answer);
17872 }
17873 });
17874 }
17875 destroy() {
17876 this.peer.destroy();
17877 }
17878 }
17879
17880 /**
17881 * @param {Room} room
17882 * @param {Uint8Array} m
17883 */
17884 const broadcastBcMessage = (room, m) => encrypt(m, room.key).then(data => room.mux(() => publish(room.name, data)));
17885
17886 /**
17887 * @param {Room} room
17888 * @param {Uint8Array} m
17889 */
17890 const broadcastRoomMessage = (room, m) => {
17891 if (room.bcconnected) {
17892 broadcastBcMessage(room, m);
17893 }
17894 broadcastWebrtcConn(room, m);
17895 };
17896
17897 /**
17898 * @param {Room} room
17899 */
17900 const announceSignalingInfo = room => {
17901 signalingConns.forEach(conn => {
17902 // only subscribe if connection is established, otherwise the conn automatically subscribes to all rooms
17903 if (conn.connected) {
17904 conn.send({
17905 type: 'subscribe',
17906 topics: [room.name]
17907 });
17908 if (room.webrtcConns.size < room.provider.maxConns) {
17909 publishSignalingMessage(conn, room, {
17910 type: 'announce',
17911 from: room.peerId
17912 });
17913 }
17914 }
17915 });
17916 };
17917
17918 /**
17919 * @param {Room} room
17920 */
17921 const broadcastBcPeerId = room => {
17922 if (room.provider.filterBcConns) {
17923 // broadcast peerId via broadcastchannel
17924 const encoderPeerIdBc = createEncoder();
17925 writeVarUint(encoderPeerIdBc, messageBcPeerId);
17926 writeUint8(encoderPeerIdBc, 1);
17927 writeVarString(encoderPeerIdBc, room.peerId);
17928 broadcastBcMessage(room, toUint8Array(encoderPeerIdBc));
17929 }
17930 };
17931 class Room {
17932 /**
17933 * @param {Y.Doc} doc
17934 * @param {WebrtcProvider} provider
17935 * @param {string} name
17936 * @param {CryptoKey|null} key
17937 */
17938 constructor(doc, provider, name, key) {
17939 /**
17940 * Do not assume that peerId is unique. This is only meant for sending signaling messages.
17941 *
17942 * @type {string}
17943 */
17944 this.peerId = uuidv4();
17945 this.doc = doc;
17946 /**
17947 * @type {awarenessProtocol.Awareness}
17948 */
17949 this.awareness = provider.awareness;
17950 this.provider = provider;
17951 this.synced = false;
17952 this.name = name;
17953 // @todo make key secret by scoping
17954 this.key = key;
17955 /**
17956 * @type {Map<string, WebrtcConn>}
17957 */
17958 this.webrtcConns = new Map();
17959 /**
17960 * @type {Set<string>}
17961 */
17962 this.bcConns = new Set();
17963 this.mux = createMutex();
17964 this.bcconnected = false;
17965 /**
17966 * @param {ArrayBuffer} data
17967 */
17968 this._bcSubscriber = data => decrypt(new Uint8Array(data), key).then(m => this.mux(() => {
17969 const reply = readMessage(this, m, () => {});
17970 if (reply) {
17971 broadcastBcMessage(this, toUint8Array(reply));
17972 }
17973 }));
17974 /**
17975 * Listens to Yjs updates and sends them to remote peers
17976 *
17977 * @param {Uint8Array} update
17978 * @param {any} origin
17979 */
17980 this._docUpdateHandler = (update, origin) => {
17981 const encoder = createEncoder();
17982 writeVarUint(encoder, messageSync);
17983 writeUpdate(encoder, update);
17984 broadcastRoomMessage(this, toUint8Array(encoder));
17985 };
17986 /**
17987 * Listens to Awareness updates and sends them to remote peers
17988 *
17989 * @param {any} changed
17990 * @param {any} origin
17991 */
17992 this._awarenessUpdateHandler = ({
17993 added,
17994 updated,
17995 removed
17996 }, origin) => {
17997 const changedClients = added.concat(updated).concat(removed);
17998 const encoderAwareness = createEncoder();
17999 writeVarUint(encoderAwareness, messageAwareness);
18000 writeVarUint8Array(encoderAwareness, encodeAwarenessUpdate(this.awareness, changedClients));
18001 broadcastRoomMessage(this, toUint8Array(encoderAwareness));
18002 };
18003 this._beforeUnloadHandler = () => {
18004 removeAwarenessStates(this.awareness, [doc.clientID], 'window unload');
18005 rooms.forEach(room => {
18006 room.disconnect();
18007 });
18008 };
18009 if (typeof window !== 'undefined') {
18010 window.addEventListener('beforeunload', this._beforeUnloadHandler);
18011 } else if (typeof process !== 'undefined') {
18012 process.on('exit', this._beforeUnloadHandler);
18013 }
18014 }
18015 connect() {
18016 this.doc.on('update', this._docUpdateHandler);
18017 this.awareness.on('update', this._awarenessUpdateHandler);
18018 // signal through all available signaling connections
18019 announceSignalingInfo(this);
18020 const roomName = this.name;
18021 subscribe(roomName, this._bcSubscriber);
18022 this.bcconnected = true;
18023 // broadcast peerId via broadcastchannel
18024 broadcastBcPeerId(this);
18025 // write sync step 1
18026 const encoderSync = createEncoder();
18027 writeVarUint(encoderSync, messageSync);
18028 writeSyncStep1(encoderSync, this.doc);
18029 broadcastBcMessage(this, toUint8Array(encoderSync));
18030 // broadcast local state
18031 const encoderState = createEncoder();
18032 writeVarUint(encoderState, messageSync);
18033 writeSyncStep2(encoderState, this.doc);
18034 broadcastBcMessage(this, toUint8Array(encoderState));
18035 // write queryAwareness
18036 const encoderAwarenessQuery = createEncoder();
18037 writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
18038 broadcastBcMessage(this, toUint8Array(encoderAwarenessQuery));
18039 // broadcast local awareness state
18040 const encoderAwarenessState = createEncoder();
18041 writeVarUint(encoderAwarenessState, messageAwareness);
18042 writeVarUint8Array(encoderAwarenessState, encodeAwarenessUpdate(this.awareness, [this.doc.clientID]));
18043 broadcastBcMessage(this, toUint8Array(encoderAwarenessState));
18044 }
18045 disconnect() {
18046 // signal through all available signaling connections
18047 signalingConns.forEach(conn => {
18048 if (conn.connected) {
18049 conn.send({
18050 type: 'unsubscribe',
18051 topics: [this.name]
18052 });
18053 }
18054 });
18055 removeAwarenessStates(this.awareness, [this.doc.clientID], 'disconnect');
18056 // broadcast peerId removal via broadcastchannel
18057 const encoderPeerIdBc = createEncoder();
18058 writeVarUint(encoderPeerIdBc, messageBcPeerId);
18059 writeUint8(encoderPeerIdBc, 0); // remove peerId from other bc peers
18060 writeVarString(encoderPeerIdBc, this.peerId);
18061 broadcastBcMessage(this, toUint8Array(encoderPeerIdBc));
18062 unsubscribe(this.name, this._bcSubscriber);
18063 this.bcconnected = false;
18064 this.doc.off('update', this._docUpdateHandler);
18065 this.awareness.off('update', this._awarenessUpdateHandler);
18066 this.webrtcConns.forEach(conn => conn.destroy());
18067 }
18068 destroy() {
18069 this.disconnect();
18070 if (typeof window !== 'undefined') {
18071 window.removeEventListener('beforeunload', this._beforeUnloadHandler);
18072 } else if (typeof process !== 'undefined') {
18073 process.off('exit', this._beforeUnloadHandler);
18074 }
18075 }
18076 }
18077
18078 /**
18079 * @param {Y.Doc} doc
18080 * @param {WebrtcProvider} provider
18081 * @param {string} name
18082 * @param {CryptoKey|null} key
18083 * @return {Room}
18084 */
18085 const openRoom = (doc, provider, name, key) => {
18086 // there must only be one room
18087 if (rooms.has(name)) {
18088 throw error_create(`A Yjs Doc connected to room "${name}" already exists!`);
18089 }
18090 const room = new Room(doc, provider, name, key);
18091 rooms.set(name, /** @type {Room} */room);
18092 return room;
18093 };
18094
18095 /**
18096 * @param {SignalingConn} conn
18097 * @param {Room} room
18098 * @param {any} data
18099 */
18100 const publishSignalingMessage = (conn, room, data) => {
18101 if (room.key) {
18102 encryptJson(data, room.key).then(data => {
18103 conn.send({
18104 type: 'publish',
18105 topic: room.name,
18106 data: toBase64(data)
18107 });
18108 });
18109 } else {
18110 conn.send({
18111 type: 'publish',
18112 topic: room.name,
18113 data
18114 });
18115 }
18116 };
18117 class SignalingConn extends WebsocketClient {
18118 constructor(url) {
18119 super(url);
18120 /**
18121 * @type {Set<WebrtcProvider>}
18122 */
18123 this.providers = new Set();
18124 this.on('connect', () => {
18125 y_webrtc_log(`connected (${url})`);
18126 const topics = Array.from(rooms.keys());
18127 this.send({
18128 type: 'subscribe',
18129 topics
18130 });
18131 rooms.forEach(room => publishSignalingMessage(this, room, {
18132 type: 'announce',
18133 from: room.peerId
18134 }));
18135 });
18136 this.on('message', m => {
18137 switch (m.type) {
18138 case 'publish':
18139 {
18140 const roomName = m.topic;
18141 const room = rooms.get(roomName);
18142 if (room == null || typeof roomName !== 'string') {
18143 return;
18144 }
18145 const execMessage = data => {
18146 const webrtcConns = room.webrtcConns;
18147 const peerId = room.peerId;
18148 if (data == null || data.from === peerId || data.to !== undefined && data.to !== peerId || room.bcConns.has(data.from)) {
18149 // ignore messages that are not addressed to this conn, or from clients that are connected via broadcastchannel
18150 return;
18151 }
18152 const emitPeerChange = webrtcConns.has(data.from) ? () => {} : () => room.provider.emit('peers', [{
18153 removed: [],
18154 added: [data.from],
18155 webrtcPeers: Array.from(room.webrtcConns.keys()),
18156 bcPeers: Array.from(room.bcConns)
18157 }]);
18158 switch (data.type) {
18159 case 'announce':
18160 if (webrtcConns.size < room.provider.maxConns) {
18161 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(this, true, data.from, room));
18162 emitPeerChange();
18163 }
18164 break;
18165 case 'signal':
18166 if (data.signal.type === 'offer') {
18167 const existingConn = webrtcConns.get(data.from);
18168 if (existingConn) {
18169 const remoteToken = data.token;
18170 const localToken = existingConn.glareToken;
18171 if (localToken && localToken > remoteToken) {
18172 y_webrtc_log('offer rejected: ', data.from);
18173 return;
18174 }
18175 // if we don't reject the offer, we will be accepting it and answering it
18176 existingConn.glareToken = undefined;
18177 }
18178 }
18179 if (data.signal.type === 'answer') {
18180 y_webrtc_log('offer answered by: ', data.from);
18181 const existingConn = webrtcConns.get(data.from);
18182 existingConn.glareToken = undefined;
18183 }
18184 if (data.to === peerId) {
18185 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(this, false, data.from, room)).peer.signal(data.signal);
18186 emitPeerChange();
18187 }
18188 break;
18189 }
18190 };
18191 if (room.key) {
18192 if (typeof m.data === 'string') {
18193 decryptJson(fromBase64(m.data), room.key).then(execMessage);
18194 }
18195 } else {
18196 execMessage(m.data);
18197 }
18198 }
18199 }
18200 });
18201 this.on('disconnect', () => y_webrtc_log(`disconnect (${url})`));
18202 }
18203 }
18204
18205 /**
18206 * @typedef {Object} ProviderOptions
18207 * @property {Array<string>} [signaling]
18208 * @property {string} [password]
18209 * @property {awarenessProtocol.Awareness} [awareness]
18210 * @property {number} [maxConns]
18211 * @property {boolean} [filterBcConns]
18212 * @property {any} [peerOpts]
18213 */
18214
18215 /**
18216 * @extends Observable<string>
18217 */
18218 class WebrtcProvider extends observable_Observable {
18219 /**
18220 * @param {string} roomName
18221 * @param {Y.Doc} doc
18222 * @param {ProviderOptions?} opts
18223 */
18224 constructor(roomName, doc, {
18225 signaling = ['wss://y-webrtc-eu.fly.dev'],
18226 password = null,
18227 awareness = new Awareness(doc),
18228 maxConns = 20 + floor(rand() * 15),
18229 // the random factor reduces the chance that n clients form a cluster
18230 filterBcConns = true,
18231 peerOpts = {} // simple-peer options. See https://github.com/feross/simple-peer#peer--new-peeropts
18232 } = {}) {
18233 super();
18234 this.roomName = roomName;
18235 this.doc = doc;
18236 this.filterBcConns = filterBcConns;
18237 /**
18238 * @type {awarenessProtocol.Awareness}
18239 */
18240 this.awareness = awareness;
18241 this.shouldConnect = false;
18242 this.signalingUrls = signaling;
18243 this.signalingConns = [];
18244 this.maxConns = maxConns;
18245 this.peerOpts = peerOpts;
18246 /**
18247 * @type {PromiseLike<CryptoKey | null>}
18248 */
18249 this.key = password ? deriveKey(password, roomName) : /** @type {PromiseLike<null>} */resolve(null);
18250 /**
18251 * @type {Room|null}
18252 */
18253 this.room = null;
18254 this.key.then(key => {
18255 this.room = openRoom(doc, this, roomName, key);
18256 if (this.shouldConnect) {
18257 this.room.connect();
18258 } else {
18259 this.room.disconnect();
18260 }
18261 });
18262 this.connect();
18263 this.destroy = this.destroy.bind(this);
18264 doc.on('destroy', this.destroy);
18265 }
18266
18267 /**
18268 * @type {boolean}
18269 */
18270 get connected() {
18271 return this.room !== null && this.shouldConnect;
18272 }
18273 connect() {
18274 this.shouldConnect = true;
18275 this.signalingUrls.forEach(url => {
18276 const signalingConn = setIfUndefined(signalingConns, url, () => new SignalingConn(url));
18277 this.signalingConns.push(signalingConn);
18278 signalingConn.providers.add(this);
18279 });
18280 if (this.room) {
18281 this.room.connect();
18282 }
18283 }
18284 disconnect() {
18285 this.shouldConnect = false;
18286 this.signalingConns.forEach(conn => {
18287 conn.providers.delete(this);
18288 if (conn.providers.size === 0) {
18289 conn.destroy();
18290 signalingConns.delete(conn.url);
18291 }
18292 });
18293 if (this.room) {
18294 this.room.disconnect();
18295 }
18296 }
18297 destroy() {
18298 this.doc.off('destroy', this.destroy);
18299 // need to wait for key before deleting room
18300 this.key.then(() => {
18301 /** @type {Room} */this.room.destroy();
18302 rooms.delete(this.roomName);
18303 });
18304 super.destroy();
18305 }
18306 }
18307
18308 ;// CONCATENATED MODULE: ./packages/sync/build-module/webrtc-http-stream-signaling.js
18309 /**
18310 * External dependencies
18311 */
18312 /**
18313 * Internal dependencies
18314 */
18315
18316
18317
18318
18319
18320
18321 /**
18322 * WordPress dependencies
18323 */
18324
18325
18326 /**
18327 * Method copied as is from the SignalingConn constructor.
18328 * Setups the needed event handlers for an http signaling connection.
18329 *
18330 * @param {HttpSignalingConn} signalCon The signaling connection.
18331 * @param {string} url The url.
18332 */
18333 function setupSignalEventHandlers(signalCon, url) {
18334 signalCon.on('connect', () => {
18335 y_webrtc_log(`connected (${url})`);
18336 const topics = Array.from(rooms.keys());
18337 signalCon.send({
18338 type: 'subscribe',
18339 topics
18340 });
18341 rooms.forEach(room => publishSignalingMessage(signalCon, room, {
18342 type: 'announce',
18343 from: room.peerId
18344 }));
18345 });
18346 signalCon.on('message', ( /** @type {{ type: any; topic: any; data: string; }} */m) => {
18347 switch (m.type) {
18348 case 'publish':
18349 {
18350 const roomName = m.topic;
18351 const room = rooms.get(roomName);
18352 if (room === null || typeof roomName !== 'string' || room === undefined) {
18353 return;
18354 }
18355 const execMessage = ( /** @type {any} */data) => {
18356 const webrtcConns = room.webrtcConns;
18357 const peerId = room.peerId;
18358 if (data === null || data.from === peerId || data.to !== undefined && data.to !== peerId || room.bcConns.has(data.from)) {
18359 // ignore messages that are not addressed to this conn, or from clients that are connected via broadcastchannel
18360 return;
18361 }
18362 const emitPeerChange = webrtcConns.has(data.from) ? () => {} : () => room.provider.emit('peers', [{
18363 removed: [],
18364 added: [data.from],
18365 webrtcPeers: Array.from(room.webrtcConns.keys()),
18366 bcPeers: Array.from(room.bcConns)
18367 }]);
18368 switch (data.type) {
18369 case 'announce':
18370 if (webrtcConns.size < room.provider.maxConns) {
18371 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(signalCon, true, data.from, room));
18372 emitPeerChange();
18373 }
18374 break;
18375 case 'signal':
18376 if (data.signal.type === 'offer') {
18377 const existingConn = webrtcConns.get(data.from);
18378 if (existingConn) {
18379 const remoteToken = data.token;
18380 const localToken = existingConn.glareToken;
18381 if (localToken && localToken > remoteToken) {
18382 y_webrtc_log('offer rejected: ', data.from);
18383 return;
18384 }
18385 // if we don't reject the offer, we will be accepting it and answering it
18386 existingConn.glareToken = undefined;
18387 }
18388 }
18389 if (data.signal.type === 'answer') {
18390 y_webrtc_log('offer answered by: ', data.from);
18391 const existingConn = webrtcConns.get(data.from);
18392 if (existingConn) {
18393 existingConn.glareToken = undefined;
18394 }
18395 }
18396 if (data.to === peerId) {
18397 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(signalCon, false, data.from, room)).peer.signal(data.signal);
18398 emitPeerChange();
18399 }
18400 break;
18401 }
18402 };
18403 if (room.key) {
18404 if (typeof m.data === 'string') {
18405 decryptJson(fromBase64(m.data), room.key).then(execMessage);
18406 }
18407 } else {
18408 execMessage(m.data);
18409 }
18410 }
18411 }
18412 });
18413 signalCon.on('disconnect', () => y_webrtc_log(`disconnect (${url})`));
18414 }
18415
18416 /**
18417 * Method that instantiates the http signaling connection.
18418 * Tries to implement the same methods a websocket provides using ajax requests
18419 * to send messages and EventSource to retrieve messages.
18420 *
18421 * @param {HttpSignalingConn} httpClient The signaling connection.
18422 */
18423 function setupHttpSignal(httpClient) {
18424 if (httpClient.shouldConnect && httpClient.ws === null) {
18425 // eslint-disable-next-line no-restricted-syntax
18426 const subscriberId = Math.floor(100000 + Math.random() * 900000);
18427 const url = httpClient.url;
18428 const eventSource = new window.EventSource((0,external_wp_url_namespaceObject.addQueryArgs)(url, {
18429 subscriber_id: subscriberId,
18430 action: 'gutenberg_signaling_server'
18431 }));
18432 /**
18433 * @type {any}
18434 */
18435 let pingTimeout = null;
18436 eventSource.onmessage = event => {
18437 httpClient.lastMessageReceived = Date.now();
18438 const data = event.data;
18439 if (data) {
18440 const messages = JSON.parse(data);
18441 if (Array.isArray(messages)) {
18442 messages.forEach(onSingleMessage);
18443 }
18444 }
18445 };
18446 // @ts-ignore
18447 httpClient.ws = eventSource;
18448 httpClient.connecting = true;
18449 httpClient.connected = false;
18450 const onSingleMessage = ( /** @type {any} */message) => {
18451 if (message && message.type === 'pong') {
18452 clearTimeout(pingTimeout);
18453 pingTimeout = setTimeout(sendPing, webrtc_http_stream_signaling_messageReconnectTimeout / 2);
18454 }
18455 httpClient.emit('message', [message, httpClient]);
18456 };
18457
18458 /**
18459 * @param {any} error
18460 */
18461 const onclose = error => {
18462 if (httpClient.ws !== null) {
18463 httpClient.ws.close();
18464 httpClient.ws = null;
18465 httpClient.connecting = false;
18466 if (httpClient.connected) {
18467 httpClient.connected = false;
18468 httpClient.emit('disconnect', [{
18469 type: 'disconnect',
18470 error
18471 }, httpClient]);
18472 } else {
18473 httpClient.unsuccessfulReconnects++;
18474 }
18475 }
18476 clearTimeout(pingTimeout);
18477 };
18478 const sendPing = () => {
18479 if (httpClient.ws && httpClient.ws.readyState === window.EventSource.OPEN) {
18480 httpClient.send({
18481 type: 'ping'
18482 });
18483 }
18484 };
18485 if (httpClient.ws) {
18486 httpClient.ws.onclose = () => {
18487 onclose(null);
18488 };
18489 httpClient.ws.send = function send( /** @type {string} */message) {
18490 window.fetch(url, {
18491 body: new URLSearchParams({
18492 subscriber_id: subscriberId.toString(),
18493 action: 'gutenberg_signaling_server',
18494 message
18495 }),
18496 method: 'POST'
18497 }).catch(() => {
18498 y_webrtc_log('Error sending to server with message: ' + message);
18499 });
18500 };
18501 }
18502 eventSource.onerror = () => {
18503 // Todo: add an error handler
18504 };
18505 eventSource.onopen = () => {
18506 if (httpClient.connected) {
18507 return;
18508 }
18509 if (eventSource.readyState === window.EventSource.OPEN) {
18510 httpClient.lastMessageReceived = Date.now();
18511 httpClient.connecting = false;
18512 httpClient.connected = true;
18513 httpClient.unsuccessfulReconnects = 0;
18514 httpClient.emit('connect', [{
18515 type: 'connect'
18516 }, httpClient]);
18517 // set ping
18518 pingTimeout = setTimeout(sendPing, webrtc_http_stream_signaling_messageReconnectTimeout / 2);
18519 }
18520 };
18521 }
18522 }
18523 const webrtc_http_stream_signaling_messageReconnectTimeout = 30000;
18524
18525 /**
18526 * @augments Observable<string>
18527 */
18528 class HttpSignalingConn extends observable_Observable {
18529 /**
18530 * @param {string} url
18531 */
18532 constructor(url) {
18533 super();
18534
18535 //WebsocketClient from lib0/websocket.js
18536 this.url = url;
18537 /**
18538 * @type {WebSocket?}
18539 */
18540 this.ws = null;
18541 // @ts-ignore
18542 this.binaryType = null; // this.binaryType = binaryType
18543 this.connected = false;
18544 this.connecting = false;
18545 this.unsuccessfulReconnects = 0;
18546 this.lastMessageReceived = 0;
18547 /**
18548 * Whether to connect to other peers or not
18549 *
18550 * @type {boolean}
18551 */
18552 this.shouldConnect = true;
18553 this._checkInterval = setInterval(() => {
18554 if (this.connected && webrtc_http_stream_signaling_messageReconnectTimeout < Date.now() - this.lastMessageReceived && this.ws) {
18555 // no message received in a long time - not even your own awareness
18556 // updates (which are updated every 15 seconds)
18557 this.ws.close();
18558 }
18559 }, webrtc_http_stream_signaling_messageReconnectTimeout / 2);
18560 //setupWS( this );
18561 setupHttpSignal(this);
18562
18563 // From SignalingConn
18564 /**
18565 * @type {Set<WebrtcProvider>}
18566 */
18567 this.providers = new Set();
18568 setupSignalEventHandlers(this, url);
18569 }
18570
18571 /**
18572 * @param {any} message
18573 */
18574 send(message) {
18575 if (this.ws) {
18576 this.ws.send(JSON.stringify(message));
18577 }
18578 }
18579 destroy() {
18580 clearInterval(this._checkInterval);
18581 this.disconnect();
18582 super.destroy();
18583 }
18584 disconnect() {
18585 this.shouldConnect = false;
18586 if (this.ws !== null) {
18587 this.ws.close();
18588 }
18589 }
18590 connect() {
18591 this.shouldConnect = true;
18592 if (!this.connected && this.ws === null) {
18593 setupHttpSignal(this);
18594 }
18595 }
18596 }
18597 class WebrtcProviderWithHttpSignaling extends WebrtcProvider {
18598 connect() {
18599 this.shouldConnect = true;
18600 this.signalingUrls.forEach(( /** @type {string} */url) => {
18601 const signalingConn = setIfUndefined(signalingConns, url,
18602 // Only this conditional logic to create a normal websocket connection or
18603 // an http signaling connection was added to the constructor when compared
18604 // with the base class.
18605 url.startsWith('ws://') || url.startsWith('wss://') ? () => new SignalingConn(url) : () => new HttpSignalingConn(url));
18606 this.signalingConns.push(signalingConn);
18607 signalingConn.providers.add(this);
18608 });
18609 if (this.room) {
18610 this.room.connect();
18611 }
18612 }
18613 }
18614
18615 ;// CONCATENATED MODULE: ./packages/sync/build-module/create-webrtc-connection.js
18616 /**
18617 * External dependencies
18618 */
18619 // import { WebrtcProvider } from 'y-webrtc';
18620
18621 /**
18622 * Internal dependencies
18623 */
18624
18625
18626 /** @typedef {import('./types').ObjectType} ObjectType */
18627 /** @typedef {import('./types').ObjectID} ObjectID */
18628 /** @typedef {import('./types').CRDTDoc} CRDTDoc */
18629
18630 /**
18631 * Function that creates a new WebRTC Connection.
18632 *
18633 * @param {Object} config The object ID.
18634 *
18635 * @param {Array<string>} config.signaling
18636 * @param {string} config.password
18637 * @return {Function} Promise that resolves when the connection is established.
18638 */
18639 function createWebRTCConnection({
18640 signaling,
18641 password
18642 }) {
18643 return function ( /** @type {string} */objectId, /** @type {string} */objectType, /** @type {import("yjs").Doc} */doc) {
18644 const roomName = `${objectType}-${objectId}`;
18645 new WebrtcProviderWithHttpSignaling(roomName, doc, {
18646 signaling,
18647 // @ts-ignore
18648 password
18649 });
18650 return Promise.resolve(() => true);
18651 };
18652 }
18653
18654 ;// CONCATENATED MODULE: ./packages/core-data/build-module/sync.js
18655 /**
18656 * WordPress dependencies
18657 */
18658
18659 let syncProvider;
18660 function getSyncProvider() {
18661 if (!syncProvider) {
18662 syncProvider = createSyncProvider(connectIndexDb, createWebRTCConnection({
18663 signaling: [
18664 //'ws://localhost:4444',
18665 window?.wp?.ajax?.settings?.url],
18666 password: window?.__experimentalCollaborativeEditingSecret
18667 }));
18668 }
18669 return syncProvider;
18670 }
18671
18672 ;// CONCATENATED MODULE: ./packages/core-data/build-module/actions.js
18673 /**
18674 * External dependencies
18675 */
18676
18677
18678
18679 /**
18680 * WordPress dependencies
18681 */
18682
18683
18684
18685
18686 /**
18687 * Internal dependencies
18688 */
18689
18690
18691
18692
18693
18694
18695
18696 /**
18697 * Returns an action object used in signalling that authors have been received.
18698 * Ignored from documentation as it's internal to the data store.
18699 *
18700 * @ignore
18701 *
18702 * @param {string} queryID Query ID.
18703 * @param {Array|Object} users Users received.
18704 *
18705 * @return {Object} Action object.
18706 */
18707 function receiveUserQuery(queryID, users) {
18708 return {
18709 type: 'RECEIVE_USER_QUERY',
18710 users: Array.isArray(users) ? users : [users],
18711 queryID
18712 };
18713 }
18714
18715 /**
18716 * Returns an action used in signalling that the current user has been received.
18717 * Ignored from documentation as it's internal to the data store.
18718 *
18719 * @ignore
18720 *
18721 * @param {Object} currentUser Current user object.
18722 *
18723 * @return {Object} Action object.
18724 */
18725 function receiveCurrentUser(currentUser) {
18726 return {
18727 type: 'RECEIVE_CURRENT_USER',
18728 currentUser
18729 };
18730 }
18731
18732 /**
18733 * Returns an action object used in adding new entities.
18734 *
18735 * @param {Array} entities Entities received.
18736 *
18737 * @return {Object} Action object.
18738 */
18739 function addEntities(entities) {
18740 return {
18741 type: 'ADD_ENTITIES',
18742 entities
18743 };
18744 }
18745
18746 /**
18747 * Returns an action object used in signalling that entity records have been received.
18748 *
18749 * @param {string} kind Kind of the received entity record.
18750 * @param {string} name Name of the received entity record.
18751 * @param {Array|Object} records Records received.
18752 * @param {?Object} query Query Object.
18753 * @param {?boolean} invalidateCache Should invalidate query caches.
18754 * @param {?Object} edits Edits to reset.
18755 * @param {?Object} meta Meta information about pagination.
18756 * @return {Object} Action object.
18757 */
18758 function receiveEntityRecords(kind, name, records, query, invalidateCache = false, edits, meta) {
18759 // Auto drafts should not have titles, but some plugins rely on them so we can't filter this
18760 // on the server.
18761 if (kind === 'postType') {
18762 records = (Array.isArray(records) ? records : [records]).map(record => record.status === 'auto-draft' ? {
18763 ...record,
18764 title: ''
18765 } : record);
18766 }
18767 let action;
18768 if (query) {
18769 action = receiveQueriedItems(records, query, edits, meta);
18770 } else {
18771 action = receiveItems(records, edits, meta);
18772 }
18773 return {
18774 ...action,
18775 kind,
18776 name,
18777 invalidateCache
18778 };
18779 }
18780
18781 /**
18782 * Returns an action object used in signalling that the current theme has been received.
18783 * Ignored from documentation as it's internal to the data store.
18784 *
18785 * @ignore
18786 *
18787 * @param {Object} currentTheme The current theme.
18788 *
18789 * @return {Object} Action object.
18790 */
18791 function receiveCurrentTheme(currentTheme) {
18792 return {
18793 type: 'RECEIVE_CURRENT_THEME',
18794 currentTheme
18795 };
18796 }
18797
18798 /**
18799 * Returns an action object used in signalling that the current global styles id has been received.
18800 * Ignored from documentation as it's internal to the data store.
18801 *
18802 * @ignore
18803 *
18804 * @param {string} currentGlobalStylesId The current global styles id.
18805 *
18806 * @return {Object} Action object.
18807 */
18808 function __experimentalReceiveCurrentGlobalStylesId(currentGlobalStylesId) {
18809 return {
18810 type: 'RECEIVE_CURRENT_GLOBAL_STYLES_ID',
18811 id: currentGlobalStylesId
18812 };
18813 }
18814
18815 /**
18816 * Returns an action object used in signalling that the theme base global styles have been received
18817 * Ignored from documentation as it's internal to the data store.
18818 *
18819 * @ignore
18820 *
18821 * @param {string} stylesheet The theme's identifier
18822 * @param {Object} globalStyles The global styles object.
18823 *
18824 * @return {Object} Action object.
18825 */
18826 function __experimentalReceiveThemeBaseGlobalStyles(stylesheet, globalStyles) {
18827 return {
18828 type: 'RECEIVE_THEME_GLOBAL_STYLES',
18829 stylesheet,
18830 globalStyles
18831 };
18832 }
18833
18834 /**
18835 * Returns an action object used in signalling that the theme global styles variations have been received.
18836 * Ignored from documentation as it's internal to the data store.
18837 *
18838 * @ignore
18839 *
18840 * @param {string} stylesheet The theme's identifier
18841 * @param {Array} variations The global styles variations.
18842 *
18843 * @return {Object} Action object.
18844 */
18845 function __experimentalReceiveThemeGlobalStyleVariations(stylesheet, variations) {
18846 return {
18847 type: 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS',
18848 stylesheet,
18849 variations
18850 };
18851 }
18852
18853 /**
18854 * Returns an action object used in signalling that the index has been received.
18855 *
18856 * @deprecated since WP 5.9, this is not useful anymore, use the selector direclty.
18857 *
18858 * @return {Object} Action object.
18859 */
18860 function receiveThemeSupports() {
18861 external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveThemeSupports", {
18862 since: '5.9'
18863 });
18864 return {
18865 type: 'DO_NOTHING'
18866 };
18867 }
18868
18869 /**
18870 * Returns an action object used in signalling that the theme global styles CPT post revisions have been received.
18871 * Ignored from documentation as it's internal to the data store.
18872 *
18873 * @deprecated since WordPress 6.5.0. Callers should use `dispatch( 'core' ).receiveRevision` instead.
18874 *
18875 * @ignore
18876 *
18877 * @param {number} currentId The post id.
18878 * @param {Array} revisions The global styles revisions.
18879 *
18880 * @return {Object} Action object.
18881 */
18882 function receiveThemeGlobalStyleRevisions(currentId, revisions) {
18883 external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveThemeGlobalStyleRevisions()", {
18884 since: '6.5.0',
18885 alternative: "wp.data.dispatch( 'core' ).receiveRevisions"
18886 });
18887 return {
18888 type: 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS',
18889 currentId,
18890 revisions
18891 };
18892 }
18893
18894 /**
18895 * Returns an action object used in signalling that the preview data for
18896 * a given URl has been received.
18897 * Ignored from documentation as it's internal to the data store.
18898 *
18899 * @ignore
18900 *
18901 * @param {string} url URL to preview the embed for.
18902 * @param {*} preview Preview data.
18903 *
18904 * @return {Object} Action object.
18905 */
18906 function receiveEmbedPreview(url, preview) {
18907 return {
18908 type: 'RECEIVE_EMBED_PREVIEW',
18909 url,
18910 preview
18911 };
18912 }
18913
18914 /**
18915 * Action triggered to delete an entity record.
18916 *
18917 * @param {string} kind Kind of the deleted entity.
18918 * @param {string} name Name of the deleted entity.
18919 * @param {string} recordId Record ID of the deleted entity.
18920 * @param {?Object} query Special query parameters for the
18921 * DELETE API call.
18922 * @param {Object} [options] Delete options.
18923 * @param {Function} [options.__unstableFetch] Internal use only. Function to
18924 * call instead of `apiFetch()`.
18925 * Must return a promise.
18926 * @param {boolean} [options.throwOnError=false] If false, this action suppresses all
18927 * the exceptions. Defaults to false.
18928 */
18929 const deleteEntityRecord = (kind, name, recordId, query, {
18930 __unstableFetch = (external_wp_apiFetch_default()),
18931 throwOnError = false
18932 } = {}) => async ({
18933 dispatch
18934 }) => {
18935 const configs = await dispatch(getOrLoadEntitiesConfig(kind));
18936 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
18937 let error;
18938 let deletedRecord = false;
18939 if (!entityConfig || entityConfig?.__experimentalNoFetch) {
18940 return;
18941 }
18942 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, recordId], {
18943 exclusive: true
18944 });
18945 try {
18946 dispatch({
18947 type: 'DELETE_ENTITY_RECORD_START',
18948 kind,
18949 name,
18950 recordId
18951 });
18952 let hasError = false;
18953 try {
18954 let path = `${entityConfig.baseURL}/${recordId}`;
18955 if (query) {
18956 path = (0,external_wp_url_namespaceObject.addQueryArgs)(path, query);
18957 }
18958 deletedRecord = await __unstableFetch({
18959 path,
18960 method: 'DELETE'
18961 });
18962 await dispatch(removeItems(kind, name, recordId, true));
18963 } catch (_error) {
18964 hasError = true;
18965 error = _error;
18966 }
18967 dispatch({
18968 type: 'DELETE_ENTITY_RECORD_FINISH',
18969 kind,
18970 name,
18971 recordId,
18972 error
18973 });
18974 if (hasError && throwOnError) {
18975 throw error;
18976 }
18977 return deletedRecord;
18978 } finally {
18979 dispatch.__unstableReleaseStoreLock(lock);
18980 }
18981 };
18982
18983 /**
18984 * Returns an action object that triggers an
18985 * edit to an entity record.
18986 *
18987 * @param {string} kind Kind of the edited entity record.
18988 * @param {string} name Name of the edited entity record.
18989 * @param {number|string} recordId Record ID of the edited entity record.
18990 * @param {Object} edits The edits.
18991 * @param {Object} options Options for the edit.
18992 * @param {boolean} [options.undoIgnore] Whether to ignore the edit in undo history or not.
18993 *
18994 * @return {Object} Action object.
18995 */
18996 const editEntityRecord = (kind, name, recordId, edits, options = {}) => ({
18997 select,
18998 dispatch
18999 }) => {
19000 const entityConfig = select.getEntityConfig(kind, name);
19001 if (!entityConfig) {
19002 throw new Error(`The entity being edited (${kind}, ${name}) does not have a loaded config.`);
19003 }
19004 const {
19005 mergedEdits = {}
19006 } = entityConfig;
19007 const record = select.getRawEntityRecord(kind, name, recordId);
19008 const editedRecord = select.getEditedEntityRecord(kind, name, recordId);
19009 const edit = {
19010 kind,
19011 name,
19012 recordId,
19013 // Clear edits when they are equal to their persisted counterparts
19014 // so that the property is not considered dirty.
19015 edits: Object.keys(edits).reduce((acc, key) => {
19016 const recordValue = record[key];
19017 const editedRecordValue = editedRecord[key];
19018 const value = mergedEdits[key] ? {
19019 ...editedRecordValue,
19020 ...edits[key]
19021 } : edits[key];
19022 acc[key] = es6_default()(recordValue, value) ? undefined : value;
19023 return acc;
19024 }, {})
19025 };
19026 if (window.__experimentalEnableSync && entityConfig.syncConfig) {
19027 if (true) {
19028 const objectId = entityConfig.getSyncObjectId(recordId);
19029 getSyncProvider().update(entityConfig.syncObjectType + '--edit', objectId, edit.edits);
19030 }
19031 } else {
19032 if (!options.undoIgnore) {
19033 select.getUndoManager().addRecord([{
19034 id: {
19035 kind,
19036 name,
19037 recordId
19038 },
19039 changes: Object.keys(edits).reduce((acc, key) => {
19040 acc[key] = {
19041 from: editedRecord[key],
19042 to: edits[key]
19043 };
19044 return acc;
19045 }, {})
19046 }], options.isCached);
19047 }
19048 dispatch({
19049 type: 'EDIT_ENTITY_RECORD',
19050 ...edit
19051 });
19052 }
19053 };
19054
19055 /**
19056 * Action triggered to undo the last edit to
19057 * an entity record, if any.
19058 */
19059 const undo = () => ({
19060 select,
19061 dispatch
19062 }) => {
19063 const undoRecord = select.getUndoManager().undo();
19064 if (!undoRecord) {
19065 return;
19066 }
19067 dispatch({
19068 type: 'UNDO',
19069 record: undoRecord
19070 });
19071 };
19072
19073 /**
19074 * Action triggered to redo the last undoed
19075 * edit to an entity record, if any.
19076 */
19077 const redo = () => ({
19078 select,
19079 dispatch
19080 }) => {
19081 const redoRecord = select.getUndoManager().redo();
19082 if (!redoRecord) {
19083 return;
19084 }
19085 dispatch({
19086 type: 'REDO',
19087 record: redoRecord
19088 });
19089 };
19090
19091 /**
19092 * Forces the creation of a new undo level.
19093 *
19094 * @return {Object} Action object.
19095 */
19096 const __unstableCreateUndoLevel = () => ({
19097 select
19098 }) => {
19099 select.getUndoManager().addRecord();
19100 };
19101
19102 /**
19103 * Action triggered to save an entity record.
19104 *
19105 * @param {string} kind Kind of the received entity.
19106 * @param {string} name Name of the received entity.
19107 * @param {Object} record Record to be saved.
19108 * @param {Object} options Saving options.
19109 * @param {boolean} [options.isAutosave=false] Whether this is an autosave.
19110 * @param {Function} [options.__unstableFetch] Internal use only. Function to
19111 * call instead of `apiFetch()`.
19112 * Must return a promise.
19113 * @param {boolean} [options.throwOnError=false] If false, this action suppresses all
19114 * the exceptions. Defaults to false.
19115 */
19116 const saveEntityRecord = (kind, name, record, {
19117 isAutosave = false,
19118 __unstableFetch = (external_wp_apiFetch_default()),
19119 throwOnError = false
19120 } = {}) => async ({
19121 select,
19122 resolveSelect,
19123 dispatch
19124 }) => {
19125 const configs = await dispatch(getOrLoadEntitiesConfig(kind));
19126 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19127 if (!entityConfig || entityConfig?.__experimentalNoFetch) {
19128 return;
19129 }
19130 const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY;
19131 const recordId = record[entityIdKey];
19132 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, recordId || esm_browser_v4()], {
19133 exclusive: true
19134 });
19135 try {
19136 // Evaluate optimized edits.
19137 // (Function edits that should be evaluated on save to avoid expensive computations on every edit.)
19138 for (const [key, value] of Object.entries(record)) {
19139 if (typeof value === 'function') {
19140 const evaluatedValue = value(select.getEditedEntityRecord(kind, name, recordId));
19141 dispatch.editEntityRecord(kind, name, recordId, {
19142 [key]: evaluatedValue
19143 }, {
19144 undoIgnore: true
19145 });
19146 record[key] = evaluatedValue;
19147 }
19148 }
19149 dispatch({
19150 type: 'SAVE_ENTITY_RECORD_START',
19151 kind,
19152 name,
19153 recordId,
19154 isAutosave
19155 });
19156 let updatedRecord;
19157 let error;
19158 let hasError = false;
19159 try {
19160 const path = `${entityConfig.baseURL}${recordId ? '/' + recordId : ''}`;
19161 const persistedRecord = select.getRawEntityRecord(kind, name, recordId);
19162 if (isAutosave) {
19163 // Most of this autosave logic is very specific to posts.
19164 // This is fine for now as it is the only supported autosave,
19165 // but ideally this should all be handled in the back end,
19166 // so the client just sends and receives objects.
19167 const currentUser = select.getCurrentUser();
19168 const currentUserId = currentUser ? currentUser.id : undefined;
19169 const autosavePost = await resolveSelect.getAutosave(persistedRecord.type, persistedRecord.id, currentUserId);
19170 // Autosaves need all expected fields to be present.
19171 // So we fallback to the previous autosave and then
19172 // to the actual persisted entity if the edits don't
19173 // have a value.
19174 let data = {
19175 ...persistedRecord,
19176 ...autosavePost,
19177 ...record
19178 };
19179 data = Object.keys(data).reduce((acc, key) => {
19180 if (['title', 'excerpt', 'content', 'meta'].includes(key)) {
19181 acc[key] = data[key];
19182 }
19183 return acc;
19184 }, {
19185 status: data.status === 'auto-draft' ? 'draft' : data.status
19186 });
19187 updatedRecord = await __unstableFetch({
19188 path: `${path}/autosaves`,
19189 method: 'POST',
19190 data
19191 });
19192
19193 // An autosave may be processed by the server as a regular save
19194 // when its update is requested by the author and the post had
19195 // draft or auto-draft status.
19196 if (persistedRecord.id === updatedRecord.id) {
19197 let newRecord = {
19198 ...persistedRecord,
19199 ...data,
19200 ...updatedRecord
19201 };
19202 newRecord = Object.keys(newRecord).reduce((acc, key) => {
19203 // These properties are persisted in autosaves.
19204 if (['title', 'excerpt', 'content'].includes(key)) {
19205 acc[key] = newRecord[key];
19206 } else if (key === 'status') {
19207 // Status is only persisted in autosaves when going from
19208 // "auto-draft" to "draft".
19209 acc[key] = persistedRecord.status === 'auto-draft' && newRecord.status === 'draft' ? newRecord.status : persistedRecord.status;
19210 } else {
19211 // These properties are not persisted in autosaves.
19212 acc[key] = persistedRecord[key];
19213 }
19214 return acc;
19215 }, {});
19216 dispatch.receiveEntityRecords(kind, name, newRecord, undefined, true);
19217 } else {
19218 dispatch.receiveAutosaves(persistedRecord.id, updatedRecord);
19219 }
19220 } else {
19221 let edits = record;
19222 if (entityConfig.__unstablePrePersist) {
19223 edits = {
19224 ...edits,
19225 ...entityConfig.__unstablePrePersist(persistedRecord, edits)
19226 };
19227 }
19228 updatedRecord = await __unstableFetch({
19229 path,
19230 method: recordId ? 'PUT' : 'POST',
19231 data: edits
19232 });
19233 dispatch.receiveEntityRecords(kind, name, updatedRecord, undefined, true, edits);
19234 }
19235 } catch (_error) {
19236 hasError = true;
19237 error = _error;
19238 }
19239 dispatch({
19240 type: 'SAVE_ENTITY_RECORD_FINISH',
19241 kind,
19242 name,
19243 recordId,
19244 error,
19245 isAutosave
19246 });
19247 if (hasError && throwOnError) {
19248 throw error;
19249 }
19250 return updatedRecord;
19251 } finally {
19252 dispatch.__unstableReleaseStoreLock(lock);
19253 }
19254 };
19255
19256 /**
19257 * Runs multiple core-data actions at the same time using one API request.
19258 *
19259 * Example:
19260 *
19261 * ```
19262 * const [ savedRecord, updatedRecord, deletedRecord ] =
19263 * await dispatch( 'core' ).__experimentalBatch( [
19264 * ( { saveEntityRecord } ) => saveEntityRecord( 'root', 'widget', widget ),
19265 * ( { saveEditedEntityRecord } ) => saveEntityRecord( 'root', 'widget', 123 ),
19266 * ( { deleteEntityRecord } ) => deleteEntityRecord( 'root', 'widget', 123, null ),
19267 * ] );
19268 * ```
19269 *
19270 * @param {Array} requests Array of functions which are invoked simultaneously.
19271 * Each function is passed an object containing
19272 * `saveEntityRecord`, `saveEditedEntityRecord`, and
19273 * `deleteEntityRecord`.
19274 *
19275 * @return {(thunkArgs: Object) => Promise} A promise that resolves to an array containing the return
19276 * values of each function given in `requests`.
19277 */
19278 const __experimentalBatch = requests => async ({
19279 dispatch
19280 }) => {
19281 const batch = createBatch();
19282 const api = {
19283 saveEntityRecord(kind, name, record, options) {
19284 return batch.add(add => dispatch.saveEntityRecord(kind, name, record, {
19285 ...options,
19286 __unstableFetch: add
19287 }));
19288 },
19289 saveEditedEntityRecord(kind, name, recordId, options) {
19290 return batch.add(add => dispatch.saveEditedEntityRecord(kind, name, recordId, {
19291 ...options,
19292 __unstableFetch: add
19293 }));
19294 },
19295 deleteEntityRecord(kind, name, recordId, query, options) {
19296 return batch.add(add => dispatch.deleteEntityRecord(kind, name, recordId, query, {
19297 ...options,
19298 __unstableFetch: add
19299 }));
19300 }
19301 };
19302 const resultPromises = requests.map(request => request(api));
19303 const [, ...results] = await Promise.all([batch.run(), ...resultPromises]);
19304 return results;
19305 };
19306
19307 /**
19308 * Action triggered to save an entity record's edits.
19309 *
19310 * @param {string} kind Kind of the entity.
19311 * @param {string} name Name of the entity.
19312 * @param {Object} recordId ID of the record.
19313 * @param {Object} options Saving options.
19314 */
19315 const saveEditedEntityRecord = (kind, name, recordId, options) => async ({
19316 select,
19317 dispatch
19318 }) => {
19319 if (!select.hasEditsForEntityRecord(kind, name, recordId)) {
19320 return;
19321 }
19322 const configs = await dispatch(getOrLoadEntitiesConfig(kind));
19323 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19324 if (!entityConfig) {
19325 return;
19326 }
19327 const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY;
19328 const edits = select.getEntityRecordNonTransientEdits(kind, name, recordId);
19329 const record = {
19330 [entityIdKey]: recordId,
19331 ...edits
19332 };
19333 return await dispatch.saveEntityRecord(kind, name, record, options);
19334 };
19335
19336 /**
19337 * Action triggered to save only specified properties for the entity.
19338 *
19339 * @param {string} kind Kind of the entity.
19340 * @param {string} name Name of the entity.
19341 * @param {Object} recordId ID of the record.
19342 * @param {Array} itemsToSave List of entity properties or property paths to save.
19343 * @param {Object} options Saving options.
19344 */
19345 const __experimentalSaveSpecifiedEntityEdits = (kind, name, recordId, itemsToSave, options) => async ({
19346 select,
19347 dispatch
19348 }) => {
19349 if (!select.hasEditsForEntityRecord(kind, name, recordId)) {
19350 return;
19351 }
19352 const edits = select.getEntityRecordNonTransientEdits(kind, name, recordId);
19353 const editsToSave = {};
19354 for (const item of itemsToSave) {
19355 setNestedValue(editsToSave, item, getNestedValue(edits, item));
19356 }
19357 const configs = await dispatch(getOrLoadEntitiesConfig(kind));
19358 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19359 const entityIdKey = entityConfig?.key || DEFAULT_ENTITY_KEY;
19360
19361 // If a record key is provided then update the existing record.
19362 // This necessitates providing `recordKey` to saveEntityRecord as part of the
19363 // `record` argument (here called `editsToSave`) to stop that action creating
19364 // a new record and instead cause it to update the existing record.
19365 if (recordId) {
19366 editsToSave[entityIdKey] = recordId;
19367 }
19368 return await dispatch.saveEntityRecord(kind, name, editsToSave, options);
19369 };
19370
19371 /**
19372 * Returns an action object used in signalling that Upload permissions have been received.
19373 *
19374 * @deprecated since WP 5.9, use receiveUserPermission instead.
19375 *
19376 * @param {boolean} hasUploadPermissions Does the user have permission to upload files?
19377 *
19378 * @return {Object} Action object.
19379 */
19380 function receiveUploadPermissions(hasUploadPermissions) {
19381 external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveUploadPermissions", {
19382 since: '5.9',
19383 alternative: 'receiveUserPermission'
19384 });
19385 return receiveUserPermission('create/media', hasUploadPermissions);
19386 }
19387
19388 /**
19389 * Returns an action object used in signalling that the current user has
19390 * permission to perform an action on a REST resource.
19391 * Ignored from documentation as it's internal to the data store.
19392 *
19393 * @ignore
19394 *
19395 * @param {string} key A key that represents the action and REST resource.
19396 * @param {boolean} isAllowed Whether or not the user can perform the action.
19397 *
19398 * @return {Object} Action object.
19399 */
19400 function receiveUserPermission(key, isAllowed) {
19401 return {
19402 type: 'RECEIVE_USER_PERMISSION',
19403 key,
19404 isAllowed
19405 };
19406 }
19407
19408 /**
19409 * Returns an action object used in signalling that the autosaves for a
19410 * post have been received.
19411 * Ignored from documentation as it's internal to the data store.
19412 *
19413 * @ignore
19414 *
19415 * @param {number} postId The id of the post that is parent to the autosave.
19416 * @param {Array|Object} autosaves An array of autosaves or singular autosave object.
19417 *
19418 * @return {Object} Action object.
19419 */
19420 function receiveAutosaves(postId, autosaves) {
19421 return {
19422 type: 'RECEIVE_AUTOSAVES',
19423 postId,
19424 autosaves: Array.isArray(autosaves) ? autosaves : [autosaves]
19425 };
19426 }
19427
19428 /**
19429 * Returns an action object signalling that the fallback Navigation
19430 * Menu id has been received.
19431 *
19432 * @param {integer} fallbackId the id of the fallback Navigation Menu
19433 * @return {Object} Action object.
19434 */
19435 function receiveNavigationFallbackId(fallbackId) {
19436 return {
19437 type: 'RECEIVE_NAVIGATION_FALLBACK_ID',
19438 fallbackId
19439 };
19440 }
19441
19442 /**
19443 * Returns an action object used to set the template for a given query.
19444 *
19445 * @param {Object} query The lookup query.
19446 * @param {string} templateId The resolved template id.
19447 *
19448 * @return {Object} Action object.
19449 */
19450 function receiveDefaultTemplateId(query, templateId) {
19451 return {
19452 type: 'RECEIVE_DEFAULT_TEMPLATE',
19453 query,
19454 templateId
19455 };
19456 }
19457
19458 /**
19459 * Action triggered to receive revision items.
19460 *
19461 * @param {string} kind Kind of the received entity record revisions.
19462 * @param {string} name Name of the received entity record revisions.
19463 * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
19464 * @param {Array|Object} records Revisions received.
19465 * @param {?Object} query Query Object.
19466 * @param {?boolean} invalidateCache Should invalidate query caches.
19467 * @param {?Object} meta Meta information about pagination.
19468 */
19469 const receiveRevisions = (kind, name, recordKey, records, query, invalidateCache = false, meta) => async ({
19470 dispatch
19471 }) => {
19472 const configs = await dispatch(getOrLoadEntitiesConfig(kind));
19473 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19474 const key = entityConfig && entityConfig?.revisionKey ? entityConfig.revisionKey : DEFAULT_ENTITY_KEY;
19475 dispatch({
19476 type: 'RECEIVE_ITEM_REVISIONS',
19477 key,
19478 items: Array.isArray(records) ? records : [records],
19479 recordKey,
19480 meta,
19481 query,
19482 kind,
19483 name,
19484 invalidateCache
19485 });
19486 };
19487
19488 ;// CONCATENATED MODULE: ./packages/core-data/build-module/entities.js
19489 /**
19490 * External dependencies
19491 */
19492
19493
19494 /**
19495 * WordPress dependencies
19496 */
19497
19498
19499
19500 /**
19501 * Internal dependencies
19502 */
19503
19504
19505 const DEFAULT_ENTITY_KEY = 'id';
19506 const POST_RAW_ATTRIBUTES = ['title', 'excerpt', 'content'];
19507
19508 // A hardcoded list of post types that support revisions.
19509 // Reflects post types in Core's src/wp-includes/post.php.
19510 // @TODO: Ideally this should be fetched from the `/types` REST API's view context.
19511 const POST_TYPE_ENTITIES_WITH_REVISIONS_SUPPORT = ['post', 'page', 'wp_block', 'wp_navigation', 'wp_template', 'wp_template_part'];
19512 const rootEntitiesConfig = [{
19513 label: (0,external_wp_i18n_namespaceObject.__)('Base'),
19514 kind: 'root',
19515 name: '__unstableBase',
19516 baseURL: '/',
19517 baseURLParams: {
19518 _fields: ['description', 'gmt_offset', 'home', 'name', 'site_icon', 'site_icon_url', 'site_logo', 'timezone_string', 'url'].join(',')
19519 },
19520 syncConfig: {
19521 fetch: async () => {
19522 return external_wp_apiFetch_default()({
19523 path: '/'
19524 });
19525 },
19526 applyChangesToDoc: (doc, changes) => {
19527 const document = doc.getMap('document');
19528 Object.entries(changes).forEach(([key, value]) => {
19529 if (document.get(key) !== value) {
19530 document.set(key, value);
19531 }
19532 });
19533 },
19534 fromCRDTDoc: doc => {
19535 return doc.getMap('document').toJSON();
19536 }
19537 },
19538 syncObjectType: 'root/base',
19539 getSyncObjectId: () => 'index'
19540 }, {
19541 label: (0,external_wp_i18n_namespaceObject.__)('Site'),
19542 name: 'site',
19543 kind: 'root',
19544 baseURL: '/wp/v2/settings',
19545 getTitle: record => {
19546 var _record$title;
19547 return (_record$title = record?.title) !== null && _record$title !== void 0 ? _record$title : (0,external_wp_i18n_namespaceObject.__)('Site Title');
19548 },
19549 syncConfig: {
19550 fetch: async () => {
19551 return external_wp_apiFetch_default()({
19552 path: '/wp/v2/settings'
19553 });
19554 },
19555 applyChangesToDoc: (doc, changes) => {
19556 const document = doc.getMap('document');
19557 Object.entries(changes).forEach(([key, value]) => {
19558 if (document.get(key) !== value) {
19559 document.set(key, value);
19560 }
19561 });
19562 },
19563 fromCRDTDoc: doc => {
19564 return doc.getMap('document').toJSON();
19565 }
19566 },
19567 syncObjectType: 'root/site',
19568 getSyncObjectId: () => 'index'
19569 }, {
19570 label: (0,external_wp_i18n_namespaceObject.__)('Post Type'),
19571 name: 'postType',
19572 kind: 'root',
19573 key: 'slug',
19574 baseURL: '/wp/v2/types',
19575 baseURLParams: {
19576 context: 'edit'
19577 },
19578 syncConfig: {
19579 fetch: async id => {
19580 return external_wp_apiFetch_default()({
19581 path: `/wp/v2/types/${id}?context=edit`
19582 });
19583 },
19584 applyChangesToDoc: (doc, changes) => {
19585 const document = doc.getMap('document');
19586 Object.entries(changes).forEach(([key, value]) => {
19587 if (document.get(key) !== value) {
19588 document.set(key, value);
19589 }
19590 });
19591 },
19592 fromCRDTDoc: doc => {
19593 return doc.getMap('document').toJSON();
19594 }
19595 },
19596 syncObjectType: 'root/postType',
19597 getSyncObjectId: id => id
19598 }, {
19599 name: 'media',
19600 kind: 'root',
19601 baseURL: '/wp/v2/media',
19602 baseURLParams: {
19603 context: 'edit'
19604 },
19605 plural: 'mediaItems',
19606 label: (0,external_wp_i18n_namespaceObject.__)('Media'),
19607 rawAttributes: ['caption', 'title', 'description'],
19608 supportsPagination: true
19609 }, {
19610 name: 'taxonomy',
19611 kind: 'root',
19612 key: 'slug',
19613 baseURL: '/wp/v2/taxonomies',
19614 baseURLParams: {
19615 context: 'edit'
19616 },
19617 plural: 'taxonomies',
19618 label: (0,external_wp_i18n_namespaceObject.__)('Taxonomy')
19619 }, {
19620 name: 'sidebar',
19621 kind: 'root',
19622 baseURL: '/wp/v2/sidebars',
19623 baseURLParams: {
19624 context: 'edit'
19625 },
19626 plural: 'sidebars',
19627 transientEdits: {
19628 blocks: true
19629 },
19630 label: (0,external_wp_i18n_namespaceObject.__)('Widget areas')
19631 }, {
19632 name: 'widget',
19633 kind: 'root',
19634 baseURL: '/wp/v2/widgets',
19635 baseURLParams: {
19636 context: 'edit'
19637 },
19638 plural: 'widgets',
19639 transientEdits: {
19640 blocks: true
19641 },
19642 label: (0,external_wp_i18n_namespaceObject.__)('Widgets')
19643 }, {
19644 name: 'widgetType',
19645 kind: 'root',
19646 baseURL: '/wp/v2/widget-types',
19647 baseURLParams: {
19648 context: 'edit'
19649 },
19650 plural: 'widgetTypes',
19651 label: (0,external_wp_i18n_namespaceObject.__)('Widget types')
19652 }, {
19653 label: (0,external_wp_i18n_namespaceObject.__)('User'),
19654 name: 'user',
19655 kind: 'root',
19656 baseURL: '/wp/v2/users',
19657 baseURLParams: {
19658 context: 'edit'
19659 },
19660 plural: 'users'
19661 }, {
19662 name: 'comment',
19663 kind: 'root',
19664 baseURL: '/wp/v2/comments',
19665 baseURLParams: {
19666 context: 'edit'
19667 },
19668 plural: 'comments',
19669 label: (0,external_wp_i18n_namespaceObject.__)('Comment')
19670 }, {
19671 name: 'menu',
19672 kind: 'root',
19673 baseURL: '/wp/v2/menus',
19674 baseURLParams: {
19675 context: 'edit'
19676 },
19677 plural: 'menus',
19678 label: (0,external_wp_i18n_namespaceObject.__)('Menu')
19679 }, {
19680 name: 'menuItem',
19681 kind: 'root',
19682 baseURL: '/wp/v2/menu-items',
19683 baseURLParams: {
19684 context: 'edit'
19685 },
19686 plural: 'menuItems',
19687 label: (0,external_wp_i18n_namespaceObject.__)('Menu Item'),
19688 rawAttributes: ['title']
19689 }, {
19690 name: 'menuLocation',
19691 kind: 'root',
19692 baseURL: '/wp/v2/menu-locations',
19693 baseURLParams: {
19694 context: 'edit'
19695 },
19696 plural: 'menuLocations',
19697 label: (0,external_wp_i18n_namespaceObject.__)('Menu Location'),
19698 key: 'name'
19699 }, {
19700 label: (0,external_wp_i18n_namespaceObject.__)('Global Styles'),
19701 name: 'globalStyles',
19702 kind: 'root',
19703 baseURL: '/wp/v2/global-styles',
19704 baseURLParams: {
19705 context: 'edit'
19706 },
19707 plural: 'globalStylesVariations',
19708 // Should be different from name.
19709 getTitle: record => record?.title?.rendered || record?.title,
19710 getRevisionsUrl: (parentId, revisionId) => `/wp/v2/global-styles/${parentId}/revisions${revisionId ? '/' + revisionId : ''}`,
19711 supports: {
19712 revisions: true
19713 },
19714 supportsPagination: true
19715 }, {
19716 label: (0,external_wp_i18n_namespaceObject.__)('Themes'),
19717 name: 'theme',
19718 kind: 'root',
19719 baseURL: '/wp/v2/themes',
19720 baseURLParams: {
19721 context: 'edit'
19722 },
19723 key: 'stylesheet'
19724 }, {
19725 label: (0,external_wp_i18n_namespaceObject.__)('Plugins'),
19726 name: 'plugin',
19727 kind: 'root',
19728 baseURL: '/wp/v2/plugins',
19729 baseURLParams: {
19730 context: 'edit'
19731 },
19732 key: 'plugin'
19733 }, {
19734 label: (0,external_wp_i18n_namespaceObject.__)('Status'),
19735 name: 'status',
19736 kind: 'root',
19737 baseURL: '/wp/v2/statuses',
19738 baseURLParams: {
19739 context: 'edit'
19740 },
19741 plural: 'statuses',
19742 key: 'slug'
19743 }];
19744 const additionalEntityConfigLoaders = [{
19745 kind: 'postType',
19746 loadEntities: loadPostTypeEntities
19747 }, {
19748 kind: 'taxonomy',
19749 loadEntities: loadTaxonomyEntities
19750 }];
19751
19752 /**
19753 * Returns a function to be used to retrieve extra edits to apply before persisting a post type.
19754 *
19755 * @param {Object} persistedRecord Already persisted Post
19756 * @param {Object} edits Edits.
19757 * @return {Object} Updated edits.
19758 */
19759 const prePersistPostType = (persistedRecord, edits) => {
19760 const newEdits = {};
19761 if (persistedRecord?.status === 'auto-draft') {
19762 // Saving an auto-draft should create a draft by default.
19763 if (!edits.status && !newEdits.status) {
19764 newEdits.status = 'draft';
19765 }
19766
19767 // Fix the auto-draft default title.
19768 if ((!edits.title || edits.title === 'Auto Draft') && !newEdits.title && (!persistedRecord?.title || persistedRecord?.title === 'Auto Draft')) {
19769 newEdits.title = '';
19770 }
19771 }
19772 return newEdits;
19773 };
19774
19775 /**
19776 * Returns the list of post type entities.
19777 *
19778 * @return {Promise} Entities promise
19779 */
19780 async function loadPostTypeEntities() {
19781 const postTypes = await external_wp_apiFetch_default()({
19782 path: '/wp/v2/types?context=view'
19783 });
19784 return Object.entries(postTypes !== null && postTypes !== void 0 ? postTypes : {}).map(([name, postType]) => {
19785 var _postType$rest_namesp;
19786 const isTemplate = ['wp_template', 'wp_template_part'].includes(name);
19787 const namespace = (_postType$rest_namesp = postType?.rest_namespace) !== null && _postType$rest_namesp !== void 0 ? _postType$rest_namesp : 'wp/v2';
19788 return {
19789 kind: 'postType',
19790 baseURL: `/${namespace}/${postType.rest_base}`,
19791 baseURLParams: {
19792 context: 'edit'
19793 },
19794 name,
19795 label: postType.name,
19796 transientEdits: {
19797 blocks: true,
19798 selection: true
19799 },
19800 mergedEdits: {
19801 meta: true
19802 },
19803 supports: {
19804 revisions: POST_TYPE_ENTITIES_WITH_REVISIONS_SUPPORT.includes(postType?.slug)
19805 },
19806 rawAttributes: POST_RAW_ATTRIBUTES,
19807 getTitle: record => {
19808 var _record$slug;
19809 return record?.title?.rendered || record?.title || (isTemplate ? capitalCase((_record$slug = record.slug) !== null && _record$slug !== void 0 ? _record$slug : '') : String(record.id));
19810 },
19811 __unstablePrePersist: isTemplate ? undefined : prePersistPostType,
19812 __unstable_rest_base: postType.rest_base,
19813 syncConfig: {
19814 fetch: async id => {
19815 return external_wp_apiFetch_default()({
19816 path: `/${namespace}/${postType.rest_base}/${id}?context=edit`
19817 });
19818 },
19819 applyChangesToDoc: (doc, changes) => {
19820 const document = doc.getMap('document');
19821 Object.entries(changes).forEach(([key, value]) => {
19822 if (document.get(key) !== value && typeof value !== 'function') {
19823 document.set(key, value);
19824 }
19825 });
19826 },
19827 fromCRDTDoc: doc => {
19828 return doc.getMap('document').toJSON();
19829 }
19830 },
19831 syncObjectType: 'postType/' + postType.name,
19832 getSyncObjectId: id => id,
19833 supportsPagination: true,
19834 getRevisionsUrl: (parentId, revisionId) => `/${namespace}/${postType.rest_base}/${parentId}/revisions${revisionId ? '/' + revisionId : ''}`,
19835 revisionKey: isTemplate ? 'wp_id' : DEFAULT_ENTITY_KEY
19836 };
19837 });
19838 }
19839
19840 /**
19841 * Returns the list of the taxonomies entities.
19842 *
19843 * @return {Promise} Entities promise
19844 */
19845 async function loadTaxonomyEntities() {
19846 const taxonomies = await external_wp_apiFetch_default()({
19847 path: '/wp/v2/taxonomies?context=view'
19848 });
19849 return Object.entries(taxonomies !== null && taxonomies !== void 0 ? taxonomies : {}).map(([name, taxonomy]) => {
19850 var _taxonomy$rest_namesp;
19851 const namespace = (_taxonomy$rest_namesp = taxonomy?.rest_namespace) !== null && _taxonomy$rest_namesp !== void 0 ? _taxonomy$rest_namesp : 'wp/v2';
19852 return {
19853 kind: 'taxonomy',
19854 baseURL: `/${namespace}/${taxonomy.rest_base}`,
19855 baseURLParams: {
19856 context: 'edit'
19857 },
19858 name,
19859 label: taxonomy.name
19860 };
19861 });
19862 }
19863
19864 /**
19865 * Returns the entity's getter method name given its kind and name.
19866 *
19867 * @example
19868 * ```js
19869 * const nameSingular = getMethodName( 'root', 'theme', 'get' );
19870 * // nameSingular is getRootTheme
19871 *
19872 * const namePlural = getMethodName( 'root', 'theme', 'set' );
19873 * // namePlural is setRootThemes
19874 * ```
19875 *
19876 * @param {string} kind Entity kind.
19877 * @param {string} name Entity name.
19878 * @param {string} prefix Function prefix.
19879 * @param {boolean} usePlural Whether to use the plural form or not.
19880 *
19881 * @return {string} Method name
19882 */
19883 const getMethodName = (kind, name, prefix = 'get', usePlural = false) => {
19884 const entityConfig = rootEntitiesConfig.find(config => config.kind === kind && config.name === name);
19885 const kindPrefix = kind === 'root' ? '' : pascalCase(kind);
19886 const nameSuffix = pascalCase(name) + (usePlural ? 's' : '');
19887 const suffix = usePlural && 'plural' in entityConfig && entityConfig?.plural ? pascalCase(entityConfig.plural) : nameSuffix;
19888 return `${prefix}${kindPrefix}${suffix}`;
19889 };
19890 function registerSyncConfigs(configs) {
19891 configs.forEach(({
19892 syncObjectType,
19893 syncConfig
19894 }) => {
19895 getSyncProvider().register(syncObjectType, syncConfig);
19896 const editSyncConfig = {
19897 ...syncConfig
19898 };
19899 delete editSyncConfig.fetch;
19900 getSyncProvider().register(syncObjectType + '--edit', editSyncConfig);
19901 });
19902 }
19903
19904 /**
19905 * Loads the kind entities into the store.
19906 *
19907 * @param {string} kind Kind
19908 *
19909 * @return {(thunkArgs: object) => Promise<Array>} Entities
19910 */
19911 const getOrLoadEntitiesConfig = kind => async ({
19912 select,
19913 dispatch
19914 }) => {
19915 let configs = select.getEntitiesConfig(kind);
19916 if (configs && configs.length !== 0) {
19917 if (window.__experimentalEnableSync) {
19918 if (true) {
19919 registerSyncConfigs(configs);
19920 }
19921 }
19922 return configs;
19923 }
19924 const loader = additionalEntityConfigLoaders.find(l => l.kind === kind);
19925 if (!loader) {
19926 return [];
19927 }
19928 configs = await loader.loadEntities();
19929 if (window.__experimentalEnableSync) {
19930 if (true) {
19931 registerSyncConfigs(configs);
19932 }
19933 }
19934 dispatch(addEntities(configs));
19935 return configs;
19936 };
19937
19938 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/get-normalized-comma-separable.js
19939 /**
19940 * Given a value which can be specified as one or the other of a comma-separated
19941 * string or an array, returns a value normalized to an array of strings, or
19942 * null if the value cannot be interpreted as either.
19943 *
19944 * @param {string|string[]|*} value
19945 *
19946 * @return {?(string[])} Normalized field value.
19947 */
19948 function getNormalizedCommaSeparable(value) {
19949 if (typeof value === 'string') {
19950 return value.split(',');
19951 } else if (Array.isArray(value)) {
19952 return value;
19953 }
19954 return null;
19955 }
19956 /* harmony default export */ var get_normalized_comma_separable = (getNormalizedCommaSeparable);
19957
19958 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/with-weak-map-cache.js
19959 /**
19960 * Given a function, returns an enhanced function which caches the result and
19961 * tracks in WeakMap. The result is only cached if the original function is
19962 * passed a valid object-like argument (requirement for WeakMap key).
19963 *
19964 * @param {Function} fn Original function.
19965 *
19966 * @return {Function} Enhanced caching function.
19967 */
19968 function withWeakMapCache(fn) {
19969 const cache = new WeakMap();
19970 return key => {
19971 let value;
19972 if (cache.has(key)) {
19973 value = cache.get(key);
19974 } else {
19975 value = fn(key);
19976
19977 // Can reach here if key is not valid for WeakMap, since `has`
19978 // will return false for invalid key. Since `set` will throw,
19979 // ensure that key is valid before setting into cache.
19980 if (key !== null && typeof key === 'object') {
19981 cache.set(key, value);
19982 }
19983 }
19984 return value;
19985 };
19986 }
19987 /* harmony default export */ var with_weak_map_cache = (withWeakMapCache);
19988
19989 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/get-query-parts.js
19990 /**
19991 * WordPress dependencies
19992 */
19993
19994
19995 /**
19996 * Internal dependencies
19997 */
19998
19999
20000 /**
20001 * An object of properties describing a specific query.
20002 *
20003 * @typedef {Object} WPQueriedDataQueryParts
20004 *
20005 * @property {number} page The query page (1-based index, default 1).
20006 * @property {number} perPage Items per page for query (default 10).
20007 * @property {string} stableKey An encoded stable string of all non-
20008 * pagination, non-fields query parameters.
20009 * @property {?(string[])} fields Target subset of fields to derive from
20010 * item objects.
20011 * @property {?(number[])} include Specific item IDs to include.
20012 * @property {string} context Scope under which the request is made;
20013 * determines returned fields in response.
20014 */
20015
20016 /**
20017 * Given a query object, returns an object of parts, including pagination
20018 * details (`page` and `perPage`, or default values). All other properties are
20019 * encoded into a stable (idempotent) `stableKey` value.
20020 *
20021 * @param {Object} query Optional query object.
20022 *
20023 * @return {WPQueriedDataQueryParts} Query parts.
20024 */
20025 function getQueryParts(query) {
20026 /**
20027 * @type {WPQueriedDataQueryParts}
20028 */
20029 const parts = {
20030 stableKey: '',
20031 page: 1,
20032 perPage: 10,
20033 fields: null,
20034 include: null,
20035 context: 'default'
20036 };
20037
20038 // Ensure stable key by sorting keys. Also more efficient for iterating.
20039 const keys = Object.keys(query).sort();
20040 for (let i = 0; i < keys.length; i++) {
20041 const key = keys[i];
20042 let value = query[key];
20043 switch (key) {
20044 case 'page':
20045 parts[key] = Number(value);
20046 break;
20047 case 'per_page':
20048 parts.perPage = Number(value);
20049 break;
20050 case 'context':
20051 parts.context = value;
20052 break;
20053 default:
20054 // While in theory, we could exclude "_fields" from the stableKey
20055 // because two request with different fields have the same results
20056 // We're not able to ensure that because the server can decide to omit
20057 // fields from the response even if we explicitly asked for it.
20058 // Example: Asking for titles in posts without title support.
20059 if (key === '_fields') {
20060 var _getNormalizedCommaSe;
20061 parts.fields = (_getNormalizedCommaSe = get_normalized_comma_separable(value)) !== null && _getNormalizedCommaSe !== void 0 ? _getNormalizedCommaSe : [];
20062 // Make sure to normalize value for `stableKey`
20063 value = parts.fields.join();
20064 }
20065
20066 // Two requests with different include values cannot have same results.
20067 if (key === 'include') {
20068 var _getNormalizedCommaSe2;
20069 if (typeof value === 'number') {
20070 value = value.toString();
20071 }
20072 parts.include = ((_getNormalizedCommaSe2 = get_normalized_comma_separable(value)) !== null && _getNormalizedCommaSe2 !== void 0 ? _getNormalizedCommaSe2 : []).map(Number);
20073 // Normalize value for `stableKey`.
20074 value = parts.include.join();
20075 }
20076
20077 // While it could be any deterministic string, for simplicity's
20078 // sake mimic querystring encoding for stable key.
20079 //
20080 // TODO: For consistency with PHP implementation, addQueryArgs
20081 // should accept a key value pair, which may optimize its
20082 // implementation for our use here, vs. iterating an object
20083 // with only a single key.
20084 parts.stableKey += (parts.stableKey ? '&' : '') + (0,external_wp_url_namespaceObject.addQueryArgs)('', {
20085 [key]: value
20086 }).slice(1);
20087 }
20088 }
20089 return parts;
20090 }
20091 /* harmony default export */ var get_query_parts = (with_weak_map_cache(getQueryParts));
20092
20093 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/reducer.js
20094 /**
20095 * WordPress dependencies
20096 */
20097
20098
20099
20100 /**
20101 * Internal dependencies
20102 */
20103
20104
20105
20106 function getContextFromAction(action) {
20107 const {
20108 query
20109 } = action;
20110 if (!query) {
20111 return 'default';
20112 }
20113 const queryParts = get_query_parts(query);
20114 return queryParts.context;
20115 }
20116
20117 /**
20118 * Returns a merged array of item IDs, given details of the received paginated
20119 * items. The array is sparse-like with `undefined` entries where holes exist.
20120 *
20121 * @param {?Array<number>} itemIds Original item IDs (default empty array).
20122 * @param {number[]} nextItemIds Item IDs to merge.
20123 * @param {number} page Page of items merged.
20124 * @param {number} perPage Number of items per page.
20125 *
20126 * @return {number[]} Merged array of item IDs.
20127 */
20128 function getMergedItemIds(itemIds, nextItemIds, page, perPage) {
20129 var _itemIds$length;
20130 const receivedAllIds = page === 1 && perPage === -1;
20131 if (receivedAllIds) {
20132 return nextItemIds;
20133 }
20134 const nextItemIdsStartIndex = (page - 1) * perPage;
20135
20136 // If later page has already been received, default to the larger known
20137 // size of the existing array, else calculate as extending the existing.
20138 const size = Math.max((_itemIds$length = itemIds?.length) !== null && _itemIds$length !== void 0 ? _itemIds$length : 0, nextItemIdsStartIndex + nextItemIds.length);
20139
20140 // Preallocate array since size is known.
20141 const mergedItemIds = new Array(size);
20142 for (let i = 0; i < size; i++) {
20143 // Preserve existing item ID except for subset of range of next items.
20144 // We need to check against the possible maximum upper boundary because
20145 // a page could receive fewer than what was previously stored.
20146 const isInNextItemsRange = i >= nextItemIdsStartIndex && i < nextItemIdsStartIndex + perPage;
20147 mergedItemIds[i] = isInNextItemsRange ? nextItemIds[i - nextItemIdsStartIndex] : itemIds?.[i];
20148 }
20149 return mergedItemIds;
20150 }
20151
20152 /**
20153 * Helper function to filter out entities with certain IDs.
20154 * Entities are keyed by their ID.
20155 *
20156 * @param {Object} entities Entity objects, keyed by entity ID.
20157 * @param {Array} ids Entity IDs to filter out.
20158 *
20159 * @return {Object} Filtered entities.
20160 */
20161 function removeEntitiesById(entities, ids) {
20162 return Object.fromEntries(Object.entries(entities).filter(([id]) => !ids.some(itemId => {
20163 if (Number.isInteger(itemId)) {
20164 return itemId === +id;
20165 }
20166 return itemId === id;
20167 })));
20168 }
20169
20170 /**
20171 * Reducer tracking items state, keyed by ID. Items are assumed to be normal,
20172 * where identifiers are common across all queries.
20173 *
20174 * @param {Object} state Current state.
20175 * @param {Object} action Dispatched action.
20176 *
20177 * @return {Object} Next state.
20178 */
20179 function items(state = {}, action) {
20180 switch (action.type) {
20181 case 'RECEIVE_ITEMS':
20182 {
20183 const context = getContextFromAction(action);
20184 const key = action.key || DEFAULT_ENTITY_KEY;
20185 return {
20186 ...state,
20187 [context]: {
20188 ...state[context],
20189 ...action.items.reduce((accumulator, value) => {
20190 const itemId = value[key];
20191 accumulator[itemId] = conservativeMapItem(state?.[context]?.[itemId], value);
20192 return accumulator;
20193 }, {})
20194 }
20195 };
20196 }
20197 case 'REMOVE_ITEMS':
20198 return Object.fromEntries(Object.entries(state).map(([itemId, contextState]) => [itemId, removeEntitiesById(contextState, action.itemIds)]));
20199 }
20200 return state;
20201 }
20202
20203 /**
20204 * Reducer tracking item completeness, keyed by ID. A complete item is one for
20205 * which all fields are known. This is used in supporting `_fields` queries,
20206 * where not all properties associated with an entity are necessarily returned.
20207 * In such cases, completeness is used as an indication of whether it would be
20208 * safe to use queried data for a non-`_fields`-limited request.
20209 *
20210 * @param {Object<string,Object<string,boolean>>} state Current state.
20211 * @param {Object} action Dispatched action.
20212 *
20213 * @return {Object<string,Object<string,boolean>>} Next state.
20214 */
20215 function itemIsComplete(state = {}, action) {
20216 switch (action.type) {
20217 case 'RECEIVE_ITEMS':
20218 {
20219 const context = getContextFromAction(action);
20220 const {
20221 query,
20222 key = DEFAULT_ENTITY_KEY
20223 } = action;
20224
20225 // An item is considered complete if it is received without an associated
20226 // fields query. Ideally, this would be implemented in such a way where the
20227 // complete aggregate of all fields would satisfy completeness. Since the
20228 // fields are not consistent across all entities, this would require
20229 // introspection on the REST schema for each entity to know which fields
20230 // compose a complete item for that entity.
20231 const queryParts = query ? get_query_parts(query) : {};
20232 const isCompleteQuery = !query || !Array.isArray(queryParts.fields);
20233 return {
20234 ...state,
20235 [context]: {
20236 ...state[context],
20237 ...action.items.reduce((result, item) => {
20238 const itemId = item[key];
20239
20240 // Defer to completeness if already assigned. Technically the
20241 // data may be outdated if receiving items for a field subset.
20242 result[itemId] = state?.[context]?.[itemId] || isCompleteQuery;
20243 return result;
20244 }, {})
20245 }
20246 };
20247 }
20248 case 'REMOVE_ITEMS':
20249 return Object.fromEntries(Object.entries(state).map(([itemId, contextState]) => [itemId, removeEntitiesById(contextState, action.itemIds)]));
20250 }
20251 return state;
20252 }
20253
20254 /**
20255 * Reducer tracking queries state, keyed by stable query key. Each reducer
20256 * query object includes `itemIds` and `requestingPageByPerPage`.
20257 *
20258 * @param {Object} state Current state.
20259 * @param {Object} action Dispatched action.
20260 *
20261 * @return {Object} Next state.
20262 */
20263 const receiveQueries = (0,external_wp_compose_namespaceObject.compose)([
20264 // Limit to matching action type so we don't attempt to replace action on
20265 // an unhandled action.
20266 if_matching_action(action => 'query' in action),
20267 // Inject query parts into action for use both in `onSubKey` and reducer.
20268 replace_action(action => {
20269 // `ifMatchingAction` still passes on initialization, where state is
20270 // undefined and a query is not assigned. Avoid attempting to parse
20271 // parts. `onSubKey` will omit by lack of `stableKey`.
20272 if (action.query) {
20273 return {
20274 ...action,
20275 ...get_query_parts(action.query)
20276 };
20277 }
20278 return action;
20279 }), on_sub_key('context'),
20280 // Queries shape is shared, but keyed by query `stableKey` part. Original
20281 // reducer tracks only a single query object.
20282 on_sub_key('stableKey')])((state = {}, action) => {
20283 const {
20284 type,
20285 page,
20286 perPage,
20287 key = DEFAULT_ENTITY_KEY
20288 } = action;
20289 if (type !== 'RECEIVE_ITEMS') {
20290 return state;
20291 }
20292 return {
20293 itemIds: getMergedItemIds(state?.itemIds || [], action.items.map(item => item[key]), page, perPage),
20294 meta: action.meta
20295 };
20296 });
20297
20298 /**
20299 * Reducer tracking queries state.
20300 *
20301 * @param {Object} state Current state.
20302 * @param {Object} action Dispatched action.
20303 *
20304 * @return {Object} Next state.
20305 */
20306 const queries = (state = {}, action) => {
20307 switch (action.type) {
20308 case 'RECEIVE_ITEMS':
20309 return receiveQueries(state, action);
20310 case 'REMOVE_ITEMS':
20311 const removedItems = action.itemIds.reduce((result, itemId) => {
20312 result[itemId] = true;
20313 return result;
20314 }, {});
20315 return Object.fromEntries(Object.entries(state).map(([queryGroup, contextQueries]) => [queryGroup, Object.fromEntries(Object.entries(contextQueries).map(([query, queryItems]) => [query, {
20316 ...queryItems,
20317 itemIds: queryItems.itemIds.filter(queryId => !removedItems[queryId])
20318 }]))]));
20319 default:
20320 return state;
20321 }
20322 };
20323 /* harmony default export */ var reducer = ((0,external_wp_data_namespaceObject.combineReducers)({
20324 items,
20325 itemIsComplete,
20326 queries
20327 }));
20328
20329 ;// CONCATENATED MODULE: ./packages/core-data/build-module/reducer.js
20330 /**
20331 * External dependencies
20332 */
20333
20334
20335 /**
20336 * WordPress dependencies
20337 */
20338
20339
20340
20341
20342 /**
20343 * Internal dependencies
20344 */
20345
20346
20347
20348
20349 /** @typedef {import('./types').AnyFunction} AnyFunction */
20350
20351 /**
20352 * Reducer managing terms state. Keyed by taxonomy slug, the value is either
20353 * undefined (if no request has been made for given taxonomy), null (if a
20354 * request is in-flight for given taxonomy), or the array of terms for the
20355 * taxonomy.
20356 *
20357 * @param {Object} state Current state.
20358 * @param {Object} action Dispatched action.
20359 *
20360 * @return {Object} Updated state.
20361 */
20362 function terms(state = {}, action) {
20363 switch (action.type) {
20364 case 'RECEIVE_TERMS':
20365 return {
20366 ...state,
20367 [action.taxonomy]: action.terms
20368 };
20369 }
20370 return state;
20371 }
20372
20373 /**
20374 * Reducer managing authors state. Keyed by id.
20375 *
20376 * @param {Object} state Current state.
20377 * @param {Object} action Dispatched action.
20378 *
20379 * @return {Object} Updated state.
20380 */
20381 function users(state = {
20382 byId: {},
20383 queries: {}
20384 }, action) {
20385 switch (action.type) {
20386 case 'RECEIVE_USER_QUERY':
20387 return {
20388 byId: {
20389 ...state.byId,
20390 // Key users by their ID.
20391 ...action.users.reduce((newUsers, user) => ({
20392 ...newUsers,
20393 [user.id]: user
20394 }), {})
20395 },
20396 queries: {
20397 ...state.queries,
20398 [action.queryID]: action.users.map(user => user.id)
20399 }
20400 };
20401 }
20402 return state;
20403 }
20404
20405 /**
20406 * Reducer managing current user state.
20407 *
20408 * @param {Object} state Current state.
20409 * @param {Object} action Dispatched action.
20410 *
20411 * @return {Object} Updated state.
20412 */
20413 function currentUser(state = {}, action) {
20414 switch (action.type) {
20415 case 'RECEIVE_CURRENT_USER':
20416 return action.currentUser;
20417 }
20418 return state;
20419 }
20420
20421 /**
20422 * Reducer managing taxonomies.
20423 *
20424 * @param {Object} state Current state.
20425 * @param {Object} action Dispatched action.
20426 *
20427 * @return {Object} Updated state.
20428 */
20429 function taxonomies(state = [], action) {
20430 switch (action.type) {
20431 case 'RECEIVE_TAXONOMIES':
20432 return action.taxonomies;
20433 }
20434 return state;
20435 }
20436
20437 /**
20438 * Reducer managing the current theme.
20439 *
20440 * @param {string|undefined} state Current state.
20441 * @param {Object} action Dispatched action.
20442 *
20443 * @return {string|undefined} Updated state.
20444 */
20445 function currentTheme(state = undefined, action) {
20446 switch (action.type) {
20447 case 'RECEIVE_CURRENT_THEME':
20448 return action.currentTheme.stylesheet;
20449 }
20450 return state;
20451 }
20452
20453 /**
20454 * Reducer managing the current global styles id.
20455 *
20456 * @param {string|undefined} state Current state.
20457 * @param {Object} action Dispatched action.
20458 *
20459 * @return {string|undefined} Updated state.
20460 */
20461 function currentGlobalStylesId(state = undefined, action) {
20462 switch (action.type) {
20463 case 'RECEIVE_CURRENT_GLOBAL_STYLES_ID':
20464 return action.id;
20465 }
20466 return state;
20467 }
20468
20469 /**
20470 * Reducer managing the theme base global styles.
20471 *
20472 * @param {Record<string, object>} state Current state.
20473 * @param {Object} action Dispatched action.
20474 *
20475 * @return {Record<string, object>} Updated state.
20476 */
20477 function themeBaseGlobalStyles(state = {}, action) {
20478 switch (action.type) {
20479 case 'RECEIVE_THEME_GLOBAL_STYLES':
20480 return {
20481 ...state,
20482 [action.stylesheet]: action.globalStyles
20483 };
20484 }
20485 return state;
20486 }
20487
20488 /**
20489 * Reducer managing the theme global styles variations.
20490 *
20491 * @param {Record<string, object>} state Current state.
20492 * @param {Object} action Dispatched action.
20493 *
20494 * @return {Record<string, object>} Updated state.
20495 */
20496 function themeGlobalStyleVariations(state = {}, action) {
20497 switch (action.type) {
20498 case 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS':
20499 return {
20500 ...state,
20501 [action.stylesheet]: action.variations
20502 };
20503 }
20504 return state;
20505 }
20506 const withMultiEntityRecordEdits = reducer => (state, action) => {
20507 if (action.type === 'UNDO' || action.type === 'REDO') {
20508 const {
20509 record
20510 } = action;
20511 let newState = state;
20512 record.forEach(({
20513 id: {
20514 kind,
20515 name,
20516 recordId
20517 },
20518 changes
20519 }) => {
20520 newState = reducer(newState, {
20521 type: 'EDIT_ENTITY_RECORD',
20522 kind,
20523 name,
20524 recordId,
20525 edits: Object.entries(changes).reduce((acc, [key, value]) => {
20526 acc[key] = action.type === 'UNDO' ? value.from : value.to;
20527 return acc;
20528 }, {})
20529 });
20530 });
20531 return newState;
20532 }
20533 return reducer(state, action);
20534 };
20535
20536 /**
20537 * Higher Order Reducer for a given entity config. It supports:
20538 *
20539 * - Fetching
20540 * - Editing
20541 * - Saving
20542 *
20543 * @param {Object} entityConfig Entity config.
20544 *
20545 * @return {AnyFunction} Reducer.
20546 */
20547 function entity(entityConfig) {
20548 return (0,external_wp_compose_namespaceObject.compose)([withMultiEntityRecordEdits,
20549 // Limit to matching action type so we don't attempt to replace action on
20550 // an unhandled action.
20551 if_matching_action(action => action.name && action.kind && action.name === entityConfig.name && action.kind === entityConfig.kind),
20552 // Inject the entity config into the action.
20553 replace_action(action => {
20554 return {
20555 key: entityConfig.key || DEFAULT_ENTITY_KEY,
20556 ...action
20557 };
20558 })])((0,external_wp_data_namespaceObject.combineReducers)({
20559 queriedData: reducer,
20560 edits: (state = {}, action) => {
20561 var _action$query$context;
20562 switch (action.type) {
20563 case 'RECEIVE_ITEMS':
20564 const context = (_action$query$context = action?.query?.context) !== null && _action$query$context !== void 0 ? _action$query$context : 'default';
20565 if (context !== 'default') {
20566 return state;
20567 }
20568 const nextState = {
20569 ...state
20570 };
20571 for (const record of action.items) {
20572 const recordId = record[action.key];
20573 const edits = nextState[recordId];
20574 if (!edits) {
20575 continue;
20576 }
20577 const nextEdits = Object.keys(edits).reduce((acc, key) => {
20578 var _record$key$raw;
20579 // If the edited value is still different to the persisted value,
20580 // keep the edited value in edits.
20581 if (
20582 // Edits are the "raw" attribute values, but records may have
20583 // objects with more properties, so we use `get` here for the
20584 // comparison.
20585 !es6_default()(edits[key], (_record$key$raw = record[key]?.raw) !== null && _record$key$raw !== void 0 ? _record$key$raw : record[key]) && (
20586 // Sometimes the server alters the sent value which means
20587 // we need to also remove the edits before the api request.
20588 !action.persistedEdits || !es6_default()(edits[key], action.persistedEdits[key]))) {
20589 acc[key] = edits[key];
20590 }
20591 return acc;
20592 }, {});
20593 if (Object.keys(nextEdits).length) {
20594 nextState[recordId] = nextEdits;
20595 } else {
20596 delete nextState[recordId];
20597 }
20598 }
20599 return nextState;
20600 case 'EDIT_ENTITY_RECORD':
20601 const nextEdits = {
20602 ...state[action.recordId],
20603 ...action.edits
20604 };
20605 Object.keys(nextEdits).forEach(key => {
20606 // Delete cleared edits so that the properties
20607 // are not considered dirty.
20608 if (nextEdits[key] === undefined) {
20609 delete nextEdits[key];
20610 }
20611 });
20612 return {
20613 ...state,
20614 [action.recordId]: nextEdits
20615 };
20616 }
20617 return state;
20618 },
20619 saving: (state = {}, action) => {
20620 switch (action.type) {
20621 case 'SAVE_ENTITY_RECORD_START':
20622 case 'SAVE_ENTITY_RECORD_FINISH':
20623 return {
20624 ...state,
20625 [action.recordId]: {
20626 pending: action.type === 'SAVE_ENTITY_RECORD_START',
20627 error: action.error,
20628 isAutosave: action.isAutosave
20629 }
20630 };
20631 }
20632 return state;
20633 },
20634 deleting: (state = {}, action) => {
20635 switch (action.type) {
20636 case 'DELETE_ENTITY_RECORD_START':
20637 case 'DELETE_ENTITY_RECORD_FINISH':
20638 return {
20639 ...state,
20640 [action.recordId]: {
20641 pending: action.type === 'DELETE_ENTITY_RECORD_START',
20642 error: action.error
20643 }
20644 };
20645 }
20646 return state;
20647 },
20648 // Add revisions to the state tree if the post type supports it.
20649 ...(entityConfig?.supports?.revisions ? {
20650 revisions: (state = {}, action) => {
20651 // Use the same queriedDataReducer shape for revisions.
20652 if (action.type === 'RECEIVE_ITEM_REVISIONS') {
20653 const recordKey = action.recordKey;
20654 delete action.recordKey;
20655 const newState = reducer(state[recordKey], {
20656 ...action,
20657 type: 'RECEIVE_ITEMS'
20658 });
20659 return {
20660 ...state,
20661 [recordKey]: newState
20662 };
20663 }
20664 if (action.type === 'REMOVE_ITEMS') {
20665 return Object.fromEntries(Object.entries(state).filter(([id]) => !action.itemIds.some(itemId => {
20666 if (Number.isInteger(itemId)) {
20667 return itemId === +id;
20668 }
20669 return itemId === id;
20670 })));
20671 }
20672 return state;
20673 }
20674 } : {})
20675 }));
20676 }
20677
20678 /**
20679 * Reducer keeping track of the registered entities.
20680 *
20681 * @param {Object} state Current state.
20682 * @param {Object} action Dispatched action.
20683 *
20684 * @return {Object} Updated state.
20685 */
20686 function entitiesConfig(state = rootEntitiesConfig, action) {
20687 switch (action.type) {
20688 case 'ADD_ENTITIES':
20689 return [...state, ...action.entities];
20690 }
20691 return state;
20692 }
20693
20694 /**
20695 * Reducer keeping track of the registered entities config and data.
20696 *
20697 * @param {Object} state Current state.
20698 * @param {Object} action Dispatched action.
20699 *
20700 * @return {Object} Updated state.
20701 */
20702 const entities = (state = {}, action) => {
20703 const newConfig = entitiesConfig(state.config, action);
20704
20705 // Generates a dynamic reducer for the entities.
20706 let entitiesDataReducer = state.reducer;
20707 if (!entitiesDataReducer || newConfig !== state.config) {
20708 const entitiesByKind = newConfig.reduce((acc, record) => {
20709 const {
20710 kind
20711 } = record;
20712 if (!acc[kind]) {
20713 acc[kind] = [];
20714 }
20715 acc[kind].push(record);
20716 return acc;
20717 }, {});
20718 entitiesDataReducer = (0,external_wp_data_namespaceObject.combineReducers)(Object.entries(entitiesByKind).reduce((memo, [kind, subEntities]) => {
20719 const kindReducer = (0,external_wp_data_namespaceObject.combineReducers)(subEntities.reduce((kindMemo, entityConfig) => ({
20720 ...kindMemo,
20721 [entityConfig.name]: entity(entityConfig)
20722 }), {}));
20723 memo[kind] = kindReducer;
20724 return memo;
20725 }, {}));
20726 }
20727 const newData = entitiesDataReducer(state.records, action);
20728 if (newData === state.records && newConfig === state.config && entitiesDataReducer === state.reducer) {
20729 return state;
20730 }
20731 return {
20732 reducer: entitiesDataReducer,
20733 records: newData,
20734 config: newConfig
20735 };
20736 };
20737
20738 /**
20739 * @type {UndoManager}
20740 */
20741 function undoManager(state = createUndoManager()) {
20742 return state;
20743 }
20744 function editsReference(state = {}, action) {
20745 switch (action.type) {
20746 case 'EDIT_ENTITY_RECORD':
20747 case 'UNDO':
20748 case 'REDO':
20749 return {};
20750 }
20751 return state;
20752 }
20753
20754 /**
20755 * Reducer managing embed preview data.
20756 *
20757 * @param {Object} state Current state.
20758 * @param {Object} action Dispatched action.
20759 *
20760 * @return {Object} Updated state.
20761 */
20762 function embedPreviews(state = {}, action) {
20763 switch (action.type) {
20764 case 'RECEIVE_EMBED_PREVIEW':
20765 const {
20766 url,
20767 preview
20768 } = action;
20769 return {
20770 ...state,
20771 [url]: preview
20772 };
20773 }
20774 return state;
20775 }
20776
20777 /**
20778 * State which tracks whether the user can perform an action on a REST
20779 * resource.
20780 *
20781 * @param {Object} state Current state.
20782 * @param {Object} action Dispatched action.
20783 *
20784 * @return {Object} Updated state.
20785 */
20786 function userPermissions(state = {}, action) {
20787 switch (action.type) {
20788 case 'RECEIVE_USER_PERMISSION':
20789 return {
20790 ...state,
20791 [action.key]: action.isAllowed
20792 };
20793 }
20794 return state;
20795 }
20796
20797 /**
20798 * Reducer returning autosaves keyed by their parent's post id.
20799 *
20800 * @param {Object} state Current state.
20801 * @param {Object} action Dispatched action.
20802 *
20803 * @return {Object} Updated state.
20804 */
20805 function autosaves(state = {}, action) {
20806 switch (action.type) {
20807 case 'RECEIVE_AUTOSAVES':
20808 const {
20809 postId,
20810 autosaves: autosavesData
20811 } = action;
20812 return {
20813 ...state,
20814 [postId]: autosavesData
20815 };
20816 }
20817 return state;
20818 }
20819 function blockPatterns(state = [], action) {
20820 switch (action.type) {
20821 case 'RECEIVE_BLOCK_PATTERNS':
20822 return action.patterns;
20823 }
20824 return state;
20825 }
20826 function blockPatternCategories(state = [], action) {
20827 switch (action.type) {
20828 case 'RECEIVE_BLOCK_PATTERN_CATEGORIES':
20829 return action.categories;
20830 }
20831 return state;
20832 }
20833 function userPatternCategories(state = [], action) {
20834 switch (action.type) {
20835 case 'RECEIVE_USER_PATTERN_CATEGORIES':
20836 return action.patternCategories;
20837 }
20838 return state;
20839 }
20840 function navigationFallbackId(state = null, action) {
20841 switch (action.type) {
20842 case 'RECEIVE_NAVIGATION_FALLBACK_ID':
20843 return action.fallbackId;
20844 }
20845 return state;
20846 }
20847
20848 /**
20849 * Reducer managing the theme global styles revisions.
20850 *
20851 * @param {Record<string, object>} state Current state.
20852 * @param {Object} action Dispatched action.
20853 *
20854 * @return {Record<string, object>} Updated state.
20855 */
20856 function themeGlobalStyleRevisions(state = {}, action) {
20857 switch (action.type) {
20858 case 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS':
20859 return {
20860 ...state,
20861 [action.currentId]: action.revisions
20862 };
20863 }
20864 return state;
20865 }
20866
20867 /**
20868 * Reducer managing the template lookup per query.
20869 *
20870 * @param {Record<string, string>} state Current state.
20871 * @param {Object} action Dispatched action.
20872 *
20873 * @return {Record<string, string>} Updated state.
20874 */
20875 function defaultTemplates(state = {}, action) {
20876 switch (action.type) {
20877 case 'RECEIVE_DEFAULT_TEMPLATE':
20878 return {
20879 ...state,
20880 [JSON.stringify(action.query)]: action.templateId
20881 };
20882 }
20883 return state;
20884 }
20885 /* harmony default export */ var build_module_reducer = ((0,external_wp_data_namespaceObject.combineReducers)({
20886 terms,
20887 users,
20888 currentTheme,
20889 currentGlobalStylesId,
20890 currentUser,
20891 themeGlobalStyleVariations,
20892 themeBaseGlobalStyles,
20893 themeGlobalStyleRevisions,
20894 taxonomies,
20895 entities,
20896 editsReference,
20897 undoManager,
20898 embedPreviews,
20899 userPermissions,
20900 autosaves,
20901 blockPatterns,
20902 blockPatternCategories,
20903 userPatternCategories,
20904 navigationFallbackId,
20905 defaultTemplates
20906 }));
20907
20908 ;// CONCATENATED MODULE: ./node_modules/rememo/rememo.js
20909
20910
20911 /** @typedef {(...args: any[]) => *[]} GetDependants */
20912
20913 /** @typedef {() => void} Clear */
20914
20915 /**
20916 * @typedef {{
20917 * getDependants: GetDependants,
20918 * clear: Clear
20919 * }} EnhancedSelector
20920 */
20921
20922 /**
20923 * Internal cache entry.
20924 *
20925 * @typedef CacheNode
20926 *
20927 * @property {?CacheNode|undefined} [prev] Previous node.
20928 * @property {?CacheNode|undefined} [next] Next node.
20929 * @property {*[]} args Function arguments for cache entry.
20930 * @property {*} val Function result.
20931 */
20932
20933 /**
20934 * @typedef Cache
20935 *
20936 * @property {Clear} clear Function to clear cache.
20937 * @property {boolean} [isUniqueByDependants] Whether dependants are valid in
20938 * considering cache uniqueness. A cache is unique if dependents are all arrays
20939 * or objects.
20940 * @property {CacheNode?} [head] Cache head.
20941 * @property {*[]} [lastDependants] Dependants from previous invocation.
20942 */
20943
20944 /**
20945 * Arbitrary value used as key for referencing cache object in WeakMap tree.
20946 *
20947 * @type {{}}
20948 */
20949 var LEAF_KEY = {};
20950
20951 /**
20952 * Returns the first argument as the sole entry in an array.
20953 *
20954 * @template T
20955 *
20956 * @param {T} value Value to return.
20957 *
20958 * @return {[T]} Value returned as entry in array.
20959 */
20960 function arrayOf(value) {
20961 return [value];
20962 }
20963
20964 /**
20965 * Returns true if the value passed is object-like, or false otherwise. A value
20966 * is object-like if it can support property assignment, e.g. object or array.
20967 *
20968 * @param {*} value Value to test.
20969 *
20970 * @return {boolean} Whether value is object-like.
20971 */
20972 function isObjectLike(value) {
20973 return !!value && 'object' === typeof value;
20974 }
20975
20976 /**
20977 * Creates and returns a new cache object.
20978 *
20979 * @return {Cache} Cache object.
20980 */
20981 function createCache() {
20982 /** @type {Cache} */
20983 var cache = {
20984 clear: function () {
20985 cache.head = null;
20986 },
20987 };
20988
20989 return cache;
20990 }
20991
20992 /**
20993 * Returns true if entries within the two arrays are strictly equal by
20994 * reference from a starting index.
20995 *
20996 * @param {*[]} a First array.
20997 * @param {*[]} b Second array.
20998 * @param {number} fromIndex Index from which to start comparison.
20999 *
21000 * @return {boolean} Whether arrays are shallowly equal.
21001 */
21002 function isShallowEqual(a, b, fromIndex) {
21003 var i;
21004
21005 if (a.length !== b.length) {
21006 return false;
21007 }
21008
21009 for (i = fromIndex; i < a.length; i++) {
21010 if (a[i] !== b[i]) {
21011 return false;
21012 }
21013 }
21014
21015 return true;
21016 }
21017
21018 /**
21019 * Returns a memoized selector function. The getDependants function argument is
21020 * called before the memoized selector and is expected to return an immutable
21021 * reference or array of references on which the selector depends for computing
21022 * its own return value. The memoize cache is preserved only as long as those
21023 * dependant references remain the same. If getDependants returns a different
21024 * reference(s), the cache is cleared and the selector value regenerated.
21025 *
21026 * @template {(...args: *[]) => *} S
21027 *
21028 * @param {S} selector Selector function.
21029 * @param {GetDependants=} getDependants Dependant getter returning an array of
21030 * references used in cache bust consideration.
21031 */
21032 /* harmony default export */ function rememo(selector, getDependants) {
21033 /** @type {WeakMap<*,*>} */
21034 var rootCache;
21035
21036 /** @type {GetDependants} */
21037 var normalizedGetDependants = getDependants ? getDependants : arrayOf;
21038
21039 /**
21040 * Returns the cache for a given dependants array. When possible, a WeakMap
21041 * will be used to create a unique cache for each set of dependants. This
21042 * is feasible due to the nature of WeakMap in allowing garbage collection
21043 * to occur on entries where the key object is no longer referenced. Since
21044 * WeakMap requires the key to be an object, this is only possible when the
21045 * dependant is object-like. The root cache is created as a hierarchy where
21046 * each top-level key is the first entry in a dependants set, the value a
21047 * WeakMap where each key is the next dependant, and so on. This continues
21048 * so long as the dependants are object-like. If no dependants are object-
21049 * like, then the cache is shared across all invocations.
21050 *
21051 * @see isObjectLike
21052 *
21053 * @param {*[]} dependants Selector dependants.
21054 *
21055 * @return {Cache} Cache object.
21056 */
21057 function getCache(dependants) {
21058 var caches = rootCache,
21059 isUniqueByDependants = true,
21060 i,
21061 dependant,
21062 map,
21063 cache;
21064
21065 for (i = 0; i < dependants.length; i++) {
21066 dependant = dependants[i];
21067
21068 // Can only compose WeakMap from object-like key.
21069 if (!isObjectLike(dependant)) {
21070 isUniqueByDependants = false;
21071 break;
21072 }
21073
21074 // Does current segment of cache already have a WeakMap?
21075 if (caches.has(dependant)) {
21076 // Traverse into nested WeakMap.
21077 caches = caches.get(dependant);
21078 } else {
21079 // Create, set, and traverse into a new one.
21080 map = new WeakMap();
21081 caches.set(dependant, map);
21082 caches = map;
21083 }
21084 }
21085
21086 // We use an arbitrary (but consistent) object as key for the last item
21087 // in the WeakMap to serve as our running cache.
21088 if (!caches.has(LEAF_KEY)) {
21089 cache = createCache();
21090 cache.isUniqueByDependants = isUniqueByDependants;
21091 caches.set(LEAF_KEY, cache);
21092 }
21093
21094 return caches.get(LEAF_KEY);
21095 }
21096
21097 /**
21098 * Resets root memoization cache.
21099 */
21100 function clear() {
21101 rootCache = new WeakMap();
21102 }
21103
21104 /* eslint-disable jsdoc/check-param-names */
21105 /**
21106 * The augmented selector call, considering first whether dependants have
21107 * changed before passing it to underlying memoize function.
21108 *
21109 * @param {*} source Source object for derivation.
21110 * @param {...*} extraArgs Additional arguments to pass to selector.
21111 *
21112 * @return {*} Selector result.
21113 */
21114 /* eslint-enable jsdoc/check-param-names */
21115 function callSelector(/* source, ...extraArgs */) {
21116 var len = arguments.length,
21117 cache,
21118 node,
21119 i,
21120 args,
21121 dependants;
21122
21123 // Create copy of arguments (avoid leaking deoptimization).
21124 args = new Array(len);
21125 for (i = 0; i < len; i++) {
21126 args[i] = arguments[i];
21127 }
21128
21129 dependants = normalizedGetDependants.apply(null, args);
21130 cache = getCache(dependants);
21131
21132 // If not guaranteed uniqueness by dependants (primitive type), shallow
21133 // compare against last dependants and, if references have changed,
21134 // destroy cache to recalculate result.
21135 if (!cache.isUniqueByDependants) {
21136 if (
21137 cache.lastDependants &&
21138 !isShallowEqual(dependants, cache.lastDependants, 0)
21139 ) {
21140 cache.clear();
21141 }
21142
21143 cache.lastDependants = dependants;
21144 }
21145
21146 node = cache.head;
21147 while (node) {
21148 // Check whether node arguments match arguments
21149 if (!isShallowEqual(node.args, args, 1)) {
21150 node = node.next;
21151 continue;
21152 }
21153
21154 // At this point we can assume we've found a match
21155
21156 // Surface matched node to head if not already
21157 if (node !== cache.head) {
21158 // Adjust siblings to point to each other.
21159 /** @type {CacheNode} */ (node.prev).next = node.next;
21160 if (node.next) {
21161 node.next.prev = node.prev;
21162 }
21163
21164 node.next = cache.head;
21165 node.prev = null;
21166 /** @type {CacheNode} */ (cache.head).prev = node;
21167 cache.head = node;
21168 }
21169
21170 // Return immediately
21171 return node.val;
21172 }
21173
21174 // No cached value found. Continue to insertion phase:
21175
21176 node = /** @type {CacheNode} */ ({
21177 // Generate the result from original function
21178 val: selector.apply(null, args),
21179 });
21180
21181 // Avoid including the source object in the cache.
21182 args[0] = null;
21183 node.args = args;
21184
21185 // Don't need to check whether node is already head, since it would
21186 // have been returned above already if it was
21187
21188 // Shift existing head down list
21189 if (cache.head) {
21190 cache.head.prev = node;
21191 node.next = cache.head;
21192 }
21193
21194 cache.head = node;
21195
21196 return node.val;
21197 }
21198
21199 callSelector.getDependants = normalizedGetDependants;
21200 callSelector.clear = clear;
21201 clear();
21202
21203 return /** @type {S & EnhancedSelector} */ (callSelector);
21204 }
21205
21206 // EXTERNAL MODULE: ./node_modules/equivalent-key-map/equivalent-key-map.js
21207 var equivalent_key_map = __webpack_require__(2167);
21208 var equivalent_key_map_default = /*#__PURE__*/__webpack_require__.n(equivalent_key_map);
21209 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/selectors.js
21210 /**
21211 * External dependencies
21212 */
21213
21214
21215
21216 /**
21217 * Internal dependencies
21218 */
21219
21220
21221
21222 /**
21223 * Cache of state keys to EquivalentKeyMap where the inner map tracks queries
21224 * to their resulting items set. WeakMap allows garbage collection on expired
21225 * state references.
21226 *
21227 * @type {WeakMap<Object,EquivalentKeyMap>}
21228 */
21229 const queriedItemsCacheByState = new WeakMap();
21230
21231 /**
21232 * Returns items for a given query, or null if the items are not known.
21233 *
21234 * @param {Object} state State object.
21235 * @param {?Object} query Optional query.
21236 *
21237 * @return {?Array} Query items.
21238 */
21239 function getQueriedItemsUncached(state, query) {
21240 const {
21241 stableKey,
21242 page,
21243 perPage,
21244 include,
21245 fields,
21246 context
21247 } = get_query_parts(query);
21248 let itemIds;
21249 if (state.queries?.[context]?.[stableKey]) {
21250 itemIds = state.queries[context][stableKey].itemIds;
21251 }
21252 if (!itemIds) {
21253 return null;
21254 }
21255 const startOffset = perPage === -1 ? 0 : (page - 1) * perPage;
21256 const endOffset = perPage === -1 ? itemIds.length : Math.min(startOffset + perPage, itemIds.length);
21257 const items = [];
21258 for (let i = startOffset; i < endOffset; i++) {
21259 const itemId = itemIds[i];
21260 if (Array.isArray(include) && !include.includes(itemId)) {
21261 continue;
21262 }
21263 if (itemId === undefined) {
21264 continue;
21265 }
21266 // Having a target item ID doesn't guarantee that this object has been queried.
21267 if (!state.items[context]?.hasOwnProperty(itemId)) {
21268 return null;
21269 }
21270 const item = state.items[context][itemId];
21271 let filteredItem;
21272 if (Array.isArray(fields)) {
21273 filteredItem = {};
21274 for (let f = 0; f < fields.length; f++) {
21275 const field = fields[f].split('.');
21276 let value = item;
21277 field.forEach(fieldName => {
21278 value = value?.[fieldName];
21279 });
21280 setNestedValue(filteredItem, field, value);
21281 }
21282 } else {
21283 // If expecting a complete item, validate that completeness, or
21284 // otherwise abort.
21285 if (!state.itemIsComplete[context]?.[itemId]) {
21286 return null;
21287 }
21288 filteredItem = item;
21289 }
21290 items.push(filteredItem);
21291 }
21292 return items;
21293 }
21294
21295 /**
21296 * Returns items for a given query, or null if the items are not known. Caches
21297 * result both per state (by reference) and per query (by deep equality).
21298 * The caching approach is intended to be durable to query objects which are
21299 * deeply but not referentially equal, since otherwise:
21300 *
21301 * `getQueriedItems( state, {} ) !== getQueriedItems( state, {} )`
21302 *
21303 * @param {Object} state State object.
21304 * @param {?Object} query Optional query.
21305 *
21306 * @return {?Array} Query items.
21307 */
21308 const getQueriedItems = rememo((state, query = {}) => {
21309 let queriedItemsCache = queriedItemsCacheByState.get(state);
21310 if (queriedItemsCache) {
21311 const queriedItems = queriedItemsCache.get(query);
21312 if (queriedItems !== undefined) {
21313 return queriedItems;
21314 }
21315 } else {
21316 queriedItemsCache = new (equivalent_key_map_default())();
21317 queriedItemsCacheByState.set(state, queriedItemsCache);
21318 }
21319 const items = getQueriedItemsUncached(state, query);
21320 queriedItemsCache.set(query, items);
21321 return items;
21322 });
21323 function getQueriedTotalItems(state, query = {}) {
21324 var _state$queries$contex;
21325 const {
21326 stableKey,
21327 context
21328 } = get_query_parts(query);
21329 return (_state$queries$contex = state.queries?.[context]?.[stableKey]?.meta?.totalItems) !== null && _state$queries$contex !== void 0 ? _state$queries$contex : null;
21330 }
21331
21332 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/is-numeric-id.js
21333 /**
21334 * Checks argument to determine if it's a numeric ID.
21335 * For example, '123' is a numeric ID, but '123abc' is not.
21336 *
21337 * @param {any} id the argument to determine if it's a numeric ID.
21338 * @return {boolean} true if the string is a numeric ID, false otherwise.
21339 */
21340 function isNumericID(id) {
21341 return /^\s*\d+\s*$/.test(id);
21342 }
21343
21344 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/is-raw-attribute.js
21345 /**
21346 * Checks whether the attribute is a "raw" attribute or not.
21347 *
21348 * @param {Object} entity Entity record.
21349 * @param {string} attribute Attribute name.
21350 *
21351 * @return {boolean} Is the attribute raw
21352 */
21353 function isRawAttribute(entity, attribute) {
21354 return (entity.rawAttributes || []).includes(attribute);
21355 }
21356
21357 ;// CONCATENATED MODULE: ./packages/core-data/build-module/selectors.js
21358 /**
21359 * External dependencies
21360 */
21361
21362
21363 /**
21364 * WordPress dependencies
21365 */
21366
21367
21368
21369
21370 /**
21371 * Internal dependencies
21372 */
21373
21374
21375
21376
21377 /**
21378 * Shared reference to an empty object for cases where it is important to avoid
21379 * returning a new object reference on every invocation, as in a connected or
21380 * other pure component which performs `shouldComponentUpdate` check on props.
21381 * This should be used as a last resort, since the normalized data should be
21382 * maintained by the reducer result in state.
21383 */
21384 const EMPTY_OBJECT = {};
21385
21386 /**
21387 * Returns true if a request is in progress for embed preview data, or false
21388 * otherwise.
21389 *
21390 * @param state Data state.
21391 * @param url URL the preview would be for.
21392 *
21393 * @return Whether a request is in progress for an embed preview.
21394 */
21395 const isRequestingEmbedPreview = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, url) => {
21396 return select(STORE_NAME).isResolving('getEmbedPreview', [url]);
21397 });
21398
21399 /**
21400 * Returns all available authors.
21401 *
21402 * @deprecated since 11.3. Callers should use `select( 'core' ).getUsers({ who: 'authors' })` instead.
21403 *
21404 * @param state Data state.
21405 * @param query Optional object of query parameters to
21406 * 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).
21407 * @return Authors list.
21408 */
21409 function getAuthors(state, query) {
21410 external_wp_deprecated_default()("select( 'core' ).getAuthors()", {
21411 since: '5.9',
21412 alternative: "select( 'core' ).getUsers({ who: 'authors' })"
21413 });
21414 const path = (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/users/?who=authors&per_page=100', query);
21415 return getUserQueryResults(state, path);
21416 }
21417
21418 /**
21419 * Returns the current user.
21420 *
21421 * @param state Data state.
21422 *
21423 * @return Current user object.
21424 */
21425 function getCurrentUser(state) {
21426 return state.currentUser;
21427 }
21428
21429 /**
21430 * Returns all the users returned by a query ID.
21431 *
21432 * @param state Data state.
21433 * @param queryID Query ID.
21434 *
21435 * @return Users list.
21436 */
21437 const getUserQueryResults = rememo((state, queryID) => {
21438 var _state$users$queries$;
21439 const queryResults = (_state$users$queries$ = state.users.queries[queryID]) !== null && _state$users$queries$ !== void 0 ? _state$users$queries$ : [];
21440 return queryResults.map(id => state.users.byId[id]);
21441 }, (state, queryID) => [state.users.queries[queryID], state.users.byId]);
21442
21443 /**
21444 * Returns the loaded entities for the given kind.
21445 *
21446 * @deprecated since WordPress 6.0. Use getEntitiesConfig instead
21447 * @param state Data state.
21448 * @param kind Entity kind.
21449 *
21450 * @return Array of entities with config matching kind.
21451 */
21452 function getEntitiesByKind(state, kind) {
21453 external_wp_deprecated_default()("wp.data.select( 'core' ).getEntitiesByKind()", {
21454 since: '6.0',
21455 alternative: "wp.data.select( 'core' ).getEntitiesConfig()"
21456 });
21457 return getEntitiesConfig(state, kind);
21458 }
21459
21460 /**
21461 * Returns the loaded entities for the given kind.
21462 *
21463 * @param state Data state.
21464 * @param kind Entity kind.
21465 *
21466 * @return Array of entities with config matching kind.
21467 */
21468 function getEntitiesConfig(state, kind) {
21469 return state.entities.config.filter(entity => entity.kind === kind);
21470 }
21471
21472 /**
21473 * Returns the entity config given its kind and name.
21474 *
21475 * @deprecated since WordPress 6.0. Use getEntityConfig instead
21476 * @param state Data state.
21477 * @param kind Entity kind.
21478 * @param name Entity name.
21479 *
21480 * @return Entity config
21481 */
21482 function getEntity(state, kind, name) {
21483 external_wp_deprecated_default()("wp.data.select( 'core' ).getEntity()", {
21484 since: '6.0',
21485 alternative: "wp.data.select( 'core' ).getEntityConfig()"
21486 });
21487 return getEntityConfig(state, kind, name);
21488 }
21489
21490 /**
21491 * Returns the entity config given its kind and name.
21492 *
21493 * @param state Data state.
21494 * @param kind Entity kind.
21495 * @param name Entity name.
21496 *
21497 * @return Entity config
21498 */
21499 function getEntityConfig(state, kind, name) {
21500 return state.entities.config?.find(config => config.kind === kind && config.name === name);
21501 }
21502
21503 /**
21504 * GetEntityRecord is declared as a *callable interface* with
21505 * two signatures to work around the fact that TypeScript doesn't
21506 * allow currying generic functions:
21507 *
21508 * ```ts
21509 * type CurriedState = F extends ( state: any, ...args: infer P ) => infer R
21510 * ? ( ...args: P ) => R
21511 * : F;
21512 * type Selector = <K extends string | number>(
21513 * state: any,
21514 * kind: K,
21515 * key: K extends string ? 'string value' : false
21516 * ) => K;
21517 * type BadlyInferredSignature = CurriedState< Selector >
21518 * // BadlyInferredSignature evaluates to:
21519 * // (kind: string number, key: false | "string value") => string number
21520 * ```
21521 *
21522 * The signature without the state parameter shipped as CurriedSignature
21523 * is used in the return value of `select( coreStore )`.
21524 *
21525 * See https://github.com/WordPress/gutenberg/pull/41578 for more details.
21526 */
21527
21528 /**
21529 * Returns the Entity's record object by key. Returns `null` if the value is not
21530 * yet received, undefined if the value entity is known to not exist, or the
21531 * entity object if it exists and is received.
21532 *
21533 * @param state State tree
21534 * @param kind Entity kind.
21535 * @param name Entity name.
21536 * @param key Record's key
21537 * @param query Optional query. If requesting specific
21538 * 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]".
21539 *
21540 * @return Record.
21541 */
21542 const getEntityRecord = rememo((state, kind, name, key, query) => {
21543 var _query$context;
21544 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21545 if (!queriedState) {
21546 return undefined;
21547 }
21548 const context = (_query$context = query?.context) !== null && _query$context !== void 0 ? _query$context : 'default';
21549 if (query === undefined) {
21550 // If expecting a complete item, validate that completeness.
21551 if (!queriedState.itemIsComplete[context]?.[key]) {
21552 return undefined;
21553 }
21554 return queriedState.items[context][key];
21555 }
21556 const item = queriedState.items[context]?.[key];
21557 if (item && query._fields) {
21558 var _getNormalizedCommaSe;
21559 const filteredItem = {};
21560 const fields = (_getNormalizedCommaSe = get_normalized_comma_separable(query._fields)) !== null && _getNormalizedCommaSe !== void 0 ? _getNormalizedCommaSe : [];
21561 for (let f = 0; f < fields.length; f++) {
21562 const field = fields[f].split('.');
21563 let value = item;
21564 field.forEach(fieldName => {
21565 value = value?.[fieldName];
21566 });
21567 setNestedValue(filteredItem, field, value);
21568 }
21569 return filteredItem;
21570 }
21571 return item;
21572 }, (state, kind, name, recordId, query) => {
21573 var _query$context2;
21574 const context = (_query$context2 = query?.context) !== null && _query$context2 !== void 0 ? _query$context2 : 'default';
21575 return [state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]];
21576 });
21577
21578 /**
21579 * Normalizes `recordKey`s that look like numeric IDs to numbers.
21580 *
21581 * @param args EntityRecordArgs the selector arguments.
21582 * @return EntityRecordArgs the normalized arguments.
21583 */
21584 getEntityRecord.__unstableNormalizeArgs = args => {
21585 const newArgs = [...args];
21586 const recordKey = newArgs?.[2];
21587
21588 // If recordKey looks to be a numeric ID then coerce to number.
21589 newArgs[2] = isNumericID(recordKey) ? Number(recordKey) : recordKey;
21590 return newArgs;
21591 };
21592
21593 /**
21594 * 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.
21595 *
21596 * @param state State tree
21597 * @param kind Entity kind.
21598 * @param name Entity name.
21599 * @param key Record's key
21600 *
21601 * @return Record.
21602 */
21603 function __experimentalGetEntityRecordNoResolver(state, kind, name, key) {
21604 return getEntityRecord(state, kind, name, key);
21605 }
21606
21607 /**
21608 * Returns the entity's record object by key,
21609 * with its attributes mapped to their raw values.
21610 *
21611 * @param state State tree.
21612 * @param kind Entity kind.
21613 * @param name Entity name.
21614 * @param key Record's key.
21615 *
21616 * @return Object with the entity's raw attributes.
21617 */
21618 const getRawEntityRecord = rememo((state, kind, name, key) => {
21619 const record = getEntityRecord(state, kind, name, key);
21620 return record && Object.keys(record).reduce((accumulator, _key) => {
21621 if (isRawAttribute(getEntityConfig(state, kind, name), _key)) {
21622 var _record$_key$raw;
21623 // Because edits are the "raw" attribute values,
21624 // we return those from record selectors to make rendering,
21625 // comparisons, and joins with edits easier.
21626 accumulator[_key] = (_record$_key$raw = record[_key]?.raw) !== null && _record$_key$raw !== void 0 ? _record$_key$raw : record[_key];
21627 } else {
21628 accumulator[_key] = record[_key];
21629 }
21630 return accumulator;
21631 }, {});
21632 }, (state, kind, name, recordId, query) => {
21633 var _query$context3;
21634 const context = (_query$context3 = query?.context) !== null && _query$context3 !== void 0 ? _query$context3 : 'default';
21635 return [state.entities.config, state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]];
21636 });
21637
21638 /**
21639 * Returns true if records have been received for the given set of parameters,
21640 * or false otherwise.
21641 *
21642 * @param state State tree
21643 * @param kind Entity kind.
21644 * @param name Entity name.
21645 * @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".
21646 *
21647 * @return Whether entity records have been received.
21648 */
21649 function hasEntityRecords(state, kind, name, query) {
21650 return Array.isArray(getEntityRecords(state, kind, name, query));
21651 }
21652
21653 /**
21654 * GetEntityRecord is declared as a *callable interface* with
21655 * two signatures to work around the fact that TypeScript doesn't
21656 * allow currying generic functions.
21657 *
21658 * @see GetEntityRecord
21659 * @see https://github.com/WordPress/gutenberg/pull/41578
21660 */
21661
21662 /**
21663 * Returns the Entity's records.
21664 *
21665 * @param state State tree
21666 * @param kind Entity kind.
21667 * @param name Entity name.
21668 * @param query Optional terms query. If requesting specific
21669 * 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".
21670 *
21671 * @return Records.
21672 */
21673 const getEntityRecords = (state, kind, name, query) => {
21674 // Queried data state is prepopulated for all known entities. If this is not
21675 // assigned for the given parameters, then it is known to not exist.
21676 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21677 if (!queriedState) {
21678 return null;
21679 }
21680 return getQueriedItems(queriedState, query);
21681 };
21682
21683 /**
21684 * Returns the Entity's total available records for a given query (ignoring pagination).
21685 *
21686 * @param state State tree
21687 * @param kind Entity kind.
21688 * @param name Entity name.
21689 * @param query Optional terms query. If requesting specific
21690 * 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".
21691 *
21692 * @return number | null.
21693 */
21694 const getEntityRecordsTotalItems = (state, kind, name, query) => {
21695 // Queried data state is prepopulated for all known entities. If this is not
21696 // assigned for the given parameters, then it is known to not exist.
21697 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21698 if (!queriedState) {
21699 return null;
21700 }
21701 return getQueriedTotalItems(queriedState, query);
21702 };
21703
21704 /**
21705 * Returns the number of available pages for the given query.
21706 *
21707 * @param state State tree
21708 * @param kind Entity kind.
21709 * @param name Entity name.
21710 * @param query Optional terms query. If requesting specific
21711 * 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".
21712 *
21713 * @return number | null.
21714 */
21715 const getEntityRecordsTotalPages = (state, kind, name, query) => {
21716 // Queried data state is prepopulated for all known entities. If this is not
21717 // assigned for the given parameters, then it is known to not exist.
21718 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21719 if (!queriedState) {
21720 return null;
21721 }
21722 if (query.per_page === -1) return 1;
21723 const totalItems = getQueriedTotalItems(queriedState, query);
21724 if (!totalItems) return totalItems;
21725 return Math.ceil(totalItems / query.per_page);
21726 };
21727 /**
21728 * Returns the list of dirty entity records.
21729 *
21730 * @param state State tree.
21731 *
21732 * @return The list of updated records
21733 */
21734 const __experimentalGetDirtyEntityRecords = rememo(state => {
21735 const {
21736 entities: {
21737 records
21738 }
21739 } = state;
21740 const dirtyRecords = [];
21741 Object.keys(records).forEach(kind => {
21742 Object.keys(records[kind]).forEach(name => {
21743 const primaryKeys = Object.keys(records[kind][name].edits).filter(primaryKey =>
21744 // The entity record must exist (not be deleted),
21745 // and it must have edits.
21746 getEntityRecord(state, kind, name, primaryKey) && hasEditsForEntityRecord(state, kind, name, primaryKey));
21747 if (primaryKeys.length) {
21748 const entityConfig = getEntityConfig(state, kind, name);
21749 primaryKeys.forEach(primaryKey => {
21750 const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey);
21751 dirtyRecords.push({
21752 // We avoid using primaryKey because it's transformed into a string
21753 // when it's used as an object key.
21754 key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined,
21755 title: entityConfig?.getTitle?.(entityRecord) || '',
21756 name,
21757 kind
21758 });
21759 });
21760 }
21761 });
21762 });
21763 return dirtyRecords;
21764 }, state => [state.entities.records]);
21765
21766 /**
21767 * Returns the list of entities currently being saved.
21768 *
21769 * @param state State tree.
21770 *
21771 * @return The list of records being saved.
21772 */
21773 const __experimentalGetEntitiesBeingSaved = rememo(state => {
21774 const {
21775 entities: {
21776 records
21777 }
21778 } = state;
21779 const recordsBeingSaved = [];
21780 Object.keys(records).forEach(kind => {
21781 Object.keys(records[kind]).forEach(name => {
21782 const primaryKeys = Object.keys(records[kind][name].saving).filter(primaryKey => isSavingEntityRecord(state, kind, name, primaryKey));
21783 if (primaryKeys.length) {
21784 const entityConfig = getEntityConfig(state, kind, name);
21785 primaryKeys.forEach(primaryKey => {
21786 const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey);
21787 recordsBeingSaved.push({
21788 // We avoid using primaryKey because it's transformed into a string
21789 // when it's used as an object key.
21790 key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined,
21791 title: entityConfig?.getTitle?.(entityRecord) || '',
21792 name,
21793 kind
21794 });
21795 });
21796 }
21797 });
21798 });
21799 return recordsBeingSaved;
21800 }, state => [state.entities.records]);
21801
21802 /**
21803 * Returns the specified entity record's edits.
21804 *
21805 * @param state State tree.
21806 * @param kind Entity kind.
21807 * @param name Entity name.
21808 * @param recordId Record ID.
21809 *
21810 * @return The entity record's edits.
21811 */
21812 function getEntityRecordEdits(state, kind, name, recordId) {
21813 return state.entities.records?.[kind]?.[name]?.edits?.[recordId];
21814 }
21815
21816 /**
21817 * Returns the specified entity record's non transient edits.
21818 *
21819 * Transient edits don't create an undo level, and
21820 * are not considered for change detection.
21821 * They are defined in the entity's config.
21822 *
21823 * @param state State tree.
21824 * @param kind Entity kind.
21825 * @param name Entity name.
21826 * @param recordId Record ID.
21827 *
21828 * @return The entity record's non transient edits.
21829 */
21830 const getEntityRecordNonTransientEdits = rememo((state, kind, name, recordId) => {
21831 const {
21832 transientEdits
21833 } = getEntityConfig(state, kind, name) || {};
21834 const edits = getEntityRecordEdits(state, kind, name, recordId) || {};
21835 if (!transientEdits) {
21836 return edits;
21837 }
21838 return Object.keys(edits).reduce((acc, key) => {
21839 if (!transientEdits[key]) {
21840 acc[key] = edits[key];
21841 }
21842 return acc;
21843 }, {});
21844 }, (state, kind, name, recordId) => [state.entities.config, state.entities.records?.[kind]?.[name]?.edits?.[recordId]]);
21845
21846 /**
21847 * Returns true if the specified entity record has edits,
21848 * and false otherwise.
21849 *
21850 * @param state State tree.
21851 * @param kind Entity kind.
21852 * @param name Entity name.
21853 * @param recordId Record ID.
21854 *
21855 * @return Whether the entity record has edits or not.
21856 */
21857 function hasEditsForEntityRecord(state, kind, name, recordId) {
21858 return isSavingEntityRecord(state, kind, name, recordId) || Object.keys(getEntityRecordNonTransientEdits(state, kind, name, recordId)).length > 0;
21859 }
21860
21861 /**
21862 * Returns the specified entity record, merged with its edits.
21863 *
21864 * @param state State tree.
21865 * @param kind Entity kind.
21866 * @param name Entity name.
21867 * @param recordId Record ID.
21868 *
21869 * @return The entity record, merged with its edits.
21870 */
21871 const getEditedEntityRecord = rememo((state, kind, name, recordId) => ({
21872 ...getRawEntityRecord(state, kind, name, recordId),
21873 ...getEntityRecordEdits(state, kind, name, recordId)
21874 }), (state, kind, name, recordId, query) => {
21875 var _query$context4;
21876 const context = (_query$context4 = query?.context) !== null && _query$context4 !== void 0 ? _query$context4 : 'default';
21877 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]];
21878 });
21879
21880 /**
21881 * Returns true if the specified entity record is autosaving, and false otherwise.
21882 *
21883 * @param state State tree.
21884 * @param kind Entity kind.
21885 * @param name Entity name.
21886 * @param recordId Record ID.
21887 *
21888 * @return Whether the entity record is autosaving or not.
21889 */
21890 function isAutosavingEntityRecord(state, kind, name, recordId) {
21891 var _state$entities$recor;
21892 const {
21893 pending,
21894 isAutosave
21895 } = (_state$entities$recor = state.entities.records?.[kind]?.[name]?.saving?.[recordId]) !== null && _state$entities$recor !== void 0 ? _state$entities$recor : {};
21896 return Boolean(pending && isAutosave);
21897 }
21898
21899 /**
21900 * Returns true if the specified entity record is saving, and false otherwise.
21901 *
21902 * @param state State tree.
21903 * @param kind Entity kind.
21904 * @param name Entity name.
21905 * @param recordId Record ID.
21906 *
21907 * @return Whether the entity record is saving or not.
21908 */
21909 function isSavingEntityRecord(state, kind, name, recordId) {
21910 var _state$entities$recor2;
21911 return (_state$entities$recor2 = state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.pending) !== null && _state$entities$recor2 !== void 0 ? _state$entities$recor2 : false;
21912 }
21913
21914 /**
21915 * Returns true if the specified entity record is deleting, and false otherwise.
21916 *
21917 * @param state State tree.
21918 * @param kind Entity kind.
21919 * @param name Entity name.
21920 * @param recordId Record ID.
21921 *
21922 * @return Whether the entity record is deleting or not.
21923 */
21924 function isDeletingEntityRecord(state, kind, name, recordId) {
21925 var _state$entities$recor3;
21926 return (_state$entities$recor3 = state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.pending) !== null && _state$entities$recor3 !== void 0 ? _state$entities$recor3 : false;
21927 }
21928
21929 /**
21930 * Returns the specified entity record's last save error.
21931 *
21932 * @param state State tree.
21933 * @param kind Entity kind.
21934 * @param name Entity name.
21935 * @param recordId Record ID.
21936 *
21937 * @return The entity record's save error.
21938 */
21939 function getLastEntitySaveError(state, kind, name, recordId) {
21940 return state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.error;
21941 }
21942
21943 /**
21944 * Returns the specified entity record's last delete error.
21945 *
21946 * @param state State tree.
21947 * @param kind Entity kind.
21948 * @param name Entity name.
21949 * @param recordId Record ID.
21950 *
21951 * @return The entity record's save error.
21952 */
21953 function getLastEntityDeleteError(state, kind, name, recordId) {
21954 return state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.error;
21955 }
21956
21957 /**
21958 * Returns the previous edit from the current undo offset
21959 * for the entity records edits history, if any.
21960 *
21961 * @deprecated since 6.3
21962 *
21963 * @param state State tree.
21964 *
21965 * @return The edit.
21966 */
21967 function getUndoEdit(state) {
21968 external_wp_deprecated_default()("select( 'core' ).getUndoEdit()", {
21969 since: '6.3'
21970 });
21971 return undefined;
21972 }
21973
21974 /**
21975 * Returns the next edit from the current undo offset
21976 * for the entity records edits history, if any.
21977 *
21978 * @deprecated since 6.3
21979 *
21980 * @param state State tree.
21981 *
21982 * @return The edit.
21983 */
21984 function getRedoEdit(state) {
21985 external_wp_deprecated_default()("select( 'core' ).getRedoEdit()", {
21986 since: '6.3'
21987 });
21988 return undefined;
21989 }
21990
21991 /**
21992 * Returns true if there is a previous edit from the current undo offset
21993 * for the entity records edits history, and false otherwise.
21994 *
21995 * @param state State tree.
21996 *
21997 * @return Whether there is a previous edit or not.
21998 */
21999 function hasUndo(state) {
22000 return state.undoManager.hasUndo();
22001 }
22002
22003 /**
22004 * Returns true if there is a next edit from the current undo offset
22005 * for the entity records edits history, and false otherwise.
22006 *
22007 * @param state State tree.
22008 *
22009 * @return Whether there is a next edit or not.
22010 */
22011 function hasRedo(state) {
22012 return state.undoManager.hasRedo();
22013 }
22014
22015 /**
22016 * Return the current theme.
22017 *
22018 * @param state Data state.
22019 *
22020 * @return The current theme.
22021 */
22022 function getCurrentTheme(state) {
22023 if (!state.currentTheme) {
22024 return null;
22025 }
22026 return getEntityRecord(state, 'root', 'theme', state.currentTheme);
22027 }
22028
22029 /**
22030 * Return the ID of the current global styles object.
22031 *
22032 * @param state Data state.
22033 *
22034 * @return The current global styles ID.
22035 */
22036 function __experimentalGetCurrentGlobalStylesId(state) {
22037 return state.currentGlobalStylesId;
22038 }
22039
22040 /**
22041 * Return theme supports data in the index.
22042 *
22043 * @param state Data state.
22044 *
22045 * @return Index data.
22046 */
22047 function getThemeSupports(state) {
22048 var _getCurrentTheme$them;
22049 return (_getCurrentTheme$them = getCurrentTheme(state)?.theme_supports) !== null && _getCurrentTheme$them !== void 0 ? _getCurrentTheme$them : EMPTY_OBJECT;
22050 }
22051
22052 /**
22053 * Returns the embed preview for the given URL.
22054 *
22055 * @param state Data state.
22056 * @param url Embedded URL.
22057 *
22058 * @return Undefined if the preview has not been fetched, otherwise, the preview fetched from the embed preview API.
22059 */
22060 function getEmbedPreview(state, url) {
22061 return state.embedPreviews[url];
22062 }
22063
22064 /**
22065 * Determines if the returned preview is an oEmbed link fallback.
22066 *
22067 * WordPress can be configured to return a simple link to a URL if it is not embeddable.
22068 * We need to be able to determine if a URL is embeddable or not, based on what we
22069 * get back from the oEmbed preview API.
22070 *
22071 * @param state Data state.
22072 * @param url Embedded URL.
22073 *
22074 * @return Is the preview for the URL an oEmbed link fallback.
22075 */
22076 function isPreviewEmbedFallback(state, url) {
22077 const preview = state.embedPreviews[url];
22078 const oEmbedLinkCheck = '<a href="' + url + '">' + url + '</a>';
22079 if (!preview) {
22080 return false;
22081 }
22082 return preview.html === oEmbedLinkCheck;
22083 }
22084
22085 /**
22086 * Returns whether the current user can perform the given action on the given
22087 * REST resource.
22088 *
22089 * Calling this may trigger an OPTIONS request to the REST API via the
22090 * `canUser()` resolver.
22091 *
22092 * https://developer.wordpress.org/rest-api/reference/
22093 *
22094 * @param state Data state.
22095 * @param action Action to check. One of: 'create', 'read', 'update', 'delete'.
22096 * @param resource REST resource to check, e.g. 'media' or 'posts'.
22097 * @param id Optional ID of the rest resource to check.
22098 *
22099 * @return Whether or not the user can perform the action,
22100 * or `undefined` if the OPTIONS request is still being made.
22101 */
22102 function canUser(state, action, resource, id) {
22103 const key = [action, resource, id].filter(Boolean).join('/');
22104 return state.userPermissions[key];
22105 }
22106
22107 /**
22108 * Returns whether the current user can edit the given entity.
22109 *
22110 * Calling this may trigger an OPTIONS request to the REST API via the
22111 * `canUser()` resolver.
22112 *
22113 * https://developer.wordpress.org/rest-api/reference/
22114 *
22115 * @param state Data state.
22116 * @param kind Entity kind.
22117 * @param name Entity name.
22118 * @param recordId Record's id.
22119 * @return Whether or not the user can edit,
22120 * or `undefined` if the OPTIONS request is still being made.
22121 */
22122 function canUserEditEntityRecord(state, kind, name, recordId) {
22123 const entityConfig = getEntityConfig(state, kind, name);
22124 if (!entityConfig) {
22125 return false;
22126 }
22127 const resource = entityConfig.__unstable_rest_base;
22128 return canUser(state, 'update', resource, recordId);
22129 }
22130
22131 /**
22132 * Returns the latest autosaves for the post.
22133 *
22134 * May return multiple autosaves since the backend stores one autosave per
22135 * author for each post.
22136 *
22137 * @param state State tree.
22138 * @param postType The type of the parent post.
22139 * @param postId The id of the parent post.
22140 *
22141 * @return An array of autosaves for the post, or undefined if there is none.
22142 */
22143 function getAutosaves(state, postType, postId) {
22144 return state.autosaves[postId];
22145 }
22146
22147 /**
22148 * Returns the autosave for the post and author.
22149 *
22150 * @param state State tree.
22151 * @param postType The type of the parent post.
22152 * @param postId The id of the parent post.
22153 * @param authorId The id of the author.
22154 *
22155 * @return The autosave for the post and author.
22156 */
22157 function getAutosave(state, postType, postId, authorId) {
22158 if (authorId === undefined) {
22159 return;
22160 }
22161 const autosaves = state.autosaves[postId];
22162 return autosaves?.find(autosave => autosave.author === authorId);
22163 }
22164
22165 /**
22166 * Returns true if the REST request for autosaves has completed.
22167 *
22168 * @param state State tree.
22169 * @param postType The type of the parent post.
22170 * @param postId The id of the parent post.
22171 *
22172 * @return True if the REST request was completed. False otherwise.
22173 */
22174 const hasFetchedAutosaves = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, postType, postId) => {
22175 return select(STORE_NAME).hasFinishedResolution('getAutosaves', [postType, postId]);
22176 });
22177
22178 /**
22179 * Returns a new reference when edited values have changed. This is useful in
22180 * inferring where an edit has been made between states by comparison of the
22181 * return values using strict equality.
22182 *
22183 * @example
22184 *
22185 * ```
22186 * const hasEditOccurred = (
22187 * getReferenceByDistinctEdits( beforeState ) !==
22188 * getReferenceByDistinctEdits( afterState )
22189 * );
22190 * ```
22191 *
22192 * @param state Editor state.
22193 *
22194 * @return A value whose reference will change only when an edit occurs.
22195 */
22196 function getReferenceByDistinctEdits(state) {
22197 return state.editsReference;
22198 }
22199
22200 /**
22201 * Retrieve the frontend template used for a given link.
22202 *
22203 * @param state Editor state.
22204 * @param link Link.
22205 *
22206 * @return The template record.
22207 */
22208 function __experimentalGetTemplateForLink(state, link) {
22209 const records = getEntityRecords(state, 'postType', 'wp_template', {
22210 'find-template': link
22211 });
22212 if (records?.length) {
22213 return getEditedEntityRecord(state, 'postType', 'wp_template', records[0].id);
22214 }
22215 return null;
22216 }
22217
22218 /**
22219 * Retrieve the current theme's base global styles
22220 *
22221 * @param state Editor state.
22222 *
22223 * @return The Global Styles object.
22224 */
22225 function __experimentalGetCurrentThemeBaseGlobalStyles(state) {
22226 const currentTheme = getCurrentTheme(state);
22227 if (!currentTheme) {
22228 return null;
22229 }
22230 return state.themeBaseGlobalStyles[currentTheme.stylesheet];
22231 }
22232
22233 /**
22234 * Return the ID of the current global styles object.
22235 *
22236 * @param state Data state.
22237 *
22238 * @return The current global styles ID.
22239 */
22240 function __experimentalGetCurrentThemeGlobalStylesVariations(state) {
22241 const currentTheme = getCurrentTheme(state);
22242 if (!currentTheme) {
22243 return null;
22244 }
22245 return state.themeGlobalStyleVariations[currentTheme.stylesheet];
22246 }
22247
22248 /**
22249 * Retrieve the list of registered block patterns.
22250 *
22251 * @param state Data state.
22252 *
22253 * @return Block pattern list.
22254 */
22255 function getBlockPatterns(state) {
22256 return state.blockPatterns;
22257 }
22258
22259 /**
22260 * Retrieve the list of registered block pattern categories.
22261 *
22262 * @param state Data state.
22263 *
22264 * @return Block pattern category list.
22265 */
22266 function getBlockPatternCategories(state) {
22267 return state.blockPatternCategories;
22268 }
22269
22270 /**
22271 * Retrieve the registered user pattern categories.
22272 *
22273 * @param state Data state.
22274 *
22275 * @return User patterns category array.
22276 */
22277
22278 function getUserPatternCategories(state) {
22279 return state.userPatternCategories;
22280 }
22281
22282 /**
22283 * Returns the revisions of the current global styles theme.
22284 *
22285 * @deprecated since WordPress 6.5.0. Callers should use `select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )` instead, where `recordKey` is the id of the global styles parent post.
22286 *
22287 * @param state Data state.
22288 *
22289 * @return The current global styles.
22290 */
22291 function getCurrentThemeGlobalStylesRevisions(state) {
22292 external_wp_deprecated_default()("select( 'core' ).getCurrentThemeGlobalStylesRevisions()", {
22293 since: '6.5.0',
22294 alternative: "select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )"
22295 });
22296 const currentGlobalStylesId = __experimentalGetCurrentGlobalStylesId(state);
22297 if (!currentGlobalStylesId) {
22298 return null;
22299 }
22300 return state.themeGlobalStyleRevisions[currentGlobalStylesId];
22301 }
22302
22303 /**
22304 * Returns the default template use to render a given query.
22305 *
22306 * @param state Data state.
22307 * @param query Query.
22308 *
22309 * @return The default template id for the given query.
22310 */
22311 function getDefaultTemplateId(state, query) {
22312 return state.defaultTemplates[JSON.stringify(query)];
22313 }
22314
22315 /**
22316 * Returns an entity's revisions.
22317 *
22318 * @param state State tree
22319 * @param kind Entity kind.
22320 * @param name Entity name.
22321 * @param recordKey The key of the entity record whose revisions you want to fetch.
22322 * @param query Optional query. If requesting specific
22323 * fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [Entity kind]".
22324 *
22325 * @return Record.
22326 */
22327 const getRevisions = (state, kind, name, recordKey, query) => {
22328 const queriedStateRevisions = state.entities.records?.[kind]?.[name]?.revisions?.[recordKey];
22329 if (!queriedStateRevisions) {
22330 return null;
22331 }
22332 return getQueriedItems(queriedStateRevisions, query);
22333 };
22334
22335 /**
22336 * Returns a single, specific revision of a parent entity.
22337 *
22338 * @param state State tree
22339 * @param kind Entity kind.
22340 * @param name Entity name.
22341 * @param recordKey The key of the entity record whose revisions you want to fetch.
22342 * @param revisionKey The revision's key.
22343 * @param query Optional query. If requesting specific
22344 * fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [entity kind]".
22345 *
22346 * @return Record.
22347 */
22348 const getRevision = rememo((state, kind, name, recordKey, revisionKey, query) => {
22349 var _query$context5;
22350 const queriedState = state.entities.records?.[kind]?.[name]?.revisions?.[recordKey];
22351 if (!queriedState) {
22352 return undefined;
22353 }
22354 const context = (_query$context5 = query?.context) !== null && _query$context5 !== void 0 ? _query$context5 : 'default';
22355 if (query === undefined) {
22356 // If expecting a complete item, validate that completeness.
22357 if (!queriedState.itemIsComplete[context]?.[revisionKey]) {
22358 return undefined;
22359 }
22360 return queriedState.items[context][revisionKey];
22361 }
22362 const item = queriedState.items[context]?.[revisionKey];
22363 if (item && query._fields) {
22364 var _getNormalizedCommaSe2;
22365 const filteredItem = {};
22366 const fields = (_getNormalizedCommaSe2 = get_normalized_comma_separable(query._fields)) !== null && _getNormalizedCommaSe2 !== void 0 ? _getNormalizedCommaSe2 : [];
22367 for (let f = 0; f < fields.length; f++) {
22368 const field = fields[f].split('.');
22369 let value = item;
22370 field.forEach(fieldName => {
22371 value = value?.[fieldName];
22372 });
22373 setNestedValue(filteredItem, field, value);
22374 }
22375 return filteredItem;
22376 }
22377 return item;
22378 }, (state, kind, name, recordKey, revisionKey, query) => {
22379 var _query$context6;
22380 const context = (_query$context6 = query?.context) !== null && _query$context6 !== void 0 ? _query$context6 : 'default';
22381 return [state.entities.records?.[kind]?.[name]?.revisions?.[recordKey]?.items?.[context]?.[revisionKey], state.entities.records?.[kind]?.[name]?.revisions?.[recordKey]?.itemIsComplete?.[context]?.[revisionKey]];
22382 });
22383
22384 ;// CONCATENATED MODULE: ./packages/core-data/build-module/private-selectors.js
22385 /**
22386 * Internal dependencies
22387 */
22388
22389 /**
22390 * Returns the previous edit from the current undo offset
22391 * for the entity records edits history, if any.
22392 *
22393 * @param state State tree.
22394 *
22395 * @return The undo manager.
22396 */
22397 function getUndoManager(state) {
22398 return state.undoManager;
22399 }
22400
22401 /**
22402 * Retrieve the fallback Navigation.
22403 *
22404 * @param state Data state.
22405 * @return The ID for the fallback Navigation post.
22406 */
22407 function getNavigationFallbackId(state) {
22408 return state.navigationFallbackId;
22409 }
22410
22411 ;// CONCATENATED MODULE: ./node_modules/camel-case/dist.es2015/index.js
22412
22413
22414 function camelCaseTransform(input, index) {
22415 if (index === 0)
22416 return input.toLowerCase();
22417 return pascalCaseTransform(input, index);
22418 }
22419 function camelCaseTransformMerge(input, index) {
22420 if (index === 0)
22421 return input.toLowerCase();
22422 return pascalCaseTransformMerge(input);
22423 }
22424 function camelCase(input, options) {
22425 if (options === void 0) { options = {}; }
22426 return pascalCase(input, __assign({ transform: camelCaseTransform }, options));
22427 }
22428
22429 ;// CONCATENATED MODULE: external ["wp","htmlEntities"]
22430 var external_wp_htmlEntities_namespaceObject = window["wp"]["htmlEntities"];
22431 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/forward-resolver.js
22432 /**
22433 * Higher-order function which forward the resolution to another resolver with the same arguments.
22434 *
22435 * @param {string} resolverName forwarded resolver.
22436 *
22437 * @return {Function} Enhanced resolver.
22438 */
22439 const forwardResolver = resolverName => (...args) => async ({
22440 resolveSelect
22441 }) => {
22442 await resolveSelect[resolverName](...args);
22443 };
22444 /* harmony default export */ var forward_resolver = (forwardResolver);
22445
22446 ;// CONCATENATED MODULE: ./packages/core-data/build-module/resolvers.js
22447 /**
22448 * External dependencies
22449 */
22450
22451
22452 /**
22453 * WordPress dependencies
22454 */
22455
22456
22457
22458
22459 /**
22460 * Internal dependencies
22461 */
22462
22463
22464
22465
22466
22467 /**
22468 * Requests authors from the REST API.
22469 *
22470 * @param {Object|undefined} query Optional object of query parameters to
22471 * include with request.
22472 */
22473 const resolvers_getAuthors = query => async ({
22474 dispatch
22475 }) => {
22476 const path = (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/users/?who=authors&per_page=100', query);
22477 const users = await external_wp_apiFetch_default()({
22478 path
22479 });
22480 dispatch.receiveUserQuery(path, users);
22481 };
22482
22483 /**
22484 * Requests the current user from the REST API.
22485 */
22486 const resolvers_getCurrentUser = () => async ({
22487 dispatch
22488 }) => {
22489 const currentUser = await external_wp_apiFetch_default()({
22490 path: '/wp/v2/users/me'
22491 });
22492 dispatch.receiveCurrentUser(currentUser);
22493 };
22494
22495 /**
22496 * Requests an entity's record from the REST API.
22497 *
22498 * @param {string} kind Entity kind.
22499 * @param {string} name Entity name.
22500 * @param {number|string} key Record's key
22501 * @param {Object|undefined} query Optional object of query parameters to
22502 * include with request. If requesting specific
22503 * fields, fields must always include the ID.
22504 */
22505 const resolvers_getEntityRecord = (kind, name, key = '', query) => async ({
22506 select,
22507 dispatch
22508 }) => {
22509 const configs = await dispatch(getOrLoadEntitiesConfig(kind));
22510 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
22511 if (!entityConfig || entityConfig?.__experimentalNoFetch) {
22512 return;
22513 }
22514 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, key], {
22515 exclusive: false
22516 });
22517 try {
22518 // Entity supports configs,
22519 // use the sync algorithm instead of the old fetch behavior.
22520 if (window.__experimentalEnableSync && entityConfig.syncConfig && !query) {
22521 if (true) {
22522 const objectId = entityConfig.getSyncObjectId(key);
22523
22524 // Loads the persisted document.
22525 await getSyncProvider().bootstrap(entityConfig.syncObjectType, objectId, record => {
22526 dispatch.receiveEntityRecords(kind, name, record, query);
22527 });
22528
22529 // Boostraps the edited document as well (and load from peers).
22530 await getSyncProvider().bootstrap(entityConfig.syncObjectType + '--edit', objectId, record => {
22531 dispatch({
22532 type: 'EDIT_ENTITY_RECORD',
22533 kind,
22534 name,
22535 recordId: key,
22536 edits: record,
22537 meta: {
22538 undo: undefined
22539 }
22540 });
22541 });
22542 }
22543 } else {
22544 if (query !== undefined && query._fields) {
22545 // If requesting specific fields, items and query association to said
22546 // records are stored by ID reference. Thus, fields must always include
22547 // the ID.
22548 query = {
22549 ...query,
22550 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.key || DEFAULT_ENTITY_KEY])].join()
22551 };
22552 }
22553
22554 // Disable reason: While true that an early return could leave `path`
22555 // unused, it's important that path is derived using the query prior to
22556 // additional query modifications in the condition below, since those
22557 // modifications are relevant to how the data is tracked in state, and not
22558 // for how the request is made to the REST API.
22559
22560 // eslint-disable-next-line @wordpress/no-unused-vars-before-return
22561 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.baseURL + (key ? '/' + key : ''), {
22562 ...entityConfig.baseURLParams,
22563 ...query
22564 });
22565 if (query !== undefined) {
22566 query = {
22567 ...query,
22568 include: [key]
22569 };
22570
22571 // The resolution cache won't consider query as reusable based on the
22572 // fields, so it's tested here, prior to initiating the REST request,
22573 // and without causing `getEntityRecords` resolution to occur.
22574 const hasRecords = select.hasEntityRecords(kind, name, query);
22575 if (hasRecords) {
22576 return;
22577 }
22578 }
22579 const record = await external_wp_apiFetch_default()({
22580 path
22581 });
22582 dispatch.receiveEntityRecords(kind, name, record, query);
22583 }
22584 } finally {
22585 dispatch.__unstableReleaseStoreLock(lock);
22586 }
22587 };
22588
22589 /**
22590 * Requests an entity's record from the REST API.
22591 */
22592 const resolvers_getRawEntityRecord = forward_resolver('getEntityRecord');
22593
22594 /**
22595 * Requests an entity's record from the REST API.
22596 */
22597 const resolvers_getEditedEntityRecord = forward_resolver('getEntityRecord');
22598
22599 /**
22600 * Requests the entity's records from the REST API.
22601 *
22602 * @param {string} kind Entity kind.
22603 * @param {string} name Entity name.
22604 * @param {Object?} query Query Object. If requesting specific fields, fields
22605 * must always include the ID.
22606 */
22607 const resolvers_getEntityRecords = (kind, name, query = {}) => async ({
22608 dispatch
22609 }) => {
22610 const configs = await dispatch(getOrLoadEntitiesConfig(kind));
22611 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
22612 if (!entityConfig || entityConfig?.__experimentalNoFetch) {
22613 return;
22614 }
22615 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name], {
22616 exclusive: false
22617 });
22618 try {
22619 if (query._fields) {
22620 // If requesting specific fields, items and query association to said
22621 // records are stored by ID reference. Thus, fields must always include
22622 // the ID.
22623 query = {
22624 ...query,
22625 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.key || DEFAULT_ENTITY_KEY])].join()
22626 };
22627 }
22628 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.baseURL, {
22629 ...entityConfig.baseURLParams,
22630 ...query
22631 });
22632 let records, meta;
22633 if (entityConfig.supportsPagination && query.per_page !== -1) {
22634 const response = await external_wp_apiFetch_default()({
22635 path,
22636 parse: false
22637 });
22638 records = Object.values(await response.json());
22639 meta = {
22640 totalItems: parseInt(response.headers.get('X-WP-Total'))
22641 };
22642 } else {
22643 records = Object.values(await external_wp_apiFetch_default()({
22644 path
22645 }));
22646 }
22647
22648 // If we request fields but the result doesn't contain the fields,
22649 // explicitly set these fields as "undefined"
22650 // that way we consider the query "fulfilled".
22651 if (query._fields) {
22652 records = records.map(record => {
22653 query._fields.split(',').forEach(field => {
22654 if (!record.hasOwnProperty(field)) {
22655 record[field] = undefined;
22656 }
22657 });
22658 return record;
22659 });
22660 }
22661 dispatch.receiveEntityRecords(kind, name, records, query, false, undefined, meta);
22662
22663 // When requesting all fields, the list of results can be used to
22664 // resolve the `getEntityRecord` selector in addition to `getEntityRecords`.
22665 // See https://github.com/WordPress/gutenberg/pull/26575
22666 if (!query?._fields && !query.context) {
22667 const key = entityConfig.key || DEFAULT_ENTITY_KEY;
22668 const resolutionsArgs = records.filter(record => record[key]).map(record => [kind, name, record[key]]);
22669 dispatch({
22670 type: 'START_RESOLUTIONS',
22671 selectorName: 'getEntityRecord',
22672 args: resolutionsArgs
22673 });
22674 dispatch({
22675 type: 'FINISH_RESOLUTIONS',
22676 selectorName: 'getEntityRecord',
22677 args: resolutionsArgs
22678 });
22679 }
22680 } finally {
22681 dispatch.__unstableReleaseStoreLock(lock);
22682 }
22683 };
22684 resolvers_getEntityRecords.shouldInvalidate = (action, kind, name) => {
22685 return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && kind === action.kind && name === action.name;
22686 };
22687
22688 /**
22689 * Requests the current theme.
22690 */
22691 const resolvers_getCurrentTheme = () => async ({
22692 dispatch,
22693 resolveSelect
22694 }) => {
22695 const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', {
22696 status: 'active'
22697 });
22698 dispatch.receiveCurrentTheme(activeThemes[0]);
22699 };
22700
22701 /**
22702 * Requests theme supports data from the index.
22703 */
22704 const resolvers_getThemeSupports = forward_resolver('getCurrentTheme');
22705
22706 /**
22707 * Requests a preview from the Embed API.
22708 *
22709 * @param {string} url URL to get the preview for.
22710 */
22711 const resolvers_getEmbedPreview = url => async ({
22712 dispatch
22713 }) => {
22714 try {
22715 const embedProxyResponse = await external_wp_apiFetch_default()({
22716 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/oembed/1.0/proxy', {
22717 url
22718 })
22719 });
22720 dispatch.receiveEmbedPreview(url, embedProxyResponse);
22721 } catch (error) {
22722 // Embed API 404s if the URL cannot be embedded, so we have to catch the error from the apiRequest here.
22723 dispatch.receiveEmbedPreview(url, false);
22724 }
22725 };
22726
22727 /**
22728 * Checks whether the current user can perform the given action on the given
22729 * REST resource.
22730 *
22731 * @param {string} requestedAction Action to check. One of: 'create', 'read', 'update',
22732 * 'delete'.
22733 * @param {string} resource REST resource to check, e.g. 'media' or 'posts'.
22734 * @param {?string} id ID of the rest resource to check.
22735 */
22736 const resolvers_canUser = (requestedAction, resource, id) => async ({
22737 dispatch,
22738 registry
22739 }) => {
22740 const {
22741 hasStartedResolution
22742 } = registry.select(STORE_NAME);
22743 const resourcePath = id ? `${resource}/${id}` : resource;
22744 const retrievedActions = ['create', 'read', 'update', 'delete'];
22745 if (!retrievedActions.includes(requestedAction)) {
22746 throw new Error(`'${requestedAction}' is not a valid action.`);
22747 }
22748
22749 // Prevent resolving the same resource twice.
22750 for (const relatedAction of retrievedActions) {
22751 if (relatedAction === requestedAction) {
22752 continue;
22753 }
22754 const isAlreadyResolving = hasStartedResolution('canUser', [relatedAction, resource, id]);
22755 if (isAlreadyResolving) {
22756 return;
22757 }
22758 }
22759 let response;
22760 try {
22761 response = await external_wp_apiFetch_default()({
22762 path: `/wp/v2/${resourcePath}`,
22763 method: 'OPTIONS',
22764 parse: false
22765 });
22766 } catch (error) {
22767 // Do nothing if our OPTIONS request comes back with an API error (4xx or
22768 // 5xx). The previously determined isAllowed value will remain in the store.
22769 return;
22770 }
22771
22772 // Optional chaining operator is used here because the API requests don't
22773 // return the expected result in the native version. Instead, API requests
22774 // only return the result, without including response properties like the headers.
22775 const allowHeader = response.headers?.get('allow');
22776 const allowedMethods = allowHeader?.allow || allowHeader || '';
22777 const permissions = {};
22778 const methods = {
22779 create: 'POST',
22780 read: 'GET',
22781 update: 'PUT',
22782 delete: 'DELETE'
22783 };
22784 for (const [actionName, methodName] of Object.entries(methods)) {
22785 permissions[actionName] = allowedMethods.includes(methodName);
22786 }
22787 for (const action of retrievedActions) {
22788 dispatch.receiveUserPermission(`${action}/${resourcePath}`, permissions[action]);
22789 }
22790 };
22791
22792 /**
22793 * Checks whether the current user can perform the given action on the given
22794 * REST resource.
22795 *
22796 * @param {string} kind Entity kind.
22797 * @param {string} name Entity name.
22798 * @param {string} recordId Record's id.
22799 */
22800 const resolvers_canUserEditEntityRecord = (kind, name, recordId) => async ({
22801 dispatch
22802 }) => {
22803 const configs = await dispatch(getOrLoadEntitiesConfig(kind));
22804 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
22805 if (!entityConfig) {
22806 return;
22807 }
22808 const resource = entityConfig.__unstable_rest_base;
22809 await dispatch(resolvers_canUser('update', resource, recordId));
22810 };
22811
22812 /**
22813 * Request autosave data from the REST API.
22814 *
22815 * @param {string} postType The type of the parent post.
22816 * @param {number} postId The id of the parent post.
22817 */
22818 const resolvers_getAutosaves = (postType, postId) => async ({
22819 dispatch,
22820 resolveSelect
22821 }) => {
22822 const {
22823 rest_base: restBase,
22824 rest_namespace: restNamespace = 'wp/v2'
22825 } = await resolveSelect.getPostType(postType);
22826 const autosaves = await external_wp_apiFetch_default()({
22827 path: `/${restNamespace}/${restBase}/${postId}/autosaves?context=edit`
22828 });
22829 if (autosaves && autosaves.length) {
22830 dispatch.receiveAutosaves(postId, autosaves);
22831 }
22832 };
22833
22834 /**
22835 * Request autosave data from the REST API.
22836 *
22837 * This resolver exists to ensure the underlying autosaves are fetched via
22838 * `getAutosaves` when a call to the `getAutosave` selector is made.
22839 *
22840 * @param {string} postType The type of the parent post.
22841 * @param {number} postId The id of the parent post.
22842 */
22843 const resolvers_getAutosave = (postType, postId) => async ({
22844 resolveSelect
22845 }) => {
22846 await resolveSelect.getAutosaves(postType, postId);
22847 };
22848
22849 /**
22850 * Retrieve the frontend template used for a given link.
22851 *
22852 * @param {string} link Link.
22853 */
22854 const resolvers_experimentalGetTemplateForLink = link => async ({
22855 dispatch,
22856 resolveSelect
22857 }) => {
22858 let template;
22859 try {
22860 // This is NOT calling a REST endpoint but rather ends up with a response from
22861 // an Ajax function which has a different shape from a WP_REST_Response.
22862 template = await external_wp_apiFetch_default()({
22863 url: (0,external_wp_url_namespaceObject.addQueryArgs)(link, {
22864 '_wp-find-template': true
22865 })
22866 }).then(({
22867 data
22868 }) => data);
22869 } catch (e) {
22870 // For non-FSE themes, it is possible that this request returns an error.
22871 }
22872 if (!template) {
22873 return;
22874 }
22875 const record = await resolveSelect.getEntityRecord('postType', 'wp_template', template.id);
22876 if (record) {
22877 dispatch.receiveEntityRecords('postType', 'wp_template', [record], {
22878 'find-template': link
22879 });
22880 }
22881 };
22882 resolvers_experimentalGetTemplateForLink.shouldInvalidate = action => {
22883 return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && action.kind === 'postType' && action.name === 'wp_template';
22884 };
22885 const resolvers_experimentalGetCurrentGlobalStylesId = () => async ({
22886 dispatch,
22887 resolveSelect
22888 }) => {
22889 const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', {
22890 status: 'active'
22891 });
22892 const globalStylesURL = activeThemes?.[0]?._links?.['wp:user-global-styles']?.[0]?.href;
22893 if (globalStylesURL) {
22894 const globalStylesObject = await external_wp_apiFetch_default()({
22895 url: globalStylesURL
22896 });
22897 dispatch.__experimentalReceiveCurrentGlobalStylesId(globalStylesObject.id);
22898 }
22899 };
22900 const resolvers_experimentalGetCurrentThemeBaseGlobalStyles = () => async ({
22901 resolveSelect,
22902 dispatch
22903 }) => {
22904 const currentTheme = await resolveSelect.getCurrentTheme();
22905 const themeGlobalStyles = await external_wp_apiFetch_default()({
22906 path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}`
22907 });
22908 dispatch.__experimentalReceiveThemeBaseGlobalStyles(currentTheme.stylesheet, themeGlobalStyles);
22909 };
22910 const resolvers_experimentalGetCurrentThemeGlobalStylesVariations = () => async ({
22911 resolveSelect,
22912 dispatch
22913 }) => {
22914 const currentTheme = await resolveSelect.getCurrentTheme();
22915 const variations = await external_wp_apiFetch_default()({
22916 path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}/variations`
22917 });
22918 dispatch.__experimentalReceiveThemeGlobalStyleVariations(currentTheme.stylesheet, variations);
22919 };
22920
22921 /**
22922 * Fetches and returns the revisions of the current global styles theme.
22923 */
22924 const resolvers_getCurrentThemeGlobalStylesRevisions = () => async ({
22925 resolveSelect,
22926 dispatch
22927 }) => {
22928 const globalStylesId = await resolveSelect.__experimentalGetCurrentGlobalStylesId();
22929 const record = globalStylesId ? await resolveSelect.getEntityRecord('root', 'globalStyles', globalStylesId) : undefined;
22930 const revisionsURL = record?._links?.['version-history']?.[0]?.href;
22931 if (revisionsURL) {
22932 const resetRevisions = await external_wp_apiFetch_default()({
22933 url: revisionsURL
22934 });
22935 const revisions = resetRevisions?.map(revision => Object.fromEntries(Object.entries(revision).map(([key, value]) => [camelCase(key), value])));
22936 dispatch.receiveThemeGlobalStyleRevisions(globalStylesId, revisions);
22937 }
22938 };
22939 resolvers_getCurrentThemeGlobalStylesRevisions.shouldInvalidate = action => {
22940 return action.type === 'SAVE_ENTITY_RECORD_FINISH' && action.kind === 'root' && !action.error && action.name === 'globalStyles';
22941 };
22942 const resolvers_getBlockPatterns = () => async ({
22943 dispatch
22944 }) => {
22945 const restPatterns = await external_wp_apiFetch_default()({
22946 path: '/wp/v2/block-patterns/patterns'
22947 });
22948 const patterns = restPatterns?.map(pattern => Object.fromEntries(Object.entries(pattern).map(([key, value]) => [camelCase(key), value])));
22949 dispatch({
22950 type: 'RECEIVE_BLOCK_PATTERNS',
22951 patterns
22952 });
22953 };
22954 const resolvers_getBlockPatternCategories = () => async ({
22955 dispatch
22956 }) => {
22957 const categories = await external_wp_apiFetch_default()({
22958 path: '/wp/v2/block-patterns/categories'
22959 });
22960 dispatch({
22961 type: 'RECEIVE_BLOCK_PATTERN_CATEGORIES',
22962 categories
22963 });
22964 };
22965 const resolvers_getUserPatternCategories = () => async ({
22966 dispatch,
22967 resolveSelect
22968 }) => {
22969 const patternCategories = await resolveSelect.getEntityRecords('taxonomy', 'wp_pattern_category', {
22970 per_page: -1,
22971 _fields: 'id,name,description,slug',
22972 context: 'view'
22973 });
22974 const mappedPatternCategories = patternCategories?.map(userCategory => ({
22975 ...userCategory,
22976 label: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(userCategory.name),
22977 name: userCategory.slug
22978 })) || [];
22979 dispatch({
22980 type: 'RECEIVE_USER_PATTERN_CATEGORIES',
22981 patternCategories: mappedPatternCategories
22982 });
22983 };
22984 const resolvers_getNavigationFallbackId = () => async ({
22985 dispatch,
22986 select
22987 }) => {
22988 const fallback = await external_wp_apiFetch_default()({
22989 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp-block-editor/v1/navigation-fallback', {
22990 _embed: true
22991 })
22992 });
22993 const record = fallback?._embedded?.self;
22994 dispatch.receiveNavigationFallbackId(fallback?.id);
22995 if (record) {
22996 // If the fallback is already in the store, don't invalidate navigation queries.
22997 // Otherwise, invalidate the cache for the scenario where there were no Navigation
22998 // posts in the state and the fallback created one.
22999 const existingFallbackEntityRecord = select.getEntityRecord('postType', 'wp_navigation', fallback?.id);
23000 const invalidateNavigationQueries = !existingFallbackEntityRecord;
23001 dispatch.receiveEntityRecords('postType', 'wp_navigation', record, undefined, invalidateNavigationQueries);
23002
23003 // Resolve to avoid further network requests.
23004 dispatch.finishResolution('getEntityRecord', ['postType', 'wp_navigation', fallback?.id]);
23005 }
23006 };
23007 const resolvers_getDefaultTemplateId = query => async ({
23008 dispatch
23009 }) => {
23010 const template = await external_wp_apiFetch_default()({
23011 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/templates/lookup', query)
23012 });
23013 if (template) {
23014 dispatch.receiveDefaultTemplateId(query, template.id);
23015 }
23016 };
23017
23018 /**
23019 * Requests an entity's revisions from the REST API.
23020 *
23021 * @param {string} kind Entity kind.
23022 * @param {string} name Entity name.
23023 * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
23024 * @param {Object|undefined} query Optional object of query parameters to
23025 * include with request. If requesting specific
23026 * fields, fields must always include the ID.
23027 */
23028 const resolvers_getRevisions = (kind, name, recordKey, query = {}) => async ({
23029 dispatch
23030 }) => {
23031 const configs = await dispatch(getOrLoadEntitiesConfig(kind));
23032 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
23033 if (!entityConfig || entityConfig?.__experimentalNoFetch || !entityConfig?.supports?.revisions) {
23034 return;
23035 }
23036 if (query._fields) {
23037 // If requesting specific fields, items and query association to said
23038 // records are stored by ID reference. Thus, fields must always include
23039 // the ID.
23040 query = {
23041 ...query,
23042 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.revisionKey || DEFAULT_ENTITY_KEY])].join()
23043 };
23044 }
23045 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.getRevisionsUrl(recordKey), query);
23046 let records, meta;
23047 if (entityConfig.supportsPagination && query.per_page !== -1) {
23048 const response = await external_wp_apiFetch_default()({
23049 path,
23050 parse: false
23051 });
23052 records = Object.values(await response.json());
23053 meta = {
23054 totalItems: parseInt(response.headers.get('X-WP-Total'))
23055 };
23056 } else {
23057 records = Object.values(await external_wp_apiFetch_default()({
23058 path
23059 }));
23060 }
23061
23062 // If we request fields but the result doesn't contain the fields,
23063 // explicitly set these fields as "undefined"
23064 // that way we consider the query "fulfilled".
23065 if (query._fields) {
23066 records = records.map(record => {
23067 query._fields.split(',').forEach(field => {
23068 if (!record.hasOwnProperty(field)) {
23069 record[field] = undefined;
23070 }
23071 });
23072 return record;
23073 });
23074 }
23075 dispatch.receiveRevisions(kind, name, recordKey, records, query, false, meta);
23076
23077 // When requesting all fields, the list of results can be used to
23078 // resolve the `getRevision` selector in addition to `getRevisions`.
23079 if (!query?._fields && !query.context) {
23080 const key = entityConfig.key || DEFAULT_ENTITY_KEY;
23081 const resolutionsArgs = records.filter(record => record[key]).map(record => [kind, name, recordKey, record[key]]);
23082 dispatch({
23083 type: 'START_RESOLUTIONS',
23084 selectorName: 'getRevision',
23085 args: resolutionsArgs
23086 });
23087 dispatch({
23088 type: 'FINISH_RESOLUTIONS',
23089 selectorName: 'getRevision',
23090 args: resolutionsArgs
23091 });
23092 }
23093 };
23094
23095 // Invalidate cache when a new revision is created.
23096 resolvers_getRevisions.shouldInvalidate = (action, kind, name, recordKey) => action.type === 'SAVE_ENTITY_RECORD_FINISH' && name === action.name && kind === action.kind && !action.error && recordKey === action.recordId;
23097
23098 /**
23099 * Requests a specific Entity revision from the REST API.
23100 *
23101 * @param {string} kind Entity kind.
23102 * @param {string} name Entity name.
23103 * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
23104 * @param {number|string} revisionKey The revision's key.
23105 * @param {Object|undefined} query Optional object of query parameters to
23106 * include with request. If requesting specific
23107 * fields, fields must always include the ID.
23108 */
23109 const resolvers_getRevision = (kind, name, recordKey, revisionKey, query) => async ({
23110 dispatch
23111 }) => {
23112 const configs = await dispatch(getOrLoadEntitiesConfig(kind));
23113 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
23114 if (!entityConfig || entityConfig?.__experimentalNoFetch || !entityConfig?.supports?.revisions) {
23115 return;
23116 }
23117 if (query !== undefined && query._fields) {
23118 // If requesting specific fields, items and query association to said
23119 // records are stored by ID reference. Thus, fields must always include
23120 // the ID.
23121 query = {
23122 ...query,
23123 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.revisionKey || DEFAULT_ENTITY_KEY])].join()
23124 };
23125 }
23126 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.getRevisionsUrl(recordKey, revisionKey), query);
23127 const record = await external_wp_apiFetch_default()({
23128 path
23129 });
23130 dispatch.receiveRevisions(kind, name, recordKey, record, query);
23131 };
23132
23133 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/utils.js
23134 function deepCopyLocksTreePath(tree, path) {
23135 const newTree = {
23136 ...tree
23137 };
23138 let currentNode = newTree;
23139 for (const branchName of path) {
23140 currentNode.children = {
23141 ...currentNode.children,
23142 [branchName]: {
23143 locks: [],
23144 children: {},
23145 ...currentNode.children[branchName]
23146 }
23147 };
23148 currentNode = currentNode.children[branchName];
23149 }
23150 return newTree;
23151 }
23152 function getNode(tree, path) {
23153 let currentNode = tree;
23154 for (const branchName of path) {
23155 const nextNode = currentNode.children[branchName];
23156 if (!nextNode) {
23157 return null;
23158 }
23159 currentNode = nextNode;
23160 }
23161 return currentNode;
23162 }
23163 function* iteratePath(tree, path) {
23164 let currentNode = tree;
23165 yield currentNode;
23166 for (const branchName of path) {
23167 const nextNode = currentNode.children[branchName];
23168 if (!nextNode) {
23169 break;
23170 }
23171 yield nextNode;
23172 currentNode = nextNode;
23173 }
23174 }
23175 function* iterateDescendants(node) {
23176 const stack = Object.values(node.children);
23177 while (stack.length) {
23178 const childNode = stack.pop();
23179 yield childNode;
23180 stack.push(...Object.values(childNode.children));
23181 }
23182 }
23183 function hasConflictingLock({
23184 exclusive
23185 }, locks) {
23186 if (exclusive && locks.length) {
23187 return true;
23188 }
23189 if (!exclusive && locks.filter(lock => lock.exclusive).length) {
23190 return true;
23191 }
23192 return false;
23193 }
23194
23195 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/reducer.js
23196 /**
23197 * Internal dependencies
23198 */
23199
23200 const DEFAULT_STATE = {
23201 requests: [],
23202 tree: {
23203 locks: [],
23204 children: {}
23205 }
23206 };
23207
23208 /**
23209 * Reducer returning locks.
23210 *
23211 * @param {Object} state Current state.
23212 * @param {Object} action Dispatched action.
23213 *
23214 * @return {Object} Updated state.
23215 */
23216 function locks(state = DEFAULT_STATE, action) {
23217 switch (action.type) {
23218 case 'ENQUEUE_LOCK_REQUEST':
23219 {
23220 const {
23221 request
23222 } = action;
23223 return {
23224 ...state,
23225 requests: [request, ...state.requests]
23226 };
23227 }
23228 case 'GRANT_LOCK_REQUEST':
23229 {
23230 const {
23231 lock,
23232 request
23233 } = action;
23234 const {
23235 store,
23236 path
23237 } = request;
23238 const storePath = [store, ...path];
23239 const newTree = deepCopyLocksTreePath(state.tree, storePath);
23240 const node = getNode(newTree, storePath);
23241 node.locks = [...node.locks, lock];
23242 return {
23243 ...state,
23244 requests: state.requests.filter(r => r !== request),
23245 tree: newTree
23246 };
23247 }
23248 case 'RELEASE_LOCK':
23249 {
23250 const {
23251 lock
23252 } = action;
23253 const storePath = [lock.store, ...lock.path];
23254 const newTree = deepCopyLocksTreePath(state.tree, storePath);
23255 const node = getNode(newTree, storePath);
23256 node.locks = node.locks.filter(l => l !== lock);
23257 return {
23258 ...state,
23259 tree: newTree
23260 };
23261 }
23262 }
23263 return state;
23264 }
23265
23266 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/selectors.js
23267 /**
23268 * Internal dependencies
23269 */
23270
23271 function getPendingLockRequests(state) {
23272 return state.requests;
23273 }
23274 function isLockAvailable(state, store, path, {
23275 exclusive
23276 }) {
23277 const storePath = [store, ...path];
23278 const locks = state.tree;
23279
23280 // Validate all parents and the node itself
23281 for (const node of iteratePath(locks, storePath)) {
23282 if (hasConflictingLock({
23283 exclusive
23284 }, node.locks)) {
23285 return false;
23286 }
23287 }
23288
23289 // iteratePath terminates early if path is unreachable, let's
23290 // re-fetch the node and check it exists in the tree.
23291 const node = getNode(locks, storePath);
23292 if (!node) {
23293 return true;
23294 }
23295
23296 // Validate all nested nodes
23297 for (const descendant of iterateDescendants(node)) {
23298 if (hasConflictingLock({
23299 exclusive
23300 }, descendant.locks)) {
23301 return false;
23302 }
23303 }
23304 return true;
23305 }
23306
23307 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/engine.js
23308 /**
23309 * Internal dependencies
23310 */
23311
23312
23313 function createLocks() {
23314 let state = locks(undefined, {
23315 type: '@@INIT'
23316 });
23317 function processPendingLockRequests() {
23318 for (const request of getPendingLockRequests(state)) {
23319 const {
23320 store,
23321 path,
23322 exclusive,
23323 notifyAcquired
23324 } = request;
23325 if (isLockAvailable(state, store, path, {
23326 exclusive
23327 })) {
23328 const lock = {
23329 store,
23330 path,
23331 exclusive
23332 };
23333 state = locks(state, {
23334 type: 'GRANT_LOCK_REQUEST',
23335 lock,
23336 request
23337 });
23338 notifyAcquired(lock);
23339 }
23340 }
23341 }
23342 function acquire(store, path, exclusive) {
23343 return new Promise(resolve => {
23344 state = locks(state, {
23345 type: 'ENQUEUE_LOCK_REQUEST',
23346 request: {
23347 store,
23348 path,
23349 exclusive,
23350 notifyAcquired: resolve
23351 }
23352 });
23353 processPendingLockRequests();
23354 });
23355 }
23356 function release(lock) {
23357 state = locks(state, {
23358 type: 'RELEASE_LOCK',
23359 lock
23360 });
23361 processPendingLockRequests();
23362 }
23363 return {
23364 acquire,
23365 release
23366 };
23367 }
23368
23369 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/actions.js
23370 /**
23371 * Internal dependencies
23372 */
23373
23374 function createLocksActions() {
23375 const locks = createLocks();
23376 function __unstableAcquireStoreLock(store, path, {
23377 exclusive
23378 }) {
23379 return () => locks.acquire(store, path, exclusive);
23380 }
23381 function __unstableReleaseStoreLock(lock) {
23382 return () => locks.release(lock);
23383 }
23384 return {
23385 __unstableAcquireStoreLock,
23386 __unstableReleaseStoreLock
23387 };
23388 }
23389
23390 ;// CONCATENATED MODULE: external ["wp","privateApis"]
23391 var external_wp_privateApis_namespaceObject = window["wp"]["privateApis"];
23392 ;// CONCATENATED MODULE: ./packages/core-data/build-module/private-apis.js
23393 /**
23394 * WordPress dependencies
23395 */
23396
23397 const {
23398 lock,
23399 unlock
23400 } = (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');
23401
23402 ;// CONCATENATED MODULE: external "React"
23403 var external_React_namespaceObject = window["React"];
23404 ;// CONCATENATED MODULE: external ["wp","element"]
23405 var external_wp_element_namespaceObject = window["wp"]["element"];
23406 ;// CONCATENATED MODULE: external ["wp","blocks"]
23407 var external_wp_blocks_namespaceObject = window["wp"]["blocks"];
23408 ;// CONCATENATED MODULE: external ["wp","richText"]
23409 var external_wp_richText_namespaceObject = window["wp"]["richText"];
23410 ;// CONCATENATED MODULE: external ["wp","blockEditor"]
23411 var external_wp_blockEditor_namespaceObject = window["wp"]["blockEditor"];
23412 ;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/get-rich-text-values-cached.js
23413 /**
23414 * WordPress dependencies
23415 */
23416
23417
23418 /**
23419 * Internal dependencies
23420 */
23421
23422
23423 // TODO: The following line should have been:
23424 //
23425 // const unlockedApis = unlock( blockEditorPrivateApis );
23426 //
23427 // But there are hidden circular dependencies in RNMobile code, specifically in
23428 // certain native components in the `components` package that depend on
23429 // `block-editor`. What follows is a workaround that defers the `unlock` call
23430 // to prevent native code from failing.
23431 //
23432 // Fix once https://github.com/WordPress/gutenberg/issues/52692 is closed.
23433 let unlockedApis;
23434 const cache = new WeakMap();
23435 function getRichTextValuesCached(block) {
23436 if (!unlockedApis) {
23437 unlockedApis = unlock(external_wp_blockEditor_namespaceObject.privateApis);
23438 }
23439 if (!cache.has(block)) {
23440 const values = unlockedApis.getRichTextValues([block]);
23441 cache.set(block, values);
23442 }
23443 return cache.get(block);
23444 }
23445
23446 ;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/get-footnotes-order.js
23447 /**
23448 * WordPress dependencies
23449 */
23450
23451
23452 /**
23453 * Internal dependencies
23454 */
23455
23456 const get_footnotes_order_cache = new WeakMap();
23457 function getBlockFootnotesOrder(block) {
23458 if (!get_footnotes_order_cache.has(block)) {
23459 const order = [];
23460 for (const value of getRichTextValuesCached(block)) {
23461 if (!value || !value.includes('data-fn')) {
23462 continue;
23463 }
23464
23465 // replacements is a sparse array, use forEach to skip empty slots.
23466 (0,external_wp_richText_namespaceObject.create)({
23467 html: value
23468 }).replacements.forEach(({
23469 type,
23470 attributes
23471 }) => {
23472 if (type === 'core/footnote') {
23473 order.push(attributes['data-fn']);
23474 }
23475 });
23476 }
23477 get_footnotes_order_cache.set(block, order);
23478 }
23479 return get_footnotes_order_cache.get(block);
23480 }
23481 function getFootnotesOrder(blocks) {
23482 // We can only separate getting order from blocks at the root level. For
23483 // deeper inner blocks, this will not work since it's possible to have both
23484 // inner blocks and block attributes, so order needs to be computed from the
23485 // Edit functions as a whole.
23486 return blocks.flatMap(getBlockFootnotesOrder);
23487 }
23488
23489 ;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/index.js
23490 /**
23491 * WordPress dependencies
23492 */
23493
23494
23495 /**
23496 * Internal dependencies
23497 */
23498
23499 let oldFootnotes = {};
23500 function updateFootnotesFromMeta(blocks, meta) {
23501 const output = {
23502 blocks
23503 };
23504 if (!meta) return output;
23505
23506 // If meta.footnotes is empty, it means the meta is not registered.
23507 if (meta.footnotes === undefined) return output;
23508 const newOrder = getFootnotesOrder(blocks);
23509 const footnotes = meta.footnotes ? JSON.parse(meta.footnotes) : [];
23510 const currentOrder = footnotes.map(fn => fn.id);
23511 if (currentOrder.join('') === newOrder.join('')) return output;
23512 const newFootnotes = newOrder.map(fnId => footnotes.find(fn => fn.id === fnId) || oldFootnotes[fnId] || {
23513 id: fnId,
23514 content: ''
23515 });
23516 function updateAttributes(attributes) {
23517 // Only attempt to update attributes, if attributes is an object.
23518 if (!attributes || Array.isArray(attributes) || typeof attributes !== 'object') {
23519 return attributes;
23520 }
23521 attributes = {
23522 ...attributes
23523 };
23524 for (const key in attributes) {
23525 const value = attributes[key];
23526 if (Array.isArray(value)) {
23527 attributes[key] = value.map(updateAttributes);
23528 continue;
23529 }
23530 if (typeof value !== 'string') {
23531 continue;
23532 }
23533 if (value.indexOf('data-fn') === -1) {
23534 continue;
23535 }
23536 const richTextValue = (0,external_wp_richText_namespaceObject.create)({
23537 html: value
23538 });
23539 richTextValue.replacements.forEach(replacement => {
23540 if (replacement.type === 'core/footnote') {
23541 const id = replacement.attributes['data-fn'];
23542 const index = newOrder.indexOf(id);
23543 // The innerHTML contains the count wrapped in a link.
23544 const countValue = (0,external_wp_richText_namespaceObject.create)({
23545 html: replacement.innerHTML
23546 });
23547 countValue.text = String(index + 1);
23548 replacement.innerHTML = (0,external_wp_richText_namespaceObject.toHTMLString)({
23549 value: countValue
23550 });
23551 }
23552 });
23553 attributes[key] = (0,external_wp_richText_namespaceObject.toHTMLString)({
23554 value: richTextValue
23555 });
23556 }
23557 return attributes;
23558 }
23559 function updateBlocksAttributes(__blocks) {
23560 return __blocks.map(block => {
23561 return {
23562 ...block,
23563 attributes: updateAttributes(block.attributes),
23564 innerBlocks: updateBlocksAttributes(block.innerBlocks)
23565 };
23566 });
23567 }
23568
23569 // We need to go through all block attributes deeply and update the
23570 // footnote anchor numbering (textContent) to match the new order.
23571 const newBlocks = updateBlocksAttributes(blocks);
23572 oldFootnotes = {
23573 ...oldFootnotes,
23574 ...footnotes.reduce((acc, fn) => {
23575 if (!newOrder.includes(fn.id)) {
23576 acc[fn.id] = fn;
23577 }
23578 return acc;
23579 }, {})
23580 };
23581 return {
23582 meta: {
23583 ...meta,
23584 footnotes: JSON.stringify(newFootnotes)
23585 },
23586 blocks: newBlocks
23587 };
23588 }
23589
23590 ;// CONCATENATED MODULE: ./packages/core-data/build-module/entity-provider.js
23591
23592 /**
23593 * WordPress dependencies
23594 */
23595
23596
23597
23598
23599 /**
23600 * Internal dependencies
23601 */
23602
23603
23604
23605 /** @typedef {import('@wordpress/blocks').WPBlock} WPBlock */
23606
23607 const EMPTY_ARRAY = [];
23608
23609 /**
23610 * Internal dependencies
23611 */
23612
23613 const entityContexts = {
23614 ...rootEntitiesConfig.reduce((acc, loader) => {
23615 if (!acc[loader.kind]) {
23616 acc[loader.kind] = {};
23617 }
23618 acc[loader.kind][loader.name] = {
23619 context: (0,external_wp_element_namespaceObject.createContext)(undefined)
23620 };
23621 return acc;
23622 }, {}),
23623 ...additionalEntityConfigLoaders.reduce((acc, loader) => {
23624 acc[loader.kind] = {};
23625 return acc;
23626 }, {})
23627 };
23628 const getEntityContext = (kind, name) => {
23629 if (!entityContexts[kind]) {
23630 throw new Error(`Missing entity config for kind: ${kind}.`);
23631 }
23632 if (!entityContexts[kind][name]) {
23633 entityContexts[kind][name] = {
23634 context: (0,external_wp_element_namespaceObject.createContext)(undefined)
23635 };
23636 }
23637 return entityContexts[kind][name].context;
23638 };
23639
23640 /**
23641 * Context provider component for providing
23642 * an entity for a specific entity.
23643 *
23644 * @param {Object} props The component's props.
23645 * @param {string} props.kind The entity kind.
23646 * @param {string} props.type The entity name.
23647 * @param {number} props.id The entity ID.
23648 * @param {*} props.children The children to wrap.
23649 *
23650 * @return {Object} The provided children, wrapped with
23651 * the entity's context provider.
23652 */
23653 function EntityProvider({
23654 kind,
23655 type: name,
23656 id,
23657 children
23658 }) {
23659 const Provider = getEntityContext(kind, name).Provider;
23660 return (0,external_React_namespaceObject.createElement)(Provider, {
23661 value: id
23662 }, children);
23663 }
23664
23665 /**
23666 * Hook that returns the ID for the nearest
23667 * provided entity of the specified type.
23668 *
23669 * @param {string} kind The entity kind.
23670 * @param {string} name The entity name.
23671 */
23672 function useEntityId(kind, name) {
23673 return (0,external_wp_element_namespaceObject.useContext)(getEntityContext(kind, name));
23674 }
23675
23676 /**
23677 * Hook that returns the value and a setter for the
23678 * specified property of the nearest provided
23679 * entity of the specified type.
23680 *
23681 * @param {string} kind The entity kind.
23682 * @param {string} name The entity name.
23683 * @param {string} prop The property name.
23684 * @param {string} [_id] An entity ID to use instead of the context-provided one.
23685 *
23686 * @return {[*, Function, *]} An array where the first item is the
23687 * property value, the second is the
23688 * setter and the third is the full value
23689 * object from REST API containing more
23690 * information like `raw`, `rendered` and
23691 * `protected` props.
23692 */
23693 function useEntityProp(kind, name, prop, _id) {
23694 const providerId = useEntityId(kind, name);
23695 const id = _id !== null && _id !== void 0 ? _id : providerId;
23696 const {
23697 value,
23698 fullValue
23699 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
23700 const {
23701 getEntityRecord,
23702 getEditedEntityRecord
23703 } = select(STORE_NAME);
23704 const record = getEntityRecord(kind, name, id); // Trigger resolver.
23705 const editedRecord = getEditedEntityRecord(kind, name, id);
23706 return record && editedRecord ? {
23707 value: editedRecord[prop],
23708 fullValue: record[prop]
23709 } : {};
23710 }, [kind, name, id, prop]);
23711 const {
23712 editEntityRecord
23713 } = (0,external_wp_data_namespaceObject.useDispatch)(STORE_NAME);
23714 const setValue = (0,external_wp_element_namespaceObject.useCallback)(newValue => {
23715 editEntityRecord(kind, name, id, {
23716 [prop]: newValue
23717 });
23718 }, [editEntityRecord, kind, name, id, prop]);
23719 return [value, setValue, fullValue];
23720 }
23721
23722 /**
23723 * Hook that returns block content getters and setters for
23724 * the nearest provided entity of the specified type.
23725 *
23726 * The return value has the shape `[ blocks, onInput, onChange ]`.
23727 * `onInput` is for block changes that don't create undo levels
23728 * or dirty the post, non-persistent changes, and `onChange` is for
23729 * persistent changes. They map directly to the props of a
23730 * `BlockEditorProvider` and are intended to be used with it,
23731 * or similar components or hooks.
23732 *
23733 * @param {string} kind The entity kind.
23734 * @param {string} name The entity name.
23735 * @param {Object} options
23736 * @param {string} [options.id] An entity ID to use instead of the context-provided one.
23737 *
23738 * @return {[WPBlock[], Function, Function]} The block array and setters.
23739 */
23740 function useEntityBlockEditor(kind, name, {
23741 id: _id
23742 } = {}) {
23743 const providerId = useEntityId(kind, name);
23744 const id = _id !== null && _id !== void 0 ? _id : providerId;
23745 const {
23746 content,
23747 editedBlocks,
23748 meta
23749 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
23750 if (!id) {
23751 return {};
23752 }
23753 const {
23754 getEditedEntityRecord
23755 } = select(STORE_NAME);
23756 const editedRecord = getEditedEntityRecord(kind, name, id);
23757 return {
23758 editedBlocks: editedRecord.blocks,
23759 content: editedRecord.content,
23760 meta: editedRecord.meta
23761 };
23762 }, [kind, name, id]);
23763 const {
23764 __unstableCreateUndoLevel,
23765 editEntityRecord
23766 } = (0,external_wp_data_namespaceObject.useDispatch)(STORE_NAME);
23767 const blocks = (0,external_wp_element_namespaceObject.useMemo)(() => {
23768 if (!id) {
23769 return undefined;
23770 }
23771 if (editedBlocks) {
23772 return editedBlocks;
23773 }
23774 return content && typeof content !== 'function' ? (0,external_wp_blocks_namespaceObject.parse)(content) : EMPTY_ARRAY;
23775 }, [id, editedBlocks, content]);
23776 const updateFootnotes = (0,external_wp_element_namespaceObject.useCallback)(_blocks => updateFootnotesFromMeta(_blocks, meta), [meta]);
23777 const onChange = (0,external_wp_element_namespaceObject.useCallback)((newBlocks, options) => {
23778 const noChange = blocks === newBlocks;
23779 if (noChange) {
23780 return __unstableCreateUndoLevel(kind, name, id);
23781 }
23782 const {
23783 selection
23784 } = options;
23785
23786 // We create a new function here on every persistent edit
23787 // to make sure the edit makes the post dirty and creates
23788 // a new undo level.
23789 const edits = {
23790 selection,
23791 content: ({
23792 blocks: blocksForSerialization = []
23793 }) => (0,external_wp_blocks_namespaceObject.__unstableSerializeAndClean)(blocksForSerialization),
23794 ...updateFootnotes(newBlocks)
23795 };
23796 editEntityRecord(kind, name, id, edits, {
23797 isCached: false
23798 });
23799 }, [kind, name, id, blocks, updateFootnotes, __unstableCreateUndoLevel, editEntityRecord]);
23800 const onInput = (0,external_wp_element_namespaceObject.useCallback)((newBlocks, options) => {
23801 const {
23802 selection
23803 } = options;
23804 const footnotesChanges = updateFootnotes(newBlocks);
23805 const edits = {
23806 selection,
23807 ...footnotesChanges
23808 };
23809 editEntityRecord(kind, name, id, edits, {
23810 isCached: true
23811 });
23812 }, [kind, name, id, updateFootnotes, editEntityRecord]);
23813 return [blocks, onInput, onChange];
23814 }
23815
23816 ;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/__experimental-fetch-link-suggestions.js
23817 /**
23818 * WordPress dependencies
23819 */
23820
23821
23822
23823
23824
23825 /**
23826 * Filters the search by type
23827 *
23828 * @typedef { 'attachment' | 'post' | 'term' | 'post-format' } WPLinkSearchType
23829 */
23830
23831 /**
23832 * A link with an id may be of kind post-type or taxonomy
23833 *
23834 * @typedef { 'post-type' | 'taxonomy' } WPKind
23835 */
23836
23837 /**
23838 * @typedef WPLinkSearchOptions
23839 *
23840 * @property {boolean} [isInitialSuggestions] Displays initial search suggestions, when true.
23841 * @property {WPLinkSearchType} [type] Filters by search type.
23842 * @property {string} [subtype] Slug of the post-type or taxonomy.
23843 * @property {number} [page] Which page of results to return.
23844 * @property {number} [perPage] Search results per page.
23845 */
23846
23847 /**
23848 * @typedef WPLinkSearchResult
23849 *
23850 * @property {number} id Post or term id.
23851 * @property {string} url Link url.
23852 * @property {string} title Title of the link.
23853 * @property {string} type The taxonomy or post type slug or type URL.
23854 * @property {WPKind} [kind] Link kind of post-type or taxonomy
23855 */
23856
23857 /**
23858 * @typedef WPLinkSearchResultAugments
23859 *
23860 * @property {{kind: WPKind}} [meta] Contains kind information.
23861 * @property {WPKind} [subtype] Optional subtype if it exists.
23862 */
23863
23864 /**
23865 * @typedef {WPLinkSearchResult & WPLinkSearchResultAugments} WPLinkSearchResultAugmented
23866 */
23867
23868 /**
23869 * @typedef WPEditorSettings
23870 *
23871 * @property {boolean} [ disablePostFormats ] Disables post formats, when true.
23872 */
23873
23874 /**
23875 * Fetches link suggestions from the API.
23876 *
23877 * @async
23878 * @param {string} search
23879 * @param {WPLinkSearchOptions} [searchOptions]
23880 * @param {WPEditorSettings} [settings]
23881 *
23882 * @example
23883 * ```js
23884 * import { __experimentalFetchLinkSuggestions as fetchLinkSuggestions } from '@wordpress/core-data';
23885 *
23886 * //...
23887 *
23888 * export function initialize( id, settings ) {
23889 *
23890 * settings.__experimentalFetchLinkSuggestions = (
23891 * search,
23892 * searchOptions
23893 * ) => fetchLinkSuggestions( search, searchOptions, settings );
23894 * ```
23895 * @return {Promise< WPLinkSearchResult[] >} List of search suggestions
23896 */
23897 const fetchLinkSuggestions = async (search, searchOptions = {}, settings = {}) => {
23898 const {
23899 isInitialSuggestions = false,
23900 initialSuggestionsSearchOptions = undefined
23901 } = searchOptions;
23902 const {
23903 disablePostFormats = false
23904 } = settings;
23905 let {
23906 type = undefined,
23907 subtype = undefined,
23908 page = undefined,
23909 perPage = isInitialSuggestions ? 3 : 20
23910 } = searchOptions;
23911
23912 /** @type {Promise<WPLinkSearchResult>[]} */
23913 const queries = [];
23914 if (isInitialSuggestions && initialSuggestionsSearchOptions) {
23915 type = initialSuggestionsSearchOptions.type || type;
23916 subtype = initialSuggestionsSearchOptions.subtype || subtype;
23917 page = initialSuggestionsSearchOptions.page || page;
23918 perPage = initialSuggestionsSearchOptions.perPage || perPage;
23919 }
23920 if (!type || type === 'post') {
23921 queries.push(external_wp_apiFetch_default()({
23922 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
23923 search,
23924 page,
23925 per_page: perPage,
23926 type: 'post',
23927 subtype
23928 })
23929 }).then(results => {
23930 return results.map(result => {
23931 return {
23932 ...result,
23933 meta: {
23934 kind: 'post-type',
23935 subtype
23936 }
23937 };
23938 });
23939 }).catch(() => []) // Fail by returning no results.
23940 );
23941 }
23942
23943 if (!type || type === 'term') {
23944 queries.push(external_wp_apiFetch_default()({
23945 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
23946 search,
23947 page,
23948 per_page: perPage,
23949 type: 'term',
23950 subtype
23951 })
23952 }).then(results => {
23953 return results.map(result => {
23954 return {
23955 ...result,
23956 meta: {
23957 kind: 'taxonomy',
23958 subtype
23959 }
23960 };
23961 });
23962 }).catch(() => []) // Fail by returning no results.
23963 );
23964 }
23965
23966 if (!disablePostFormats && (!type || type === 'post-format')) {
23967 queries.push(external_wp_apiFetch_default()({
23968 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
23969 search,
23970 page,
23971 per_page: perPage,
23972 type: 'post-format',
23973 subtype
23974 })
23975 }).then(results => {
23976 return results.map(result => {
23977 return {
23978 ...result,
23979 meta: {
23980 kind: 'taxonomy',
23981 subtype
23982 }
23983 };
23984 });
23985 }).catch(() => []) // Fail by returning no results.
23986 );
23987 }
23988
23989 if (!type || type === 'attachment') {
23990 queries.push(external_wp_apiFetch_default()({
23991 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/media', {
23992 search,
23993 page,
23994 per_page: perPage
23995 })
23996 }).then(results => {
23997 return results.map(result => {
23998 return {
23999 ...result,
24000 meta: {
24001 kind: 'media'
24002 }
24003 };
24004 });
24005 }).catch(() => []) // Fail by returning no results.
24006 );
24007 }
24008
24009 return Promise.all(queries).then(results => {
24010 return results.reduce(( /** @type {WPLinkSearchResult[]} */accumulator, current) => accumulator.concat(current),
24011 // Flatten list.
24012 []).filter(
24013 /**
24014 * @param {{ id: number }} result
24015 */
24016 result => {
24017 return !!result.id;
24018 }).slice(0, perPage).map(( /** @type {WPLinkSearchResultAugmented} */result) => {
24019 const isMedia = result.type === 'attachment';
24020 return {
24021 id: result.id,
24022 // @ts-ignore fix when we make this a TS file
24023 url: isMedia ? result.source_url : result.url,
24024 title: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(isMedia ?
24025 // @ts-ignore fix when we make this a TS file
24026 result.title.rendered : result.title || '') || (0,external_wp_i18n_namespaceObject.__)('(no title)'),
24027 type: result.subtype || result.type,
24028 kind: result?.meta?.kind
24029 };
24030 });
24031 });
24032 };
24033 /* harmony default export */ var _experimental_fetch_link_suggestions = (fetchLinkSuggestions);
24034
24035 ;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/__experimental-fetch-url-data.js
24036 /**
24037 * WordPress dependencies
24038 */
24039
24040
24041
24042 /**
24043 * A simple in-memory cache for requests.
24044 * This avoids repeat HTTP requests which may be beneficial
24045 * for those wishing to preserve low-bandwidth.
24046 */
24047 const CACHE = new Map();
24048
24049 /**
24050 * @typedef WPRemoteUrlData
24051 *
24052 * @property {string} title contents of the remote URL's `<title>` tag.
24053 */
24054
24055 /**
24056 * Fetches data about a remote URL.
24057 * eg: <title> tag, favicon...etc.
24058 *
24059 * @async
24060 * @param {string} url the URL to request details from.
24061 * @param {Object?} options any options to pass to the underlying fetch.
24062 * @example
24063 * ```js
24064 * import { __experimentalFetchUrlData as fetchUrlData } from '@wordpress/core-data';
24065 *
24066 * //...
24067 *
24068 * export function initialize( id, settings ) {
24069 *
24070 * settings.__experimentalFetchUrlData = (
24071 * url
24072 * ) => fetchUrlData( url );
24073 * ```
24074 * @return {Promise< WPRemoteUrlData[] >} Remote URL data.
24075 */
24076 const fetchUrlData = async (url, options = {}) => {
24077 const endpoint = '/wp-block-editor/v1/url-details';
24078 const args = {
24079 url: (0,external_wp_url_namespaceObject.prependHTTP)(url)
24080 };
24081 if (!(0,external_wp_url_namespaceObject.isURL)(url)) {
24082 return Promise.reject(`${url} is not a valid URL.`);
24083 }
24084
24085 // Test for "http" based URL as it is possible for valid
24086 // yet unusable URLs such as `tel:123456` to be passed.
24087 const protocol = (0,external_wp_url_namespaceObject.getProtocol)(url);
24088 if (!protocol || !(0,external_wp_url_namespaceObject.isValidProtocol)(protocol) || !protocol.startsWith('http') || !/^https?:\/\/[^\/\s]/i.test(url)) {
24089 return Promise.reject(`${url} does not have a valid protocol. URLs must be "http" based`);
24090 }
24091 if (CACHE.has(url)) {
24092 return CACHE.get(url);
24093 }
24094 return external_wp_apiFetch_default()({
24095 path: (0,external_wp_url_namespaceObject.addQueryArgs)(endpoint, args),
24096 ...options
24097 }).then(res => {
24098 CACHE.set(url, res);
24099 return res;
24100 });
24101 };
24102 /* harmony default export */ var _experimental_fetch_url_data = (fetchUrlData);
24103
24104 ;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/index.js
24105
24106
24107
24108 ;// CONCATENATED MODULE: ./node_modules/memize/dist/index.js
24109 /**
24110 * Memize options object.
24111 *
24112 * @typedef MemizeOptions
24113 *
24114 * @property {number} [maxSize] Maximum size of the cache.
24115 */
24116
24117 /**
24118 * Internal cache entry.
24119 *
24120 * @typedef MemizeCacheNode
24121 *
24122 * @property {?MemizeCacheNode|undefined} [prev] Previous node.
24123 * @property {?MemizeCacheNode|undefined} [next] Next node.
24124 * @property {Array<*>} args Function arguments for cache
24125 * entry.
24126 * @property {*} val Function result.
24127 */
24128
24129 /**
24130 * Properties of the enhanced function for controlling cache.
24131 *
24132 * @typedef MemizeMemoizedFunction
24133 *
24134 * @property {()=>void} clear Clear the cache.
24135 */
24136
24137 /**
24138 * Accepts a function to be memoized, and returns a new memoized function, with
24139 * optional options.
24140 *
24141 * @template {(...args: any[]) => any} F
24142 *
24143 * @param {F} fn Function to memoize.
24144 * @param {MemizeOptions} [options] Options object.
24145 *
24146 * @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function.
24147 */
24148 function memize(fn, options) {
24149 var size = 0;
24150
24151 /** @type {?MemizeCacheNode|undefined} */
24152 var head;
24153
24154 /** @type {?MemizeCacheNode|undefined} */
24155 var tail;
24156
24157 options = options || {};
24158
24159 function memoized(/* ...args */) {
24160 var node = head,
24161 len = arguments.length,
24162 args,
24163 i;
24164
24165 searchCache: while (node) {
24166 // Perform a shallow equality test to confirm that whether the node
24167 // under test is a candidate for the arguments passed. Two arrays
24168 // are shallowly equal if their length matches and each entry is
24169 // strictly equal between the two sets. Avoid abstracting to a
24170 // function which could incur an arguments leaking deoptimization.
24171
24172 // Check whether node arguments match arguments length
24173 if (node.args.length !== arguments.length) {
24174 node = node.next;
24175 continue;
24176 }
24177
24178 // Check whether node arguments match arguments values
24179 for (i = 0; i < len; i++) {
24180 if (node.args[i] !== arguments[i]) {
24181 node = node.next;
24182 continue searchCache;
24183 }
24184 }
24185
24186 // At this point we can assume we've found a match
24187
24188 // Surface matched node to head if not already
24189 if (node !== head) {
24190 // As tail, shift to previous. Must only shift if not also
24191 // head, since if both head and tail, there is no previous.
24192 if (node === tail) {
24193 tail = node.prev;
24194 }
24195
24196 // Adjust siblings to point to each other. If node was tail,
24197 // this also handles new tail's empty `next` assignment.
24198 /** @type {MemizeCacheNode} */ (node.prev).next = node.next;
24199 if (node.next) {
24200 node.next.prev = node.prev;
24201 }
24202
24203 node.next = head;
24204 node.prev = null;
24205 /** @type {MemizeCacheNode} */ (head).prev = node;
24206 head = node;
24207 }
24208
24209 // Return immediately
24210 return node.val;
24211 }
24212
24213 // No cached value found. Continue to insertion phase:
24214
24215 // Create a copy of arguments (avoid leaking deoptimization)
24216 args = new Array(len);
24217 for (i = 0; i < len; i++) {
24218 args[i] = arguments[i];
24219 }
24220
24221 node = {
24222 args: args,
24223
24224 // Generate the result from original function
24225 val: fn.apply(null, args),
24226 };
24227
24228 // Don't need to check whether node is already head, since it would
24229 // have been returned above already if it was
24230
24231 // Shift existing head down list
24232 if (head) {
24233 head.prev = node;
24234 node.next = head;
24235 } else {
24236 // If no head, follows that there's no tail (at initial or reset)
24237 tail = node;
24238 }
24239
24240 // Trim tail if we're reached max size and are pending cache insertion
24241 if (size === /** @type {MemizeOptions} */ (options).maxSize) {
24242 tail = /** @type {MemizeCacheNode} */ (tail).prev;
24243 /** @type {MemizeCacheNode} */ (tail).next = null;
24244 } else {
24245 size++;
24246 }
24247
24248 head = node;
24249
24250 return node.val;
24251 }
24252
24253 memoized.clear = function () {
24254 head = null;
24255 tail = null;
24256 size = 0;
24257 };
24258
24259 // Ignore reason: There's not a clear solution to create an intersection of
24260 // the function with additional properties, where the goal is to retain the
24261 // function signature of the incoming argument and add control properties
24262 // on the return value.
24263
24264 // @ts-ignore
24265 return memoized;
24266 }
24267
24268
24269
24270 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/memoize.js
24271 /**
24272 * External dependencies
24273 */
24274
24275
24276 // re-export due to restrictive esModuleInterop setting
24277 /* harmony default export */ var memoize = (memize);
24278
24279 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/constants.js
24280 let Status = /*#__PURE__*/function (Status) {
24281 Status["Idle"] = "IDLE";
24282 Status["Resolving"] = "RESOLVING";
24283 Status["Error"] = "ERROR";
24284 Status["Success"] = "SUCCESS";
24285 return Status;
24286 }({});
24287
24288 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-query-select.js
24289 /**
24290 * WordPress dependencies
24291 */
24292
24293
24294 /**
24295 * Internal dependencies
24296 */
24297
24298
24299 const META_SELECTORS = ['getIsResolving', 'hasStartedResolution', 'hasFinishedResolution', 'isResolving', 'getCachedResolvers'];
24300 /**
24301 * Like useSelect, but the selectors return objects containing
24302 * both the original data AND the resolution info.
24303 *
24304 * @since 6.1.0 Introduced in WordPress core.
24305 * @private
24306 *
24307 * @param {Function} mapQuerySelect see useSelect
24308 * @param {Array} deps see useSelect
24309 *
24310 * @example
24311 * ```js
24312 * import { useQuerySelect } from '@wordpress/data';
24313 * import { store as coreDataStore } from '@wordpress/core-data';
24314 *
24315 * function PageTitleDisplay( { id } ) {
24316 * const { data: page, isResolving } = useQuerySelect( ( query ) => {
24317 * return query( coreDataStore ).getEntityRecord( 'postType', 'page', id )
24318 * }, [ id ] );
24319 *
24320 * if ( isResolving ) {
24321 * return 'Loading...';
24322 * }
24323 *
24324 * return page.title;
24325 * }
24326 *
24327 * // Rendered in the application:
24328 * // <PageTitleDisplay id={ 10 } />
24329 * ```
24330 *
24331 * In the above example, when `PageTitleDisplay` is rendered into an
24332 * application, the page and the resolution details will be retrieved from
24333 * the store state using the `mapSelect` callback on `useQuerySelect`.
24334 *
24335 * If the id prop changes then any page in the state for that id is
24336 * retrieved. If the id prop doesn't change and other props are passed in
24337 * that do change, the title will not change because the dependency is just
24338 * the id.
24339 * @see useSelect
24340 *
24341 * @return {QuerySelectResponse} Queried data.
24342 */
24343 function useQuerySelect(mapQuerySelect, deps) {
24344 return (0,external_wp_data_namespaceObject.useSelect)((select, registry) => {
24345 const resolve = store => enrichSelectors(select(store));
24346 return mapQuerySelect(resolve, registry);
24347 }, deps);
24348 }
24349 /**
24350 * Transform simple selectors into ones that return an object with the
24351 * original return value AND the resolution info.
24352 *
24353 * @param {Object} selectors Selectors to enrich
24354 * @return {EnrichedSelectors} Enriched selectors
24355 */
24356 const enrichSelectors = memoize(selectors => {
24357 const resolvers = {};
24358 for (const selectorName in selectors) {
24359 if (META_SELECTORS.includes(selectorName)) {
24360 continue;
24361 }
24362 Object.defineProperty(resolvers, selectorName, {
24363 get: () => (...args) => {
24364 const {
24365 getIsResolving,
24366 hasFinishedResolution
24367 } = selectors;
24368 const isResolving = !!getIsResolving(selectorName, args);
24369 const hasResolved = !isResolving && hasFinishedResolution(selectorName, args);
24370 const data = selectors[selectorName](...args);
24371 let status;
24372 if (isResolving) {
24373 status = Status.Resolving;
24374 } else if (hasResolved) {
24375 if (data) {
24376 status = Status.Success;
24377 } else {
24378 status = Status.Error;
24379 }
24380 } else {
24381 status = Status.Idle;
24382 }
24383 return {
24384 data,
24385 status,
24386 isResolving,
24387 hasResolved
24388 };
24389 }
24390 });
24391 }
24392 return resolvers;
24393 });
24394
24395 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-entity-record.js
24396 /**
24397 * WordPress dependencies
24398 */
24399
24400
24401
24402
24403 /**
24404 * Internal dependencies
24405 */
24406
24407
24408 const use_entity_record_EMPTY_OBJECT = {};
24409
24410 /**
24411 * Resolves the specified entity record.
24412 *
24413 * @since 6.1.0 Introduced in WordPress core.
24414 *
24415 * @param kind Kind of the entity, e.g. `root` or a `postType`. See rootEntitiesConfig in ../entities.ts for a list of available kinds.
24416 * @param name Name of the entity, e.g. `plugin` or a `post`. See rootEntitiesConfig in ../entities.ts for a list of available names.
24417 * @param recordId ID of the requested entity record.
24418 * @param options Optional hook options.
24419 * @example
24420 * ```js
24421 * import { useEntityRecord } from '@wordpress/core-data';
24422 *
24423 * function PageTitleDisplay( { id } ) {
24424 * const { record, isResolving } = useEntityRecord( 'postType', 'page', id );
24425 *
24426 * if ( isResolving ) {
24427 * return 'Loading...';
24428 * }
24429 *
24430 * return record.title;
24431 * }
24432 *
24433 * // Rendered in the application:
24434 * // <PageTitleDisplay id={ 1 } />
24435 * ```
24436 *
24437 * In the above example, when `PageTitleDisplay` is rendered into an
24438 * application, the page and the resolution details will be retrieved from
24439 * the store state using `getEntityRecord()`, or resolved if missing.
24440 *
24441 * @example
24442 * ```js
24443 * import { useCallback } from 'react';
24444 * import { useDispatch } from '@wordpress/data';
24445 * import { __ } from '@wordpress/i18n';
24446 * import { TextControl } from '@wordpress/components';
24447 * import { store as noticeStore } from '@wordpress/notices';
24448 * import { useEntityRecord } from '@wordpress/core-data';
24449 *
24450 * function PageRenameForm( { id } ) {
24451 * const page = useEntityRecord( 'postType', 'page', id );
24452 * const { createSuccessNotice, createErrorNotice } =
24453 * useDispatch( noticeStore );
24454 *
24455 * const setTitle = useCallback( ( title ) => {
24456 * page.edit( { title } );
24457 * }, [ page.edit ] );
24458 *
24459 * if ( page.isResolving ) {
24460 * return 'Loading...';
24461 * }
24462 *
24463 * async function onRename( event ) {
24464 * event.preventDefault();
24465 * try {
24466 * await page.save();
24467 * createSuccessNotice( __( 'Page renamed.' ), {
24468 * type: 'snackbar',
24469 * } );
24470 * } catch ( error ) {
24471 * createErrorNotice( error.message, { type: 'snackbar' } );
24472 * }
24473 * }
24474 *
24475 * return (
24476 * <form onSubmit={ onRename }>
24477 * <TextControl
24478 * label={ __( 'Name' ) }
24479 * value={ page.editedRecord.title }
24480 * onChange={ setTitle }
24481 * />
24482 * <button type="submit">{ __( 'Save' ) }</button>
24483 * </form>
24484 * );
24485 * }
24486 *
24487 * // Rendered in the application:
24488 * // <PageRenameForm id={ 1 } />
24489 * ```
24490 *
24491 * In the above example, updating and saving the page title is handled
24492 * via the `edit()` and `save()` mutation helpers provided by
24493 * `useEntityRecord()`;
24494 *
24495 * @return Entity record data.
24496 * @template RecordType
24497 */
24498 function useEntityRecord(kind, name, recordId, options = {
24499 enabled: true
24500 }) {
24501 const {
24502 editEntityRecord,
24503 saveEditedEntityRecord
24504 } = (0,external_wp_data_namespaceObject.useDispatch)(store);
24505 const mutations = (0,external_wp_element_namespaceObject.useMemo)(() => ({
24506 edit: (record, editOptions = {}) => editEntityRecord(kind, name, recordId, record, editOptions),
24507 save: (saveOptions = {}) => saveEditedEntityRecord(kind, name, recordId, {
24508 throwOnError: true,
24509 ...saveOptions
24510 })
24511 }), [editEntityRecord, kind, name, recordId, saveEditedEntityRecord]);
24512 const {
24513 editedRecord,
24514 hasEdits,
24515 edits
24516 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
24517 if (!options.enabled) {
24518 return {
24519 editedRecord: use_entity_record_EMPTY_OBJECT,
24520 hasEdits: false,
24521 edits: use_entity_record_EMPTY_OBJECT
24522 };
24523 }
24524 return {
24525 editedRecord: select(store).getEditedEntityRecord(kind, name, recordId),
24526 hasEdits: select(store).hasEditsForEntityRecord(kind, name, recordId),
24527 edits: select(store).getEntityRecordNonTransientEdits(kind, name, recordId)
24528 };
24529 }, [kind, name, recordId, options.enabled]);
24530 const {
24531 data: record,
24532 ...querySelectRest
24533 } = useQuerySelect(query => {
24534 if (!options.enabled) {
24535 return {
24536 data: null
24537 };
24538 }
24539 return query(store).getEntityRecord(kind, name, recordId);
24540 }, [kind, name, recordId, options.enabled]);
24541 return {
24542 record,
24543 editedRecord,
24544 hasEdits,
24545 edits,
24546 ...querySelectRest,
24547 ...mutations
24548 };
24549 }
24550 function __experimentalUseEntityRecord(kind, name, recordId, options) {
24551 external_wp_deprecated_default()(`wp.data.__experimentalUseEntityRecord`, {
24552 alternative: 'wp.data.useEntityRecord',
24553 since: '6.1'
24554 });
24555 return useEntityRecord(kind, name, recordId, options);
24556 }
24557
24558 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-entity-records.js
24559 /**
24560 * WordPress dependencies
24561 */
24562
24563
24564
24565
24566 /**
24567 * Internal dependencies
24568 */
24569
24570
24571 const use_entity_records_EMPTY_ARRAY = [];
24572
24573 /**
24574 * Resolves the specified entity records.
24575 *
24576 * @since 6.1.0 Introduced in WordPress core.
24577 *
24578 * @param kind Kind of the entity, e.g. `root` or a `postType`. See rootEntitiesConfig in ../entities.ts for a list of available kinds.
24579 * @param name Name of the entity, e.g. `plugin` or a `post`. See rootEntitiesConfig in ../entities.ts for a list of available names.
24580 * @param queryArgs Optional HTTP query description for how to fetch the data, passed to the requested API endpoint.
24581 * @param options Optional hook options.
24582 * @example
24583 * ```js
24584 * import { useEntityRecords } from '@wordpress/core-data';
24585 *
24586 * function PageTitlesList() {
24587 * const { records, isResolving } = useEntityRecords( 'postType', 'page' );
24588 *
24589 * if ( isResolving ) {
24590 * return 'Loading...';
24591 * }
24592 *
24593 * return (
24594 * <ul>
24595 * {records.map(( page ) => (
24596 * <li>{ page.title }</li>
24597 * ))}
24598 * </ul>
24599 * );
24600 * }
24601 *
24602 * // Rendered in the application:
24603 * // <PageTitlesList />
24604 * ```
24605 *
24606 * In the above example, when `PageTitlesList` is rendered into an
24607 * application, the list of records and the resolution details will be retrieved from
24608 * the store state using `getEntityRecords()`, or resolved if missing.
24609 *
24610 * @return Entity records data.
24611 * @template RecordType
24612 */
24613 function useEntityRecords(kind, name, queryArgs = {}, options = {
24614 enabled: true
24615 }) {
24616 // Serialize queryArgs to a string that can be safely used as a React dep.
24617 // We can't just pass queryArgs as one of the deps, because if it is passed
24618 // as an object literal, then it will be a different object on each call even
24619 // if the values remain the same.
24620 const queryAsString = (0,external_wp_url_namespaceObject.addQueryArgs)('', queryArgs);
24621 const {
24622 data: records,
24623 ...rest
24624 } = useQuerySelect(query => {
24625 if (!options.enabled) {
24626 return {
24627 // Avoiding returning a new reference on every execution.
24628 data: use_entity_records_EMPTY_ARRAY
24629 };
24630 }
24631 return query(store).getEntityRecords(kind, name, queryArgs);
24632 }, [kind, name, queryAsString, options.enabled]);
24633 const {
24634 totalItems,
24635 totalPages
24636 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
24637 if (!options.enabled) {
24638 return {
24639 totalItems: null,
24640 totalPages: null
24641 };
24642 }
24643 return {
24644 totalItems: select(store).getEntityRecordsTotalItems(kind, name, queryArgs),
24645 totalPages: select(store).getEntityRecordsTotalPages(kind, name, queryArgs)
24646 };
24647 }, [kind, name, queryAsString, options.enabled]);
24648 return {
24649 records,
24650 totalItems,
24651 totalPages,
24652 ...rest
24653 };
24654 }
24655 function __experimentalUseEntityRecords(kind, name, queryArgs, options) {
24656 external_wp_deprecated_default()(`wp.data.__experimentalUseEntityRecords`, {
24657 alternative: 'wp.data.useEntityRecords',
24658 since: '6.1'
24659 });
24660 return useEntityRecords(kind, name, queryArgs, options);
24661 }
24662
24663 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-resource-permissions.js
24664 /**
24665 * WordPress dependencies
24666 */
24667
24668
24669 /**
24670 * Internal dependencies
24671 */
24672
24673
24674
24675 /**
24676 * Resolves resource permissions.
24677 *
24678 * @since 6.1.0 Introduced in WordPress core.
24679 *
24680 * @param resource The resource in question, e.g. media.
24681 * @param id ID of a specific resource entry, if needed, e.g. 10.
24682 *
24683 * @example
24684 * ```js
24685 * import { useResourcePermissions } from '@wordpress/core-data';
24686 *
24687 * function PagesList() {
24688 * const { canCreate, isResolving } = useResourcePermissions( 'pages' );
24689 *
24690 * if ( isResolving ) {
24691 * return 'Loading ...';
24692 * }
24693 *
24694 * return (
24695 * <div>
24696 * {canCreate ? (<button>+ Create a new page</button>) : false}
24697 * // ...
24698 * </div>
24699 * );
24700 * }
24701 *
24702 * // Rendered in the application:
24703 * // <PagesList />
24704 * ```
24705 *
24706 * @example
24707 * ```js
24708 * import { useResourcePermissions } from '@wordpress/core-data';
24709 *
24710 * function Page({ pageId }) {
24711 * const {
24712 * canCreate,
24713 * canUpdate,
24714 * canDelete,
24715 * isResolving
24716 * } = useResourcePermissions( 'pages', pageId );
24717 *
24718 * if ( isResolving ) {
24719 * return 'Loading ...';
24720 * }
24721 *
24722 * return (
24723 * <div>
24724 * {canCreate ? (<button>+ Create a new page</button>) : false}
24725 * {canUpdate ? (<button>Edit page</button>) : false}
24726 * {canDelete ? (<button>Delete page</button>) : false}
24727 * // ...
24728 * </div>
24729 * );
24730 * }
24731 *
24732 * // Rendered in the application:
24733 * // <Page pageId={ 15 } />
24734 * ```
24735 *
24736 * In the above example, when `PagesList` is rendered into an
24737 * application, the appropriate permissions and the resolution details will be retrieved from
24738 * the store state using `canUser()`, or resolved if missing.
24739 *
24740 * @return Entity records data.
24741 * @template IdType
24742 */
24743 function useResourcePermissions(resource, id) {
24744 return useQuerySelect(resolve => {
24745 const {
24746 canUser
24747 } = resolve(store);
24748 const create = canUser('create', resource);
24749 if (!id) {
24750 const read = canUser('read', resource);
24751 const isResolving = create.isResolving || read.isResolving;
24752 const hasResolved = create.hasResolved && read.hasResolved;
24753 let status = Status.Idle;
24754 if (isResolving) {
24755 status = Status.Resolving;
24756 } else if (hasResolved) {
24757 status = Status.Success;
24758 }
24759 return {
24760 status,
24761 isResolving,
24762 hasResolved,
24763 canCreate: create.hasResolved && create.data,
24764 canRead: read.hasResolved && read.data
24765 };
24766 }
24767 const read = canUser('read', resource, id);
24768 const update = canUser('update', resource, id);
24769 const _delete = canUser('delete', resource, id);
24770 const isResolving = read.isResolving || create.isResolving || update.isResolving || _delete.isResolving;
24771 const hasResolved = read.hasResolved && create.hasResolved && update.hasResolved && _delete.hasResolved;
24772 let status = Status.Idle;
24773 if (isResolving) {
24774 status = Status.Resolving;
24775 } else if (hasResolved) {
24776 status = Status.Success;
24777 }
24778 return {
24779 status,
24780 isResolving,
24781 hasResolved,
24782 canRead: hasResolved && read.data,
24783 canCreate: hasResolved && create.data,
24784 canUpdate: hasResolved && update.data,
24785 canDelete: hasResolved && _delete.data
24786 };
24787 }, [resource, id]);
24788 }
24789 function __experimentalUseResourcePermissions(resource, id) {
24790 external_wp_deprecated_default()(`wp.data.__experimentalUseResourcePermissions`, {
24791 alternative: 'wp.data.useResourcePermissions',
24792 since: '6.1'
24793 });
24794 return useResourcePermissions(resource, id);
24795 }
24796
24797 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/index.js
24798
24799
24800
24801
24802 ;// CONCATENATED MODULE: ./packages/core-data/build-module/index.js
24803 /**
24804 * WordPress dependencies
24805 */
24806
24807
24808 /**
24809 * Internal dependencies
24810 */
24811
24812
24813
24814
24815
24816
24817
24818
24819
24820
24821 // The entity selectors/resolvers and actions are shortcuts to their generic equivalents
24822 // (getEntityRecord, getEntityRecords, updateEntityRecord, updateEntityRecords)
24823 // Instead of getEntityRecord, the consumer could use more user-friendly named selector: getPostType, getTaxonomy...
24824 // The "kind" and the "name" of the entity are combined to generate these shortcuts.
24825
24826 const entitySelectors = rootEntitiesConfig.reduce((result, entity) => {
24827 const {
24828 kind,
24829 name
24830 } = entity;
24831 result[getMethodName(kind, name)] = (state, key, query) => getEntityRecord(state, kind, name, key, query);
24832 result[getMethodName(kind, name, 'get', true)] = (state, query) => getEntityRecords(state, kind, name, query);
24833 return result;
24834 }, {});
24835 const entityResolvers = rootEntitiesConfig.reduce((result, entity) => {
24836 const {
24837 kind,
24838 name
24839 } = entity;
24840 result[getMethodName(kind, name)] = (key, query) => resolvers_getEntityRecord(kind, name, key, query);
24841 const pluralMethodName = getMethodName(kind, name, 'get', true);
24842 result[pluralMethodName] = (...args) => resolvers_getEntityRecords(kind, name, ...args);
24843 result[pluralMethodName].shouldInvalidate = action => resolvers_getEntityRecords.shouldInvalidate(action, kind, name);
24844 return result;
24845 }, {});
24846 const entityActions = rootEntitiesConfig.reduce((result, entity) => {
24847 const {
24848 kind,
24849 name
24850 } = entity;
24851 result[getMethodName(kind, name, 'save')] = key => saveEntityRecord(kind, name, key);
24852 result[getMethodName(kind, name, 'delete')] = (key, query) => deleteEntityRecord(kind, name, key, query);
24853 return result;
24854 }, {});
24855 const storeConfig = () => ({
24856 reducer: build_module_reducer,
24857 actions: {
24858 ...build_module_actions_namespaceObject,
24859 ...entityActions,
24860 ...createLocksActions()
24861 },
24862 selectors: {
24863 ...build_module_selectors_namespaceObject,
24864 ...entitySelectors
24865 },
24866 resolvers: {
24867 ...resolvers_namespaceObject,
24868 ...entityResolvers
24869 }
24870 });
24871
24872 /**
24873 * Store definition for the code data namespace.
24874 *
24875 * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore
24876 */
24877 const store = (0,external_wp_data_namespaceObject.createReduxStore)(STORE_NAME, storeConfig());
24878 unlock(store).registerPrivateSelectors(private_selectors_namespaceObject);
24879 (0,external_wp_data_namespaceObject.register)(store); // Register store after unlocking private selectors to allow resolvers to use them.
24880
24881
24882
24883
24884
24885
24886
24887 }();
24888 (window.wp = window.wp || {}).coreData = __webpack_exports__;
24889 /******/ })()
24890 ;