PluginProbe
Gutenberg / 18.5.0
Gutenberg v18.5.0
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 18.5.0, at build/core-data/index.js

24,749 lines 791.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /******/ (() => { // webpackBootstrap
2 /******/ var __webpack_modules__ = ({
3
4 /***/ 2167:
5 /***/ ((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 /***/ ((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 /***/ ((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 /******/ (() => {
440 /******/ // getDefaultExport function for compatibility with non-harmony modules
441 /******/ __webpack_require__.n = (module) => {
442 /******/ var getter = module && module.__esModule ?
443 /******/ () => (module['default']) :
444 /******/ () => (module);
445 /******/ __webpack_require__.d(getter, { a: getter });
446 /******/ return getter;
447 /******/ };
448 /******/ })();
449 /******/
450 /******/ /* webpack/runtime/define property getters */
451 /******/ (() => {
452 /******/ // define getter functions for harmony exports
453 /******/ __webpack_require__.d = (exports, definition) => {
454 /******/ for(var key in definition) {
455 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
456 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
457 /******/ }
458 /******/ }
459 /******/ };
460 /******/ })();
461 /******/
462 /******/ /* webpack/runtime/global */
463 /******/ (() => {
464 /******/ __webpack_require__.g = (function() {
465 /******/ if (typeof globalThis === 'object') return globalThis;
466 /******/ try {
467 /******/ return this || new Function('return this')();
468 /******/ } catch (e) {
469 /******/ if (typeof window === 'object') return window;
470 /******/ }
471 /******/ })();
472 /******/ })();
473 /******/
474 /******/ /* webpack/runtime/hasOwnProperty shorthand */
475 /******/ (() => {
476 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
477 /******/ })();
478 /******/
479 /******/ /* webpack/runtime/make namespace object */
480 /******/ (() => {
481 /******/ // define __esModule on exports
482 /******/ __webpack_require__.r = (exports) => {
483 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
484 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
485 /******/ }
486 /******/ Object.defineProperty(exports, '__esModule', { value: true });
487 /******/ };
488 /******/ })();
489 /******/
490 /************************************************************************/
491 var __webpack_exports__ = {};
492 // This entry need to be wrapped in an IIFE because it need to be in strict mode.
493 (() => {
494 "use strict";
495 // ESM COMPAT FLAG
496 __webpack_require__.r(__webpack_exports__);
497
498 // EXPORTS
499 __webpack_require__.d(__webpack_exports__, {
500 EntityProvider: () => (/* reexport */ EntityProvider),
501 __experimentalFetchLinkSuggestions: () => (/* reexport */ _experimental_fetch_link_suggestions),
502 __experimentalFetchUrlData: () => (/* reexport */ _experimental_fetch_url_data),
503 __experimentalUseEntityRecord: () => (/* reexport */ __experimentalUseEntityRecord),
504 __experimentalUseEntityRecords: () => (/* reexport */ __experimentalUseEntityRecords),
505 __experimentalUseResourcePermissions: () => (/* reexport */ __experimentalUseResourcePermissions),
506 fetchBlockPatterns: () => (/* reexport */ fetchBlockPatterns),
507 store: () => (/* binding */ store),
508 useEntityBlockEditor: () => (/* reexport */ useEntityBlockEditor),
509 useEntityId: () => (/* reexport */ useEntityId),
510 useEntityProp: () => (/* reexport */ useEntityProp),
511 useEntityRecord: () => (/* reexport */ useEntityRecord),
512 useEntityRecords: () => (/* reexport */ useEntityRecords),
513 useResourcePermissions: () => (/* reexport */ useResourcePermissions)
514 });
515
516 // NAMESPACE OBJECT: ./packages/core-data/build-module/actions.js
517 var build_module_actions_namespaceObject = {};
518 __webpack_require__.r(build_module_actions_namespaceObject);
519 __webpack_require__.d(build_module_actions_namespaceObject, {
520 __experimentalBatch: () => (__experimentalBatch),
521 __experimentalReceiveCurrentGlobalStylesId: () => (__experimentalReceiveCurrentGlobalStylesId),
522 __experimentalReceiveThemeBaseGlobalStyles: () => (__experimentalReceiveThemeBaseGlobalStyles),
523 __experimentalReceiveThemeGlobalStyleVariations: () => (__experimentalReceiveThemeGlobalStyleVariations),
524 __experimentalSaveSpecifiedEntityEdits: () => (__experimentalSaveSpecifiedEntityEdits),
525 __unstableCreateUndoLevel: () => (__unstableCreateUndoLevel),
526 addEntities: () => (addEntities),
527 deleteEntityRecord: () => (deleteEntityRecord),
528 editEntityRecord: () => (editEntityRecord),
529 receiveAutosaves: () => (receiveAutosaves),
530 receiveCurrentTheme: () => (receiveCurrentTheme),
531 receiveCurrentUser: () => (receiveCurrentUser),
532 receiveDefaultTemplateId: () => (receiveDefaultTemplateId),
533 receiveEmbedPreview: () => (receiveEmbedPreview),
534 receiveEntityRecords: () => (receiveEntityRecords),
535 receiveNavigationFallbackId: () => (receiveNavigationFallbackId),
536 receiveRevisions: () => (receiveRevisions),
537 receiveThemeGlobalStyleRevisions: () => (receiveThemeGlobalStyleRevisions),
538 receiveThemeSupports: () => (receiveThemeSupports),
539 receiveUploadPermissions: () => (receiveUploadPermissions),
540 receiveUserPermission: () => (receiveUserPermission),
541 receiveUserQuery: () => (receiveUserQuery),
542 redo: () => (redo),
543 saveEditedEntityRecord: () => (saveEditedEntityRecord),
544 saveEntityRecord: () => (saveEntityRecord),
545 undo: () => (undo)
546 });
547
548 // NAMESPACE OBJECT: ./packages/core-data/build-module/selectors.js
549 var build_module_selectors_namespaceObject = {};
550 __webpack_require__.r(build_module_selectors_namespaceObject);
551 __webpack_require__.d(build_module_selectors_namespaceObject, {
552 __experimentalGetCurrentGlobalStylesId: () => (__experimentalGetCurrentGlobalStylesId),
553 __experimentalGetCurrentThemeBaseGlobalStyles: () => (__experimentalGetCurrentThemeBaseGlobalStyles),
554 __experimentalGetCurrentThemeGlobalStylesVariations: () => (__experimentalGetCurrentThemeGlobalStylesVariations),
555 __experimentalGetDirtyEntityRecords: () => (__experimentalGetDirtyEntityRecords),
556 __experimentalGetEntitiesBeingSaved: () => (__experimentalGetEntitiesBeingSaved),
557 __experimentalGetEntityRecordNoResolver: () => (__experimentalGetEntityRecordNoResolver),
558 __experimentalGetTemplateForLink: () => (__experimentalGetTemplateForLink),
559 canUser: () => (canUser),
560 canUserEditEntityRecord: () => (canUserEditEntityRecord),
561 getAuthors: () => (getAuthors),
562 getAutosave: () => (getAutosave),
563 getAutosaves: () => (getAutosaves),
564 getBlockPatternCategories: () => (getBlockPatternCategories),
565 getBlockPatterns: () => (getBlockPatterns),
566 getCurrentTheme: () => (getCurrentTheme),
567 getCurrentThemeGlobalStylesRevisions: () => (getCurrentThemeGlobalStylesRevisions),
568 getCurrentUser: () => (getCurrentUser),
569 getDefaultTemplateId: () => (getDefaultTemplateId),
570 getEditedEntityRecord: () => (getEditedEntityRecord),
571 getEmbedPreview: () => (getEmbedPreview),
572 getEntitiesByKind: () => (getEntitiesByKind),
573 getEntitiesConfig: () => (getEntitiesConfig),
574 getEntity: () => (getEntity),
575 getEntityConfig: () => (getEntityConfig),
576 getEntityRecord: () => (getEntityRecord),
577 getEntityRecordEdits: () => (getEntityRecordEdits),
578 getEntityRecordNonTransientEdits: () => (getEntityRecordNonTransientEdits),
579 getEntityRecords: () => (getEntityRecords),
580 getEntityRecordsTotalItems: () => (getEntityRecordsTotalItems),
581 getEntityRecordsTotalPages: () => (getEntityRecordsTotalPages),
582 getLastEntityDeleteError: () => (getLastEntityDeleteError),
583 getLastEntitySaveError: () => (getLastEntitySaveError),
584 getRawEntityRecord: () => (getRawEntityRecord),
585 getRedoEdit: () => (getRedoEdit),
586 getReferenceByDistinctEdits: () => (getReferenceByDistinctEdits),
587 getRevision: () => (getRevision),
588 getRevisions: () => (getRevisions),
589 getThemeSupports: () => (getThemeSupports),
590 getUndoEdit: () => (getUndoEdit),
591 getUserPatternCategories: () => (getUserPatternCategories),
592 getUserQueryResults: () => (getUserQueryResults),
593 hasEditsForEntityRecord: () => (hasEditsForEntityRecord),
594 hasEntityRecords: () => (hasEntityRecords),
595 hasFetchedAutosaves: () => (hasFetchedAutosaves),
596 hasRedo: () => (hasRedo),
597 hasUndo: () => (hasUndo),
598 isAutosavingEntityRecord: () => (isAutosavingEntityRecord),
599 isDeletingEntityRecord: () => (isDeletingEntityRecord),
600 isPreviewEmbedFallback: () => (isPreviewEmbedFallback),
601 isRequestingEmbedPreview: () => (isRequestingEmbedPreview),
602 isSavingEntityRecord: () => (isSavingEntityRecord)
603 });
604
605 // NAMESPACE OBJECT: ./packages/core-data/build-module/private-selectors.js
606 var private_selectors_namespaceObject = {};
607 __webpack_require__.r(private_selectors_namespaceObject);
608 __webpack_require__.d(private_selectors_namespaceObject, {
609 getBlockPatternsForPostType: () => (getBlockPatternsForPostType),
610 getNavigationFallbackId: () => (getNavigationFallbackId),
611 getUndoManager: () => (getUndoManager)
612 });
613
614 // NAMESPACE OBJECT: ./packages/core-data/build-module/resolvers.js
615 var resolvers_namespaceObject = {};
616 __webpack_require__.r(resolvers_namespaceObject);
617 __webpack_require__.d(resolvers_namespaceObject, {
618 __experimentalGetCurrentGlobalStylesId: () => (resolvers_experimentalGetCurrentGlobalStylesId),
619 __experimentalGetCurrentThemeBaseGlobalStyles: () => (resolvers_experimentalGetCurrentThemeBaseGlobalStyles),
620 __experimentalGetCurrentThemeGlobalStylesVariations: () => (resolvers_experimentalGetCurrentThemeGlobalStylesVariations),
621 __experimentalGetTemplateForLink: () => (resolvers_experimentalGetTemplateForLink),
622 canUser: () => (resolvers_canUser),
623 canUserEditEntityRecord: () => (resolvers_canUserEditEntityRecord),
624 getAuthors: () => (resolvers_getAuthors),
625 getAutosave: () => (resolvers_getAutosave),
626 getAutosaves: () => (resolvers_getAutosaves),
627 getBlockPatternCategories: () => (resolvers_getBlockPatternCategories),
628 getBlockPatterns: () => (resolvers_getBlockPatterns),
629 getCurrentTheme: () => (resolvers_getCurrentTheme),
630 getCurrentThemeGlobalStylesRevisions: () => (resolvers_getCurrentThemeGlobalStylesRevisions),
631 getCurrentUser: () => (resolvers_getCurrentUser),
632 getDefaultTemplateId: () => (resolvers_getDefaultTemplateId),
633 getEditedEntityRecord: () => (resolvers_getEditedEntityRecord),
634 getEmbedPreview: () => (resolvers_getEmbedPreview),
635 getEntityRecord: () => (resolvers_getEntityRecord),
636 getEntityRecords: () => (resolvers_getEntityRecords),
637 getNavigationFallbackId: () => (resolvers_getNavigationFallbackId),
638 getRawEntityRecord: () => (resolvers_getRawEntityRecord),
639 getRevision: () => (resolvers_getRevision),
640 getRevisions: () => (resolvers_getRevisions),
641 getThemeSupports: () => (resolvers_getThemeSupports),
642 getUserPatternCategories: () => (resolvers_getUserPatternCategories)
643 });
644
645 ;// CONCATENATED MODULE: external ["wp","data"]
646 const external_wp_data_namespaceObject = window["wp"]["data"];
647 // EXTERNAL MODULE: ./node_modules/fast-deep-equal/es6/index.js
648 var es6 = __webpack_require__(5619);
649 var es6_default = /*#__PURE__*/__webpack_require__.n(es6);
650 ;// CONCATENATED MODULE: external ["wp","compose"]
651 const external_wp_compose_namespaceObject = window["wp"]["compose"];
652 ;// CONCATENATED MODULE: external ["wp","isShallowEqual"]
653 const external_wp_isShallowEqual_namespaceObject = window["wp"]["isShallowEqual"];
654 var external_wp_isShallowEqual_default = /*#__PURE__*/__webpack_require__.n(external_wp_isShallowEqual_namespaceObject);
655 ;// CONCATENATED MODULE: ./packages/undo-manager/build-module/index.js
656 /**
657 * WordPress dependencies
658 */
659
660
661 /** @typedef {import('./types').HistoryRecord} HistoryRecord */
662 /** @typedef {import('./types').HistoryChange} HistoryChange */
663 /** @typedef {import('./types').HistoryChanges} HistoryChanges */
664 /** @typedef {import('./types').UndoManager} UndoManager */
665
666 /**
667 * Merge changes for a single item into a record of changes.
668 *
669 * @param {Record< string, HistoryChange >} changes1 Previous changes
670 * @param {Record< string, HistoryChange >} changes2 NextChanges
671 *
672 * @return {Record< string, HistoryChange >} Merged changes
673 */
674 function mergeHistoryChanges(changes1, changes2) {
675 /**
676 * @type {Record< string, HistoryChange >}
677 */
678 const newChanges = {
679 ...changes1
680 };
681 Object.entries(changes2).forEach(([key, value]) => {
682 if (newChanges[key]) {
683 newChanges[key] = {
684 ...newChanges[key],
685 to: value.to
686 };
687 } else {
688 newChanges[key] = value;
689 }
690 });
691 return newChanges;
692 }
693
694 /**
695 * Adds history changes for a single item into a record of changes.
696 *
697 * @param {HistoryRecord} record The record to merge into.
698 * @param {HistoryChanges} changes The changes to merge.
699 */
700 const addHistoryChangesIntoRecord = (record, changes) => {
701 const existingChangesIndex = record?.findIndex(({
702 id: recordIdentifier
703 }) => {
704 return typeof recordIdentifier === 'string' ? recordIdentifier === changes.id : external_wp_isShallowEqual_default()(recordIdentifier, changes.id);
705 });
706 const nextRecord = [...record];
707 if (existingChangesIndex !== -1) {
708 // If the edit is already in the stack leave the initial "from" value.
709 nextRecord[existingChangesIndex] = {
710 id: changes.id,
711 changes: mergeHistoryChanges(nextRecord[existingChangesIndex].changes, changes.changes)
712 };
713 } else {
714 nextRecord.push(changes);
715 }
716 return nextRecord;
717 };
718
719 /**
720 * Creates an undo manager.
721 *
722 * @return {UndoManager} Undo manager.
723 */
724 function createUndoManager() {
725 /**
726 * @type {HistoryRecord[]}
727 */
728 let history = [];
729 /**
730 * @type {HistoryRecord}
731 */
732 let stagedRecord = [];
733 /**
734 * @type {number}
735 */
736 let offset = 0;
737 const dropPendingRedos = () => {
738 history = history.slice(0, offset || undefined);
739 offset = 0;
740 };
741 const appendStagedRecordToLatestHistoryRecord = () => {
742 var _history$index;
743 const index = history.length === 0 ? 0 : history.length - 1;
744 let latestRecord = (_history$index = history[index]) !== null && _history$index !== void 0 ? _history$index : [];
745 stagedRecord.forEach(changes => {
746 latestRecord = addHistoryChangesIntoRecord(latestRecord, changes);
747 });
748 stagedRecord = [];
749 history[index] = latestRecord;
750 };
751
752 /**
753 * Checks whether a record is empty.
754 * A record is considered empty if it the changes keep the same values.
755 * Also updates to function values are ignored.
756 *
757 * @param {HistoryRecord} record
758 * @return {boolean} Whether the record is empty.
759 */
760 const isRecordEmpty = record => {
761 const filteredRecord = record.filter(({
762 changes
763 }) => {
764 return Object.values(changes).some(({
765 from,
766 to
767 }) => typeof from !== 'function' && typeof to !== 'function' && !external_wp_isShallowEqual_default()(from, to));
768 });
769 return !filteredRecord.length;
770 };
771 return {
772 /**
773 * Record changes into the history.
774 *
775 * @param {HistoryRecord=} record A record of changes to record.
776 * @param {boolean} isStaged Whether to immediately create an undo point or not.
777 */
778 addRecord(record, isStaged = false) {
779 const isEmpty = !record || isRecordEmpty(record);
780 if (isStaged) {
781 if (isEmpty) {
782 return;
783 }
784 record.forEach(changes => {
785 stagedRecord = addHistoryChangesIntoRecord(stagedRecord, changes);
786 });
787 } else {
788 dropPendingRedos();
789 if (stagedRecord.length) {
790 appendStagedRecordToLatestHistoryRecord();
791 }
792 if (isEmpty) {
793 return;
794 }
795 history.push(record);
796 }
797 },
798 undo() {
799 if (stagedRecord.length) {
800 dropPendingRedos();
801 appendStagedRecordToLatestHistoryRecord();
802 }
803 const undoRecord = history[history.length - 1 + offset];
804 if (!undoRecord) {
805 return;
806 }
807 offset -= 1;
808 return undoRecord;
809 },
810 redo() {
811 const redoRecord = history[history.length + offset];
812 if (!redoRecord) {
813 return;
814 }
815 offset += 1;
816 return redoRecord;
817 },
818 hasUndo() {
819 return !!history[history.length - 1 + offset];
820 },
821 hasRedo() {
822 return !!history[history.length + offset];
823 }
824 };
825 }
826
827 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/if-matching-action.js
828 /** @typedef {import('../types').AnyFunction} AnyFunction */
829
830 /**
831 * A higher-order reducer creator which invokes the original reducer only if
832 * the dispatching action matches the given predicate, **OR** if state is
833 * initializing (undefined).
834 *
835 * @param {AnyFunction} isMatch Function predicate for allowing reducer call.
836 *
837 * @return {AnyFunction} Higher-order reducer.
838 */
839 const ifMatchingAction = isMatch => reducer => (state, action) => {
840 if (state === undefined || isMatch(action)) {
841 return reducer(state, action);
842 }
843 return state;
844 };
845 /* harmony default export */ const if_matching_action = (ifMatchingAction);
846
847 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/replace-action.js
848 /** @typedef {import('../types').AnyFunction} AnyFunction */
849
850 /**
851 * Higher-order reducer creator which substitutes the action object before
852 * passing to the original reducer.
853 *
854 * @param {AnyFunction} replacer Function mapping original action to replacement.
855 *
856 * @return {AnyFunction} Higher-order reducer.
857 */
858 const replaceAction = replacer => reducer => (state, action) => {
859 return reducer(state, replacer(action));
860 };
861 /* harmony default export */ const replace_action = (replaceAction);
862
863 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/conservative-map-item.js
864 /**
865 * External dependencies
866 */
867
868
869 /**
870 * Given the current and next item entity record, returns the minimally "modified"
871 * result of the next item, preferring value references from the original item
872 * if equal. If all values match, the original item is returned.
873 *
874 * @param {Object} item Original item.
875 * @param {Object} nextItem Next item.
876 *
877 * @return {Object} Minimally modified merged item.
878 */
879 function conservativeMapItem(item, nextItem) {
880 // Return next item in its entirety if there is no original item.
881 if (!item) {
882 return nextItem;
883 }
884 let hasChanges = false;
885 const result = {};
886 for (const key in nextItem) {
887 if (es6_default()(item[key], nextItem[key])) {
888 result[key] = item[key];
889 } else {
890 hasChanges = true;
891 result[key] = nextItem[key];
892 }
893 }
894 if (!hasChanges) {
895 return item;
896 }
897
898 // Only at this point, backfill properties from the original item which
899 // weren't explicitly set into the result above. This is an optimization
900 // to allow `hasChanges` to return early.
901 for (const key in item) {
902 if (!result.hasOwnProperty(key)) {
903 result[key] = item[key];
904 }
905 }
906 return result;
907 }
908
909 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/on-sub-key.js
910 /** @typedef {import('../types').AnyFunction} AnyFunction */
911
912 /**
913 * Higher-order reducer creator which creates a combined reducer object, keyed
914 * by a property on the action object.
915 *
916 * @param {string} actionProperty Action property by which to key object.
917 *
918 * @return {AnyFunction} Higher-order reducer.
919 */
920 const onSubKey = actionProperty => reducer => (state = {}, action) => {
921 // Retrieve subkey from action. Do not track if undefined; useful for cases
922 // where reducer is scoped by action shape.
923 const key = action[actionProperty];
924 if (key === undefined) {
925 return state;
926 }
927
928 // Avoid updating state if unchanged. Note that this also accounts for a
929 // reducer which returns undefined on a key which is not yet tracked.
930 const nextKeyState = reducer(state[key], action);
931 if (nextKeyState === state[key]) {
932 return state;
933 }
934 return {
935 ...state,
936 [key]: nextKeyState
937 };
938 };
939 /* harmony default export */ const on_sub_key = (onSubKey);
940
941 ;// CONCATENATED MODULE: ./node_modules/tslib/tslib.es6.mjs
942 /******************************************************************************
943 Copyright (c) Microsoft Corporation.
944
945 Permission to use, copy, modify, and/or distribute this software for any
946 purpose with or without fee is hereby granted.
947
948 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
949 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
950 AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
951 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
952 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
953 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
954 PERFORMANCE OF THIS SOFTWARE.
955 ***************************************************************************** */
956 /* global Reflect, Promise, SuppressedError, Symbol */
957
958 var extendStatics = function(d, b) {
959 extendStatics = Object.setPrototypeOf ||
960 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
961 function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
962 return extendStatics(d, b);
963 };
964
965 function __extends(d, b) {
966 if (typeof b !== "function" && b !== null)
967 throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
968 extendStatics(d, b);
969 function __() { this.constructor = d; }
970 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
971 }
972
973 var __assign = function() {
974 __assign = Object.assign || function __assign(t) {
975 for (var s, i = 1, n = arguments.length; i < n; i++) {
976 s = arguments[i];
977 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
978 }
979 return t;
980 }
981 return __assign.apply(this, arguments);
982 }
983
984 function __rest(s, e) {
985 var t = {};
986 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
987 t[p] = s[p];
988 if (s != null && typeof Object.getOwnPropertySymbols === "function")
989 for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
990 if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
991 t[p[i]] = s[p[i]];
992 }
993 return t;
994 }
995
996 function __decorate(decorators, target, key, desc) {
997 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
998 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
999 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;
1000 return c > 3 && r && Object.defineProperty(target, key, r), r;
1001 }
1002
1003 function __param(paramIndex, decorator) {
1004 return function (target, key) { decorator(target, key, paramIndex); }
1005 }
1006
1007 function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
1008 function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
1009 var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
1010 var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
1011 var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
1012 var _, done = false;
1013 for (var i = decorators.length - 1; i >= 0; i--) {
1014 var context = {};
1015 for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
1016 for (var p in contextIn.access) context.access[p] = contextIn.access[p];
1017 context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
1018 var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
1019 if (kind === "accessor") {
1020 if (result === void 0) continue;
1021 if (result === null || typeof result !== "object") throw new TypeError("Object expected");
1022 if (_ = accept(result.get)) descriptor.get = _;
1023 if (_ = accept(result.set)) descriptor.set = _;
1024 if (_ = accept(result.init)) initializers.unshift(_);
1025 }
1026 else if (_ = accept(result)) {
1027 if (kind === "field") initializers.unshift(_);
1028 else descriptor[key] = _;
1029 }
1030 }
1031 if (target) Object.defineProperty(target, contextIn.name, descriptor);
1032 done = true;
1033 };
1034
1035 function __runInitializers(thisArg, initializers, value) {
1036 var useValue = arguments.length > 2;
1037 for (var i = 0; i < initializers.length; i++) {
1038 value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
1039 }
1040 return useValue ? value : void 0;
1041 };
1042
1043 function __propKey(x) {
1044 return typeof x === "symbol" ? x : "".concat(x);
1045 };
1046
1047 function __setFunctionName(f, name, prefix) {
1048 if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
1049 return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
1050 };
1051
1052 function __metadata(metadataKey, metadataValue) {
1053 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
1054 }
1055
1056 function __awaiter(thisArg, _arguments, P, generator) {
1057 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1058 return new (P || (P = Promise))(function (resolve, reject) {
1059 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1060 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1061 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1062 step((generator = generator.apply(thisArg, _arguments || [])).next());
1063 });
1064 }
1065
1066 function __generator(thisArg, body) {
1067 var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
1068 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
1069 function verb(n) { return function (v) { return step([n, v]); }; }
1070 function step(op) {
1071 if (f) throw new TypeError("Generator is already executing.");
1072 while (g && (g = 0, op[0] && (_ = 0)), _) try {
1073 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;
1074 if (y = 0, t) op = [op[0] & 2, t.value];
1075 switch (op[0]) {
1076 case 0: case 1: t = op; break;
1077 case 4: _.label++; return { value: op[1], done: false };
1078 case 5: _.label++; y = op[1]; op = [0]; continue;
1079 case 7: op = _.ops.pop(); _.trys.pop(); continue;
1080 default:
1081 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
1082 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
1083 if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
1084 if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
1085 if (t[2]) _.ops.pop();
1086 _.trys.pop(); continue;
1087 }
1088 op = body.call(thisArg, _);
1089 } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
1090 if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
1091 }
1092 }
1093
1094 var __createBinding = Object.create ? (function(o, m, k, k2) {
1095 if (k2 === undefined) k2 = k;
1096 var desc = Object.getOwnPropertyDescriptor(m, k);
1097 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1098 desc = { enumerable: true, get: function() { return m[k]; } };
1099 }
1100 Object.defineProperty(o, k2, desc);
1101 }) : (function(o, m, k, k2) {
1102 if (k2 === undefined) k2 = k;
1103 o[k2] = m[k];
1104 });
1105
1106 function __exportStar(m, o) {
1107 for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);
1108 }
1109
1110 function __values(o) {
1111 var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
1112 if (m) return m.call(o);
1113 if (o && typeof o.length === "number") return {
1114 next: function () {
1115 if (o && i >= o.length) o = void 0;
1116 return { value: o && o[i++], done: !o };
1117 }
1118 };
1119 throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
1120 }
1121
1122 function __read(o, n) {
1123 var m = typeof Symbol === "function" && o[Symbol.iterator];
1124 if (!m) return o;
1125 var i = m.call(o), r, ar = [], e;
1126 try {
1127 while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
1128 }
1129 catch (error) { e = { error: error }; }
1130 finally {
1131 try {
1132 if (r && !r.done && (m = i["return"])) m.call(i);
1133 }
1134 finally { if (e) throw e.error; }
1135 }
1136 return ar;
1137 }
1138
1139 /** @deprecated */
1140 function __spread() {
1141 for (var ar = [], i = 0; i < arguments.length; i++)
1142 ar = ar.concat(__read(arguments[i]));
1143 return ar;
1144 }
1145
1146 /** @deprecated */
1147 function __spreadArrays() {
1148 for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
1149 for (var r = Array(s), k = 0, i = 0; i < il; i++)
1150 for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
1151 r[k] = a[j];
1152 return r;
1153 }
1154
1155 function __spreadArray(to, from, pack) {
1156 if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
1157 if (ar || !(i in from)) {
1158 if (!ar) ar = Array.prototype.slice.call(from, 0, i);
1159 ar[i] = from[i];
1160 }
1161 }
1162 return to.concat(ar || Array.prototype.slice.call(from));
1163 }
1164
1165 function __await(v) {
1166 return this instanceof __await ? (this.v = v, this) : new __await(v);
1167 }
1168
1169 function __asyncGenerator(thisArg, _arguments, generator) {
1170 if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
1171 var g = generator.apply(thisArg, _arguments || []), i, q = [];
1172 return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
1173 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); }); }; }
1174 function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
1175 function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
1176 function fulfill(value) { resume("next", value); }
1177 function reject(value) { resume("throw", value); }
1178 function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
1179 }
1180
1181 function __asyncDelegator(o) {
1182 var i, p;
1183 return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
1184 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; }
1185 }
1186
1187 function __asyncValues(o) {
1188 if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
1189 var m = o[Symbol.asyncIterator], i;
1190 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);
1191 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); }); }; }
1192 function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
1193 }
1194
1195 function __makeTemplateObject(cooked, raw) {
1196 if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
1197 return cooked;
1198 };
1199
1200 var __setModuleDefault = Object.create ? (function(o, v) {
1201 Object.defineProperty(o, "default", { enumerable: true, value: v });
1202 }) : function(o, v) {
1203 o["default"] = v;
1204 };
1205
1206 function __importStar(mod) {
1207 if (mod && mod.__esModule) return mod;
1208 var result = {};
1209 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
1210 __setModuleDefault(result, mod);
1211 return result;
1212 }
1213
1214 function __importDefault(mod) {
1215 return (mod && mod.__esModule) ? mod : { default: mod };
1216 }
1217
1218 function __classPrivateFieldGet(receiver, state, kind, f) {
1219 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
1220 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");
1221 return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
1222 }
1223
1224 function __classPrivateFieldSet(receiver, state, value, kind, f) {
1225 if (kind === "m") throw new TypeError("Private method is not writable");
1226 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
1227 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");
1228 return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
1229 }
1230
1231 function __classPrivateFieldIn(state, receiver) {
1232 if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object");
1233 return typeof state === "function" ? receiver === state : state.has(receiver);
1234 }
1235
1236 function __addDisposableResource(env, value, async) {
1237 if (value !== null && value !== void 0) {
1238 if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
1239 var dispose;
1240 if (async) {
1241 if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
1242 dispose = value[Symbol.asyncDispose];
1243 }
1244 if (dispose === void 0) {
1245 if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
1246 dispose = value[Symbol.dispose];
1247 }
1248 if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
1249 env.stack.push({ value: value, dispose: dispose, async: async });
1250 }
1251 else if (async) {
1252 env.stack.push({ async: true });
1253 }
1254 return value;
1255 }
1256
1257 var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1258 var e = new Error(message);
1259 return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1260 };
1261
1262 function __disposeResources(env) {
1263 function fail(e) {
1264 env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
1265 env.hasError = true;
1266 }
1267 function next() {
1268 while (env.stack.length) {
1269 var rec = env.stack.pop();
1270 try {
1271 var result = rec.dispose && rec.dispose.call(rec.value);
1272 if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
1273 }
1274 catch (e) {
1275 fail(e);
1276 }
1277 }
1278 if (env.hasError) throw env.error;
1279 }
1280 return next();
1281 }
1282
1283 /* harmony default export */ const tslib_es6 = ({
1284 __extends,
1285 __assign,
1286 __rest,
1287 __decorate,
1288 __param,
1289 __metadata,
1290 __awaiter,
1291 __generator,
1292 __createBinding,
1293 __exportStar,
1294 __values,
1295 __read,
1296 __spread,
1297 __spreadArrays,
1298 __spreadArray,
1299 __await,
1300 __asyncGenerator,
1301 __asyncDelegator,
1302 __asyncValues,
1303 __makeTemplateObject,
1304 __importStar,
1305 __importDefault,
1306 __classPrivateFieldGet,
1307 __classPrivateFieldSet,
1308 __classPrivateFieldIn,
1309 __addDisposableResource,
1310 __disposeResources,
1311 });
1312
1313 ;// CONCATENATED MODULE: ./node_modules/lower-case/dist.es2015/index.js
1314 /**
1315 * Source: ftp://ftp.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt
1316 */
1317 var SUPPORTED_LOCALE = {
1318 tr: {
1319 regexp: /\u0130|\u0049|\u0049\u0307/g,
1320 map: {
1321 İ: "\u0069",
1322 I: "\u0131",
1323 İ: "\u0069",
1324 },
1325 },
1326 az: {
1327 regexp: /\u0130/g,
1328 map: {
1329 İ: "\u0069",
1330 I: "\u0131",
1331 İ: "\u0069",
1332 },
1333 },
1334 lt: {
1335 regexp: /\u0049|\u004A|\u012E|\u00CC|\u00CD|\u0128/g,
1336 map: {
1337 I: "\u0069\u0307",
1338 J: "\u006A\u0307",
1339 Į: "\u012F\u0307",
1340 Ì: "\u0069\u0307\u0300",
1341 Í: "\u0069\u0307\u0301",
1342 Ĩ: "\u0069\u0307\u0303",
1343 },
1344 },
1345 };
1346 /**
1347 * Localized lower case.
1348 */
1349 function localeLowerCase(str, locale) {
1350 var lang = SUPPORTED_LOCALE[locale.toLowerCase()];
1351 if (lang)
1352 return lowerCase(str.replace(lang.regexp, function (m) { return lang.map[m]; }));
1353 return lowerCase(str);
1354 }
1355 /**
1356 * Lower case as a function.
1357 */
1358 function lowerCase(str) {
1359 return str.toLowerCase();
1360 }
1361
1362 ;// CONCATENATED MODULE: ./node_modules/no-case/dist.es2015/index.js
1363
1364 // Support camel case ("camelCase" -> "camel Case" and "CAMELCase" -> "CAMEL Case").
1365 var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g];
1366 // Remove all non-word characters.
1367 var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;
1368 /**
1369 * Normalize the string into something other libraries can manipulate easier.
1370 */
1371 function noCase(input, options) {
1372 if (options === void 0) { options = {}; }
1373 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;
1374 var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0");
1375 var start = 0;
1376 var end = result.length;
1377 // Trim the delimiter from around the output string.
1378 while (result.charAt(start) === "\0")
1379 start++;
1380 while (result.charAt(end - 1) === "\0")
1381 end--;
1382 // Transform each token independently.
1383 return result.slice(start, end).split("\0").map(transform).join(delimiter);
1384 }
1385 /**
1386 * Replace `re` in the input string with the replacement value.
1387 */
1388 function replace(input, re, value) {
1389 if (re instanceof RegExp)
1390 return input.replace(re, value);
1391 return re.reduce(function (input, re) { return input.replace(re, value); }, input);
1392 }
1393
1394 ;// CONCATENATED MODULE: ./node_modules/upper-case-first/dist.es2015/index.js
1395 /**
1396 * Upper case the first character of an input string.
1397 */
1398 function upperCaseFirst(input) {
1399 return input.charAt(0).toUpperCase() + input.substr(1);
1400 }
1401
1402 ;// CONCATENATED MODULE: ./node_modules/capital-case/dist.es2015/index.js
1403
1404
1405
1406 function capitalCaseTransform(input) {
1407 return upperCaseFirst(input.toLowerCase());
1408 }
1409 function capitalCase(input, options) {
1410 if (options === void 0) { options = {}; }
1411 return noCase(input, __assign({ delimiter: " ", transform: capitalCaseTransform }, options));
1412 }
1413
1414 ;// CONCATENATED MODULE: ./node_modules/pascal-case/dist.es2015/index.js
1415
1416
1417 function pascalCaseTransform(input, index) {
1418 var firstChar = input.charAt(0);
1419 var lowerChars = input.substr(1).toLowerCase();
1420 if (index > 0 && firstChar >= "0" && firstChar <= "9") {
1421 return "_" + firstChar + lowerChars;
1422 }
1423 return "" + firstChar.toUpperCase() + lowerChars;
1424 }
1425 function dist_es2015_pascalCaseTransformMerge(input) {
1426 return input.charAt(0).toUpperCase() + input.slice(1).toLowerCase();
1427 }
1428 function pascalCase(input, options) {
1429 if (options === void 0) { options = {}; }
1430 return noCase(input, __assign({ delimiter: "", transform: pascalCaseTransform }, options));
1431 }
1432
1433 ;// CONCATENATED MODULE: external ["wp","apiFetch"]
1434 const external_wp_apiFetch_namespaceObject = window["wp"]["apiFetch"];
1435 var external_wp_apiFetch_default = /*#__PURE__*/__webpack_require__.n(external_wp_apiFetch_namespaceObject);
1436 ;// CONCATENATED MODULE: external ["wp","i18n"]
1437 const external_wp_i18n_namespaceObject = window["wp"]["i18n"];
1438 ;// CONCATENATED MODULE: external ["wp","richText"]
1439 const external_wp_richText_namespaceObject = window["wp"]["richText"];
1440 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/rng.js
1441 // Unique ID creation requires a high quality random # generator. In the browser we therefore
1442 // require the crypto API and do not support built-in fallback to lower quality random number
1443 // generators (like Math.random()).
1444 var rng_getRandomValues;
1445 var rnds8 = new Uint8Array(16);
1446 function rng() {
1447 // lazy load so that environments that need to polyfill have a chance to do so
1448 if (!rng_getRandomValues) {
1449 // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also,
1450 // find the complete implementation of crypto (msCrypto) on IE11.
1451 rng_getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto);
1452
1453 if (!rng_getRandomValues) {
1454 throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
1455 }
1456 }
1457
1458 return rng_getRandomValues(rnds8);
1459 }
1460 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/regex.js
1461 /* harmony default export */ const regex = (/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i);
1462 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/validate.js
1463
1464
1465 function validate(uuid) {
1466 return typeof uuid === 'string' && regex.test(uuid);
1467 }
1468
1469 /* harmony default export */ const esm_browser_validate = (validate);
1470 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/stringify.js
1471
1472 /**
1473 * Convert array of 16 byte values to UUID string format of the form:
1474 * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
1475 */
1476
1477 var byteToHex = [];
1478
1479 for (var i = 0; i < 256; ++i) {
1480 byteToHex.push((i + 0x100).toString(16).substr(1));
1481 }
1482
1483 function stringify(arr) {
1484 var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
1485 // Note: Be careful editing this code! It's been tuned for performance
1486 // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
1487 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
1488 // of the following:
1489 // - One or more input array values don't map to a hex octet (leading to
1490 // "undefined" in the uuid)
1491 // - Invalid input values for the RFC `version` or `variant` fields
1492
1493 if (!esm_browser_validate(uuid)) {
1494 throw TypeError('Stringified UUID is invalid');
1495 }
1496
1497 return uuid;
1498 }
1499
1500 /* harmony default export */ const esm_browser_stringify = (stringify);
1501 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/v4.js
1502
1503
1504
1505 function v4(options, buf, offset) {
1506 options = options || {};
1507 var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
1508
1509 rnds[6] = rnds[6] & 0x0f | 0x40;
1510 rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
1511
1512 if (buf) {
1513 offset = offset || 0;
1514
1515 for (var i = 0; i < 16; ++i) {
1516 buf[offset + i] = rnds[i];
1517 }
1518
1519 return buf;
1520 }
1521
1522 return esm_browser_stringify(rnds);
1523 }
1524
1525 /* harmony default export */ const esm_browser_v4 = (v4);
1526 ;// CONCATENATED MODULE: external ["wp","url"]
1527 const external_wp_url_namespaceObject = window["wp"]["url"];
1528 ;// CONCATENATED MODULE: external ["wp","deprecated"]
1529 const external_wp_deprecated_namespaceObject = window["wp"]["deprecated"];
1530 var external_wp_deprecated_default = /*#__PURE__*/__webpack_require__.n(external_wp_deprecated_namespaceObject);
1531 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/set-nested-value.js
1532 /**
1533 * Sets the value at path of object.
1534 * If a portion of path doesn’t exist, it’s created.
1535 * Arrays are created for missing index properties while objects are created
1536 * for all other missing properties.
1537 *
1538 * Path is specified as either:
1539 * - a string of properties, separated by dots, for example: "x.y".
1540 * - an array of properties, for example `[ 'x', 'y' ]`.
1541 *
1542 * This function intentionally mutates the input object.
1543 *
1544 * Inspired by _.set().
1545 *
1546 * @see https://lodash.com/docs/4.17.15#set
1547 *
1548 * @todo Needs to be deduplicated with its copy in `@wordpress/edit-site`.
1549 *
1550 * @param {Object} object Object to modify
1551 * @param {Array|string} path Path of the property to set.
1552 * @param {*} value Value to set.
1553 */
1554 function setNestedValue(object, path, value) {
1555 if (!object || typeof object !== 'object') {
1556 return object;
1557 }
1558 const normalizedPath = Array.isArray(path) ? path : path.split('.');
1559 normalizedPath.reduce((acc, key, idx) => {
1560 if (acc[key] === undefined) {
1561 if (Number.isInteger(normalizedPath[idx + 1])) {
1562 acc[key] = [];
1563 } else {
1564 acc[key] = {};
1565 }
1566 }
1567 if (idx === normalizedPath.length - 1) {
1568 acc[key] = value;
1569 }
1570 return acc[key];
1571 }, object);
1572 return object;
1573 }
1574
1575 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/get-nested-value.js
1576 /**
1577 * Helper util to return a value from a certain path of the object.
1578 * Path is specified as either:
1579 * - a string of properties, separated by dots, for example: "x.y".
1580 * - an array of properties, for example `[ 'x', 'y' ]`.
1581 * You can also specify a default value in case the result is nullish.
1582 *
1583 * @param {Object} object Input object.
1584 * @param {string|Array} path Path to the object property.
1585 * @param {*} defaultValue Default value if the value at the specified path is undefined.
1586 * @return {*} Value of the object property at the specified path.
1587 */
1588 function getNestedValue(object, path, defaultValue) {
1589 if (!object || typeof object !== 'object' || typeof path !== 'string' && !Array.isArray(path)) {
1590 return object;
1591 }
1592 const normalizedPath = Array.isArray(path) ? path : path.split('.');
1593 let value = object;
1594 normalizedPath.forEach(fieldName => {
1595 value = value?.[fieldName];
1596 });
1597 return value !== undefined ? value : defaultValue;
1598 }
1599
1600 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/actions.js
1601 /**
1602 * Returns an action object used in signalling that items have been received.
1603 *
1604 * @param {Array} items Items received.
1605 * @param {?Object} edits Optional edits to reset.
1606 * @param {?Object} meta Meta information about pagination.
1607 *
1608 * @return {Object} Action object.
1609 */
1610 function receiveItems(items, edits, meta) {
1611 return {
1612 type: 'RECEIVE_ITEMS',
1613 items: Array.isArray(items) ? items : [items],
1614 persistedEdits: edits,
1615 meta
1616 };
1617 }
1618
1619 /**
1620 * Returns an action object used in signalling that entity records have been
1621 * deleted and they need to be removed from entities state.
1622 *
1623 * @param {string} kind Kind of the removed entities.
1624 * @param {string} name Name of the removed entities.
1625 * @param {Array|number|string} records Record IDs of the removed entities.
1626 * @param {boolean} invalidateCache Controls whether we want to invalidate the cache.
1627 * @return {Object} Action object.
1628 */
1629 function removeItems(kind, name, records, invalidateCache = false) {
1630 return {
1631 type: 'REMOVE_ITEMS',
1632 itemIds: Array.isArray(records) ? records : [records],
1633 kind,
1634 name,
1635 invalidateCache
1636 };
1637 }
1638
1639 /**
1640 * Returns an action object used in signalling that queried data has been
1641 * received.
1642 *
1643 * @param {Array} items Queried items received.
1644 * @param {?Object} query Optional query object.
1645 * @param {?Object} edits Optional edits to reset.
1646 * @param {?Object} meta Meta information about pagination.
1647 *
1648 * @return {Object} Action object.
1649 */
1650 function receiveQueriedItems(items, query = {}, edits, meta) {
1651 return {
1652 ...receiveItems(items, edits, meta),
1653 query
1654 };
1655 }
1656
1657 ;// CONCATENATED MODULE: ./packages/core-data/build-module/batch/default-processor.js
1658 /**
1659 * WordPress dependencies
1660 */
1661
1662
1663 /**
1664 * Maximum number of requests to place in a single batch request. Obtained by
1665 * sending a preflight OPTIONS request to /batch/v1/.
1666 *
1667 * @type {number?}
1668 */
1669 let maxItems = null;
1670 function chunk(arr, chunkSize) {
1671 const tmp = [...arr];
1672 const cache = [];
1673 while (tmp.length) {
1674 cache.push(tmp.splice(0, chunkSize));
1675 }
1676 return cache;
1677 }
1678
1679 /**
1680 * Default batch processor. Sends its input requests to /batch/v1.
1681 *
1682 * @param {Array} requests List of API requests to perform at once.
1683 *
1684 * @return {Promise} Promise that resolves to a list of objects containing
1685 * either `output` (if that request was successful) or `error`
1686 * (if not ).
1687 */
1688 async function defaultProcessor(requests) {
1689 if (maxItems === null) {
1690 const preflightResponse = await external_wp_apiFetch_default()({
1691 path: '/batch/v1',
1692 method: 'OPTIONS'
1693 });
1694 maxItems = preflightResponse.endpoints[0].args.requests.maxItems;
1695 }
1696 const results = [];
1697
1698 // @ts-ignore We would have crashed or never gotten to this point if we hadn't received the maxItems count.
1699 for (const batchRequests of chunk(requests, maxItems)) {
1700 const batchResponse = await external_wp_apiFetch_default()({
1701 path: '/batch/v1',
1702 method: 'POST',
1703 data: {
1704 validation: 'require-all-validate',
1705 requests: batchRequests.map(request => ({
1706 path: request.path,
1707 body: request.data,
1708 // Rename 'data' to 'body'.
1709 method: request.method,
1710 headers: request.headers
1711 }))
1712 }
1713 });
1714 let batchResults;
1715 if (batchResponse.failed) {
1716 batchResults = batchResponse.responses.map(response => ({
1717 error: response?.body
1718 }));
1719 } else {
1720 batchResults = batchResponse.responses.map(response => {
1721 const result = {};
1722 if (response.status >= 200 && response.status < 300) {
1723 result.output = response.body;
1724 } else {
1725 result.error = response.body;
1726 }
1727 return result;
1728 });
1729 }
1730 results.push(...batchResults);
1731 }
1732 return results;
1733 }
1734
1735 ;// CONCATENATED MODULE: ./packages/core-data/build-module/batch/create-batch.js
1736 /**
1737 * Internal dependencies
1738 */
1739
1740
1741 /**
1742 * Creates a batch, which can be used to combine multiple API requests into one
1743 * API request using the WordPress batch processing API (/v1/batch).
1744 *
1745 * ```
1746 * const batch = createBatch();
1747 * const dunePromise = batch.add( {
1748 * path: '/v1/books',
1749 * method: 'POST',
1750 * data: { title: 'Dune' }
1751 * } );
1752 * const lotrPromise = batch.add( {
1753 * path: '/v1/books',
1754 * method: 'POST',
1755 * data: { title: 'Lord of the Rings' }
1756 * } );
1757 * const isSuccess = await batch.run(); // Sends one POST to /v1/batch.
1758 * if ( isSuccess ) {
1759 * console.log(
1760 * 'Saved two books:',
1761 * await dunePromise,
1762 * await lotrPromise
1763 * );
1764 * }
1765 * ```
1766 *
1767 * @param {Function} [processor] Processor function. Can be used to replace the
1768 * default functionality which is to send an API
1769 * request to /v1/batch. Is given an array of
1770 * inputs and must return a promise that
1771 * resolves to an array of objects containing
1772 * either `output` or `error`.
1773 */
1774 function createBatch(processor = defaultProcessor) {
1775 let lastId = 0;
1776 /** @type {Array<{ input: any; resolve: ( value: any ) => void; reject: ( error: any ) => void }>} */
1777 let queue = [];
1778 const pending = new ObservableSet();
1779 return {
1780 /**
1781 * Adds an input to the batch and returns a promise that is resolved or
1782 * rejected when the input is processed by `batch.run()`.
1783 *
1784 * You may also pass a thunk which allows inputs to be added
1785 * asychronously.
1786 *
1787 * ```
1788 * // Both are allowed:
1789 * batch.add( { path: '/v1/books', ... } );
1790 * batch.add( ( add ) => add( { path: '/v1/books', ... } ) );
1791 * ```
1792 *
1793 * If a thunk is passed, `batch.run()` will pause until either:
1794 *
1795 * - The thunk calls its `add` argument, or;
1796 * - The thunk returns a promise and that promise resolves, or;
1797 * - The thunk returns a non-promise.
1798 *
1799 * @param {any|Function} inputOrThunk Input to add or thunk to execute.
1800 *
1801 * @return {Promise|any} If given an input, returns a promise that
1802 * is resolved or rejected when the batch is
1803 * processed. If given a thunk, returns the return
1804 * value of that thunk.
1805 */
1806 add(inputOrThunk) {
1807 const id = ++lastId;
1808 pending.add(id);
1809 const add = input => new Promise((resolve, reject) => {
1810 queue.push({
1811 input,
1812 resolve,
1813 reject
1814 });
1815 pending.delete(id);
1816 });
1817 if (typeof inputOrThunk === 'function') {
1818 return Promise.resolve(inputOrThunk(add)).finally(() => {
1819 pending.delete(id);
1820 });
1821 }
1822 return add(inputOrThunk);
1823 },
1824 /**
1825 * Runs the batch. This calls `batchProcessor` and resolves or rejects
1826 * all promises returned by `add()`.
1827 *
1828 * @return {Promise<boolean>} A promise that resolves to a boolean that is true
1829 * if the processor returned no errors.
1830 */
1831 async run() {
1832 if (pending.size) {
1833 await new Promise(resolve => {
1834 const unsubscribe = pending.subscribe(() => {
1835 if (!pending.size) {
1836 unsubscribe();
1837 resolve(undefined);
1838 }
1839 });
1840 });
1841 }
1842 let results;
1843 try {
1844 results = await processor(queue.map(({
1845 input
1846 }) => input));
1847 if (results.length !== queue.length) {
1848 throw new Error('run: Array returned by processor must be same size as input array.');
1849 }
1850 } catch (error) {
1851 for (const {
1852 reject
1853 } of queue) {
1854 reject(error);
1855 }
1856 throw error;
1857 }
1858 let isSuccess = true;
1859 results.forEach((result, key) => {
1860 const queueItem = queue[key];
1861 if (result?.error) {
1862 queueItem?.reject(result.error);
1863 isSuccess = false;
1864 } else {
1865 var _result$output;
1866 queueItem?.resolve((_result$output = result?.output) !== null && _result$output !== void 0 ? _result$output : result);
1867 }
1868 });
1869 queue = [];
1870 return isSuccess;
1871 }
1872 };
1873 }
1874 class ObservableSet {
1875 constructor(...args) {
1876 this.set = new Set(...args);
1877 this.subscribers = new Set();
1878 }
1879 get size() {
1880 return this.set.size;
1881 }
1882 add(value) {
1883 this.set.add(value);
1884 this.subscribers.forEach(subscriber => subscriber());
1885 return this;
1886 }
1887 delete(value) {
1888 const isSuccess = this.set.delete(value);
1889 this.subscribers.forEach(subscriber => subscriber());
1890 return isSuccess;
1891 }
1892 subscribe(subscriber) {
1893 this.subscribers.add(subscriber);
1894 return () => {
1895 this.subscribers.delete(subscriber);
1896 };
1897 }
1898 }
1899
1900 ;// CONCATENATED MODULE: ./packages/core-data/build-module/name.js
1901 /**
1902 * The reducer key used by core data in store registration.
1903 * This is defined in a separate file to avoid cycle-dependency
1904 *
1905 * @type {string}
1906 */
1907 const STORE_NAME = 'core';
1908
1909 ;// CONCATENATED MODULE: ./node_modules/lib0/map.js
1910 /**
1911 * Utility module to work with key-value stores.
1912 *
1913 * @module map
1914 */
1915
1916 /**
1917 * Creates a new Map instance.
1918 *
1919 * @function
1920 * @return {Map<any, any>}
1921 *
1922 * @function
1923 */
1924 const create = () => new Map()
1925
1926 /**
1927 * Copy a Map object into a fresh Map object.
1928 *
1929 * @function
1930 * @template X,Y
1931 * @param {Map<X,Y>} m
1932 * @return {Map<X,Y>}
1933 */
1934 const copy = m => {
1935 const r = create()
1936 m.forEach((v, k) => { r.set(k, v) })
1937 return r
1938 }
1939
1940 /**
1941 * Get map property. Create T if property is undefined and set T on map.
1942 *
1943 * ```js
1944 * const listeners = map.setIfUndefined(events, 'eventName', set.create)
1945 * listeners.add(listener)
1946 * ```
1947 *
1948 * @function
1949 * @template V,K
1950 * @template {Map<K,V>} MAP
1951 * @param {MAP} map
1952 * @param {K} key
1953 * @param {function():V} createT
1954 * @return {V}
1955 */
1956 const setIfUndefined = (map, key, createT) => {
1957 let set = map.get(key)
1958 if (set === undefined) {
1959 map.set(key, set = createT())
1960 }
1961 return set
1962 }
1963
1964 /**
1965 * Creates an Array and populates it with the content of all key-value pairs using the `f(value, key)` function.
1966 *
1967 * @function
1968 * @template K
1969 * @template V
1970 * @template R
1971 * @param {Map<K,V>} m
1972 * @param {function(V,K):R} f
1973 * @return {Array<R>}
1974 */
1975 const map_map = (m, f) => {
1976 const res = []
1977 for (const [key, value] of m) {
1978 res.push(f(value, key))
1979 }
1980 return res
1981 }
1982
1983 /**
1984 * Tests whether any key-value pairs pass the test implemented by `f(value, key)`.
1985 *
1986 * @todo should rename to some - similarly to Array.some
1987 *
1988 * @function
1989 * @template K
1990 * @template V
1991 * @param {Map<K,V>} m
1992 * @param {function(V,K):boolean} f
1993 * @return {boolean}
1994 */
1995 const any = (m, f) => {
1996 for (const [key, value] of m) {
1997 if (f(value, key)) {
1998 return true
1999 }
2000 }
2001 return false
2002 }
2003
2004 /**
2005 * Tests whether all key-value pairs pass the test implemented by `f(value, key)`.
2006 *
2007 * @function
2008 * @template K
2009 * @template V
2010 * @param {Map<K,V>} m
2011 * @param {function(V,K):boolean} f
2012 * @return {boolean}
2013 */
2014 const map_all = (m, f) => {
2015 for (const [key, value] of m) {
2016 if (!f(value, key)) {
2017 return false
2018 }
2019 }
2020 return true
2021 }
2022
2023 ;// CONCATENATED MODULE: ./node_modules/lib0/set.js
2024 /**
2025 * Utility module to work with sets.
2026 *
2027 * @module set
2028 */
2029
2030 const set_create = () => new Set()
2031
2032 /**
2033 * @template T
2034 * @param {Set<T>} set
2035 * @return {Array<T>}
2036 */
2037 const toArray = set => Array.from(set)
2038
2039 /**
2040 * @template T
2041 * @param {Set<T>} set
2042 * @return {T}
2043 */
2044 const first = set =>
2045 set.values().next().value || undefined
2046
2047 /**
2048 * @template T
2049 * @param {Iterable<T>} entries
2050 * @return {Set<T>}
2051 */
2052 const from = entries => new Set(entries)
2053
2054 ;// CONCATENATED MODULE: ./node_modules/lib0/array.js
2055 /**
2056 * Utility module to work with Arrays.
2057 *
2058 * @module array
2059 */
2060
2061
2062
2063 /**
2064 * Return the last element of an array. The element must exist
2065 *
2066 * @template L
2067 * @param {ArrayLike<L>} arr
2068 * @return {L}
2069 */
2070 const last = arr => arr[arr.length - 1]
2071
2072 /**
2073 * @template C
2074 * @return {Array<C>}
2075 */
2076 const array_create = () => /** @type {Array<C>} */ ([])
2077
2078 /**
2079 * @template D
2080 * @param {Array<D>} a
2081 * @return {Array<D>}
2082 */
2083 const array_copy = a => /** @type {Array<D>} */ (a.slice())
2084
2085 /**
2086 * Append elements from src to dest
2087 *
2088 * @template M
2089 * @param {Array<M>} dest
2090 * @param {Array<M>} src
2091 */
2092 const appendTo = (dest, src) => {
2093 for (let i = 0; i < src.length; i++) {
2094 dest.push(src[i])
2095 }
2096 }
2097
2098 /**
2099 * Transforms something array-like to an actual Array.
2100 *
2101 * @function
2102 * @template T
2103 * @param {ArrayLike<T>|Iterable<T>} arraylike
2104 * @return {T}
2105 */
2106 const array_from = Array.from
2107
2108 /**
2109 * True iff condition holds on every element in the Array.
2110 *
2111 * @function
2112 * @template ITEM
2113 * @template {ArrayLike<ITEM>} ARR
2114 *
2115 * @param {ARR} arr
2116 * @param {function(ITEM, number, ARR):boolean} f
2117 * @return {boolean}
2118 */
2119 const every = (arr, f) => {
2120 for (let i = 0; i < arr.length; i++) {
2121 if (!f(arr[i], i, arr)) {
2122 return false
2123 }
2124 }
2125 return true
2126 }
2127
2128 /**
2129 * True iff condition holds on some element in the Array.
2130 *
2131 * @function
2132 * @template S
2133 * @template {ArrayLike<S>} ARR
2134 * @param {ARR} arr
2135 * @param {function(S, number, ARR):boolean} f
2136 * @return {boolean}
2137 */
2138 const some = (arr, f) => {
2139 for (let i = 0; i < arr.length; i++) {
2140 if (f(arr[i], i, arr)) {
2141 return true
2142 }
2143 }
2144 return false
2145 }
2146
2147 /**
2148 * @template ELEM
2149 *
2150 * @param {ArrayLike<ELEM>} a
2151 * @param {ArrayLike<ELEM>} b
2152 * @return {boolean}
2153 */
2154 const equalFlat = (a, b) => a.length === b.length && every(a, (item, index) => item === b[index])
2155
2156 /**
2157 * @template ELEM
2158 * @param {Array<Array<ELEM>>} arr
2159 * @return {Array<ELEM>}
2160 */
2161 const flatten = arr => fold(arr, /** @type {Array<ELEM>} */ ([]), (acc, val) => acc.concat(val))
2162
2163 /**
2164 * @template T
2165 * @param {number} len
2166 * @param {function(number, Array<T>):T} f
2167 * @return {Array<T>}
2168 */
2169 const unfold = (len, f) => {
2170 const array = new Array(len)
2171 for (let i = 0; i < len; i++) {
2172 array[i] = f(i, array)
2173 }
2174 return array
2175 }
2176
2177 /**
2178 * @template T
2179 * @template RESULT
2180 * @param {Array<T>} arr
2181 * @param {RESULT} seed
2182 * @param {function(RESULT, T, number):RESULT} folder
2183 */
2184 const fold = (arr, seed, folder) => arr.reduce(folder, seed)
2185
2186 const isArray = Array.isArray
2187
2188 /**
2189 * @template T
2190 * @param {Array<T>} arr
2191 * @return {Array<T>}
2192 */
2193 const unique = arr => array_from(set.from(arr))
2194
2195 /**
2196 * @template T
2197 * @template M
2198 * @param {ArrayLike<T>} arr
2199 * @param {function(T):M} mapper
2200 * @return {Array<T>}
2201 */
2202 const uniqueBy = (arr, mapper) => {
2203 /**
2204 * @type {Set<M>}
2205 */
2206 const happened = set.create()
2207 /**
2208 * @type {Array<T>}
2209 */
2210 const result = []
2211 for (let i = 0; i < arr.length; i++) {
2212 const el = arr[i]
2213 const mapped = mapper(el)
2214 if (!happened.has(mapped)) {
2215 happened.add(mapped)
2216 result.push(el)
2217 }
2218 }
2219 return result
2220 }
2221
2222 /**
2223 * @template {ArrayLike<any>} ARR
2224 * @template {function(ARR extends ArrayLike<infer T> ? T : never, number, ARR):any} MAPPER
2225 * @param {ARR} arr
2226 * @param {MAPPER} mapper
2227 * @return {Array<MAPPER extends function(...any): infer M ? M : never>}
2228 */
2229 const array_map = (arr, mapper) => {
2230 /**
2231 * @type {Array<any>}
2232 */
2233 const res = Array(arr.length)
2234 for (let i = 0; i < arr.length; i++) {
2235 res[i] = mapper(/** @type {any} */ (arr[i]), i, /** @type {any} */ (arr))
2236 }
2237 return /** @type {any} */ (res)
2238 }
2239
2240 ;// CONCATENATED MODULE: ./node_modules/lib0/observable.js
2241 /**
2242 * Observable class prototype.
2243 *
2244 * @module observable
2245 */
2246
2247
2248
2249
2250
2251 /**
2252 * Handles named events.
2253 *
2254 * @template N
2255 */
2256 class observable_Observable {
2257 constructor () {
2258 /**
2259 * Some desc.
2260 * @type {Map<N, any>}
2261 */
2262 this._observers = create()
2263 }
2264
2265 /**
2266 * @param {N} name
2267 * @param {function} f
2268 */
2269 on (name, f) {
2270 setIfUndefined(this._observers, name, set_create).add(f)
2271 }
2272
2273 /**
2274 * @param {N} name
2275 * @param {function} f
2276 */
2277 once (name, f) {
2278 /**
2279 * @param {...any} args
2280 */
2281 const _f = (...args) => {
2282 this.off(name, _f)
2283 f(...args)
2284 }
2285 this.on(name, _f)
2286 }
2287
2288 /**
2289 * @param {N} name
2290 * @param {function} f
2291 */
2292 off (name, f) {
2293 const observers = this._observers.get(name)
2294 if (observers !== undefined) {
2295 observers.delete(f)
2296 if (observers.size === 0) {
2297 this._observers.delete(name)
2298 }
2299 }
2300 }
2301
2302 /**
2303 * Emit a named event. All registered event listeners that listen to the
2304 * specified name will receive the event.
2305 *
2306 * @todo This should catch exceptions
2307 *
2308 * @param {N} name The event name.
2309 * @param {Array<any>} args The arguments that are applied to the event listener.
2310 */
2311 emit (name, args) {
2312 // 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.
2313 return array_from((this._observers.get(name) || create()).values()).forEach(f => f(...args))
2314 }
2315
2316 destroy () {
2317 this._observers = create()
2318 }
2319 }
2320
2321 ;// CONCATENATED MODULE: ./node_modules/lib0/math.js
2322 /**
2323 * Common Math expressions.
2324 *
2325 * @module math
2326 */
2327
2328 const floor = Math.floor
2329 const ceil = Math.ceil
2330 const abs = Math.abs
2331 const imul = Math.imul
2332 const round = Math.round
2333 const log10 = Math.log10
2334 const log2 = Math.log2
2335 const log = Math.log
2336 const sqrt = Math.sqrt
2337
2338 /**
2339 * @function
2340 * @param {number} a
2341 * @param {number} b
2342 * @return {number} The sum of a and b
2343 */
2344 const add = (a, b) => a + b
2345
2346 /**
2347 * @function
2348 * @param {number} a
2349 * @param {number} b
2350 * @return {number} The smaller element of a and b
2351 */
2352 const min = (a, b) => a < b ? a : b
2353
2354 /**
2355 * @function
2356 * @param {number} a
2357 * @param {number} b
2358 * @return {number} The bigger element of a and b
2359 */
2360 const max = (a, b) => a > b ? a : b
2361
2362 const math_isNaN = Number.isNaN
2363
2364 const pow = Math.pow
2365 /**
2366 * Base 10 exponential function. Returns the value of 10 raised to the power of pow.
2367 *
2368 * @param {number} exp
2369 * @return {number}
2370 */
2371 const exp10 = exp => Math.pow(10, exp)
2372
2373 const sign = Math.sign
2374
2375 /**
2376 * @param {number} n
2377 * @return {boolean} Wether n is negative. This function also differentiates between -0 and +0
2378 */
2379 const isNegativeZero = n => n !== 0 ? n < 0 : 1 / n < 0
2380
2381 ;// CONCATENATED MODULE: ./node_modules/lib0/string.js
2382
2383
2384 /**
2385 * Utility module to work with strings.
2386 *
2387 * @module string
2388 */
2389
2390 const fromCharCode = String.fromCharCode
2391 const fromCodePoint = String.fromCodePoint
2392
2393 /**
2394 * The largest utf16 character.
2395 * Corresponds to Uint8Array([255, 255]) or charcodeof(2x2^8)
2396 */
2397 const MAX_UTF16_CHARACTER = fromCharCode(65535)
2398
2399 /**
2400 * @param {string} s
2401 * @return {string}
2402 */
2403 const toLowerCase = s => s.toLowerCase()
2404
2405 const trimLeftRegex = /^\s*/g
2406
2407 /**
2408 * @param {string} s
2409 * @return {string}
2410 */
2411 const trimLeft = s => s.replace(trimLeftRegex, '')
2412
2413 const fromCamelCaseRegex = /([A-Z])/g
2414
2415 /**
2416 * @param {string} s
2417 * @param {string} separator
2418 * @return {string}
2419 */
2420 const fromCamelCase = (s, separator) => trimLeft(s.replace(fromCamelCaseRegex, match => `${separator}${toLowerCase(match)}`))
2421
2422 /**
2423 * Compute the utf8ByteLength
2424 * @param {string} str
2425 * @return {number}
2426 */
2427 const utf8ByteLength = str => unescape(encodeURIComponent(str)).length
2428
2429 /**
2430 * @param {string} str
2431 * @return {Uint8Array}
2432 */
2433 const _encodeUtf8Polyfill = str => {
2434 const encodedString = unescape(encodeURIComponent(str))
2435 const len = encodedString.length
2436 const buf = new Uint8Array(len)
2437 for (let i = 0; i < len; i++) {
2438 buf[i] = /** @type {number} */ (encodedString.codePointAt(i))
2439 }
2440 return buf
2441 }
2442
2443 /* c8 ignore next */
2444 const utf8TextEncoder = /** @type {TextEncoder} */ (typeof TextEncoder !== 'undefined' ? new TextEncoder() : null)
2445
2446 /**
2447 * @param {string} str
2448 * @return {Uint8Array}
2449 */
2450 const _encodeUtf8Native = str => utf8TextEncoder.encode(str)
2451
2452 /**
2453 * @param {string} str
2454 * @return {Uint8Array}
2455 */
2456 /* c8 ignore next */
2457 const encodeUtf8 = utf8TextEncoder ? _encodeUtf8Native : _encodeUtf8Polyfill
2458
2459 /**
2460 * @param {Uint8Array} buf
2461 * @return {string}
2462 */
2463 const _decodeUtf8Polyfill = buf => {
2464 let remainingLen = buf.length
2465 let encodedString = ''
2466 let bufPos = 0
2467 while (remainingLen > 0) {
2468 const nextLen = remainingLen < 10000 ? remainingLen : 10000
2469 const bytes = buf.subarray(bufPos, bufPos + nextLen)
2470 bufPos += nextLen
2471 // Starting with ES5.1 we can supply a generic array-like object as arguments
2472 encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes))
2473 remainingLen -= nextLen
2474 }
2475 return decodeURIComponent(escape(encodedString))
2476 }
2477
2478 /* c8 ignore next */
2479 let utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf-8', { fatal: true, ignoreBOM: true })
2480
2481 /* c8 ignore start */
2482 if (utf8TextDecoder && utf8TextDecoder.decode(new Uint8Array()).length === 1) {
2483 // Safari doesn't handle BOM correctly.
2484 // This fixes a bug in Safari 13.0.5 where it produces a BOM the first time it is called.
2485 // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the first call and
2486 // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the second call
2487 // Another issue is that from then on no BOM chars are recognized anymore
2488 /* c8 ignore next */
2489 utf8TextDecoder = null
2490 }
2491 /* c8 ignore stop */
2492
2493 /**
2494 * @param {Uint8Array} buf
2495 * @return {string}
2496 */
2497 const _decodeUtf8Native = buf => /** @type {TextDecoder} */ (utf8TextDecoder).decode(buf)
2498
2499 /**
2500 * @param {Uint8Array} buf
2501 * @return {string}
2502 */
2503 /* c8 ignore next */
2504 const decodeUtf8 = (/* unused pure expression or super */ null && (utf8TextDecoder ? _decodeUtf8Native : _decodeUtf8Polyfill))
2505
2506 /**
2507 * @param {string} str The initial string
2508 * @param {number} index Starting position
2509 * @param {number} remove Number of characters to remove
2510 * @param {string} insert New content to insert
2511 */
2512 const splice = (str, index, remove, insert = '') => str.slice(0, index) + insert + str.slice(index + remove)
2513
2514 /**
2515 * @param {string} source
2516 * @param {number} n
2517 */
2518 const repeat = (source, n) => array.unfold(n, () => source).join('')
2519
2520 ;// CONCATENATED MODULE: ./node_modules/lib0/conditions.js
2521 /**
2522 * Often used conditions.
2523 *
2524 * @module conditions
2525 */
2526
2527 /**
2528 * @template T
2529 * @param {T|null|undefined} v
2530 * @return {T|null}
2531 */
2532 /* c8 ignore next */
2533 const undefinedToNull = v => v === undefined ? null : v
2534
2535 ;// CONCATENATED MODULE: ./node_modules/lib0/storage.js
2536 /* eslint-env browser */
2537
2538 /**
2539 * Isomorphic variable storage.
2540 *
2541 * Uses LocalStorage in the browser and falls back to in-memory storage.
2542 *
2543 * @module storage
2544 */
2545
2546 /* c8 ignore start */
2547 class VarStoragePolyfill {
2548 constructor () {
2549 this.map = new Map()
2550 }
2551
2552 /**
2553 * @param {string} key
2554 * @param {any} newValue
2555 */
2556 setItem (key, newValue) {
2557 this.map.set(key, newValue)
2558 }
2559
2560 /**
2561 * @param {string} key
2562 */
2563 getItem (key) {
2564 return this.map.get(key)
2565 }
2566 }
2567 /* c8 ignore stop */
2568
2569 /**
2570 * @type {any}
2571 */
2572 let _localStorage = new VarStoragePolyfill()
2573 let usePolyfill = true
2574
2575 /* c8 ignore start */
2576 try {
2577 // if the same-origin rule is violated, accessing localStorage might thrown an error
2578 if (typeof localStorage !== 'undefined') {
2579 _localStorage = localStorage
2580 usePolyfill = false
2581 }
2582 } catch (e) { }
2583 /* c8 ignore stop */
2584
2585 /**
2586 * This is basically localStorage in browser, or a polyfill in nodejs
2587 */
2588 /* c8 ignore next */
2589 const varStorage = _localStorage
2590
2591 /**
2592 * A polyfill for `addEventListener('storage', event => {..})` that does nothing if the polyfill is being used.
2593 *
2594 * @param {function({ key: string, newValue: string, oldValue: string }): void} eventHandler
2595 * @function
2596 */
2597 /* c8 ignore next */
2598 const onChange = eventHandler => usePolyfill || addEventListener('storage', /** @type {any} */ (eventHandler))
2599
2600 /**
2601 * A polyfill for `removeEventListener('storage', event => {..})` that does nothing if the polyfill is being used.
2602 *
2603 * @param {function({ key: string, newValue: string, oldValue: string }): void} eventHandler
2604 * @function
2605 */
2606 /* c8 ignore next */
2607 const offChange = eventHandler => usePolyfill || removeEventListener('storage', /** @type {any} */ (eventHandler))
2608
2609 ;// CONCATENATED MODULE: ./node_modules/lib0/object.js
2610 /**
2611 * Utility functions for working with EcmaScript objects.
2612 *
2613 * @module object
2614 */
2615
2616 /**
2617 * @return {Object<string,any>} obj
2618 */
2619 const object_create = () => Object.create(null)
2620
2621 /**
2622 * Object.assign
2623 */
2624 const object_assign = Object.assign
2625
2626 /**
2627 * @param {Object<string,any>} obj
2628 */
2629 const keys = Object.keys
2630
2631 /**
2632 * @template V
2633 * @param {{[k:string]:V}} obj
2634 * @param {function(V,string):any} f
2635 */
2636 const forEach = (obj, f) => {
2637 for (const key in obj) {
2638 f(obj[key], key)
2639 }
2640 }
2641
2642 /**
2643 * @todo implement mapToArray & map
2644 *
2645 * @template R
2646 * @param {Object<string,any>} obj
2647 * @param {function(any,string):R} f
2648 * @return {Array<R>}
2649 */
2650 const object_map = (obj, f) => {
2651 const results = []
2652 for (const key in obj) {
2653 results.push(f(obj[key], key))
2654 }
2655 return results
2656 }
2657
2658 /**
2659 * @param {Object<string,any>} obj
2660 * @return {number}
2661 */
2662 const object_length = obj => keys(obj).length
2663
2664 /**
2665 * @param {Object<string,any>} obj
2666 * @param {function(any,string):boolean} f
2667 * @return {boolean}
2668 */
2669 const object_some = (obj, f) => {
2670 for (const key in obj) {
2671 if (f(obj[key], key)) {
2672 return true
2673 }
2674 }
2675 return false
2676 }
2677
2678 /**
2679 * @param {Object|undefined} obj
2680 */
2681 const isEmpty = obj => {
2682 // eslint-disable-next-line
2683 for (const _k in obj) {
2684 return false
2685 }
2686 return true
2687 }
2688
2689 /**
2690 * @param {Object<string,any>} obj
2691 * @param {function(any,string):boolean} f
2692 * @return {boolean}
2693 */
2694 const object_every = (obj, f) => {
2695 for (const key in obj) {
2696 if (!f(obj[key], key)) {
2697 return false
2698 }
2699 }
2700 return true
2701 }
2702
2703 /**
2704 * Calls `Object.prototype.hasOwnProperty`.
2705 *
2706 * @param {any} obj
2707 * @param {string|symbol} key
2708 * @return {boolean}
2709 */
2710 const hasProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key)
2711
2712 /**
2713 * @param {Object<string,any>} a
2714 * @param {Object<string,any>} b
2715 * @return {boolean}
2716 */
2717 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))
2718
2719 ;// CONCATENATED MODULE: ./node_modules/lib0/function.js
2720 /**
2721 * Common functions and function call helpers.
2722 *
2723 * @module function
2724 */
2725
2726
2727
2728
2729 /**
2730 * Calls all functions in `fs` with args. Only throws after all functions were called.
2731 *
2732 * @param {Array<function>} fs
2733 * @param {Array<any>} args
2734 */
2735 const callAll = (fs, args, i = 0) => {
2736 try {
2737 for (; i < fs.length; i++) {
2738 fs[i](...args)
2739 }
2740 } finally {
2741 if (i < fs.length) {
2742 callAll(fs, args, i + 1)
2743 }
2744 }
2745 }
2746
2747 const nop = () => {}
2748
2749 /**
2750 * @template T
2751 * @param {function():T} f
2752 * @return {T}
2753 */
2754 const apply = f => f()
2755
2756 /**
2757 * @template A
2758 *
2759 * @param {A} a
2760 * @return {A}
2761 */
2762 const id = a => a
2763
2764 /**
2765 * @template T
2766 *
2767 * @param {T} a
2768 * @param {T} b
2769 * @return {boolean}
2770 */
2771 const equalityStrict = (a, b) => a === b
2772
2773 /**
2774 * @template T
2775 *
2776 * @param {Array<T>|object} a
2777 * @param {Array<T>|object} b
2778 * @return {boolean}
2779 */
2780 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))))
2781
2782 /* c8 ignore start */
2783
2784 /**
2785 * @param {any} a
2786 * @param {any} b
2787 * @return {boolean}
2788 */
2789 const equalityDeep = (a, b) => {
2790 if (a == null || b == null) {
2791 return equalityStrict(a, b)
2792 }
2793 if (a.constructor !== b.constructor) {
2794 return false
2795 }
2796 if (a === b) {
2797 return true
2798 }
2799 switch (a.constructor) {
2800 case ArrayBuffer:
2801 a = new Uint8Array(a)
2802 b = new Uint8Array(b)
2803 // eslint-disable-next-line no-fallthrough
2804 case Uint8Array: {
2805 if (a.byteLength !== b.byteLength) {
2806 return false
2807 }
2808 for (let i = 0; i < a.length; i++) {
2809 if (a[i] !== b[i]) {
2810 return false
2811 }
2812 }
2813 break
2814 }
2815 case Set: {
2816 if (a.size !== b.size) {
2817 return false
2818 }
2819 for (const value of a) {
2820 if (!b.has(value)) {
2821 return false
2822 }
2823 }
2824 break
2825 }
2826 case Map: {
2827 if (a.size !== b.size) {
2828 return false
2829 }
2830 for (const key of a.keys()) {
2831 if (!b.has(key) || !equalityDeep(a.get(key), b.get(key))) {
2832 return false
2833 }
2834 }
2835 break
2836 }
2837 case Object:
2838 if (object_length(a) !== object_length(b)) {
2839 return false
2840 }
2841 for (const key in a) {
2842 if (!hasProperty(a, key) || !equalityDeep(a[key], b[key])) {
2843 return false
2844 }
2845 }
2846 break
2847 case Array:
2848 if (a.length !== b.length) {
2849 return false
2850 }
2851 for (let i = 0; i < a.length; i++) {
2852 if (!equalityDeep(a[i], b[i])) {
2853 return false
2854 }
2855 }
2856 break
2857 default:
2858 return false
2859 }
2860 return true
2861 }
2862
2863 /**
2864 * @template V
2865 * @template {V} OPTS
2866 *
2867 * @param {V} value
2868 * @param {Array<OPTS>} options
2869 */
2870 // @ts-ignore
2871 const isOneOf = (value, options) => options.includes(value)
2872 /* c8 ignore stop */
2873
2874 const function_isArray = isArray
2875
2876 /**
2877 * @param {any} s
2878 * @return {s is String}
2879 */
2880 const isString = (s) => s && s.constructor === String
2881
2882 /**
2883 * @param {any} n
2884 * @return {n is Number}
2885 */
2886 const isNumber = n => n != null && n.constructor === Number
2887
2888 /**
2889 * @template {abstract new (...args: any) => any} TYPE
2890 * @param {any} n
2891 * @param {TYPE} T
2892 * @return {n is InstanceType<TYPE>}
2893 */
2894 const is = (n, T) => n && n.constructor === T
2895
2896 /**
2897 * @template {abstract new (...args: any) => any} TYPE
2898 * @param {TYPE} T
2899 */
2900 const isTemplate = (T) =>
2901 /**
2902 * @param {any} n
2903 * @return {n is InstanceType<TYPE>}
2904 **/
2905 n => n && n.constructor === T
2906
2907 ;// CONCATENATED MODULE: ./node_modules/lib0/environment.js
2908 /**
2909 * Isomorphic module to work access the environment (query params, env variables).
2910 *
2911 * @module map
2912 */
2913
2914
2915
2916
2917
2918
2919
2920 /* c8 ignore next */
2921 // @ts-ignore
2922 const isNode = typeof process !== 'undefined' && process.release &&
2923 /node|io\.js/.test(process.release.name)
2924 /* c8 ignore next */
2925 const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && !isNode
2926 /* c8 ignore next 3 */
2927 const isMac = typeof navigator !== 'undefined'
2928 ? /Mac/.test(navigator.platform)
2929 : false
2930
2931 /**
2932 * @type {Map<string,string>}
2933 */
2934 let params
2935 const args = []
2936
2937 /* c8 ignore start */
2938 const computeParams = () => {
2939 if (params === undefined) {
2940 if (isNode) {
2941 params = create()
2942 const pargs = process.argv
2943 let currParamName = null
2944 for (let i = 0; i < pargs.length; i++) {
2945 const parg = pargs[i]
2946 if (parg[0] === '-') {
2947 if (currParamName !== null) {
2948 params.set(currParamName, '')
2949 }
2950 currParamName = parg
2951 } else {
2952 if (currParamName !== null) {
2953 params.set(currParamName, parg)
2954 currParamName = null
2955 } else {
2956 args.push(parg)
2957 }
2958 }
2959 }
2960 if (currParamName !== null) {
2961 params.set(currParamName, '')
2962 }
2963 // in ReactNative for example this would not be true (unless connected to the Remote Debugger)
2964 } else if (typeof location === 'object') {
2965 params = create(); // eslint-disable-next-line no-undef
2966 (location.search || '?').slice(1).split('&').forEach((kv) => {
2967 if (kv.length !== 0) {
2968 const [key, value] = kv.split('=')
2969 params.set(`--${fromCamelCase(key, '-')}`, value)
2970 params.set(`-${fromCamelCase(key, '-')}`, value)
2971 }
2972 })
2973 } else {
2974 params = create()
2975 }
2976 }
2977 return params
2978 }
2979 /* c8 ignore stop */
2980
2981 /**
2982 * @param {string} name
2983 * @return {boolean}
2984 */
2985 /* c8 ignore next */
2986 const hasParam = (name) => computeParams().has(name)
2987
2988 /**
2989 * @param {string} name
2990 * @param {string} defaultVal
2991 * @return {string}
2992 */
2993 /* c8 ignore next 2 */
2994 const getParam = (name, defaultVal) =>
2995 computeParams().get(name) || defaultVal
2996
2997 /**
2998 * @param {string} name
2999 * @return {string|null}
3000 */
3001 /* c8 ignore next 4 */
3002 const getVariable = (name) =>
3003 isNode
3004 ? undefinedToNull(process.env[name.toUpperCase()])
3005 : undefinedToNull(varStorage.getItem(name))
3006
3007 /**
3008 * @param {string} name
3009 * @return {string|null}
3010 */
3011 /* c8 ignore next 2 */
3012 const getConf = (name) =>
3013 computeParams().get('--' + name) || getVariable(name)
3014
3015 /**
3016 * @param {string} name
3017 * @return {boolean}
3018 */
3019 /* c8 ignore next 2 */
3020 const hasConf = (name) =>
3021 hasParam('--' + name) || getVariable(name) !== null
3022
3023 /* c8 ignore next */
3024 const production = hasConf('production')
3025
3026 /* c8 ignore next 2 */
3027 const forceColor = isNode &&
3028 isOneOf(process.env.FORCE_COLOR, ['true', '1', '2'])
3029
3030 /* c8 ignore start */
3031 const supportsColor = !hasParam('no-colors') &&
3032 (!isNode || process.stdout.isTTY || forceColor) && (
3033 !isNode || hasParam('color') || forceColor ||
3034 getVariable('COLORTERM') !== null ||
3035 (getVariable('TERM') || '').includes('color')
3036 )
3037 /* c8 ignore stop */
3038
3039 ;// CONCATENATED MODULE: ./node_modules/lib0/buffer.js
3040 /**
3041 * Utility functions to work with buffers (Uint8Array).
3042 *
3043 * @module buffer
3044 */
3045
3046
3047
3048
3049
3050
3051
3052
3053 /**
3054 * @param {number} len
3055 */
3056 const createUint8ArrayFromLen = len => new Uint8Array(len)
3057
3058 /**
3059 * Create Uint8Array with initial content from buffer
3060 *
3061 * @param {ArrayBuffer} buffer
3062 * @param {number} byteOffset
3063 * @param {number} length
3064 */
3065 const createUint8ArrayViewFromArrayBuffer = (buffer, byteOffset, length) => new Uint8Array(buffer, byteOffset, length)
3066
3067 /**
3068 * Create Uint8Array with initial content from buffer
3069 *
3070 * @param {ArrayBuffer} buffer
3071 */
3072 const createUint8ArrayFromArrayBuffer = buffer => new Uint8Array(buffer)
3073
3074 /* c8 ignore start */
3075 /**
3076 * @param {Uint8Array} bytes
3077 * @return {string}
3078 */
3079 const toBase64Browser = bytes => {
3080 let s = ''
3081 for (let i = 0; i < bytes.byteLength; i++) {
3082 s += fromCharCode(bytes[i])
3083 }
3084 // eslint-disable-next-line no-undef
3085 return btoa(s)
3086 }
3087 /* c8 ignore stop */
3088
3089 /**
3090 * @param {Uint8Array} bytes
3091 * @return {string}
3092 */
3093 const toBase64Node = bytes => Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64')
3094
3095 /* c8 ignore start */
3096 /**
3097 * @param {string} s
3098 * @return {Uint8Array}
3099 */
3100 const fromBase64Browser = s => {
3101 // eslint-disable-next-line no-undef
3102 const a = atob(s)
3103 const bytes = createUint8ArrayFromLen(a.length)
3104 for (let i = 0; i < a.length; i++) {
3105 bytes[i] = a.charCodeAt(i)
3106 }
3107 return bytes
3108 }
3109 /* c8 ignore stop */
3110
3111 /**
3112 * @param {string} s
3113 */
3114 const fromBase64Node = s => {
3115 const buf = Buffer.from(s, 'base64')
3116 return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)
3117 }
3118
3119 /* c8 ignore next */
3120 const toBase64 = isBrowser ? toBase64Browser : toBase64Node
3121
3122 /* c8 ignore next */
3123 const fromBase64 = isBrowser ? fromBase64Browser : fromBase64Node
3124
3125 /**
3126 * Base64 is always a more efficient choice. This exists for utility purposes only.
3127 *
3128 * @param {Uint8Array} buf
3129 */
3130 const toHexString = buf => array.map(buf, b => b.toString(16).padStart(2, '0')).join('')
3131
3132 /**
3133 * Note: This function expects that the hex doesn't start with 0x..
3134 *
3135 * @param {string} hex
3136 */
3137 const fromHexString = hex => {
3138 const hlen = hex.length
3139 const buf = new Uint8Array(math.ceil(hlen / 2))
3140 for (let i = 0; i < hlen; i += 2) {
3141 buf[buf.length - i / 2 - 1] = Number.parseInt(hex.slice(hlen - i - 2, hlen - i), 16)
3142 }
3143 return buf
3144 }
3145
3146 /**
3147 * Copy the content of an Uint8Array view to a new ArrayBuffer.
3148 *
3149 * @param {Uint8Array} uint8Array
3150 * @return {Uint8Array}
3151 */
3152 const copyUint8Array = uint8Array => {
3153 const newBuf = createUint8ArrayFromLen(uint8Array.byteLength)
3154 newBuf.set(uint8Array)
3155 return newBuf
3156 }
3157
3158 /**
3159 * Encode anything as a UInt8Array. It's a pun on typescripts's `any` type.
3160 * See encoding.writeAny for more information.
3161 *
3162 * @param {any} data
3163 * @return {Uint8Array}
3164 */
3165 const encodeAny = data => {
3166 const encoder = encoding.createEncoder()
3167 encoding.writeAny(encoder, data)
3168 return encoding.toUint8Array(encoder)
3169 }
3170
3171 /**
3172 * Decode an any-encoded value.
3173 *
3174 * @param {Uint8Array} buf
3175 * @return {any}
3176 */
3177 const decodeAny = buf => decoding.readAny(decoding.createDecoder(buf))
3178
3179 /**
3180 * Shift Byte Array {N} bits to the left. Does not expand byte array.
3181 *
3182 * @param {Uint8Array} bs
3183 * @param {number} N should be in the range of [0-7]
3184 */
3185 const shiftNBitsLeft = (bs, N) => {
3186 if (N === 0) return bs
3187 bs = new Uint8Array(bs)
3188 bs[0] <<= N
3189 for (let i = 1; i < bs.length; i++) {
3190 bs[i - 1] |= bs[i] >>> (8 - N)
3191 bs[i] <<= N
3192 }
3193 return bs
3194 }
3195
3196 ;// CONCATENATED MODULE: ./node_modules/lib0/binary.js
3197 /* eslint-env browser */
3198
3199 /**
3200 * Binary data constants.
3201 *
3202 * @module binary
3203 */
3204
3205 /**
3206 * n-th bit activated.
3207 *
3208 * @type {number}
3209 */
3210 const BIT1 = 1
3211 const BIT2 = 2
3212 const BIT3 = 4
3213 const BIT4 = 8
3214 const BIT5 = 16
3215 const BIT6 = 32
3216 const BIT7 = 64
3217 const BIT8 = 128
3218 const BIT9 = 256
3219 const BIT10 = 512
3220 const BIT11 = 1024
3221 const BIT12 = 2048
3222 const BIT13 = 4096
3223 const BIT14 = 8192
3224 const BIT15 = 16384
3225 const BIT16 = 32768
3226 const BIT17 = 65536
3227 const BIT18 = 1 << 17
3228 const BIT19 = 1 << 18
3229 const BIT20 = 1 << 19
3230 const BIT21 = 1 << 20
3231 const BIT22 = 1 << 21
3232 const BIT23 = 1 << 22
3233 const BIT24 = 1 << 23
3234 const BIT25 = 1 << 24
3235 const BIT26 = 1 << 25
3236 const BIT27 = 1 << 26
3237 const BIT28 = 1 << 27
3238 const BIT29 = 1 << 28
3239 const BIT30 = 1 << 29
3240 const BIT31 = 1 << 30
3241 const BIT32 = (/* unused pure expression or super */ null && (1 << 31))
3242
3243 /**
3244 * First n bits activated.
3245 *
3246 * @type {number}
3247 */
3248 const BITS0 = 0
3249 const BITS1 = 1
3250 const BITS2 = 3
3251 const BITS3 = 7
3252 const BITS4 = 15
3253 const BITS5 = 31
3254 const BITS6 = 63
3255 const BITS7 = 127
3256 const BITS8 = 255
3257 const BITS9 = 511
3258 const BITS10 = 1023
3259 const BITS11 = 2047
3260 const BITS12 = 4095
3261 const BITS13 = 8191
3262 const BITS14 = 16383
3263 const BITS15 = 32767
3264 const BITS16 = 65535
3265 const BITS17 = BIT18 - 1
3266 const BITS18 = BIT19 - 1
3267 const BITS19 = BIT20 - 1
3268 const BITS20 = BIT21 - 1
3269 const BITS21 = BIT22 - 1
3270 const BITS22 = BIT23 - 1
3271 const BITS23 = BIT24 - 1
3272 const BITS24 = BIT25 - 1
3273 const BITS25 = BIT26 - 1
3274 const BITS26 = BIT27 - 1
3275 const BITS27 = BIT28 - 1
3276 const BITS28 = BIT29 - 1
3277 const BITS29 = BIT30 - 1
3278 const BITS30 = BIT31 - 1
3279 /**
3280 * @type {number}
3281 */
3282 const BITS31 = 0x7FFFFFFF
3283 /**
3284 * @type {number}
3285 */
3286 const BITS32 = 0xFFFFFFFF
3287
3288 ;// CONCATENATED MODULE: ./node_modules/lib0/number.js
3289 /**
3290 * Utility helpers for working with numbers.
3291 *
3292 * @module number
3293 */
3294
3295
3296
3297
3298 const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER
3299 const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER
3300
3301 const LOWEST_INT32 = (/* unused pure expression or super */ null && (1 << 31))
3302 const HIGHEST_INT32 = BITS31
3303 const HIGHEST_UINT32 = BITS32
3304
3305 /* c8 ignore next */
3306 const isInteger = Number.isInteger || (num => typeof num === 'number' && isFinite(num) && floor(num) === num)
3307 const number_isNaN = Number.isNaN
3308 const number_parseInt = Number.parseInt
3309
3310 /**
3311 * Count the number of "1" bits in an unsigned 32bit number.
3312 *
3313 * Super fun bitcount algorithm by Brian Kernighan.
3314 *
3315 * @param {number} n
3316 */
3317 const countBits = n => {
3318 n &= binary.BITS32
3319 let count = 0
3320 while (n) {
3321 n &= (n - 1)
3322 count++
3323 }
3324 return count
3325 }
3326
3327 ;// CONCATENATED MODULE: ./node_modules/lib0/encoding.js
3328 /**
3329 * Efficient schema-less binary encoding with support for variable length encoding.
3330 *
3331 * Use [lib0/encoding] with [lib0/decoding]. Every encoding function has a corresponding decoding function.
3332 *
3333 * Encodes numbers in little-endian order (least to most significant byte order)
3334 * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
3335 * which is also used in Protocol Buffers.
3336 *
3337 * ```js
3338 * // encoding step
3339 * const encoder = encoding.createEncoder()
3340 * encoding.writeVarUint(encoder, 256)
3341 * encoding.writeVarString(encoder, 'Hello world!')
3342 * const buf = encoding.toUint8Array(encoder)
3343 * ```
3344 *
3345 * ```js
3346 * // decoding step
3347 * const decoder = decoding.createDecoder(buf)
3348 * decoding.readVarUint(decoder) // => 256
3349 * decoding.readVarString(decoder) // => 'Hello world!'
3350 * decoding.hasContent(decoder) // => false - all data is read
3351 * ```
3352 *
3353 * @module encoding
3354 */
3355
3356
3357
3358
3359
3360
3361
3362
3363 /**
3364 * A BinaryEncoder handles the encoding to an Uint8Array.
3365 */
3366 class Encoder {
3367 constructor () {
3368 this.cpos = 0
3369 this.cbuf = new Uint8Array(100)
3370 /**
3371 * @type {Array<Uint8Array>}
3372 */
3373 this.bufs = []
3374 }
3375 }
3376
3377 /**
3378 * @function
3379 * @return {Encoder}
3380 */
3381 const createEncoder = () => new Encoder()
3382
3383 /**
3384 * @param {function(Encoder):void} f
3385 */
3386 const encode = (f) => {
3387 const encoder = createEncoder()
3388 f(encoder)
3389 return toUint8Array(encoder)
3390 }
3391
3392 /**
3393 * The current length of the encoded data.
3394 *
3395 * @function
3396 * @param {Encoder} encoder
3397 * @return {number}
3398 */
3399 const encoding_length = encoder => {
3400 let len = encoder.cpos
3401 for (let i = 0; i < encoder.bufs.length; i++) {
3402 len += encoder.bufs[i].length
3403 }
3404 return len
3405 }
3406
3407 /**
3408 * Check whether encoder is empty.
3409 *
3410 * @function
3411 * @param {Encoder} encoder
3412 * @return {boolean}
3413 */
3414 const hasContent = encoder => encoder.cpos > 0 || encoder.bufs.length > 0
3415
3416 /**
3417 * Transform to Uint8Array.
3418 *
3419 * @function
3420 * @param {Encoder} encoder
3421 * @return {Uint8Array} The created ArrayBuffer.
3422 */
3423 const toUint8Array = encoder => {
3424 const uint8arr = new Uint8Array(encoding_length(encoder))
3425 let curPos = 0
3426 for (let i = 0; i < encoder.bufs.length; i++) {
3427 const d = encoder.bufs[i]
3428 uint8arr.set(d, curPos)
3429 curPos += d.length
3430 }
3431 uint8arr.set(createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos), curPos)
3432 return uint8arr
3433 }
3434
3435 /**
3436 * Verify that it is possible to write `len` bytes wtihout checking. If
3437 * necessary, a new Buffer with the required length is attached.
3438 *
3439 * @param {Encoder} encoder
3440 * @param {number} len
3441 */
3442 const verifyLen = (encoder, len) => {
3443 const bufferLen = encoder.cbuf.length
3444 if (bufferLen - encoder.cpos < len) {
3445 encoder.bufs.push(createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos))
3446 encoder.cbuf = new Uint8Array(max(bufferLen, len) * 2)
3447 encoder.cpos = 0
3448 }
3449 }
3450
3451 /**
3452 * Write one byte to the encoder.
3453 *
3454 * @function
3455 * @param {Encoder} encoder
3456 * @param {number} num The byte that is to be encoded.
3457 */
3458 const write = (encoder, num) => {
3459 const bufferLen = encoder.cbuf.length
3460 if (encoder.cpos === bufferLen) {
3461 encoder.bufs.push(encoder.cbuf)
3462 encoder.cbuf = new Uint8Array(bufferLen * 2)
3463 encoder.cpos = 0
3464 }
3465 encoder.cbuf[encoder.cpos++] = num
3466 }
3467
3468 /**
3469 * Write one byte at a specific position.
3470 * Position must already be written (i.e. encoder.length > pos)
3471 *
3472 * @function
3473 * @param {Encoder} encoder
3474 * @param {number} pos Position to which to write data
3475 * @param {number} num Unsigned 8-bit integer
3476 */
3477 const encoding_set = (encoder, pos, num) => {
3478 let buffer = null
3479 // iterate all buffers and adjust position
3480 for (let i = 0; i < encoder.bufs.length && buffer === null; i++) {
3481 const b = encoder.bufs[i]
3482 if (pos < b.length) {
3483 buffer = b // found buffer
3484 } else {
3485 pos -= b.length
3486 }
3487 }
3488 if (buffer === null) {
3489 // use current buffer
3490 buffer = encoder.cbuf
3491 }
3492 buffer[pos] = num
3493 }
3494
3495 /**
3496 * Write one byte as an unsigned integer.
3497 *
3498 * @function
3499 * @param {Encoder} encoder
3500 * @param {number} num The number that is to be encoded.
3501 */
3502 const writeUint8 = write
3503
3504 /**
3505 * Write one byte as an unsigned Integer at a specific location.
3506 *
3507 * @function
3508 * @param {Encoder} encoder
3509 * @param {number} pos The location where the data will be written.
3510 * @param {number} num The number that is to be encoded.
3511 */
3512 const setUint8 = (/* unused pure expression or super */ null && (encoding_set))
3513
3514 /**
3515 * Write two bytes as an unsigned integer.
3516 *
3517 * @function
3518 * @param {Encoder} encoder
3519 * @param {number} num The number that is to be encoded.
3520 */
3521 const writeUint16 = (encoder, num) => {
3522 write(encoder, num & binary.BITS8)
3523 write(encoder, (num >>> 8) & binary.BITS8)
3524 }
3525 /**
3526 * Write two bytes as an unsigned integer at a specific location.
3527 *
3528 * @function
3529 * @param {Encoder} encoder
3530 * @param {number} pos The location where the data will be written.
3531 * @param {number} num The number that is to be encoded.
3532 */
3533 const setUint16 = (encoder, pos, num) => {
3534 encoding_set(encoder, pos, num & binary.BITS8)
3535 encoding_set(encoder, pos + 1, (num >>> 8) & binary.BITS8)
3536 }
3537
3538 /**
3539 * Write two bytes as an unsigned integer
3540 *
3541 * @function
3542 * @param {Encoder} encoder
3543 * @param {number} num The number that is to be encoded.
3544 */
3545 const writeUint32 = (encoder, num) => {
3546 for (let i = 0; i < 4; i++) {
3547 write(encoder, num & binary.BITS8)
3548 num >>>= 8
3549 }
3550 }
3551
3552 /**
3553 * Write two bytes as an unsigned integer in big endian order.
3554 * (most significant byte first)
3555 *
3556 * @function
3557 * @param {Encoder} encoder
3558 * @param {number} num The number that is to be encoded.
3559 */
3560 const writeUint32BigEndian = (encoder, num) => {
3561 for (let i = 3; i >= 0; i--) {
3562 write(encoder, (num >>> (8 * i)) & binary.BITS8)
3563 }
3564 }
3565
3566 /**
3567 * Write two bytes as an unsigned integer at a specific location.
3568 *
3569 * @function
3570 * @param {Encoder} encoder
3571 * @param {number} pos The location where the data will be written.
3572 * @param {number} num The number that is to be encoded.
3573 */
3574 const setUint32 = (encoder, pos, num) => {
3575 for (let i = 0; i < 4; i++) {
3576 encoding_set(encoder, pos + i, num & binary.BITS8)
3577 num >>>= 8
3578 }
3579 }
3580
3581 /**
3582 * Write a variable length unsigned integer. Max encodable integer is 2^53.
3583 *
3584 * @function
3585 * @param {Encoder} encoder
3586 * @param {number} num The number that is to be encoded.
3587 */
3588 const writeVarUint = (encoder, num) => {
3589 while (num > BITS7) {
3590 write(encoder, BIT8 | (BITS7 & num))
3591 num = floor(num / 128) // shift >>> 7
3592 }
3593 write(encoder, BITS7 & num)
3594 }
3595
3596 /**
3597 * Write a variable length integer.
3598 *
3599 * We use the 7th bit instead for signaling that this is a negative number.
3600 *
3601 * @function
3602 * @param {Encoder} encoder
3603 * @param {number} num The number that is to be encoded.
3604 */
3605 const writeVarInt = (encoder, num) => {
3606 const isNegative = isNegativeZero(num)
3607 if (isNegative) {
3608 num = -num
3609 }
3610 // |- whether to continue reading |- whether is negative |- number
3611 write(encoder, (num > BITS6 ? BIT8 : 0) | (isNegative ? BIT7 : 0) | (BITS6 & num))
3612 num = floor(num / 64) // shift >>> 6
3613 // We don't need to consider the case of num === 0 so we can use a different
3614 // pattern here than above.
3615 while (num > 0) {
3616 write(encoder, (num > BITS7 ? BIT8 : 0) | (BITS7 & num))
3617 num = floor(num / 128) // shift >>> 7
3618 }
3619 }
3620
3621 /**
3622 * A cache to store strings temporarily
3623 */
3624 const _strBuffer = new Uint8Array(30000)
3625 const _maxStrBSize = _strBuffer.length / 3
3626
3627 /**
3628 * Write a variable length string.
3629 *
3630 * @function
3631 * @param {Encoder} encoder
3632 * @param {String} str The string that is to be encoded.
3633 */
3634 const _writeVarStringNative = (encoder, str) => {
3635 if (str.length < _maxStrBSize) {
3636 // We can encode the string into the existing buffer
3637 /* c8 ignore next */
3638 const written = utf8TextEncoder.encodeInto(str, _strBuffer).written || 0
3639 writeVarUint(encoder, written)
3640 for (let i = 0; i < written; i++) {
3641 write(encoder, _strBuffer[i])
3642 }
3643 } else {
3644 writeVarUint8Array(encoder, encodeUtf8(str))
3645 }
3646 }
3647
3648 /**
3649 * Write a variable length string.
3650 *
3651 * @function
3652 * @param {Encoder} encoder
3653 * @param {String} str The string that is to be encoded.
3654 */
3655 const _writeVarStringPolyfill = (encoder, str) => {
3656 const encodedString = unescape(encodeURIComponent(str))
3657 const len = encodedString.length
3658 writeVarUint(encoder, len)
3659 for (let i = 0; i < len; i++) {
3660 write(encoder, /** @type {number} */ (encodedString.codePointAt(i)))
3661 }
3662 }
3663
3664 /**
3665 * Write a variable length string.
3666 *
3667 * @function
3668 * @param {Encoder} encoder
3669 * @param {String} str The string that is to be encoded.
3670 */
3671 /* c8 ignore next */
3672 const writeVarString = (utf8TextEncoder && /** @type {any} */ (utf8TextEncoder).encodeInto) ? _writeVarStringNative : _writeVarStringPolyfill
3673
3674 /**
3675 * Write a string terminated by a special byte sequence. This is not very performant and is
3676 * generally discouraged. However, the resulting byte arrays are lexiographically ordered which
3677 * makes this a nice feature for databases.
3678 *
3679 * The string will be encoded using utf8 and then terminated and escaped using writeTerminatingUint8Array.
3680 *
3681 * @function
3682 * @param {Encoder} encoder
3683 * @param {String} str The string that is to be encoded.
3684 */
3685 const writeTerminatedString = (encoder, str) =>
3686 writeTerminatedUint8Array(encoder, string.encodeUtf8(str))
3687
3688 /**
3689 * Write a terminating Uint8Array. Note that this is not performant and is generally
3690 * discouraged. There are few situations when this is needed.
3691 *
3692 * We use 0x0 as a terminating character. 0x1 serves as an escape character for 0x0 and 0x1.
3693 *
3694 * Example: [0,1,2] is encoded to [1,0,1,1,2,0]. 0x0, and 0x1 needed to be escaped using 0x1. Then
3695 * the result is terminated using the 0x0 character.
3696 *
3697 * This is basically how many systems implement null terminated strings. However, we use an escape
3698 * character 0x1 to avoid issues and potenial attacks on our database (if this is used as a key
3699 * encoder for NoSql databases).
3700 *
3701 * @function
3702 * @param {Encoder} encoder
3703 * @param {Uint8Array} buf The string that is to be encoded.
3704 */
3705 const writeTerminatedUint8Array = (encoder, buf) => {
3706 for (let i = 0; i < buf.length; i++) {
3707 const b = buf[i]
3708 if (b === 0 || b === 1) {
3709 write(encoder, 1)
3710 }
3711 write(encoder, buf[i])
3712 }
3713 write(encoder, 0)
3714 }
3715
3716 /**
3717 * Write the content of another Encoder.
3718 *
3719 * @TODO: can be improved!
3720 * - Note: Should consider that when appending a lot of small Encoders, we should rather clone than referencing the old structure.
3721 * Encoders start with a rather big initial buffer.
3722 *
3723 * @function
3724 * @param {Encoder} encoder The enUint8Arr
3725 * @param {Encoder} append The BinaryEncoder to be written.
3726 */
3727 const writeBinaryEncoder = (encoder, append) => writeUint8Array(encoder, toUint8Array(append))
3728
3729 /**
3730 * Append fixed-length Uint8Array to the encoder.
3731 *
3732 * @function
3733 * @param {Encoder} encoder
3734 * @param {Uint8Array} uint8Array
3735 */
3736 const writeUint8Array = (encoder, uint8Array) => {
3737 const bufferLen = encoder.cbuf.length
3738 const cpos = encoder.cpos
3739 const leftCopyLen = min(bufferLen - cpos, uint8Array.length)
3740 const rightCopyLen = uint8Array.length - leftCopyLen
3741 encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos)
3742 encoder.cpos += leftCopyLen
3743 if (rightCopyLen > 0) {
3744 // Still something to write, write right half..
3745 // Append new buffer
3746 encoder.bufs.push(encoder.cbuf)
3747 // must have at least size of remaining buffer
3748 encoder.cbuf = new Uint8Array(max(bufferLen * 2, rightCopyLen))
3749 // copy array
3750 encoder.cbuf.set(uint8Array.subarray(leftCopyLen))
3751 encoder.cpos = rightCopyLen
3752 }
3753 }
3754
3755 /**
3756 * Append an Uint8Array to Encoder.
3757 *
3758 * @function
3759 * @param {Encoder} encoder
3760 * @param {Uint8Array} uint8Array
3761 */
3762 const writeVarUint8Array = (encoder, uint8Array) => {
3763 writeVarUint(encoder, uint8Array.byteLength)
3764 writeUint8Array(encoder, uint8Array)
3765 }
3766
3767 /**
3768 * Create an DataView of the next `len` bytes. Use it to write data after
3769 * calling this function.
3770 *
3771 * ```js
3772 * // write float32 using DataView
3773 * const dv = writeOnDataView(encoder, 4)
3774 * dv.setFloat32(0, 1.1)
3775 * // read float32 using DataView
3776 * const dv = readFromDataView(encoder, 4)
3777 * dv.getFloat32(0) // => 1.100000023841858 (leaving it to the reader to find out why this is the correct result)
3778 * ```
3779 *
3780 * @param {Encoder} encoder
3781 * @param {number} len
3782 * @return {DataView}
3783 */
3784 const writeOnDataView = (encoder, len) => {
3785 verifyLen(encoder, len)
3786 const dview = new DataView(encoder.cbuf.buffer, encoder.cpos, len)
3787 encoder.cpos += len
3788 return dview
3789 }
3790
3791 /**
3792 * @param {Encoder} encoder
3793 * @param {number} num
3794 */
3795 const writeFloat32 = (encoder, num) => writeOnDataView(encoder, 4).setFloat32(0, num, false)
3796
3797 /**
3798 * @param {Encoder} encoder
3799 * @param {number} num
3800 */
3801 const writeFloat64 = (encoder, num) => writeOnDataView(encoder, 8).setFloat64(0, num, false)
3802
3803 /**
3804 * @param {Encoder} encoder
3805 * @param {bigint} num
3806 */
3807 const writeBigInt64 = (encoder, num) => /** @type {any} */ (writeOnDataView(encoder, 8)).setBigInt64(0, num, false)
3808
3809 /**
3810 * @param {Encoder} encoder
3811 * @param {bigint} num
3812 */
3813 const writeBigUint64 = (encoder, num) => /** @type {any} */ (writeOnDataView(encoder, 8)).setBigUint64(0, num, false)
3814
3815 const floatTestBed = new DataView(new ArrayBuffer(4))
3816 /**
3817 * Check if a number can be encoded as a 32 bit float.
3818 *
3819 * @param {number} num
3820 * @return {boolean}
3821 */
3822 const isFloat32 = num => {
3823 floatTestBed.setFloat32(0, num)
3824 return floatTestBed.getFloat32(0) === num
3825 }
3826
3827 /**
3828 * Encode data with efficient binary format.
3829 *
3830 * Differences to JSON:
3831 * • Transforms data to a binary format (not to a string)
3832 * • Encodes undefined, NaN, and ArrayBuffer (these can't be represented in JSON)
3833 * • Numbers are efficiently encoded either as a variable length integer, as a
3834 * 32 bit float, as a 64 bit float, or as a 64 bit bigint.
3835 *
3836 * Encoding table:
3837 *
3838 * | Data Type | Prefix | Encoding Method | Comment |
3839 * | ------------------- | -------- | ------------------ | ------- |
3840 * | undefined | 127 | | Functions, symbol, and everything that cannot be identified is encoded as undefined |
3841 * | null | 126 | | |
3842 * | integer | 125 | writeVarInt | Only encodes 32 bit signed integers |
3843 * | float32 | 124 | writeFloat32 | |
3844 * | float64 | 123 | writeFloat64 | |
3845 * | bigint | 122 | writeBigInt64 | |
3846 * | boolean (false) | 121 | | True and false are different data types so we save the following byte |
3847 * | boolean (true) | 120 | | - 0b01111000 so the last bit determines whether true or false |
3848 * | string | 119 | writeVarString | |
3849 * | object<string,any> | 118 | custom | Writes {length} then {length} key-value pairs |
3850 * | array<any> | 117 | custom | Writes {length} then {length} json values |
3851 * | Uint8Array | 116 | writeVarUint8Array | We use Uint8Array for any kind of binary data |
3852 *
3853 * Reasons for the decreasing prefix:
3854 * We need the first bit for extendability (later we may want to encode the
3855 * prefix with writeVarUint). The remaining 7 bits are divided as follows:
3856 * [0-30] the beginning of the data range is used for custom purposes
3857 * (defined by the function that uses this library)
3858 * [31-127] the end of the data range is used for data encoding by
3859 * lib0/encoding.js
3860 *
3861 * @param {Encoder} encoder
3862 * @param {undefined|null|number|bigint|boolean|string|Object<string,any>|Array<any>|Uint8Array} data
3863 */
3864 const writeAny = (encoder, data) => {
3865 switch (typeof data) {
3866 case 'string':
3867 // TYPE 119: STRING
3868 write(encoder, 119)
3869 writeVarString(encoder, data)
3870 break
3871 case 'number':
3872 if (isInteger(data) && abs(data) <= BITS31) {
3873 // TYPE 125: INTEGER
3874 write(encoder, 125)
3875 writeVarInt(encoder, data)
3876 } else if (isFloat32(data)) {
3877 // TYPE 124: FLOAT32
3878 write(encoder, 124)
3879 writeFloat32(encoder, data)
3880 } else {
3881 // TYPE 123: FLOAT64
3882 write(encoder, 123)
3883 writeFloat64(encoder, data)
3884 }
3885 break
3886 case 'bigint':
3887 // TYPE 122: BigInt
3888 write(encoder, 122)
3889 writeBigInt64(encoder, data)
3890 break
3891 case 'object':
3892 if (data === null) {
3893 // TYPE 126: null
3894 write(encoder, 126)
3895 } else if (isArray(data)) {
3896 // TYPE 117: Array
3897 write(encoder, 117)
3898 writeVarUint(encoder, data.length)
3899 for (let i = 0; i < data.length; i++) {
3900 writeAny(encoder, data[i])
3901 }
3902 } else if (data instanceof Uint8Array) {
3903 // TYPE 116: ArrayBuffer
3904 write(encoder, 116)
3905 writeVarUint8Array(encoder, data)
3906 } else {
3907 // TYPE 118: Object
3908 write(encoder, 118)
3909 const keys = Object.keys(data)
3910 writeVarUint(encoder, keys.length)
3911 for (let i = 0; i < keys.length; i++) {
3912 const key = keys[i]
3913 writeVarString(encoder, key)
3914 writeAny(encoder, data[key])
3915 }
3916 }
3917 break
3918 case 'boolean':
3919 // TYPE 120/121: boolean (true/false)
3920 write(encoder, data ? 120 : 121)
3921 break
3922 default:
3923 // TYPE 127: undefined
3924 write(encoder, 127)
3925 }
3926 }
3927
3928 /**
3929 * Now come a few stateful encoder that have their own classes.
3930 */
3931
3932 /**
3933 * Basic Run Length Encoder - a basic compression implementation.
3934 *
3935 * 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.
3936 *
3937 * It was originally used for image compression. Cool .. article http://csbruce.com/cbm/transactor/pdfs/trans_v7_i06.pdf
3938 *
3939 * @note T must not be null!
3940 *
3941 * @template T
3942 */
3943 class RleEncoder extends Encoder {
3944 /**
3945 * @param {function(Encoder, T):void} writer
3946 */
3947 constructor (writer) {
3948 super()
3949 /**
3950 * The writer
3951 */
3952 this.w = writer
3953 /**
3954 * Current state
3955 * @type {T|null}
3956 */
3957 this.s = null
3958 this.count = 0
3959 }
3960
3961 /**
3962 * @param {T} v
3963 */
3964 write (v) {
3965 if (this.s === v) {
3966 this.count++
3967 } else {
3968 if (this.count > 0) {
3969 // flush counter, unless this is the first value (count = 0)
3970 writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw
3971 }
3972 this.count = 1
3973 // write first value
3974 this.w(this, v)
3975 this.s = v
3976 }
3977 }
3978 }
3979
3980 /**
3981 * Basic diff decoder using variable length encoding.
3982 *
3983 * Encodes the values [3, 1100, 1101, 1050, 0] to [3, 1097, 1, -51, -1050] using writeVarInt.
3984 */
3985 class IntDiffEncoder extends (/* unused pure expression or super */ null && (Encoder)) {
3986 /**
3987 * @param {number} start
3988 */
3989 constructor (start) {
3990 super()
3991 /**
3992 * Current state
3993 * @type {number}
3994 */
3995 this.s = start
3996 }
3997
3998 /**
3999 * @param {number} v
4000 */
4001 write (v) {
4002 writeVarInt(this, v - this.s)
4003 this.s = v
4004 }
4005 }
4006
4007 /**
4008 * A combination of IntDiffEncoder and RleEncoder.
4009 *
4010 * Basically first writes the IntDiffEncoder and then counts duplicate diffs using RleEncoding.
4011 *
4012 * 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])
4013 */
4014 class RleIntDiffEncoder extends (/* unused pure expression or super */ null && (Encoder)) {
4015 /**
4016 * @param {number} start
4017 */
4018 constructor (start) {
4019 super()
4020 /**
4021 * Current state
4022 * @type {number}
4023 */
4024 this.s = start
4025 this.count = 0
4026 }
4027
4028 /**
4029 * @param {number} v
4030 */
4031 write (v) {
4032 if (this.s === v && this.count > 0) {
4033 this.count++
4034 } else {
4035 if (this.count > 0) {
4036 // flush counter, unless this is the first value (count = 0)
4037 writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw
4038 }
4039 this.count = 1
4040 // write first value
4041 writeVarInt(this, v - this.s)
4042 this.s = v
4043 }
4044 }
4045 }
4046
4047 /**
4048 * @param {UintOptRleEncoder} encoder
4049 */
4050 const flushUintOptRleEncoder = encoder => {
4051 if (encoder.count > 0) {
4052 // flush counter, unless this is the first value (count = 0)
4053 // case 1: just a single value. set sign to positive
4054 // case 2: write several values. set sign to negative to indicate that there is a length coming
4055 writeVarInt(encoder.encoder, encoder.count === 1 ? encoder.s : -encoder.s)
4056 if (encoder.count > 1) {
4057 writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw
4058 }
4059 }
4060 }
4061
4062 /**
4063 * Optimized Rle encoder that does not suffer from the mentioned problem of the basic Rle encoder.
4064 *
4065 * Internally uses VarInt encoder to write unsigned integers. If the input occurs multiple times, we write
4066 * write it as a negative number. The UintOptRleDecoder then understands that it needs to read a count.
4067 *
4068 * Encodes [1,2,3,3,3] as [1,2,-3,3] (once 1, once 2, three times 3)
4069 */
4070 class UintOptRleEncoder {
4071 constructor () {
4072 this.encoder = new Encoder()
4073 /**
4074 * @type {number}
4075 */
4076 this.s = 0
4077 this.count = 0
4078 }
4079
4080 /**
4081 * @param {number} v
4082 */
4083 write (v) {
4084 if (this.s === v) {
4085 this.count++
4086 } else {
4087 flushUintOptRleEncoder(this)
4088 this.count = 1
4089 this.s = v
4090 }
4091 }
4092
4093 toUint8Array () {
4094 flushUintOptRleEncoder(this)
4095 return toUint8Array(this.encoder)
4096 }
4097 }
4098
4099 /**
4100 * Increasing Uint Optimized RLE Encoder
4101 *
4102 * The RLE encoder counts the number of same occurences of the same value.
4103 * The IncUintOptRle encoder counts if the value increases.
4104 * I.e. 7, 8, 9, 10 will be encoded as [-7, 4]. 1, 3, 5 will be encoded
4105 * as [1, 3, 5].
4106 */
4107 class IncUintOptRleEncoder {
4108 constructor () {
4109 this.encoder = new Encoder()
4110 /**
4111 * @type {number}
4112 */
4113 this.s = 0
4114 this.count = 0
4115 }
4116
4117 /**
4118 * @param {number} v
4119 */
4120 write (v) {
4121 if (this.s + this.count === v) {
4122 this.count++
4123 } else {
4124 flushUintOptRleEncoder(this)
4125 this.count = 1
4126 this.s = v
4127 }
4128 }
4129
4130 toUint8Array () {
4131 flushUintOptRleEncoder(this)
4132 return toUint8Array(this.encoder)
4133 }
4134 }
4135
4136 /**
4137 * @param {IntDiffOptRleEncoder} encoder
4138 */
4139 const flushIntDiffOptRleEncoder = encoder => {
4140 if (encoder.count > 0) {
4141 // 31 bit making up the diff | wether to write the counter
4142 // const encodedDiff = encoder.diff << 1 | (encoder.count === 1 ? 0 : 1)
4143 const encodedDiff = encoder.diff * 2 + (encoder.count === 1 ? 0 : 1)
4144 // flush counter, unless this is the first value (count = 0)
4145 // case 1: just a single value. set first bit to positive
4146 // case 2: write several values. set first bit to negative to indicate that there is a length coming
4147 writeVarInt(encoder.encoder, encodedDiff)
4148 if (encoder.count > 1) {
4149 writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw
4150 }
4151 }
4152 }
4153
4154 /**
4155 * A combination of the IntDiffEncoder and the UintOptRleEncoder.
4156 *
4157 * The count approach is similar to the UintDiffOptRleEncoder, but instead of using the negative bitflag, it encodes
4158 * in the LSB whether a count is to be read. Therefore this Encoder only supports 31 bit integers!
4159 *
4160 * Encodes [1, 2, 3, 2] as [3, 1, 6, -1] (more specifically [(1 << 1) | 1, (3 << 0) | 0, -1])
4161 *
4162 * Internally uses variable length encoding. Contrary to normal UintVar encoding, the first byte contains:
4163 * * 1 bit that denotes whether the next value is a count (LSB)
4164 * * 1 bit that denotes whether this value is negative (MSB - 1)
4165 * * 1 bit that denotes whether to continue reading the variable length integer (MSB)
4166 *
4167 * Therefore, only five bits remain to encode diff ranges.
4168 *
4169 * Use this Encoder only when appropriate. In most cases, this is probably a bad idea.
4170 */
4171 class IntDiffOptRleEncoder {
4172 constructor () {
4173 this.encoder = new Encoder()
4174 /**
4175 * @type {number}
4176 */
4177 this.s = 0
4178 this.count = 0
4179 this.diff = 0
4180 }
4181
4182 /**
4183 * @param {number} v
4184 */
4185 write (v) {
4186 if (this.diff === v - this.s) {
4187 this.s = v
4188 this.count++
4189 } else {
4190 flushIntDiffOptRleEncoder(this)
4191 this.count = 1
4192 this.diff = v - this.s
4193 this.s = v
4194 }
4195 }
4196
4197 toUint8Array () {
4198 flushIntDiffOptRleEncoder(this)
4199 return toUint8Array(this.encoder)
4200 }
4201 }
4202
4203 /**
4204 * Optimized String Encoder.
4205 *
4206 * 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.
4207 * 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?).
4208 *
4209 * This string encoder solves the above problem. All strings are concatenated and written as a single string using a single encoding call.
4210 *
4211 * The lengths are encoded using a UintOptRleEncoder.
4212 */
4213 class StringEncoder {
4214 constructor () {
4215 /**
4216 * @type {Array<string>}
4217 */
4218 this.sarr = []
4219 this.s = ''
4220 this.lensE = new UintOptRleEncoder()
4221 }
4222
4223 /**
4224 * @param {string} string
4225 */
4226 write (string) {
4227 this.s += string
4228 if (this.s.length > 19) {
4229 this.sarr.push(this.s)
4230 this.s = ''
4231 }
4232 this.lensE.write(string.length)
4233 }
4234
4235 toUint8Array () {
4236 const encoder = new Encoder()
4237 this.sarr.push(this.s)
4238 this.s = ''
4239 writeVarString(encoder, this.sarr.join(''))
4240 writeUint8Array(encoder, this.lensE.toUint8Array())
4241 return toUint8Array(encoder)
4242 }
4243 }
4244
4245 ;// CONCATENATED MODULE: ./node_modules/lib0/error.js
4246 /**
4247 * Error helpers.
4248 *
4249 * @module error
4250 */
4251
4252 /**
4253 * @param {string} s
4254 * @return {Error}
4255 */
4256 /* c8 ignore next */
4257 const error_create = s => new Error(s)
4258
4259 /**
4260 * @throws {Error}
4261 * @return {never}
4262 */
4263 /* c8 ignore next 3 */
4264 const methodUnimplemented = () => {
4265 throw error_create('Method unimplemented')
4266 }
4267
4268 /**
4269 * @throws {Error}
4270 * @return {never}
4271 */
4272 /* c8 ignore next 3 */
4273 const unexpectedCase = () => {
4274 throw error_create('Unexpected case')
4275 }
4276
4277 ;// CONCATENATED MODULE: ./node_modules/lib0/decoding.js
4278 /**
4279 * Efficient schema-less binary decoding with support for variable length encoding.
4280 *
4281 * Use [lib0/decoding] with [lib0/encoding]. Every encoding function has a corresponding decoding function.
4282 *
4283 * Encodes numbers in little-endian order (least to most significant byte order)
4284 * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
4285 * which is also used in Protocol Buffers.
4286 *
4287 * ```js
4288 * // encoding step
4289 * const encoder = encoding.createEncoder()
4290 * encoding.writeVarUint(encoder, 256)
4291 * encoding.writeVarString(encoder, 'Hello world!')
4292 * const buf = encoding.toUint8Array(encoder)
4293 * ```
4294 *
4295 * ```js
4296 * // decoding step
4297 * const decoder = decoding.createDecoder(buf)
4298 * decoding.readVarUint(decoder) // => 256
4299 * decoding.readVarString(decoder) // => 'Hello world!'
4300 * decoding.hasContent(decoder) // => false - all data is read
4301 * ```
4302 *
4303 * @module decoding
4304 */
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314 const errorUnexpectedEndOfArray = error_create('Unexpected end of array')
4315 const errorIntegerOutOfRange = error_create('Integer out of Range')
4316
4317 /**
4318 * A Decoder handles the decoding of an Uint8Array.
4319 */
4320 class Decoder {
4321 /**
4322 * @param {Uint8Array} uint8Array Binary data to decode
4323 */
4324 constructor (uint8Array) {
4325 /**
4326 * Decoding target.
4327 *
4328 * @type {Uint8Array}
4329 */
4330 this.arr = uint8Array
4331 /**
4332 * Current decoding position.
4333 *
4334 * @type {number}
4335 */
4336 this.pos = 0
4337 }
4338 }
4339
4340 /**
4341 * @function
4342 * @param {Uint8Array} uint8Array
4343 * @return {Decoder}
4344 */
4345 const createDecoder = uint8Array => new Decoder(uint8Array)
4346
4347 /**
4348 * @function
4349 * @param {Decoder} decoder
4350 * @return {boolean}
4351 */
4352 const decoding_hasContent = decoder => decoder.pos !== decoder.arr.length
4353
4354 /**
4355 * Clone a decoder instance.
4356 * Optionally set a new position parameter.
4357 *
4358 * @function
4359 * @param {Decoder} decoder The decoder instance
4360 * @param {number} [newPos] Defaults to current position
4361 * @return {Decoder} A clone of `decoder`
4362 */
4363 const clone = (decoder, newPos = decoder.pos) => {
4364 const _decoder = createDecoder(decoder.arr)
4365 _decoder.pos = newPos
4366 return _decoder
4367 }
4368
4369 /**
4370 * Create an Uint8Array view of the next `len` bytes and advance the position by `len`.
4371 *
4372 * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
4373 * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
4374 *
4375 * @function
4376 * @param {Decoder} decoder The decoder instance
4377 * @param {number} len The length of bytes to read
4378 * @return {Uint8Array}
4379 */
4380 const readUint8Array = (decoder, len) => {
4381 const view = createUint8ArrayViewFromArrayBuffer(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len)
4382 decoder.pos += len
4383 return view
4384 }
4385
4386 /**
4387 * Read variable length Uint8Array.
4388 *
4389 * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
4390 * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
4391 *
4392 * @function
4393 * @param {Decoder} decoder
4394 * @return {Uint8Array}
4395 */
4396 const readVarUint8Array = decoder => readUint8Array(decoder, readVarUint(decoder))
4397
4398 /**
4399 * Read the rest of the content as an ArrayBuffer
4400 * @function
4401 * @param {Decoder} decoder
4402 * @return {Uint8Array}
4403 */
4404 const readTailAsUint8Array = decoder => readUint8Array(decoder, decoder.arr.length - decoder.pos)
4405
4406 /**
4407 * Skip one byte, jump to the next position.
4408 * @function
4409 * @param {Decoder} decoder The decoder instance
4410 * @return {number} The next position
4411 */
4412 const skip8 = decoder => decoder.pos++
4413
4414 /**
4415 * Read one byte as unsigned integer.
4416 * @function
4417 * @param {Decoder} decoder The decoder instance
4418 * @return {number} Unsigned 8-bit integer
4419 */
4420 const readUint8 = decoder => decoder.arr[decoder.pos++]
4421
4422 /**
4423 * Read 2 bytes as unsigned integer.
4424 *
4425 * @function
4426 * @param {Decoder} decoder
4427 * @return {number} An unsigned integer.
4428 */
4429 const readUint16 = decoder => {
4430 const uint =
4431 decoder.arr[decoder.pos] +
4432 (decoder.arr[decoder.pos + 1] << 8)
4433 decoder.pos += 2
4434 return uint
4435 }
4436
4437 /**
4438 * Read 4 bytes as unsigned integer.
4439 *
4440 * @function
4441 * @param {Decoder} decoder
4442 * @return {number} An unsigned integer.
4443 */
4444 const readUint32 = decoder => {
4445 const uint =
4446 (decoder.arr[decoder.pos] +
4447 (decoder.arr[decoder.pos + 1] << 8) +
4448 (decoder.arr[decoder.pos + 2] << 16) +
4449 (decoder.arr[decoder.pos + 3] << 24)) >>> 0
4450 decoder.pos += 4
4451 return uint
4452 }
4453
4454 /**
4455 * Read 4 bytes as unsigned integer in big endian order.
4456 * (most significant byte first)
4457 *
4458 * @function
4459 * @param {Decoder} decoder
4460 * @return {number} An unsigned integer.
4461 */
4462 const readUint32BigEndian = decoder => {
4463 const uint =
4464 (decoder.arr[decoder.pos + 3] +
4465 (decoder.arr[decoder.pos + 2] << 8) +
4466 (decoder.arr[decoder.pos + 1] << 16) +
4467 (decoder.arr[decoder.pos] << 24)) >>> 0
4468 decoder.pos += 4
4469 return uint
4470 }
4471
4472 /**
4473 * Look ahead without incrementing the position
4474 * to the next byte and read it as unsigned integer.
4475 *
4476 * @function
4477 * @param {Decoder} decoder
4478 * @return {number} An unsigned integer.
4479 */
4480 const peekUint8 = decoder => decoder.arr[decoder.pos]
4481
4482 /**
4483 * Look ahead without incrementing the position
4484 * to the next byte and read it as unsigned integer.
4485 *
4486 * @function
4487 * @param {Decoder} decoder
4488 * @return {number} An unsigned integer.
4489 */
4490 const peekUint16 = decoder =>
4491 decoder.arr[decoder.pos] +
4492 (decoder.arr[decoder.pos + 1] << 8)
4493
4494 /**
4495 * Look ahead without incrementing the position
4496 * to the next byte and read it as unsigned integer.
4497 *
4498 * @function
4499 * @param {Decoder} decoder
4500 * @return {number} An unsigned integer.
4501 */
4502 const peekUint32 = decoder => (
4503 decoder.arr[decoder.pos] +
4504 (decoder.arr[decoder.pos + 1] << 8) +
4505 (decoder.arr[decoder.pos + 2] << 16) +
4506 (decoder.arr[decoder.pos + 3] << 24)
4507 ) >>> 0
4508
4509 /**
4510 * Read unsigned integer (32bit) with variable length.
4511 * 1/8th of the storage is used as encoding overhead.
4512 * * numbers < 2^7 is stored in one bytlength
4513 * * numbers < 2^14 is stored in two bylength
4514 *
4515 * @function
4516 * @param {Decoder} decoder
4517 * @return {number} An unsigned integer.length
4518 */
4519 const readVarUint = decoder => {
4520 let num = 0
4521 let mult = 1
4522 const len = decoder.arr.length
4523 while (decoder.pos < len) {
4524 const r = decoder.arr[decoder.pos++]
4525 // num = num | ((r & binary.BITS7) << len)
4526 num = num + (r & BITS7) * mult // shift $r << (7*#iterations) and add it to num
4527 mult *= 128 // next iteration, shift 7 "more" to the left
4528 if (r < BIT8) {
4529 return num
4530 }
4531 /* c8 ignore start */
4532 if (num > MAX_SAFE_INTEGER) {
4533 throw errorIntegerOutOfRange
4534 }
4535 /* c8 ignore stop */
4536 }
4537 throw errorUnexpectedEndOfArray
4538 }
4539
4540 /**
4541 * Read signed integer (32bit) with variable length.
4542 * 1/8th of the storage is used as encoding overhead.
4543 * * numbers < 2^7 is stored in one bytlength
4544 * * numbers < 2^14 is stored in two bylength
4545 * @todo This should probably create the inverse ~num if number is negative - but this would be a breaking change.
4546 *
4547 * @function
4548 * @param {Decoder} decoder
4549 * @return {number} An unsigned integer.length
4550 */
4551 const readVarInt = decoder => {
4552 let r = decoder.arr[decoder.pos++]
4553 let num = r & BITS6
4554 let mult = 64
4555 const sign = (r & BIT7) > 0 ? -1 : 1
4556 if ((r & BIT8) === 0) {
4557 // don't continue reading
4558 return sign * num
4559 }
4560 const len = decoder.arr.length
4561 while (decoder.pos < len) {
4562 r = decoder.arr[decoder.pos++]
4563 // num = num | ((r & binary.BITS7) << len)
4564 num = num + (r & BITS7) * mult
4565 mult *= 128
4566 if (r < BIT8) {
4567 return sign * num
4568 }
4569 /* c8 ignore start */
4570 if (num > MAX_SAFE_INTEGER) {
4571 throw errorIntegerOutOfRange
4572 }
4573 /* c8 ignore stop */
4574 }
4575 throw errorUnexpectedEndOfArray
4576 }
4577
4578 /**
4579 * Look ahead and read varUint without incrementing position
4580 *
4581 * @function
4582 * @param {Decoder} decoder
4583 * @return {number}
4584 */
4585 const peekVarUint = decoder => {
4586 const pos = decoder.pos
4587 const s = readVarUint(decoder)
4588 decoder.pos = pos
4589 return s
4590 }
4591
4592 /**
4593 * Look ahead and read varUint without incrementing position
4594 *
4595 * @function
4596 * @param {Decoder} decoder
4597 * @return {number}
4598 */
4599 const peekVarInt = decoder => {
4600 const pos = decoder.pos
4601 const s = readVarInt(decoder)
4602 decoder.pos = pos
4603 return s
4604 }
4605
4606 /**
4607 * We don't test this function anymore as we use native decoding/encoding by default now.
4608 * Better not modify this anymore..
4609 *
4610 * Transforming utf8 to a string is pretty expensive. The code performs 10x better
4611 * when String.fromCodePoint is fed with all characters as arguments.
4612 * But most environments have a maximum number of arguments per functions.
4613 * For effiency reasons we apply a maximum of 10000 characters at once.
4614 *
4615 * @function
4616 * @param {Decoder} decoder
4617 * @return {String} The read String.
4618 */
4619 /* c8 ignore start */
4620 const _readVarStringPolyfill = decoder => {
4621 let remainingLen = readVarUint(decoder)
4622 if (remainingLen === 0) {
4623 return ''
4624 } else {
4625 let encodedString = String.fromCodePoint(readUint8(decoder)) // remember to decrease remainingLen
4626 if (--remainingLen < 100) { // do not create a Uint8Array for small strings
4627 while (remainingLen--) {
4628 encodedString += String.fromCodePoint(readUint8(decoder))
4629 }
4630 } else {
4631 while (remainingLen > 0) {
4632 const nextLen = remainingLen < 10000 ? remainingLen : 10000
4633 // this is dangerous, we create a fresh array view from the existing buffer
4634 const bytes = decoder.arr.subarray(decoder.pos, decoder.pos + nextLen)
4635 decoder.pos += nextLen
4636 // Starting with ES5.1 we can supply a generic array-like object as arguments
4637 encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes))
4638 remainingLen -= nextLen
4639 }
4640 }
4641 return decodeURIComponent(escape(encodedString))
4642 }
4643 }
4644 /* c8 ignore stop */
4645
4646 /**
4647 * @function
4648 * @param {Decoder} decoder
4649 * @return {String} The read String
4650 */
4651 const _readVarStringNative = decoder =>
4652 /** @type any */ (utf8TextDecoder).decode(readVarUint8Array(decoder))
4653
4654 /**
4655 * Read string of variable length
4656 * * varUint is used to store the length of the string
4657 *
4658 * @function
4659 * @param {Decoder} decoder
4660 * @return {String} The read String
4661 *
4662 */
4663 /* c8 ignore next */
4664 const readVarString = utf8TextDecoder ? _readVarStringNative : _readVarStringPolyfill
4665
4666 /**
4667 * @param {Decoder} decoder
4668 * @return {Uint8Array}
4669 */
4670 const readTerminatedUint8Array = decoder => {
4671 const encoder = encoding.createEncoder()
4672 let b
4673 while (true) {
4674 b = readUint8(decoder)
4675 if (b === 0) {
4676 return encoding.toUint8Array(encoder)
4677 }
4678 if (b === 1) {
4679 b = readUint8(decoder)
4680 }
4681 encoding.write(encoder, b)
4682 }
4683 }
4684
4685 /**
4686 * @param {Decoder} decoder
4687 * @return {string}
4688 */
4689 const readTerminatedString = decoder => string.decodeUtf8(readTerminatedUint8Array(decoder))
4690
4691 /**
4692 * Look ahead and read varString without incrementing position
4693 *
4694 * @function
4695 * @param {Decoder} decoder
4696 * @return {string}
4697 */
4698 const peekVarString = decoder => {
4699 const pos = decoder.pos
4700 const s = readVarString(decoder)
4701 decoder.pos = pos
4702 return s
4703 }
4704
4705 /**
4706 * @param {Decoder} decoder
4707 * @param {number} len
4708 * @return {DataView}
4709 */
4710 const readFromDataView = (decoder, len) => {
4711 const dv = new DataView(decoder.arr.buffer, decoder.arr.byteOffset + decoder.pos, len)
4712 decoder.pos += len
4713 return dv
4714 }
4715
4716 /**
4717 * @param {Decoder} decoder
4718 */
4719 const readFloat32 = decoder => readFromDataView(decoder, 4).getFloat32(0, false)
4720
4721 /**
4722 * @param {Decoder} decoder
4723 */
4724 const readFloat64 = decoder => readFromDataView(decoder, 8).getFloat64(0, false)
4725
4726 /**
4727 * @param {Decoder} decoder
4728 */
4729 const readBigInt64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigInt64(0, false)
4730
4731 /**
4732 * @param {Decoder} decoder
4733 */
4734 const readBigUint64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigUint64(0, false)
4735
4736 /**
4737 * @type {Array<function(Decoder):any>}
4738 */
4739 const readAnyLookupTable = [
4740 decoder => undefined, // CASE 127: undefined
4741 decoder => null, // CASE 126: null
4742 readVarInt, // CASE 125: integer
4743 readFloat32, // CASE 124: float32
4744 readFloat64, // CASE 123: float64
4745 readBigInt64, // CASE 122: bigint
4746 decoder => false, // CASE 121: boolean (false)
4747 decoder => true, // CASE 120: boolean (true)
4748 readVarString, // CASE 119: string
4749 decoder => { // CASE 118: object<string,any>
4750 const len = readVarUint(decoder)
4751 /**
4752 * @type {Object<string,any>}
4753 */
4754 const obj = {}
4755 for (let i = 0; i < len; i++) {
4756 const key = readVarString(decoder)
4757 obj[key] = readAny(decoder)
4758 }
4759 return obj
4760 },
4761 decoder => { // CASE 117: array<any>
4762 const len = readVarUint(decoder)
4763 const arr = []
4764 for (let i = 0; i < len; i++) {
4765 arr.push(readAny(decoder))
4766 }
4767 return arr
4768 },
4769 readVarUint8Array // CASE 116: Uint8Array
4770 ]
4771
4772 /**
4773 * @param {Decoder} decoder
4774 */
4775 const readAny = decoder => readAnyLookupTable[127 - readUint8(decoder)](decoder)
4776
4777 /**
4778 * T must not be null.
4779 *
4780 * @template T
4781 */
4782 class RleDecoder extends Decoder {
4783 /**
4784 * @param {Uint8Array} uint8Array
4785 * @param {function(Decoder):T} reader
4786 */
4787 constructor (uint8Array, reader) {
4788 super(uint8Array)
4789 /**
4790 * The reader
4791 */
4792 this.reader = reader
4793 /**
4794 * Current state
4795 * @type {T|null}
4796 */
4797 this.s = null
4798 this.count = 0
4799 }
4800
4801 read () {
4802 if (this.count === 0) {
4803 this.s = this.reader(this)
4804 if (decoding_hasContent(this)) {
4805 this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented
4806 } else {
4807 this.count = -1 // read the current value forever
4808 }
4809 }
4810 this.count--
4811 return /** @type {T} */ (this.s)
4812 }
4813 }
4814
4815 class IntDiffDecoder extends (/* unused pure expression or super */ null && (Decoder)) {
4816 /**
4817 * @param {Uint8Array} uint8Array
4818 * @param {number} start
4819 */
4820 constructor (uint8Array, start) {
4821 super(uint8Array)
4822 /**
4823 * Current state
4824 * @type {number}
4825 */
4826 this.s = start
4827 }
4828
4829 /**
4830 * @return {number}
4831 */
4832 read () {
4833 this.s += readVarInt(this)
4834 return this.s
4835 }
4836 }
4837
4838 class RleIntDiffDecoder extends (/* unused pure expression or super */ null && (Decoder)) {
4839 /**
4840 * @param {Uint8Array} uint8Array
4841 * @param {number} start
4842 */
4843 constructor (uint8Array, start) {
4844 super(uint8Array)
4845 /**
4846 * Current state
4847 * @type {number}
4848 */
4849 this.s = start
4850 this.count = 0
4851 }
4852
4853 /**
4854 * @return {number}
4855 */
4856 read () {
4857 if (this.count === 0) {
4858 this.s += readVarInt(this)
4859 if (decoding_hasContent(this)) {
4860 this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented
4861 } else {
4862 this.count = -1 // read the current value forever
4863 }
4864 }
4865 this.count--
4866 return /** @type {number} */ (this.s)
4867 }
4868 }
4869
4870 class UintOptRleDecoder extends Decoder {
4871 /**
4872 * @param {Uint8Array} uint8Array
4873 */
4874 constructor (uint8Array) {
4875 super(uint8Array)
4876 /**
4877 * @type {number}
4878 */
4879 this.s = 0
4880 this.count = 0
4881 }
4882
4883 read () {
4884 if (this.count === 0) {
4885 this.s = readVarInt(this)
4886 // if the sign is negative, we read the count too, otherwise count is 1
4887 const isNegative = isNegativeZero(this.s)
4888 this.count = 1
4889 if (isNegative) {
4890 this.s = -this.s
4891 this.count = readVarUint(this) + 2
4892 }
4893 }
4894 this.count--
4895 return /** @type {number} */ (this.s)
4896 }
4897 }
4898
4899 class IncUintOptRleDecoder extends (/* unused pure expression or super */ null && (Decoder)) {
4900 /**
4901 * @param {Uint8Array} uint8Array
4902 */
4903 constructor (uint8Array) {
4904 super(uint8Array)
4905 /**
4906 * @type {number}
4907 */
4908 this.s = 0
4909 this.count = 0
4910 }
4911
4912 read () {
4913 if (this.count === 0) {
4914 this.s = readVarInt(this)
4915 // if the sign is negative, we read the count too, otherwise count is 1
4916 const isNegative = math.isNegativeZero(this.s)
4917 this.count = 1
4918 if (isNegative) {
4919 this.s = -this.s
4920 this.count = readVarUint(this) + 2
4921 }
4922 }
4923 this.count--
4924 return /** @type {number} */ (this.s++)
4925 }
4926 }
4927
4928 class IntDiffOptRleDecoder extends Decoder {
4929 /**
4930 * @param {Uint8Array} uint8Array
4931 */
4932 constructor (uint8Array) {
4933 super(uint8Array)
4934 /**
4935 * @type {number}
4936 */
4937 this.s = 0
4938 this.count = 0
4939 this.diff = 0
4940 }
4941
4942 /**
4943 * @return {number}
4944 */
4945 read () {
4946 if (this.count === 0) {
4947 const diff = readVarInt(this)
4948 // if the first bit is set, we read more data
4949 const hasCount = diff & 1
4950 this.diff = floor(diff / 2) // shift >> 1
4951 this.count = 1
4952 if (hasCount) {
4953 this.count = readVarUint(this) + 2
4954 }
4955 }
4956 this.s += this.diff
4957 this.count--
4958 return this.s
4959 }
4960 }
4961
4962 class StringDecoder {
4963 /**
4964 * @param {Uint8Array} uint8Array
4965 */
4966 constructor (uint8Array) {
4967 this.decoder = new UintOptRleDecoder(uint8Array)
4968 this.str = readVarString(this.decoder)
4969 /**
4970 * @type {number}
4971 */
4972 this.spos = 0
4973 }
4974
4975 /**
4976 * @return {string}
4977 */
4978 read () {
4979 const end = this.spos + this.decoder.read()
4980 const res = this.str.slice(this.spos, end)
4981 this.spos = end
4982 return res
4983 }
4984 }
4985
4986 ;// CONCATENATED MODULE: ./node_modules/lib0/webcrypto.js
4987 /* eslint-env browser */
4988
4989 const subtle = crypto.subtle
4990 const webcrypto_getRandomValues = crypto.getRandomValues.bind(crypto)
4991
4992 ;// CONCATENATED MODULE: ./node_modules/lib0/random.js
4993 /**
4994 * Isomorphic module for true random numbers / buffers / uuids.
4995 *
4996 * Attention: falls back to Math.random if the browser does not support crypto.
4997 *
4998 * @module random
4999 */
5000
5001
5002
5003
5004
5005 const rand = Math.random
5006
5007 const uint32 = () => webcrypto_getRandomValues(new Uint32Array(1))[0]
5008
5009 const uint53 = () => {
5010 const arr = getRandomValues(new Uint32Array(8))
5011 return (arr[0] & binary.BITS21) * (binary.BITS32 + 1) + (arr[1] >>> 0)
5012 }
5013
5014 /**
5015 * @template T
5016 * @param {Array<T>} arr
5017 * @return {T}
5018 */
5019 const oneOf = arr => arr[math.floor(rand() * arr.length)]
5020
5021 // @ts-ignore
5022 const uuidv4Template = [1e7] + -1e3 + -4e3 + -8e3 + -1e11
5023
5024 /**
5025 * @return {string}
5026 */
5027 const uuidv4 = () => uuidv4Template.replace(/[018]/g, /** @param {number} c */ c =>
5028 (c ^ uint32() & 15 >> c / 4).toString(16)
5029 )
5030
5031 ;// CONCATENATED MODULE: ./node_modules/lib0/promise.js
5032 /**
5033 * Utility helpers to work with promises.
5034 *
5035 * @module promise
5036 */
5037
5038
5039
5040 /**
5041 * @template T
5042 * @callback PromiseResolve
5043 * @param {T|PromiseLike<T>} [result]
5044 */
5045
5046 /**
5047 * @template T
5048 * @param {function(PromiseResolve<T>,function(Error):void):any} f
5049 * @return {Promise<T>}
5050 */
5051 const promise_create = f => /** @type {Promise<T>} */ (new Promise(f))
5052
5053 /**
5054 * @param {function(function():void,function(Error):void):void} f
5055 * @return {Promise<void>}
5056 */
5057 const createEmpty = f => new Promise(f)
5058
5059 /**
5060 * `Promise.all` wait for all promises in the array to resolve and return the result
5061 * @template {unknown[] | []} PS
5062 *
5063 * @param {PS} ps
5064 * @return {Promise<{ -readonly [P in keyof PS]: Awaited<PS[P]> }>}
5065 */
5066 const promise_all = Promise.all.bind(Promise)
5067
5068 /**
5069 * @param {Error} [reason]
5070 * @return {Promise<never>}
5071 */
5072 const reject = reason => Promise.reject(reason)
5073
5074 /**
5075 * @template T
5076 * @param {T|void} res
5077 * @return {Promise<T|void>}
5078 */
5079 const resolve = res => Promise.resolve(res)
5080
5081 /**
5082 * @template T
5083 * @param {T} res
5084 * @return {Promise<T>}
5085 */
5086 const resolveWith = res => Promise.resolve(res)
5087
5088 /**
5089 * @todo Next version, reorder parameters: check, [timeout, [intervalResolution]]
5090 *
5091 * @param {number} timeout
5092 * @param {function():boolean} check
5093 * @param {number} [intervalResolution]
5094 * @return {Promise<void>}
5095 */
5096 const until = (timeout, check, intervalResolution = 10) => promise_create((resolve, reject) => {
5097 const startTime = time.getUnixTime()
5098 const hasTimeout = timeout > 0
5099 const untilInterval = () => {
5100 if (check()) {
5101 clearInterval(intervalHandle)
5102 resolve()
5103 } else if (hasTimeout) {
5104 /* c8 ignore else */
5105 if (time.getUnixTime() - startTime > timeout) {
5106 clearInterval(intervalHandle)
5107 reject(new Error('Timeout'))
5108 }
5109 }
5110 }
5111 const intervalHandle = setInterval(untilInterval, intervalResolution)
5112 })
5113
5114 /**
5115 * @param {number} timeout
5116 * @return {Promise<undefined>}
5117 */
5118 const wait = timeout => promise_create((resolve, reject) => setTimeout(resolve, timeout))
5119
5120 /**
5121 * Checks if an object is a promise using ducktyping.
5122 *
5123 * Promises are often polyfilled, so it makes sense to add some additional guarantees if the user of this
5124 * library has some insane environment where global Promise objects are overwritten.
5125 *
5126 * @param {any} p
5127 * @return {boolean}
5128 */
5129 const isPromise = p => p instanceof Promise || (p && p.then && p.catch && p.finally)
5130
5131 ;// CONCATENATED MODULE: ./node_modules/lib0/pair.js
5132 /**
5133 * Working with value pairs.
5134 *
5135 * @module pair
5136 */
5137
5138 /**
5139 * @template L,R
5140 */
5141 class Pair {
5142 /**
5143 * @param {L} left
5144 * @param {R} right
5145 */
5146 constructor (left, right) {
5147 this.left = left
5148 this.right = right
5149 }
5150 }
5151
5152 /**
5153 * @template L,R
5154 * @param {L} left
5155 * @param {R} right
5156 * @return {Pair<L,R>}
5157 */
5158 const pair_create = (left, right) => new Pair(left, right)
5159
5160 /**
5161 * @template L,R
5162 * @param {R} right
5163 * @param {L} left
5164 * @return {Pair<L,R>}
5165 */
5166 const createReversed = (right, left) => new Pair(left, right)
5167
5168 /**
5169 * @template L,R
5170 * @param {Array<Pair<L,R>>} arr
5171 * @param {function(L, R):any} f
5172 */
5173 const pair_forEach = (arr, f) => arr.forEach(p => f(p.left, p.right))
5174
5175 /**
5176 * @template L,R,X
5177 * @param {Array<Pair<L,R>>} arr
5178 * @param {function(L, R):X} f
5179 * @return {Array<X>}
5180 */
5181 const pair_map = (arr, f) => arr.map(p => f(p.left, p.right))
5182
5183 ;// CONCATENATED MODULE: ./node_modules/lib0/dom.js
5184 /* eslint-env browser */
5185
5186 /**
5187 * Utility module to work with the DOM.
5188 *
5189 * @module dom
5190 */
5191
5192
5193
5194
5195 /* c8 ignore start */
5196 /**
5197 * @type {Document}
5198 */
5199 const doc = /** @type {Document} */ (typeof document !== 'undefined' ? document : {})
5200
5201 /**
5202 * @param {string} name
5203 * @return {HTMLElement}
5204 */
5205 const createElement = name => doc.createElement(name)
5206
5207 /**
5208 * @return {DocumentFragment}
5209 */
5210 const createDocumentFragment = () => doc.createDocumentFragment()
5211
5212 /**
5213 * @param {string} text
5214 * @return {Text}
5215 */
5216 const createTextNode = text => doc.createTextNode(text)
5217
5218 const domParser = /** @type {DOMParser} */ (typeof DOMParser !== 'undefined' ? new DOMParser() : null)
5219
5220 /**
5221 * @param {HTMLElement} el
5222 * @param {string} name
5223 * @param {Object} opts
5224 */
5225 const emitCustomEvent = (el, name, opts) => el.dispatchEvent(new CustomEvent(name, opts))
5226
5227 /**
5228 * @param {Element} el
5229 * @param {Array<pair.Pair<string,string|boolean>>} attrs Array of key-value pairs
5230 * @return {Element}
5231 */
5232 const setAttributes = (el, attrs) => {
5233 pair.forEach(attrs, (key, value) => {
5234 if (value === false) {
5235 el.removeAttribute(key)
5236 } else if (value === true) {
5237 el.setAttribute(key, '')
5238 } else {
5239 // @ts-ignore
5240 el.setAttribute(key, value)
5241 }
5242 })
5243 return el
5244 }
5245
5246 /**
5247 * @param {Element} el
5248 * @param {Map<string, string>} attrs Array of key-value pairs
5249 * @return {Element}
5250 */
5251 const setAttributesMap = (el, attrs) => {
5252 attrs.forEach((value, key) => { el.setAttribute(key, value) })
5253 return el
5254 }
5255
5256 /**
5257 * @param {Array<Node>|HTMLCollection} children
5258 * @return {DocumentFragment}
5259 */
5260 const fragment = children => {
5261 const fragment = createDocumentFragment()
5262 for (let i = 0; i < children.length; i++) {
5263 appendChild(fragment, children[i])
5264 }
5265 return fragment
5266 }
5267
5268 /**
5269 * @param {Element} parent
5270 * @param {Array<Node>} nodes
5271 * @return {Element}
5272 */
5273 const append = (parent, nodes) => {
5274 appendChild(parent, fragment(nodes))
5275 return parent
5276 }
5277
5278 /**
5279 * @param {HTMLElement} el
5280 */
5281 const remove = el => el.remove()
5282
5283 /**
5284 * @param {EventTarget} el
5285 * @param {string} name
5286 * @param {EventListener} f
5287 */
5288 const dom_addEventListener = (el, name, f) => el.addEventListener(name, f)
5289
5290 /**
5291 * @param {EventTarget} el
5292 * @param {string} name
5293 * @param {EventListener} f
5294 */
5295 const dom_removeEventListener = (el, name, f) => el.removeEventListener(name, f)
5296
5297 /**
5298 * @param {Node} node
5299 * @param {Array<pair.Pair<string,EventListener>>} listeners
5300 * @return {Node}
5301 */
5302 const addEventListeners = (node, listeners) => {
5303 pair.forEach(listeners, (name, f) => dom_addEventListener(node, name, f))
5304 return node
5305 }
5306
5307 /**
5308 * @param {Node} node
5309 * @param {Array<pair.Pair<string,EventListener>>} listeners
5310 * @return {Node}
5311 */
5312 const removeEventListeners = (node, listeners) => {
5313 pair.forEach(listeners, (name, f) => dom_removeEventListener(node, name, f))
5314 return node
5315 }
5316
5317 /**
5318 * @param {string} name
5319 * @param {Array<pair.Pair<string,string>|pair.Pair<string,boolean>>} attrs Array of key-value pairs
5320 * @param {Array<Node>} children
5321 * @return {Element}
5322 */
5323 const dom_element = (name, attrs = [], children = []) =>
5324 append(setAttributes(createElement(name), attrs), children)
5325
5326 /**
5327 * @param {number} width
5328 * @param {number} height
5329 */
5330 const canvas = (width, height) => {
5331 const c = /** @type {HTMLCanvasElement} */ (createElement('canvas'))
5332 c.height = height
5333 c.width = width
5334 return c
5335 }
5336
5337 /**
5338 * @param {string} t
5339 * @return {Text}
5340 */
5341 const dom_text = (/* unused pure expression or super */ null && (createTextNode))
5342
5343 /**
5344 * @param {pair.Pair<string,string>} pair
5345 */
5346 const pairToStyleString = pair => `${pair.left}:${pair.right};`
5347
5348 /**
5349 * @param {Array<pair.Pair<string,string>>} pairs
5350 * @return {string}
5351 */
5352 const pairsToStyleString = pairs => pairs.map(pairToStyleString).join('')
5353
5354 /**
5355 * @param {Map<string,string>} m
5356 * @return {string}
5357 */
5358 const mapToStyleString = m => map_map(m, (value, key) => `${key}:${value};`).join('')
5359
5360 /**
5361 * @todo should always query on a dom element
5362 *
5363 * @param {HTMLElement|ShadowRoot} el
5364 * @param {string} query
5365 * @return {HTMLElement | null}
5366 */
5367 const querySelector = (el, query) => el.querySelector(query)
5368
5369 /**
5370 * @param {HTMLElement|ShadowRoot} el
5371 * @param {string} query
5372 * @return {NodeListOf<HTMLElement>}
5373 */
5374 const querySelectorAll = (el, query) => el.querySelectorAll(query)
5375
5376 /**
5377 * @param {string} id
5378 * @return {HTMLElement}
5379 */
5380 const getElementById = id => /** @type {HTMLElement} */ (doc.getElementById(id))
5381
5382 /**
5383 * @param {string} html
5384 * @return {HTMLElement}
5385 */
5386 const _parse = html => domParser.parseFromString(`<html><body>${html}</body></html>`, 'text/html').body
5387
5388 /**
5389 * @param {string} html
5390 * @return {DocumentFragment}
5391 */
5392 const parseFragment = html => fragment(/** @type {any} */ (_parse(html).childNodes))
5393
5394 /**
5395 * @param {string} html
5396 * @return {HTMLElement}
5397 */
5398 const parseElement = html => /** @type HTMLElement */ (_parse(html).firstElementChild)
5399
5400 /**
5401 * @param {HTMLElement} oldEl
5402 * @param {HTMLElement|DocumentFragment} newEl
5403 */
5404 const replaceWith = (oldEl, newEl) => oldEl.replaceWith(newEl)
5405
5406 /**
5407 * @param {HTMLElement} parent
5408 * @param {HTMLElement} el
5409 * @param {Node|null} ref
5410 * @return {HTMLElement}
5411 */
5412 const insertBefore = (parent, el, ref) => parent.insertBefore(el, ref)
5413
5414 /**
5415 * @param {Node} parent
5416 * @param {Node} child
5417 * @return {Node}
5418 */
5419 const appendChild = (parent, child) => parent.appendChild(child)
5420
5421 const ELEMENT_NODE = doc.ELEMENT_NODE
5422 const TEXT_NODE = doc.TEXT_NODE
5423 const CDATA_SECTION_NODE = doc.CDATA_SECTION_NODE
5424 const COMMENT_NODE = doc.COMMENT_NODE
5425 const DOCUMENT_NODE = doc.DOCUMENT_NODE
5426 const DOCUMENT_TYPE_NODE = doc.DOCUMENT_TYPE_NODE
5427 const DOCUMENT_FRAGMENT_NODE = doc.DOCUMENT_FRAGMENT_NODE
5428
5429 /**
5430 * @param {any} node
5431 * @param {number} type
5432 */
5433 const checkNodeType = (node, type) => node.nodeType === type
5434
5435 /**
5436 * @param {Node} parent
5437 * @param {HTMLElement} child
5438 */
5439 const isParentOf = (parent, child) => {
5440 let p = child.parentNode
5441 while (p && p !== parent) {
5442 p = p.parentNode
5443 }
5444 return p === parent
5445 }
5446 /* c8 ignore stop */
5447
5448 ;// CONCATENATED MODULE: ./node_modules/lib0/symbol.js
5449 /**
5450 * Utility module to work with EcmaScript Symbols.
5451 *
5452 * @module symbol
5453 */
5454
5455 /**
5456 * Return fresh symbol.
5457 *
5458 * @return {Symbol}
5459 */
5460 const symbol_create = Symbol
5461
5462 /**
5463 * @param {any} s
5464 * @return {boolean}
5465 */
5466 const isSymbol = s => typeof s === 'symbol'
5467
5468 ;// CONCATENATED MODULE: ./node_modules/lib0/time.js
5469 /**
5470 * Utility module to work with time.
5471 *
5472 * @module time
5473 */
5474
5475
5476
5477
5478 /**
5479 * Return current time.
5480 *
5481 * @return {Date}
5482 */
5483 const getDate = () => new Date()
5484
5485 /**
5486 * Return current unix time.
5487 *
5488 * @return {number}
5489 */
5490 const getUnixTime = Date.now
5491
5492 /**
5493 * Transform time (in ms) to a human readable format. E.g. 1100 => 1.1s. 60s => 1min. .001 => 10μs.
5494 *
5495 * @param {number} d duration in milliseconds
5496 * @return {string} humanized approximation of time
5497 */
5498 const humanizeDuration = d => {
5499 if (d < 60000) {
5500 const p = metric.prefix(d, -1)
5501 return math.round(p.n * 100) / 100 + p.prefix + 's'
5502 }
5503 d = math.floor(d / 1000)
5504 const seconds = d % 60
5505 const minutes = math.floor(d / 60) % 60
5506 const hours = math.floor(d / 3600) % 24
5507 const days = math.floor(d / 86400)
5508 if (days > 0) {
5509 return days + 'd' + ((hours > 0 || minutes > 30) ? ' ' + (minutes > 30 ? hours + 1 : hours) + 'h' : '')
5510 }
5511 if (hours > 0) {
5512 /* c8 ignore next */
5513 return hours + 'h' + ((minutes > 0 || seconds > 30) ? ' ' + (seconds > 30 ? minutes + 1 : minutes) + 'min' : '')
5514 }
5515 return minutes + 'min' + (seconds > 0 ? ' ' + seconds + 's' : '')
5516 }
5517
5518 ;// CONCATENATED MODULE: ./node_modules/lib0/logging.common.js
5519
5520
5521
5522
5523
5524 const BOLD = symbol_create()
5525 const UNBOLD = symbol_create()
5526 const BLUE = symbol_create()
5527 const GREY = symbol_create()
5528 const GREEN = symbol_create()
5529 const RED = symbol_create()
5530 const PURPLE = symbol_create()
5531 const ORANGE = symbol_create()
5532 const UNCOLOR = symbol_create()
5533
5534 /* c8 ignore start */
5535 /**
5536 * @param {Array<string|Symbol|Object|number>} args
5537 * @return {Array<string|object|number>}
5538 */
5539 const computeNoColorLoggingArgs = args => {
5540 const strBuilder = []
5541 const logArgs = []
5542 // try with formatting until we find something unsupported
5543 let i = 0
5544 for (; i < args.length; i++) {
5545 const arg = args[i]
5546 if (arg.constructor === String || arg.constructor === Number) {
5547 strBuilder.push(arg)
5548 } else if (arg.constructor === Object) {
5549 logArgs.push(JSON.stringify(arg))
5550 }
5551 }
5552 return logArgs
5553 }
5554 /* c8 ignore stop */
5555
5556 const loggingColors = [GREEN, PURPLE, ORANGE, BLUE]
5557 let nextColor = 0
5558 let lastLoggingTime = getUnixTime()
5559
5560 /* c8 ignore start */
5561 /**
5562 * @param {function(...any):void} _print
5563 * @param {string} moduleName
5564 * @return {function(...any):void}
5565 */
5566 const createModuleLogger = (_print, moduleName) => {
5567 const color = loggingColors[nextColor]
5568 const debugRegexVar = getVariable('log')
5569 const doLogging = debugRegexVar !== null &&
5570 (debugRegexVar === '*' || debugRegexVar === 'true' ||
5571 new RegExp(debugRegexVar, 'gi').test(moduleName))
5572 nextColor = (nextColor + 1) % loggingColors.length
5573 moduleName += ': '
5574 return !doLogging
5575 ? nop
5576 : (...args) => {
5577 const timeNow = getUnixTime()
5578 const timeDiff = timeNow - lastLoggingTime
5579 lastLoggingTime = timeNow
5580 _print(
5581 color,
5582 moduleName,
5583 UNCOLOR,
5584 ...args.map((arg) =>
5585 (typeof arg === 'string' || typeof arg === 'symbol')
5586 ? arg
5587 : JSON.stringify(arg)
5588 ),
5589 color,
5590 ' +' + timeDiff + 'ms'
5591 )
5592 }
5593 }
5594 /* c8 ignore stop */
5595
5596 ;// CONCATENATED MODULE: ./node_modules/lib0/logging.js
5597 /**
5598 * Isomorphic logging module with support for colors!
5599 *
5600 * @module logging
5601 */
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615 /**
5616 * @type {Object<Symbol,pair.Pair<string,string>>}
5617 */
5618 const _browserStyleMap = {
5619 [BOLD]: pair_create('font-weight', 'bold'),
5620 [UNBOLD]: pair_create('font-weight', 'normal'),
5621 [BLUE]: pair_create('color', 'blue'),
5622 [GREEN]: pair_create('color', 'green'),
5623 [GREY]: pair_create('color', 'grey'),
5624 [RED]: pair_create('color', 'red'),
5625 [PURPLE]: pair_create('color', 'purple'),
5626 [ORANGE]: pair_create('color', 'orange'), // not well supported in chrome when debugging node with inspector - TODO: deprecate
5627 [UNCOLOR]: pair_create('color', 'black')
5628 }
5629
5630 /**
5631 * @param {Array<string|Symbol|Object|number>} args
5632 * @return {Array<string|object|number>}
5633 */
5634 /* c8 ignore start */
5635 const computeBrowserLoggingArgs = (args) => {
5636 const strBuilder = []
5637 const styles = []
5638 const currentStyle = create()
5639 /**
5640 * @type {Array<string|Object|number>}
5641 */
5642 let logArgs = []
5643 // try with formatting until we find something unsupported
5644 let i = 0
5645 for (; i < args.length; i++) {
5646 const arg = args[i]
5647 // @ts-ignore
5648 const style = _browserStyleMap[arg]
5649 if (style !== undefined) {
5650 currentStyle.set(style.left, style.right)
5651 } else {
5652 if (arg.constructor === String || arg.constructor === Number) {
5653 const style = mapToStyleString(currentStyle)
5654 if (i > 0 || style.length > 0) {
5655 strBuilder.push('%c' + arg)
5656 styles.push(style)
5657 } else {
5658 strBuilder.push(arg)
5659 }
5660 } else {
5661 break
5662 }
5663 }
5664 }
5665 if (i > 0) {
5666 // create logArgs with what we have so far
5667 logArgs = styles
5668 logArgs.unshift(strBuilder.join(''))
5669 }
5670 // append the rest
5671 for (; i < args.length; i++) {
5672 const arg = args[i]
5673 if (!(arg instanceof Symbol)) {
5674 logArgs.push(arg)
5675 }
5676 }
5677 return logArgs
5678 }
5679 /* c8 ignore stop */
5680
5681 /* c8 ignore start */
5682 const computeLoggingArgs = supportsColor
5683 ? computeBrowserLoggingArgs
5684 : computeNoColorLoggingArgs
5685 /* c8 ignore stop */
5686
5687 /**
5688 * @param {Array<string|Symbol|Object|number>} args
5689 */
5690 const print = (...args) => {
5691 console.log(...computeLoggingArgs(args))
5692 /* c8 ignore next */
5693 vconsoles.forEach((vc) => vc.print(args))
5694 }
5695
5696 /* c8 ignore start */
5697 /**
5698 * @param {Array<string|Symbol|Object|number>} args
5699 */
5700 const warn = (...args) => {
5701 console.warn(...computeLoggingArgs(args))
5702 args.unshift(common.ORANGE)
5703 vconsoles.forEach((vc) => vc.print(args))
5704 }
5705 /* c8 ignore stop */
5706
5707 /**
5708 * @param {Error} err
5709 */
5710 /* c8 ignore start */
5711 const printError = (err) => {
5712 console.error(err)
5713 vconsoles.forEach((vc) => vc.printError(err))
5714 }
5715 /* c8 ignore stop */
5716
5717 /**
5718 * @param {string} url image location
5719 * @param {number} height height of the image in pixel
5720 */
5721 /* c8 ignore start */
5722 const printImg = (url, height) => {
5723 if (env.isBrowser) {
5724 console.log(
5725 '%c ',
5726 `font-size: ${height}px; background-size: contain; background-repeat: no-repeat; background-image: url(${url})`
5727 )
5728 // console.log('%c ', `font-size: ${height}x; background: url(${url}) no-repeat;`)
5729 }
5730 vconsoles.forEach((vc) => vc.printImg(url, height))
5731 }
5732 /* c8 ignore stop */
5733
5734 /**
5735 * @param {string} base64
5736 * @param {number} height
5737 */
5738 /* c8 ignore next 2 */
5739 const printImgBase64 = (base64, height) =>
5740 printImg(`data:image/gif;base64,${base64}`, height)
5741
5742 /**
5743 * @param {Array<string|Symbol|Object|number>} args
5744 */
5745 const group = (...args) => {
5746 console.group(...computeLoggingArgs(args))
5747 /* c8 ignore next */
5748 vconsoles.forEach((vc) => vc.group(args))
5749 }
5750
5751 /**
5752 * @param {Array<string|Symbol|Object|number>} args
5753 */
5754 const groupCollapsed = (...args) => {
5755 console.groupCollapsed(...computeLoggingArgs(args))
5756 /* c8 ignore next */
5757 vconsoles.forEach((vc) => vc.groupCollapsed(args))
5758 }
5759
5760 const groupEnd = () => {
5761 console.groupEnd()
5762 /* c8 ignore next */
5763 vconsoles.forEach((vc) => vc.groupEnd())
5764 }
5765
5766 /**
5767 * @param {function():Node} createNode
5768 */
5769 /* c8 ignore next 2 */
5770 const printDom = (createNode) =>
5771 vconsoles.forEach((vc) => vc.printDom(createNode()))
5772
5773 /**
5774 * @param {HTMLCanvasElement} canvas
5775 * @param {number} height
5776 */
5777 /* c8 ignore next 2 */
5778 const printCanvas = (canvas, height) =>
5779 printImg(canvas.toDataURL(), height)
5780
5781 const vconsoles = set_create()
5782
5783 /**
5784 * @param {Array<string|Symbol|Object|number>} args
5785 * @return {Array<Element>}
5786 */
5787 /* c8 ignore start */
5788 const _computeLineSpans = (args) => {
5789 const spans = []
5790 const currentStyle = new Map()
5791 // try with formatting until we find something unsupported
5792 let i = 0
5793 for (; i < args.length; i++) {
5794 const arg = args[i]
5795 // @ts-ignore
5796 const style = _browserStyleMap[arg]
5797 if (style !== undefined) {
5798 currentStyle.set(style.left, style.right)
5799 } else {
5800 if (arg.constructor === String || arg.constructor === Number) {
5801 // @ts-ignore
5802 const span = dom.element('span', [
5803 pair.create('style', dom.mapToStyleString(currentStyle))
5804 ], [dom.text(arg.toString())])
5805 if (span.innerHTML === '') {
5806 span.innerHTML = '&nbsp;'
5807 }
5808 spans.push(span)
5809 } else {
5810 break
5811 }
5812 }
5813 }
5814 // append the rest
5815 for (; i < args.length; i++) {
5816 let content = args[i]
5817 if (!(content instanceof Symbol)) {
5818 if (content.constructor !== String && content.constructor !== Number) {
5819 content = ' ' + json.stringify(content) + ' '
5820 }
5821 spans.push(
5822 dom.element('span', [], [dom.text(/** @type {string} */ (content))])
5823 )
5824 }
5825 }
5826 return spans
5827 }
5828 /* c8 ignore stop */
5829
5830 const lineStyle =
5831 'font-family:monospace;border-bottom:1px solid #e2e2e2;padding:2px;'
5832
5833 /* c8 ignore start */
5834 class VConsole {
5835 /**
5836 * @param {Element} dom
5837 */
5838 constructor (dom) {
5839 this.dom = dom
5840 /**
5841 * @type {Element}
5842 */
5843 this.ccontainer = this.dom
5844 this.depth = 0
5845 vconsoles.add(this)
5846 }
5847
5848 /**
5849 * @param {Array<string|Symbol|Object|number>} args
5850 * @param {boolean} collapsed
5851 */
5852 group (args, collapsed = false) {
5853 eventloop.enqueue(() => {
5854 const triangleDown = dom.element('span', [
5855 pair.create('hidden', collapsed),
5856 pair.create('style', 'color:grey;font-size:120%;')
5857 ], [dom.text('▼')])
5858 const triangleRight = dom.element('span', [
5859 pair.create('hidden', !collapsed),
5860 pair.create('style', 'color:grey;font-size:125%;')
5861 ], [dom.text('▶')])
5862 const content = dom.element(
5863 'div',
5864 [pair.create(
5865 'style',
5866 `${lineStyle};padding-left:${this.depth * 10}px`
5867 )],
5868 [triangleDown, triangleRight, dom.text(' ')].concat(
5869 _computeLineSpans(args)
5870 )
5871 )
5872 const nextContainer = dom.element('div', [
5873 pair.create('hidden', collapsed)
5874 ])
5875 const nextLine = dom.element('div', [], [content, nextContainer])
5876 dom.append(this.ccontainer, [nextLine])
5877 this.ccontainer = nextContainer
5878 this.depth++
5879 // when header is clicked, collapse/uncollapse container
5880 dom.addEventListener(content, 'click', (_event) => {
5881 nextContainer.toggleAttribute('hidden')
5882 triangleDown.toggleAttribute('hidden')
5883 triangleRight.toggleAttribute('hidden')
5884 })
5885 })
5886 }
5887
5888 /**
5889 * @param {Array<string|Symbol|Object|number>} args
5890 */
5891 groupCollapsed (args) {
5892 this.group(args, true)
5893 }
5894
5895 groupEnd () {
5896 eventloop.enqueue(() => {
5897 if (this.depth > 0) {
5898 this.depth--
5899 // @ts-ignore
5900 this.ccontainer = this.ccontainer.parentElement.parentElement
5901 }
5902 })
5903 }
5904
5905 /**
5906 * @param {Array<string|Symbol|Object|number>} args
5907 */
5908 print (args) {
5909 eventloop.enqueue(() => {
5910 dom.append(this.ccontainer, [
5911 dom.element('div', [
5912 pair.create(
5913 'style',
5914 `${lineStyle};padding-left:${this.depth * 10}px`
5915 )
5916 ], _computeLineSpans(args))
5917 ])
5918 })
5919 }
5920
5921 /**
5922 * @param {Error} err
5923 */
5924 printError (err) {
5925 this.print([common.RED, common.BOLD, err.toString()])
5926 }
5927
5928 /**
5929 * @param {string} url
5930 * @param {number} height
5931 */
5932 printImg (url, height) {
5933 eventloop.enqueue(() => {
5934 dom.append(this.ccontainer, [
5935 dom.element('img', [
5936 pair.create('src', url),
5937 pair.create('height', `${math.round(height * 1.5)}px`)
5938 ])
5939 ])
5940 })
5941 }
5942
5943 /**
5944 * @param {Node} node
5945 */
5946 printDom (node) {
5947 eventloop.enqueue(() => {
5948 dom.append(this.ccontainer, [node])
5949 })
5950 }
5951
5952 destroy () {
5953 eventloop.enqueue(() => {
5954 vconsoles.delete(this)
5955 })
5956 }
5957 }
5958 /* c8 ignore stop */
5959
5960 /**
5961 * @param {Element} dom
5962 */
5963 /* c8 ignore next */
5964 const createVConsole = (dom) => new VConsole(dom)
5965
5966 /**
5967 * @param {string} moduleName
5968 * @return {function(...any):void}
5969 */
5970 const logging_createModuleLogger = (moduleName) => createModuleLogger(print, moduleName)
5971
5972 ;// CONCATENATED MODULE: ./node_modules/lib0/iterator.js
5973 /**
5974 * Utility module to create and manipulate Iterators.
5975 *
5976 * @module iterator
5977 */
5978
5979 /**
5980 * @template T,R
5981 * @param {Iterator<T>} iterator
5982 * @param {function(T):R} f
5983 * @return {IterableIterator<R>}
5984 */
5985 const mapIterator = (iterator, f) => ({
5986 [Symbol.iterator] () {
5987 return this
5988 },
5989 // @ts-ignore
5990 next () {
5991 const r = iterator.next()
5992 return { value: r.done ? undefined : f(r.value), done: r.done }
5993 }
5994 })
5995
5996 /**
5997 * @template T
5998 * @param {function():IteratorResult<T>} next
5999 * @return {IterableIterator<T>}
6000 */
6001 const createIterator = next => ({
6002 /**
6003 * @return {IterableIterator<T>}
6004 */
6005 [Symbol.iterator] () {
6006 return this
6007 },
6008 // @ts-ignore
6009 next
6010 })
6011
6012 /**
6013 * @template T
6014 * @param {Iterator<T>} iterator
6015 * @param {function(T):boolean} filter
6016 */
6017 const iteratorFilter = (iterator, filter) => createIterator(() => {
6018 let res
6019 do {
6020 res = iterator.next()
6021 } while (!res.done && !filter(res.value))
6022 return res
6023 })
6024
6025 /**
6026 * @template T,M
6027 * @param {Iterator<T>} iterator
6028 * @param {function(T):M} fmap
6029 */
6030 const iteratorMap = (iterator, fmap) => createIterator(() => {
6031 const { done, value } = iterator.next()
6032 return { done, value: done ? undefined : fmap(value) }
6033 })
6034
6035 ;// CONCATENATED MODULE: ./node_modules/yjs/dist/yjs.mjs
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
6056 /**
6057 * This is an abstract interface that all Connectors should implement to keep them interchangeable.
6058 *
6059 * @note This interface is experimental and it is not advised to actually inherit this class.
6060 * It just serves as typing information.
6061 *
6062 * @extends {Observable<any>}
6063 */
6064 class AbstractConnector extends (/* unused pure expression or super */ null && (Observable)) {
6065 /**
6066 * @param {Doc} ydoc
6067 * @param {any} awareness
6068 */
6069 constructor (ydoc, awareness) {
6070 super();
6071 this.doc = ydoc;
6072 this.awareness = awareness;
6073 }
6074 }
6075
6076 class DeleteItem {
6077 /**
6078 * @param {number} clock
6079 * @param {number} len
6080 */
6081 constructor (clock, len) {
6082 /**
6083 * @type {number}
6084 */
6085 this.clock = clock;
6086 /**
6087 * @type {number}
6088 */
6089 this.len = len;
6090 }
6091 }
6092
6093 /**
6094 * We no longer maintain a DeleteStore. DeleteSet is a temporary object that is created when needed.
6095 * - When created in a transaction, it must only be accessed after sorting, and merging
6096 * - This DeleteSet is send to other clients
6097 * - We do not create a DeleteSet when we send a sync message. The DeleteSet message is created directly from StructStore
6098 * - We read a DeleteSet as part of a sync/update message. In this case the DeleteSet is already sorted and merged.
6099 */
6100 class DeleteSet {
6101 constructor () {
6102 /**
6103 * @type {Map<number,Array<DeleteItem>>}
6104 */
6105 this.clients = new Map();
6106 }
6107 }
6108
6109 /**
6110 * Iterate over all structs that the DeleteSet gc's.
6111 *
6112 * @param {Transaction} transaction
6113 * @param {DeleteSet} ds
6114 * @param {function(GC|Item):void} f
6115 *
6116 * @function
6117 */
6118 const iterateDeletedStructs = (transaction, ds, f) =>
6119 ds.clients.forEach((deletes, clientid) => {
6120 const structs = /** @type {Array<GC|Item>} */ (transaction.doc.store.clients.get(clientid));
6121 for (let i = 0; i < deletes.length; i++) {
6122 const del = deletes[i];
6123 iterateStructs(transaction, structs, del.clock, del.len, f);
6124 }
6125 });
6126
6127 /**
6128 * @param {Array<DeleteItem>} dis
6129 * @param {number} clock
6130 * @return {number|null}
6131 *
6132 * @private
6133 * @function
6134 */
6135 const findIndexDS = (dis, clock) => {
6136 let left = 0;
6137 let right = dis.length - 1;
6138 while (left <= right) {
6139 const midindex = floor((left + right) / 2);
6140 const mid = dis[midindex];
6141 const midclock = mid.clock;
6142 if (midclock <= clock) {
6143 if (clock < midclock + mid.len) {
6144 return midindex
6145 }
6146 left = midindex + 1;
6147 } else {
6148 right = midindex - 1;
6149 }
6150 }
6151 return null
6152 };
6153
6154 /**
6155 * @param {DeleteSet} ds
6156 * @param {ID} id
6157 * @return {boolean}
6158 *
6159 * @private
6160 * @function
6161 */
6162 const isDeleted = (ds, id) => {
6163 const dis = ds.clients.get(id.client);
6164 return dis !== undefined && findIndexDS(dis, id.clock) !== null
6165 };
6166
6167 /**
6168 * @param {DeleteSet} ds
6169 *
6170 * @private
6171 * @function
6172 */
6173 const sortAndMergeDeleteSet = ds => {
6174 ds.clients.forEach(dels => {
6175 dels.sort((a, b) => a.clock - b.clock);
6176 // merge items without filtering or splicing the array
6177 // i is the current pointer
6178 // j refers to the current insert position for the pointed item
6179 // try to merge dels[i] into dels[j-1] or set dels[j]=dels[i]
6180 let i, j;
6181 for (i = 1, j = 1; i < dels.length; i++) {
6182 const left = dels[j - 1];
6183 const right = dels[i];
6184 if (left.clock + left.len >= right.clock) {
6185 left.len = max(left.len, right.clock + right.len - left.clock);
6186 } else {
6187 if (j < i) {
6188 dels[j] = right;
6189 }
6190 j++;
6191 }
6192 }
6193 dels.length = j;
6194 });
6195 };
6196
6197 /**
6198 * @param {Array<DeleteSet>} dss
6199 * @return {DeleteSet} A fresh DeleteSet
6200 */
6201 const mergeDeleteSets = dss => {
6202 const merged = new DeleteSet();
6203 for (let dssI = 0; dssI < dss.length; dssI++) {
6204 dss[dssI].clients.forEach((delsLeft, client) => {
6205 if (!merged.clients.has(client)) {
6206 // Write all missing keys from current ds and all following.
6207 // If merged already contains `client` current ds has already been added.
6208 /**
6209 * @type {Array<DeleteItem>}
6210 */
6211 const dels = delsLeft.slice();
6212 for (let i = dssI + 1; i < dss.length; i++) {
6213 appendTo(dels, dss[i].clients.get(client) || []);
6214 }
6215 merged.clients.set(client, dels);
6216 }
6217 });
6218 }
6219 sortAndMergeDeleteSet(merged);
6220 return merged
6221 };
6222
6223 /**
6224 * @param {DeleteSet} ds
6225 * @param {number} client
6226 * @param {number} clock
6227 * @param {number} length
6228 *
6229 * @private
6230 * @function
6231 */
6232 const addToDeleteSet = (ds, client, clock, length) => {
6233 setIfUndefined(ds.clients, client, () => /** @type {Array<DeleteItem>} */ ([])).push(new DeleteItem(clock, length));
6234 };
6235
6236 const createDeleteSet = () => new DeleteSet();
6237
6238 /**
6239 * @param {StructStore} ss
6240 * @return {DeleteSet} Merged and sorted DeleteSet
6241 *
6242 * @private
6243 * @function
6244 */
6245 const createDeleteSetFromStructStore = ss => {
6246 const ds = createDeleteSet();
6247 ss.clients.forEach((structs, client) => {
6248 /**
6249 * @type {Array<DeleteItem>}
6250 */
6251 const dsitems = [];
6252 for (let i = 0; i < structs.length; i++) {
6253 const struct = structs[i];
6254 if (struct.deleted) {
6255 const clock = struct.id.clock;
6256 let len = struct.length;
6257 if (i + 1 < structs.length) {
6258 for (let next = structs[i + 1]; i + 1 < structs.length && next.deleted; next = structs[++i + 1]) {
6259 len += next.length;
6260 }
6261 }
6262 dsitems.push(new DeleteItem(clock, len));
6263 }
6264 }
6265 if (dsitems.length > 0) {
6266 ds.clients.set(client, dsitems);
6267 }
6268 });
6269 return ds
6270 };
6271
6272 /**
6273 * @param {DSEncoderV1 | DSEncoderV2} encoder
6274 * @param {DeleteSet} ds
6275 *
6276 * @private
6277 * @function
6278 */
6279 const writeDeleteSet = (encoder, ds) => {
6280 writeVarUint(encoder.restEncoder, ds.clients.size);
6281
6282 // Ensure that the delete set is written in a deterministic order
6283 array_from(ds.clients.entries())
6284 .sort((a, b) => b[0] - a[0])
6285 .forEach(([client, dsitems]) => {
6286 encoder.resetDsCurVal();
6287 writeVarUint(encoder.restEncoder, client);
6288 const len = dsitems.length;
6289 writeVarUint(encoder.restEncoder, len);
6290 for (let i = 0; i < len; i++) {
6291 const item = dsitems[i];
6292 encoder.writeDsClock(item.clock);
6293 encoder.writeDsLen(item.len);
6294 }
6295 });
6296 };
6297
6298 /**
6299 * @param {DSDecoderV1 | DSDecoderV2} decoder
6300 * @return {DeleteSet}
6301 *
6302 * @private
6303 * @function
6304 */
6305 const readDeleteSet = decoder => {
6306 const ds = new DeleteSet();
6307 const numClients = readVarUint(decoder.restDecoder);
6308 for (let i = 0; i < numClients; i++) {
6309 decoder.resetDsCurVal();
6310 const client = readVarUint(decoder.restDecoder);
6311 const numberOfDeletes = readVarUint(decoder.restDecoder);
6312 if (numberOfDeletes > 0) {
6313 const dsField = setIfUndefined(ds.clients, client, () => /** @type {Array<DeleteItem>} */ ([]));
6314 for (let i = 0; i < numberOfDeletes; i++) {
6315 dsField.push(new DeleteItem(decoder.readDsClock(), decoder.readDsLen()));
6316 }
6317 }
6318 }
6319 return ds
6320 };
6321
6322 /**
6323 * @todo YDecoder also contains references to String and other Decoders. Would make sense to exchange YDecoder.toUint8Array for YDecoder.DsToUint8Array()..
6324 */
6325
6326 /**
6327 * @param {DSDecoderV1 | DSDecoderV2} decoder
6328 * @param {Transaction} transaction
6329 * @param {StructStore} store
6330 * @return {Uint8Array|null} Returns a v2 update containing all deletes that couldn't be applied yet; or null if all deletes were applied successfully.
6331 *
6332 * @private
6333 * @function
6334 */
6335 const readAndApplyDeleteSet = (decoder, transaction, store) => {
6336 const unappliedDS = new DeleteSet();
6337 const numClients = readVarUint(decoder.restDecoder);
6338 for (let i = 0; i < numClients; i++) {
6339 decoder.resetDsCurVal();
6340 const client = readVarUint(decoder.restDecoder);
6341 const numberOfDeletes = readVarUint(decoder.restDecoder);
6342 const structs = store.clients.get(client) || [];
6343 const state = getState(store, client);
6344 for (let i = 0; i < numberOfDeletes; i++) {
6345 const clock = decoder.readDsClock();
6346 const clockEnd = clock + decoder.readDsLen();
6347 if (clock < state) {
6348 if (state < clockEnd) {
6349 addToDeleteSet(unappliedDS, client, state, clockEnd - state);
6350 }
6351 let index = findIndexSS(structs, clock);
6352 /**
6353 * We can ignore the case of GC and Delete structs, because we are going to skip them
6354 * @type {Item}
6355 */
6356 // @ts-ignore
6357 let struct = structs[index];
6358 // split the first item if necessary
6359 if (!struct.deleted && struct.id.clock < clock) {
6360 structs.splice(index + 1, 0, splitItem(transaction, struct, clock - struct.id.clock));
6361 index++; // increase we now want to use the next struct
6362 }
6363 while (index < structs.length) {
6364 // @ts-ignore
6365 struct = structs[index++];
6366 if (struct.id.clock < clockEnd) {
6367 if (!struct.deleted) {
6368 if (clockEnd < struct.id.clock + struct.length) {
6369 structs.splice(index, 0, splitItem(transaction, struct, clockEnd - struct.id.clock));
6370 }
6371 struct.delete(transaction);
6372 }
6373 } else {
6374 break
6375 }
6376 }
6377 } else {
6378 addToDeleteSet(unappliedDS, client, clock, clockEnd - clock);
6379 }
6380 }
6381 }
6382 if (unappliedDS.clients.size > 0) {
6383 const ds = new UpdateEncoderV2();
6384 writeVarUint(ds.restEncoder, 0); // encode 0 structs
6385 writeDeleteSet(ds, unappliedDS);
6386 return ds.toUint8Array()
6387 }
6388 return null
6389 };
6390
6391 /**
6392 * @param {DeleteSet} ds1
6393 * @param {DeleteSet} ds2
6394 */
6395 const equalDeleteSets = (ds1, ds2) => {
6396 if (ds1.clients.size !== ds2.clients.size) return false
6397 for (const [client, deleteItems1] of ds1.clients.entries()) {
6398 const deleteItems2 = /** @type {Array<import('../internals.js').DeleteItem>} */ (ds2.clients.get(client));
6399 if (deleteItems2 === undefined || deleteItems1.length !== deleteItems2.length) return false
6400 for (let i = 0; i < deleteItems1.length; i++) {
6401 const di1 = deleteItems1[i];
6402 const di2 = deleteItems2[i];
6403 if (di1.clock !== di2.clock || di1.len !== di2.len) {
6404 return false
6405 }
6406 }
6407 }
6408 return true
6409 };
6410
6411 /**
6412 * @module Y
6413 */
6414
6415 const generateNewClientId = uint32;
6416
6417 /**
6418 * @typedef {Object} DocOpts
6419 * @property {boolean} [DocOpts.gc=true] Disable garbage collection (default: gc=true)
6420 * @property {function(Item):boolean} [DocOpts.gcFilter] Will be called before an Item is garbage collected. Return false to keep the Item.
6421 * @property {string} [DocOpts.guid] Define a globally unique identifier for this document
6422 * @property {string | null} [DocOpts.collectionid] Associate this document with a collection. This only plays a role if your provider has a concept of collection.
6423 * @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.
6424 * @property {boolean} [DocOpts.autoLoad] If a subdocument, automatically load document. If this is a subdocument, remote peers will load the document as well automatically.
6425 * @property {boolean} [DocOpts.shouldLoad] Whether the document should be synced by the provider now. This is toggled to true when you call ydoc.load()
6426 */
6427
6428 /**
6429 * A Yjs instance handles the state of shared data.
6430 * @extends Observable<string>
6431 */
6432 class Doc extends observable_Observable {
6433 /**
6434 * @param {DocOpts} opts configuration
6435 */
6436 constructor ({ guid = uuidv4(), collectionid = null, gc = true, gcFilter = () => true, meta = null, autoLoad = false, shouldLoad = true } = {}) {
6437 super();
6438 this.gc = gc;
6439 this.gcFilter = gcFilter;
6440 this.clientID = generateNewClientId();
6441 this.guid = guid;
6442 this.collectionid = collectionid;
6443 /**
6444 * @type {Map<string, AbstractType<YEvent<any>>>}
6445 */
6446 this.share = new Map();
6447 this.store = new StructStore();
6448 /**
6449 * @type {Transaction | null}
6450 */
6451 this._transaction = null;
6452 /**
6453 * @type {Array<Transaction>}
6454 */
6455 this._transactionCleanups = [];
6456 /**
6457 * @type {Set<Doc>}
6458 */
6459 this.subdocs = new Set();
6460 /**
6461 * If this document is a subdocument - a document integrated into another document - then _item is defined.
6462 * @type {Item?}
6463 */
6464 this._item = null;
6465 this.shouldLoad = shouldLoad;
6466 this.autoLoad = autoLoad;
6467 this.meta = meta;
6468 /**
6469 * This is set to true when the persistence provider loaded the document from the database or when the `sync` event fires.
6470 * 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.
6471 *
6472 * @type {boolean}
6473 */
6474 this.isLoaded = false;
6475 /**
6476 * This is set to true when the connection provider has successfully synced with a backend.
6477 * Note that when using peer-to-peer providers this event may not provide very useful.
6478 * Also note that not all providers implement this feature. Provider authors are encouraged to fire
6479 * the `sync` event when the doc has been synced (with `true` as a parameter) or if connection is
6480 * lost (with false as a parameter).
6481 */
6482 this.isSynced = false;
6483 /**
6484 * Promise that resolves once the document has been loaded from a presistence provider.
6485 */
6486 this.whenLoaded = promise_create(resolve => {
6487 this.on('load', () => {
6488 this.isLoaded = true;
6489 resolve(this);
6490 });
6491 });
6492 const provideSyncedPromise = () => promise_create(resolve => {
6493 /**
6494 * @param {boolean} isSynced
6495 */
6496 const eventHandler = (isSynced) => {
6497 if (isSynced === undefined || isSynced === true) {
6498 this.off('sync', eventHandler);
6499 resolve();
6500 }
6501 };
6502 this.on('sync', eventHandler);
6503 });
6504 this.on('sync', isSynced => {
6505 if (isSynced === false && this.isSynced) {
6506 this.whenSynced = provideSyncedPromise();
6507 }
6508 this.isSynced = isSynced === undefined || isSynced === true;
6509 if (!this.isLoaded) {
6510 this.emit('load', []);
6511 }
6512 });
6513 /**
6514 * Promise that resolves once the document has been synced with a backend.
6515 * This promise is recreated when the connection is lost.
6516 * Note the documentation about the `isSynced` property.
6517 */
6518 this.whenSynced = provideSyncedPromise();
6519 }
6520
6521 /**
6522 * Notify the parent document that you request to load data into this subdocument (if it is a subdocument).
6523 *
6524 * `load()` might be used in the future to request any provider to load the most current data.
6525 *
6526 * It is safe to call `load()` multiple times.
6527 */
6528 load () {
6529 const item = this._item;
6530 if (item !== null && !this.shouldLoad) {
6531 transact(/** @type {any} */ (item.parent).doc, transaction => {
6532 transaction.subdocsLoaded.add(this);
6533 }, null, true);
6534 }
6535 this.shouldLoad = true;
6536 }
6537
6538 getSubdocs () {
6539 return this.subdocs
6540 }
6541
6542 getSubdocGuids () {
6543 return new Set(array_from(this.subdocs).map(doc => doc.guid))
6544 }
6545
6546 /**
6547 * Changes that happen inside of a transaction are bundled. This means that
6548 * the observer fires _after_ the transaction is finished and that all changes
6549 * that happened inside of the transaction are sent as one message to the
6550 * other peers.
6551 *
6552 * @template T
6553 * @param {function(Transaction):T} f The function that should be executed as a transaction
6554 * @param {any} [origin] Origin of who started the transaction. Will be stored on transaction.origin
6555 * @return T
6556 *
6557 * @public
6558 */
6559 transact (f, origin = null) {
6560 return transact(this, f, origin)
6561 }
6562
6563 /**
6564 * Define a shared data type.
6565 *
6566 * Multiple calls of `y.get(name, TypeConstructor)` yield the same result
6567 * and do not overwrite each other. I.e.
6568 * `y.define(name, Y.Array) === y.define(name, Y.Array)`
6569 *
6570 * After this method is called, the type is also available on `y.share.get(name)`.
6571 *
6572 * *Best Practices:*
6573 * Define all types right after the Yjs instance is created and store them in a separate object.
6574 * Also use the typed methods `getText(name)`, `getArray(name)`, ..
6575 *
6576 * @example
6577 * const y = new Y(..)
6578 * const appState = {
6579 * document: y.getText('document')
6580 * comments: y.getArray('comments')
6581 * }
6582 *
6583 * @param {string} name
6584 * @param {Function} TypeConstructor The constructor of the type definition. E.g. Y.Text, Y.Array, Y.Map, ...
6585 * @return {AbstractType<any>} The created type. Constructed with TypeConstructor
6586 *
6587 * @public
6588 */
6589 get (name, TypeConstructor = AbstractType) {
6590 const type = setIfUndefined(this.share, name, () => {
6591 // @ts-ignore
6592 const t = new TypeConstructor();
6593 t._integrate(this, null);
6594 return t
6595 });
6596 const Constr = type.constructor;
6597 if (TypeConstructor !== AbstractType && Constr !== TypeConstructor) {
6598 if (Constr === AbstractType) {
6599 // @ts-ignore
6600 const t = new TypeConstructor();
6601 t._map = type._map;
6602 type._map.forEach(/** @param {Item?} n */ n => {
6603 for (; n !== null; n = n.left) {
6604 // @ts-ignore
6605 n.parent = t;
6606 }
6607 });
6608 t._start = type._start;
6609 for (let n = t._start; n !== null; n = n.right) {
6610 n.parent = t;
6611 }
6612 t._length = type._length;
6613 this.share.set(name, t);
6614 t._integrate(this, null);
6615 return t
6616 } else {
6617 throw new Error(`Type with the name ${name} has already been defined with a different constructor`)
6618 }
6619 }
6620 return type
6621 }
6622
6623 /**
6624 * @template T
6625 * @param {string} [name]
6626 * @return {YArray<T>}
6627 *
6628 * @public
6629 */
6630 getArray (name = '') {
6631 // @ts-ignore
6632 return this.get(name, YArray)
6633 }
6634
6635 /**
6636 * @param {string} [name]
6637 * @return {YText}
6638 *
6639 * @public
6640 */
6641 getText (name = '') {
6642 // @ts-ignore
6643 return this.get(name, YText)
6644 }
6645
6646 /**
6647 * @template T
6648 * @param {string} [name]
6649 * @return {YMap<T>}
6650 *
6651 * @public
6652 */
6653 getMap (name = '') {
6654 // @ts-ignore
6655 return this.get(name, YMap)
6656 }
6657
6658 /**
6659 * @param {string} [name]
6660 * @return {YXmlFragment}
6661 *
6662 * @public
6663 */
6664 getXmlFragment (name = '') {
6665 // @ts-ignore
6666 return this.get(name, YXmlFragment)
6667 }
6668
6669 /**
6670 * Converts the entire document into a js object, recursively traversing each yjs type
6671 * Doesn't log types that have not been defined (using ydoc.getType(..)).
6672 *
6673 * @deprecated Do not use this method and rather call toJSON directly on the shared types.
6674 *
6675 * @return {Object<string, any>}
6676 */
6677 toJSON () {
6678 /**
6679 * @type {Object<string, any>}
6680 */
6681 const doc = {};
6682
6683 this.share.forEach((value, key) => {
6684 doc[key] = value.toJSON();
6685 });
6686
6687 return doc
6688 }
6689
6690 /**
6691 * Emit `destroy` event and unregister all event handlers.
6692 */
6693 destroy () {
6694 array_from(this.subdocs).forEach(subdoc => subdoc.destroy());
6695 const item = this._item;
6696 if (item !== null) {
6697 this._item = null;
6698 const content = /** @type {ContentDoc} */ (item.content);
6699 content.doc = new Doc({ guid: this.guid, ...content.opts, shouldLoad: false });
6700 content.doc._item = item;
6701 transact(/** @type {any} */ (item).parent.doc, transaction => {
6702 const doc = content.doc;
6703 if (!item.deleted) {
6704 transaction.subdocsAdded.add(doc);
6705 }
6706 transaction.subdocsRemoved.add(this);
6707 }, null, true);
6708 }
6709 this.emit('destroyed', [true]);
6710 this.emit('destroy', [this]);
6711 super.destroy();
6712 }
6713
6714 /**
6715 * @param {string} eventName
6716 * @param {function(...any):any} f
6717 */
6718 on (eventName, f) {
6719 super.on(eventName, f);
6720 }
6721
6722 /**
6723 * @param {string} eventName
6724 * @param {function} f
6725 */
6726 off (eventName, f) {
6727 super.off(eventName, f);
6728 }
6729 }
6730
6731 class DSDecoderV1 {
6732 /**
6733 * @param {decoding.Decoder} decoder
6734 */
6735 constructor (decoder) {
6736 this.restDecoder = decoder;
6737 }
6738
6739 resetDsCurVal () {
6740 // nop
6741 }
6742
6743 /**
6744 * @return {number}
6745 */
6746 readDsClock () {
6747 return readVarUint(this.restDecoder)
6748 }
6749
6750 /**
6751 * @return {number}
6752 */
6753 readDsLen () {
6754 return readVarUint(this.restDecoder)
6755 }
6756 }
6757
6758 class UpdateDecoderV1 extends DSDecoderV1 {
6759 /**
6760 * @return {ID}
6761 */
6762 readLeftID () {
6763 return createID(readVarUint(this.restDecoder), readVarUint(this.restDecoder))
6764 }
6765
6766 /**
6767 * @return {ID}
6768 */
6769 readRightID () {
6770 return createID(readVarUint(this.restDecoder), readVarUint(this.restDecoder))
6771 }
6772
6773 /**
6774 * Read the next client id.
6775 * Use this in favor of readID whenever possible to reduce the number of objects created.
6776 */
6777 readClient () {
6778 return readVarUint(this.restDecoder)
6779 }
6780
6781 /**
6782 * @return {number} info An unsigned 8-bit integer
6783 */
6784 readInfo () {
6785 return readUint8(this.restDecoder)
6786 }
6787
6788 /**
6789 * @return {string}
6790 */
6791 readString () {
6792 return readVarString(this.restDecoder)
6793 }
6794
6795 /**
6796 * @return {boolean} isKey
6797 */
6798 readParentInfo () {
6799 return readVarUint(this.restDecoder) === 1
6800 }
6801
6802 /**
6803 * @return {number} info An unsigned 8-bit integer
6804 */
6805 readTypeRef () {
6806 return readVarUint(this.restDecoder)
6807 }
6808
6809 /**
6810 * Write len of a struct - well suited for Opt RLE encoder.
6811 *
6812 * @return {number} len
6813 */
6814 readLen () {
6815 return readVarUint(this.restDecoder)
6816 }
6817
6818 /**
6819 * @return {any}
6820 */
6821 readAny () {
6822 return readAny(this.restDecoder)
6823 }
6824
6825 /**
6826 * @return {Uint8Array}
6827 */
6828 readBuf () {
6829 return copyUint8Array(readVarUint8Array(this.restDecoder))
6830 }
6831
6832 /**
6833 * Legacy implementation uses JSON parse. We use any-decoding in v2.
6834 *
6835 * @return {any}
6836 */
6837 readJSON () {
6838 return JSON.parse(readVarString(this.restDecoder))
6839 }
6840
6841 /**
6842 * @return {string}
6843 */
6844 readKey () {
6845 return readVarString(this.restDecoder)
6846 }
6847 }
6848
6849 class DSDecoderV2 {
6850 /**
6851 * @param {decoding.Decoder} decoder
6852 */
6853 constructor (decoder) {
6854 /**
6855 * @private
6856 */
6857 this.dsCurrVal = 0;
6858 this.restDecoder = decoder;
6859 }
6860
6861 resetDsCurVal () {
6862 this.dsCurrVal = 0;
6863 }
6864
6865 /**
6866 * @return {number}
6867 */
6868 readDsClock () {
6869 this.dsCurrVal += readVarUint(this.restDecoder);
6870 return this.dsCurrVal
6871 }
6872
6873 /**
6874 * @return {number}
6875 */
6876 readDsLen () {
6877 const diff = readVarUint(this.restDecoder) + 1;
6878 this.dsCurrVal += diff;
6879 return diff
6880 }
6881 }
6882
6883 class UpdateDecoderV2 extends DSDecoderV2 {
6884 /**
6885 * @param {decoding.Decoder} decoder
6886 */
6887 constructor (decoder) {
6888 super(decoder);
6889 /**
6890 * List of cached keys. If the keys[id] does not exist, we read a new key
6891 * from stringEncoder and push it to keys.
6892 *
6893 * @type {Array<string>}
6894 */
6895 this.keys = [];
6896 readVarUint(decoder); // read feature flag - currently unused
6897 this.keyClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder));
6898 this.clientDecoder = new UintOptRleDecoder(readVarUint8Array(decoder));
6899 this.leftClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder));
6900 this.rightClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder));
6901 this.infoDecoder = new RleDecoder(readVarUint8Array(decoder), readUint8);
6902 this.stringDecoder = new StringDecoder(readVarUint8Array(decoder));
6903 this.parentInfoDecoder = new RleDecoder(readVarUint8Array(decoder), readUint8);
6904 this.typeRefDecoder = new UintOptRleDecoder(readVarUint8Array(decoder));
6905 this.lenDecoder = new UintOptRleDecoder(readVarUint8Array(decoder));
6906 }
6907
6908 /**
6909 * @return {ID}
6910 */
6911 readLeftID () {
6912 return new ID(this.clientDecoder.read(), this.leftClockDecoder.read())
6913 }
6914
6915 /**
6916 * @return {ID}
6917 */
6918 readRightID () {
6919 return new ID(this.clientDecoder.read(), this.rightClockDecoder.read())
6920 }
6921
6922 /**
6923 * Read the next client id.
6924 * Use this in favor of readID whenever possible to reduce the number of objects created.
6925 */
6926 readClient () {
6927 return this.clientDecoder.read()
6928 }
6929
6930 /**
6931 * @return {number} info An unsigned 8-bit integer
6932 */
6933 readInfo () {
6934 return /** @type {number} */ (this.infoDecoder.read())
6935 }
6936
6937 /**
6938 * @return {string}
6939 */
6940 readString () {
6941 return this.stringDecoder.read()
6942 }
6943
6944 /**
6945 * @return {boolean}
6946 */
6947 readParentInfo () {
6948 return this.parentInfoDecoder.read() === 1
6949 }
6950
6951 /**
6952 * @return {number} An unsigned 8-bit integer
6953 */
6954 readTypeRef () {
6955 return this.typeRefDecoder.read()
6956 }
6957
6958 /**
6959 * Write len of a struct - well suited for Opt RLE encoder.
6960 *
6961 * @return {number}
6962 */
6963 readLen () {
6964 return this.lenDecoder.read()
6965 }
6966
6967 /**
6968 * @return {any}
6969 */
6970 readAny () {
6971 return readAny(this.restDecoder)
6972 }
6973
6974 /**
6975 * @return {Uint8Array}
6976 */
6977 readBuf () {
6978 return readVarUint8Array(this.restDecoder)
6979 }
6980
6981 /**
6982 * This is mainly here for legacy purposes.
6983 *
6984 * 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.
6985 *
6986 * @return {any}
6987 */
6988 readJSON () {
6989 return readAny(this.restDecoder)
6990 }
6991
6992 /**
6993 * @return {string}
6994 */
6995 readKey () {
6996 const keyClock = this.keyClockDecoder.read();
6997 if (keyClock < this.keys.length) {
6998 return this.keys[keyClock]
6999 } else {
7000 const key = this.stringDecoder.read();
7001 this.keys.push(key);
7002 return key
7003 }
7004 }
7005 }
7006
7007 class DSEncoderV1 {
7008 constructor () {
7009 this.restEncoder = createEncoder();
7010 }
7011
7012 toUint8Array () {
7013 return toUint8Array(this.restEncoder)
7014 }
7015
7016 resetDsCurVal () {
7017 // nop
7018 }
7019
7020 /**
7021 * @param {number} clock
7022 */
7023 writeDsClock (clock) {
7024 writeVarUint(this.restEncoder, clock);
7025 }
7026
7027 /**
7028 * @param {number} len
7029 */
7030 writeDsLen (len) {
7031 writeVarUint(this.restEncoder, len);
7032 }
7033 }
7034
7035 class UpdateEncoderV1 extends DSEncoderV1 {
7036 /**
7037 * @param {ID} id
7038 */
7039 writeLeftID (id) {
7040 writeVarUint(this.restEncoder, id.client);
7041 writeVarUint(this.restEncoder, id.clock);
7042 }
7043
7044 /**
7045 * @param {ID} id
7046 */
7047 writeRightID (id) {
7048 writeVarUint(this.restEncoder, id.client);
7049 writeVarUint(this.restEncoder, id.clock);
7050 }
7051
7052 /**
7053 * Use writeClient and writeClock instead of writeID if possible.
7054 * @param {number} client
7055 */
7056 writeClient (client) {
7057 writeVarUint(this.restEncoder, client);
7058 }
7059
7060 /**
7061 * @param {number} info An unsigned 8-bit integer
7062 */
7063 writeInfo (info) {
7064 writeUint8(this.restEncoder, info);
7065 }
7066
7067 /**
7068 * @param {string} s
7069 */
7070 writeString (s) {
7071 writeVarString(this.restEncoder, s);
7072 }
7073
7074 /**
7075 * @param {boolean} isYKey
7076 */
7077 writeParentInfo (isYKey) {
7078 writeVarUint(this.restEncoder, isYKey ? 1 : 0);
7079 }
7080
7081 /**
7082 * @param {number} info An unsigned 8-bit integer
7083 */
7084 writeTypeRef (info) {
7085 writeVarUint(this.restEncoder, info);
7086 }
7087
7088 /**
7089 * Write len of a struct - well suited for Opt RLE encoder.
7090 *
7091 * @param {number} len
7092 */
7093 writeLen (len) {
7094 writeVarUint(this.restEncoder, len);
7095 }
7096
7097 /**
7098 * @param {any} any
7099 */
7100 writeAny (any) {
7101 writeAny(this.restEncoder, any);
7102 }
7103
7104 /**
7105 * @param {Uint8Array} buf
7106 */
7107 writeBuf (buf) {
7108 writeVarUint8Array(this.restEncoder, buf);
7109 }
7110
7111 /**
7112 * @param {any} embed
7113 */
7114 writeJSON (embed) {
7115 writeVarString(this.restEncoder, JSON.stringify(embed));
7116 }
7117
7118 /**
7119 * @param {string} key
7120 */
7121 writeKey (key) {
7122 writeVarString(this.restEncoder, key);
7123 }
7124 }
7125
7126 class DSEncoderV2 {
7127 constructor () {
7128 this.restEncoder = createEncoder(); // encodes all the rest / non-optimized
7129 this.dsCurrVal = 0;
7130 }
7131
7132 toUint8Array () {
7133 return toUint8Array(this.restEncoder)
7134 }
7135
7136 resetDsCurVal () {
7137 this.dsCurrVal = 0;
7138 }
7139
7140 /**
7141 * @param {number} clock
7142 */
7143 writeDsClock (clock) {
7144 const diff = clock - this.dsCurrVal;
7145 this.dsCurrVal = clock;
7146 writeVarUint(this.restEncoder, diff);
7147 }
7148
7149 /**
7150 * @param {number} len
7151 */
7152 writeDsLen (len) {
7153 if (len === 0) {
7154 unexpectedCase();
7155 }
7156 writeVarUint(this.restEncoder, len - 1);
7157 this.dsCurrVal += len;
7158 }
7159 }
7160
7161 class UpdateEncoderV2 extends DSEncoderV2 {
7162 constructor () {
7163 super();
7164 /**
7165 * @type {Map<string,number>}
7166 */
7167 this.keyMap = new Map();
7168 /**
7169 * Refers to the next uniqe key-identifier to me used.
7170 * See writeKey method for more information.
7171 *
7172 * @type {number}
7173 */
7174 this.keyClock = 0;
7175 this.keyClockEncoder = new IntDiffOptRleEncoder();
7176 this.clientEncoder = new UintOptRleEncoder();
7177 this.leftClockEncoder = new IntDiffOptRleEncoder();
7178 this.rightClockEncoder = new IntDiffOptRleEncoder();
7179 this.infoEncoder = new RleEncoder(writeUint8);
7180 this.stringEncoder = new StringEncoder();
7181 this.parentInfoEncoder = new RleEncoder(writeUint8);
7182 this.typeRefEncoder = new UintOptRleEncoder();
7183 this.lenEncoder = new UintOptRleEncoder();
7184 }
7185
7186 toUint8Array () {
7187 const encoder = createEncoder();
7188 writeVarUint(encoder, 0); // this is a feature flag that we might use in the future
7189 writeVarUint8Array(encoder, this.keyClockEncoder.toUint8Array());
7190 writeVarUint8Array(encoder, this.clientEncoder.toUint8Array());
7191 writeVarUint8Array(encoder, this.leftClockEncoder.toUint8Array());
7192 writeVarUint8Array(encoder, this.rightClockEncoder.toUint8Array());
7193 writeVarUint8Array(encoder, toUint8Array(this.infoEncoder));
7194 writeVarUint8Array(encoder, this.stringEncoder.toUint8Array());
7195 writeVarUint8Array(encoder, toUint8Array(this.parentInfoEncoder));
7196 writeVarUint8Array(encoder, this.typeRefEncoder.toUint8Array());
7197 writeVarUint8Array(encoder, this.lenEncoder.toUint8Array());
7198 // @note The rest encoder is appended! (note the missing var)
7199 writeUint8Array(encoder, toUint8Array(this.restEncoder));
7200 return toUint8Array(encoder)
7201 }
7202
7203 /**
7204 * @param {ID} id
7205 */
7206 writeLeftID (id) {
7207 this.clientEncoder.write(id.client);
7208 this.leftClockEncoder.write(id.clock);
7209 }
7210
7211 /**
7212 * @param {ID} id
7213 */
7214 writeRightID (id) {
7215 this.clientEncoder.write(id.client);
7216 this.rightClockEncoder.write(id.clock);
7217 }
7218
7219 /**
7220 * @param {number} client
7221 */
7222 writeClient (client) {
7223 this.clientEncoder.write(client);
7224 }
7225
7226 /**
7227 * @param {number} info An unsigned 8-bit integer
7228 */
7229 writeInfo (info) {
7230 this.infoEncoder.write(info);
7231 }
7232
7233 /**
7234 * @param {string} s
7235 */
7236 writeString (s) {
7237 this.stringEncoder.write(s);
7238 }
7239
7240 /**
7241 * @param {boolean} isYKey
7242 */
7243 writeParentInfo (isYKey) {
7244 this.parentInfoEncoder.write(isYKey ? 1 : 0);
7245 }
7246
7247 /**
7248 * @param {number} info An unsigned 8-bit integer
7249 */
7250 writeTypeRef (info) {
7251 this.typeRefEncoder.write(info);
7252 }
7253
7254 /**
7255 * Write len of a struct - well suited for Opt RLE encoder.
7256 *
7257 * @param {number} len
7258 */
7259 writeLen (len) {
7260 this.lenEncoder.write(len);
7261 }
7262
7263 /**
7264 * @param {any} any
7265 */
7266 writeAny (any) {
7267 writeAny(this.restEncoder, any);
7268 }
7269
7270 /**
7271 * @param {Uint8Array} buf
7272 */
7273 writeBuf (buf) {
7274 writeVarUint8Array(this.restEncoder, buf);
7275 }
7276
7277 /**
7278 * This is mainly here for legacy purposes.
7279 *
7280 * 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.
7281 *
7282 * @param {any} embed
7283 */
7284 writeJSON (embed) {
7285 writeAny(this.restEncoder, embed);
7286 }
7287
7288 /**
7289 * Property keys are often reused. For example, in y-prosemirror the key `bold` might
7290 * occur very often. For a 3d application, the key `position` might occur very often.
7291 *
7292 * We cache these keys in a Map and refer to them via a unique number.
7293 *
7294 * @param {string} key
7295 */
7296 writeKey (key) {
7297 const clock = this.keyMap.get(key);
7298 if (clock === undefined) {
7299 /**
7300 * @todo uncomment to introduce this feature finally
7301 *
7302 * Background. The ContentFormat object was always encoded using writeKey, but the decoder used to use readString.
7303 * Furthermore, I forgot to set the keyclock. So everything was working fine.
7304 *
7305 * However, this feature here is basically useless as it is not being used (it actually only consumes extra memory).
7306 *
7307 * I don't know yet how to reintroduce this feature..
7308 *
7309 * Older clients won't be able to read updates when we reintroduce this feature. So this should probably be done using a flag.
7310 *
7311 */
7312 // this.keyMap.set(key, this.keyClock)
7313 this.keyClockEncoder.write(this.keyClock++);
7314 this.stringEncoder.write(key);
7315 } else {
7316 this.keyClockEncoder.write(clock);
7317 }
7318 }
7319 }
7320
7321 /**
7322 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7323 * @param {Array<GC|Item>} structs All structs by `client`
7324 * @param {number} client
7325 * @param {number} clock write structs starting with `ID(client,clock)`
7326 *
7327 * @function
7328 */
7329 const writeStructs = (encoder, structs, client, clock) => {
7330 // write first id
7331 clock = max(clock, structs[0].id.clock); // make sure the first id exists
7332 const startNewStructs = findIndexSS(structs, clock);
7333 // write # encoded structs
7334 writeVarUint(encoder.restEncoder, structs.length - startNewStructs);
7335 encoder.writeClient(client);
7336 writeVarUint(encoder.restEncoder, clock);
7337 const firstStruct = structs[startNewStructs];
7338 // write first struct with an offset
7339 firstStruct.write(encoder, clock - firstStruct.id.clock);
7340 for (let i = startNewStructs + 1; i < structs.length; i++) {
7341 structs[i].write(encoder, 0);
7342 }
7343 };
7344
7345 /**
7346 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7347 * @param {StructStore} store
7348 * @param {Map<number,number>} _sm
7349 *
7350 * @private
7351 * @function
7352 */
7353 const writeClientsStructs = (encoder, store, _sm) => {
7354 // we filter all valid _sm entries into sm
7355 const sm = new Map();
7356 _sm.forEach((clock, client) => {
7357 // only write if new structs are available
7358 if (getState(store, client) > clock) {
7359 sm.set(client, clock);
7360 }
7361 });
7362 getStateVector(store).forEach((_clock, client) => {
7363 if (!_sm.has(client)) {
7364 sm.set(client, 0);
7365 }
7366 });
7367 // write # states that were updated
7368 writeVarUint(encoder.restEncoder, sm.size);
7369 // Write items with higher client ids first
7370 // This heavily improves the conflict algorithm.
7371 array_from(sm.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
7372 writeStructs(encoder, /** @type {Array<GC|Item>} */ (store.clients.get(client)), client, clock);
7373 });
7374 };
7375
7376 /**
7377 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder The decoder object to read data from.
7378 * @param {Doc} doc
7379 * @return {Map<number, { i: number, refs: Array<Item | GC> }>}
7380 *
7381 * @private
7382 * @function
7383 */
7384 const readClientsStructRefs = (decoder, doc) => {
7385 /**
7386 * @type {Map<number, { i: number, refs: Array<Item | GC> }>}
7387 */
7388 const clientRefs = create();
7389 const numOfStateUpdates = readVarUint(decoder.restDecoder);
7390 for (let i = 0; i < numOfStateUpdates; i++) {
7391 const numberOfStructs = readVarUint(decoder.restDecoder);
7392 /**
7393 * @type {Array<GC|Item>}
7394 */
7395 const refs = new Array(numberOfStructs);
7396 const client = decoder.readClient();
7397 let clock = readVarUint(decoder.restDecoder);
7398 // const start = performance.now()
7399 clientRefs.set(client, { i: 0, refs });
7400 for (let i = 0; i < numberOfStructs; i++) {
7401 const info = decoder.readInfo();
7402 switch (BITS5 & info) {
7403 case 0: { // GC
7404 const len = decoder.readLen();
7405 refs[i] = new GC(createID(client, clock), len);
7406 clock += len;
7407 break
7408 }
7409 case 10: { // Skip Struct (nothing to apply)
7410 // @todo we could reduce the amount of checks by adding Skip struct to clientRefs so we know that something is missing.
7411 const len = readVarUint(decoder.restDecoder);
7412 refs[i] = new Skip(createID(client, clock), len);
7413 clock += len;
7414 break
7415 }
7416 default: { // Item with content
7417 /**
7418 * The optimized implementation doesn't use any variables because inlining variables is faster.
7419 * Below a non-optimized version is shown that implements the basic algorithm with
7420 * a few comments
7421 */
7422 const cantCopyParentInfo = (info & (BIT7 | BIT8)) === 0;
7423 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
7424 // and we read the next string as parentYKey.
7425 // It indicates how we store/retrieve parent from `y.share`
7426 // @type {string|null}
7427 const struct = new Item(
7428 createID(client, clock),
7429 null, // leftd
7430 (info & BIT8) === BIT8 ? decoder.readLeftID() : null, // origin
7431 null, // right
7432 (info & BIT7) === BIT7 ? decoder.readRightID() : null, // right origin
7433 cantCopyParentInfo ? (decoder.readParentInfo() ? doc.get(decoder.readString()) : decoder.readLeftID()) : null, // parent
7434 cantCopyParentInfo && (info & BIT6) === BIT6 ? decoder.readString() : null, // parentSub
7435 readItemContent(decoder, info) // item content
7436 );
7437 /* A non-optimized implementation of the above algorithm:
7438
7439 // The item that was originally to the left of this item.
7440 const origin = (info & binary.BIT8) === binary.BIT8 ? decoder.readLeftID() : null
7441 // The item that was originally to the right of this item.
7442 const rightOrigin = (info & binary.BIT7) === binary.BIT7 ? decoder.readRightID() : null
7443 const cantCopyParentInfo = (info & (binary.BIT7 | binary.BIT8)) === 0
7444 const hasParentYKey = cantCopyParentInfo ? decoder.readParentInfo() : false
7445 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
7446 // and we read the next string as parentYKey.
7447 // It indicates how we store/retrieve parent from `y.share`
7448 // @type {string|null}
7449 const parentYKey = cantCopyParentInfo && hasParentYKey ? decoder.readString() : null
7450
7451 const struct = new Item(
7452 createID(client, clock),
7453 null, // leftd
7454 origin, // origin
7455 null, // right
7456 rightOrigin, // right origin
7457 cantCopyParentInfo && !hasParentYKey ? decoder.readLeftID() : (parentYKey !== null ? doc.get(parentYKey) : null), // parent
7458 cantCopyParentInfo && (info & binary.BIT6) === binary.BIT6 ? decoder.readString() : null, // parentSub
7459 readItemContent(decoder, info) // item content
7460 )
7461 */
7462 refs[i] = struct;
7463 clock += struct.length;
7464 }
7465 }
7466 }
7467 // console.log('time to read: ', performance.now() - start) // @todo remove
7468 }
7469 return clientRefs
7470 };
7471
7472 /**
7473 * Resume computing structs generated by struct readers.
7474 *
7475 * While there is something to do, we integrate structs in this order
7476 * 1. top element on stack, if stack is not empty
7477 * 2. next element from current struct reader (if empty, use next struct reader)
7478 *
7479 * If struct causally depends on another struct (ref.missing), we put next reader of
7480 * `ref.id.client` on top of stack.
7481 *
7482 * At some point we find a struct that has no causal dependencies,
7483 * then we start emptying the stack.
7484 *
7485 * It is not possible to have circles: i.e. struct1 (from client1) depends on struct2 (from client2)
7486 * depends on struct3 (from client1). Therefore the max stack size is eqaul to `structReaders.length`.
7487 *
7488 * This method is implemented in a way so that we can resume computation if this update
7489 * causally depends on another update.
7490 *
7491 * @param {Transaction} transaction
7492 * @param {StructStore} store
7493 * @param {Map<number, { i: number, refs: (GC | Item)[] }>} clientsStructRefs
7494 * @return { null | { update: Uint8Array, missing: Map<number,number> } }
7495 *
7496 * @private
7497 * @function
7498 */
7499 const integrateStructs = (transaction, store, clientsStructRefs) => {
7500 /**
7501 * @type {Array<Item | GC>}
7502 */
7503 const stack = [];
7504 // 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.
7505 let clientsStructRefsIds = array_from(clientsStructRefs.keys()).sort((a, b) => a - b);
7506 if (clientsStructRefsIds.length === 0) {
7507 return null
7508 }
7509 const getNextStructTarget = () => {
7510 if (clientsStructRefsIds.length === 0) {
7511 return null
7512 }
7513 let nextStructsTarget = /** @type {{i:number,refs:Array<GC|Item>}} */ (clientsStructRefs.get(clientsStructRefsIds[clientsStructRefsIds.length - 1]));
7514 while (nextStructsTarget.refs.length === nextStructsTarget.i) {
7515 clientsStructRefsIds.pop();
7516 if (clientsStructRefsIds.length > 0) {
7517 nextStructsTarget = /** @type {{i:number,refs:Array<GC|Item>}} */ (clientsStructRefs.get(clientsStructRefsIds[clientsStructRefsIds.length - 1]));
7518 } else {
7519 return null
7520 }
7521 }
7522 return nextStructsTarget
7523 };
7524 let curStructsTarget = getNextStructTarget();
7525 if (curStructsTarget === null && stack.length === 0) {
7526 return null
7527 }
7528
7529 /**
7530 * @type {StructStore}
7531 */
7532 const restStructs = new StructStore();
7533 const missingSV = new Map();
7534 /**
7535 * @param {number} client
7536 * @param {number} clock
7537 */
7538 const updateMissingSv = (client, clock) => {
7539 const mclock = missingSV.get(client);
7540 if (mclock == null || mclock > clock) {
7541 missingSV.set(client, clock);
7542 }
7543 };
7544 /**
7545 * @type {GC|Item}
7546 */
7547 let stackHead = /** @type {any} */ (curStructsTarget).refs[/** @type {any} */ (curStructsTarget).i++];
7548 // caching the state because it is used very often
7549 const state = new Map();
7550
7551 const addStackToRestSS = () => {
7552 for (const item of stack) {
7553 const client = item.id.client;
7554 const unapplicableItems = clientsStructRefs.get(client);
7555 if (unapplicableItems) {
7556 // decrement because we weren't able to apply previous operation
7557 unapplicableItems.i--;
7558 restStructs.clients.set(client, unapplicableItems.refs.slice(unapplicableItems.i));
7559 clientsStructRefs.delete(client);
7560 unapplicableItems.i = 0;
7561 unapplicableItems.refs = [];
7562 } else {
7563 // item was the last item on clientsStructRefs and the field was already cleared. Add item to restStructs and continue
7564 restStructs.clients.set(client, [item]);
7565 }
7566 // remove client from clientsStructRefsIds to prevent users from applying the same update again
7567 clientsStructRefsIds = clientsStructRefsIds.filter(c => c !== client);
7568 }
7569 stack.length = 0;
7570 };
7571
7572 // iterate over all struct readers until we are done
7573 while (true) {
7574 if (stackHead.constructor !== Skip) {
7575 const localClock = setIfUndefined(state, stackHead.id.client, () => getState(store, stackHead.id.client));
7576 const offset = localClock - stackHead.id.clock;
7577 if (offset < 0) {
7578 // update from the same client is missing
7579 stack.push(stackHead);
7580 updateMissingSv(stackHead.id.client, stackHead.id.clock - 1);
7581 // hid a dead wall, add all items from stack to restSS
7582 addStackToRestSS();
7583 } else {
7584 const missing = stackHead.getMissing(transaction, store);
7585 if (missing !== null) {
7586 stack.push(stackHead);
7587 // get the struct reader that has the missing struct
7588 /**
7589 * @type {{ refs: Array<GC|Item>, i: number }}
7590 */
7591 const structRefs = clientsStructRefs.get(/** @type {number} */ (missing)) || { refs: [], i: 0 };
7592 if (structRefs.refs.length === structRefs.i) {
7593 // This update message causally depends on another update message that doesn't exist yet
7594 updateMissingSv(/** @type {number} */ (missing), getState(store, missing));
7595 addStackToRestSS();
7596 } else {
7597 stackHead = structRefs.refs[structRefs.i++];
7598 continue
7599 }
7600 } else if (offset === 0 || offset < stackHead.length) {
7601 // all fine, apply the stackhead
7602 stackHead.integrate(transaction, offset);
7603 state.set(stackHead.id.client, stackHead.id.clock + stackHead.length);
7604 }
7605 }
7606 }
7607 // iterate to next stackHead
7608 if (stack.length > 0) {
7609 stackHead = /** @type {GC|Item} */ (stack.pop());
7610 } else if (curStructsTarget !== null && curStructsTarget.i < curStructsTarget.refs.length) {
7611 stackHead = /** @type {GC|Item} */ (curStructsTarget.refs[curStructsTarget.i++]);
7612 } else {
7613 curStructsTarget = getNextStructTarget();
7614 if (curStructsTarget === null) {
7615 // we are done!
7616 break
7617 } else {
7618 stackHead = /** @type {GC|Item} */ (curStructsTarget.refs[curStructsTarget.i++]);
7619 }
7620 }
7621 }
7622 if (restStructs.clients.size > 0) {
7623 const encoder = new UpdateEncoderV2();
7624 writeClientsStructs(encoder, restStructs, new Map());
7625 // write empty deleteset
7626 // writeDeleteSet(encoder, new DeleteSet())
7627 writeVarUint(encoder.restEncoder, 0); // => no need for an extra function call, just write 0 deletes
7628 return { missing: missingSV, update: encoder.toUint8Array() }
7629 }
7630 return null
7631 };
7632
7633 /**
7634 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7635 * @param {Transaction} transaction
7636 *
7637 * @private
7638 * @function
7639 */
7640 const writeStructsFromTransaction = (encoder, transaction) => writeClientsStructs(encoder, transaction.doc.store, transaction.beforeState);
7641
7642 /**
7643 * Read and apply a document update.
7644 *
7645 * This function has the same effect as `applyUpdate` but accepts an decoder.
7646 *
7647 * @param {decoding.Decoder} decoder
7648 * @param {Doc} ydoc
7649 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7650 * @param {UpdateDecoderV1 | UpdateDecoderV2} [structDecoder]
7651 *
7652 * @function
7653 */
7654 const readUpdateV2 = (decoder, ydoc, transactionOrigin, structDecoder = new UpdateDecoderV2(decoder)) =>
7655 transact(ydoc, transaction => {
7656 // force that transaction.local is set to non-local
7657 transaction.local = false;
7658 let retry = false;
7659 const doc = transaction.doc;
7660 const store = doc.store;
7661 // let start = performance.now()
7662 const ss = readClientsStructRefs(structDecoder, doc);
7663 // console.log('time to read structs: ', performance.now() - start) // @todo remove
7664 // start = performance.now()
7665 // console.log('time to merge: ', performance.now() - start) // @todo remove
7666 // start = performance.now()
7667 const restStructs = integrateStructs(transaction, store, ss);
7668 const pending = store.pendingStructs;
7669 if (pending) {
7670 // check if we can apply something
7671 for (const [client, clock] of pending.missing) {
7672 if (clock < getState(store, client)) {
7673 retry = true;
7674 break
7675 }
7676 }
7677 if (restStructs) {
7678 // merge restStructs into store.pending
7679 for (const [client, clock] of restStructs.missing) {
7680 const mclock = pending.missing.get(client);
7681 if (mclock == null || mclock > clock) {
7682 pending.missing.set(client, clock);
7683 }
7684 }
7685 pending.update = mergeUpdatesV2([pending.update, restStructs.update]);
7686 }
7687 } else {
7688 store.pendingStructs = restStructs;
7689 }
7690 // console.log('time to integrate: ', performance.now() - start) // @todo remove
7691 // start = performance.now()
7692 const dsRest = readAndApplyDeleteSet(structDecoder, transaction, store);
7693 if (store.pendingDs) {
7694 // @todo we could make a lower-bound state-vector check as we do above
7695 const pendingDSUpdate = new UpdateDecoderV2(createDecoder(store.pendingDs));
7696 readVarUint(pendingDSUpdate.restDecoder); // read 0 structs, because we only encode deletes in pendingdsupdate
7697 const dsRest2 = readAndApplyDeleteSet(pendingDSUpdate, transaction, store);
7698 if (dsRest && dsRest2) {
7699 // case 1: ds1 != null && ds2 != null
7700 store.pendingDs = mergeUpdatesV2([dsRest, dsRest2]);
7701 } else {
7702 // case 2: ds1 != null
7703 // case 3: ds2 != null
7704 // case 4: ds1 == null && ds2 == null
7705 store.pendingDs = dsRest || dsRest2;
7706 }
7707 } else {
7708 // Either dsRest == null && pendingDs == null OR dsRest != null
7709 store.pendingDs = dsRest;
7710 }
7711 // console.log('time to cleanup: ', performance.now() - start) // @todo remove
7712 // start = performance.now()
7713
7714 // console.log('time to resume delete readers: ', performance.now() - start) // @todo remove
7715 // start = performance.now()
7716 if (retry) {
7717 const update = /** @type {{update: Uint8Array}} */ (store.pendingStructs).update;
7718 store.pendingStructs = null;
7719 applyUpdateV2(transaction.doc, update);
7720 }
7721 }, transactionOrigin, false);
7722
7723 /**
7724 * Read and apply a document update.
7725 *
7726 * This function has the same effect as `applyUpdate` but accepts an decoder.
7727 *
7728 * @param {decoding.Decoder} decoder
7729 * @param {Doc} ydoc
7730 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7731 *
7732 * @function
7733 */
7734 const readUpdate = (decoder, ydoc, transactionOrigin) => readUpdateV2(decoder, ydoc, transactionOrigin, new UpdateDecoderV1(decoder));
7735
7736 /**
7737 * Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`.
7738 *
7739 * This function has the same effect as `readUpdate` but accepts an Uint8Array instead of a Decoder.
7740 *
7741 * @param {Doc} ydoc
7742 * @param {Uint8Array} update
7743 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7744 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
7745 *
7746 * @function
7747 */
7748 const applyUpdateV2 = (ydoc, update, transactionOrigin, YDecoder = UpdateDecoderV2) => {
7749 const decoder = createDecoder(update);
7750 readUpdateV2(decoder, ydoc, transactionOrigin, new YDecoder(decoder));
7751 };
7752
7753 /**
7754 * Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`.
7755 *
7756 * This function has the same effect as `readUpdate` but accepts an Uint8Array instead of a Decoder.
7757 *
7758 * @param {Doc} ydoc
7759 * @param {Uint8Array} update
7760 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7761 *
7762 * @function
7763 */
7764 const applyUpdate = (ydoc, update, transactionOrigin) => applyUpdateV2(ydoc, update, transactionOrigin, UpdateDecoderV1);
7765
7766 /**
7767 * Write all the document as a single update message. If you specify the state of the remote client (`targetStateVector`) it will
7768 * only write the operations that are missing.
7769 *
7770 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7771 * @param {Doc} doc
7772 * @param {Map<number,number>} [targetStateVector] The state of the target that receives the update. Leave empty to write all known structs
7773 *
7774 * @function
7775 */
7776 const writeStateAsUpdate = (encoder, doc, targetStateVector = new Map()) => {
7777 writeClientsStructs(encoder, doc.store, targetStateVector);
7778 writeDeleteSet(encoder, createDeleteSetFromStructStore(doc.store));
7779 };
7780
7781 /**
7782 * 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
7783 * only write the operations that are missing.
7784 *
7785 * Use `writeStateAsUpdate` instead if you are working with lib0/encoding.js#Encoder
7786 *
7787 * @param {Doc} doc
7788 * @param {Uint8Array} [encodedTargetStateVector] The state of the target that receives the update. Leave empty to write all known structs
7789 * @param {UpdateEncoderV1 | UpdateEncoderV2} [encoder]
7790 * @return {Uint8Array}
7791 *
7792 * @function
7793 */
7794 const encodeStateAsUpdateV2 = (doc, encodedTargetStateVector = new Uint8Array([0]), encoder = new UpdateEncoderV2()) => {
7795 const targetStateVector = decodeStateVector(encodedTargetStateVector);
7796 writeStateAsUpdate(encoder, doc, targetStateVector);
7797 const updates = [encoder.toUint8Array()];
7798 // also add the pending updates (if there are any)
7799 if (doc.store.pendingDs) {
7800 updates.push(doc.store.pendingDs);
7801 }
7802 if (doc.store.pendingStructs) {
7803 updates.push(diffUpdateV2(doc.store.pendingStructs.update, encodedTargetStateVector));
7804 }
7805 if (updates.length > 1) {
7806 if (encoder.constructor === UpdateEncoderV1) {
7807 return mergeUpdates(updates.map((update, i) => i === 0 ? update : convertUpdateFormatV2ToV1(update)))
7808 } else if (encoder.constructor === UpdateEncoderV2) {
7809 return mergeUpdatesV2(updates)
7810 }
7811 }
7812 return updates[0]
7813 };
7814
7815 /**
7816 * 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
7817 * only write the operations that are missing.
7818 *
7819 * Use `writeStateAsUpdate` instead if you are working with lib0/encoding.js#Encoder
7820 *
7821 * @param {Doc} doc
7822 * @param {Uint8Array} [encodedTargetStateVector] The state of the target that receives the update. Leave empty to write all known structs
7823 * @return {Uint8Array}
7824 *
7825 * @function
7826 */
7827 const encodeStateAsUpdate = (doc, encodedTargetStateVector) => encodeStateAsUpdateV2(doc, encodedTargetStateVector, new UpdateEncoderV1());
7828
7829 /**
7830 * Read state vector from Decoder and return as Map
7831 *
7832 * @param {DSDecoderV1 | DSDecoderV2} decoder
7833 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client.
7834 *
7835 * @function
7836 */
7837 const readStateVector = decoder => {
7838 const ss = new Map();
7839 const ssLength = readVarUint(decoder.restDecoder);
7840 for (let i = 0; i < ssLength; i++) {
7841 const client = readVarUint(decoder.restDecoder);
7842 const clock = readVarUint(decoder.restDecoder);
7843 ss.set(client, clock);
7844 }
7845 return ss
7846 };
7847
7848 /**
7849 * Read decodedState and return State as Map.
7850 *
7851 * @param {Uint8Array} decodedState
7852 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client.
7853 *
7854 * @function
7855 */
7856 // export const decodeStateVectorV2 = decodedState => readStateVector(new DSDecoderV2(decoding.createDecoder(decodedState)))
7857
7858 /**
7859 * Read decodedState and return State as Map.
7860 *
7861 * @param {Uint8Array} decodedState
7862 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client.
7863 *
7864 * @function
7865 */
7866 const decodeStateVector = decodedState => readStateVector(new DSDecoderV1(createDecoder(decodedState)));
7867
7868 /**
7869 * @param {DSEncoderV1 | DSEncoderV2} encoder
7870 * @param {Map<number,number>} sv
7871 * @function
7872 */
7873 const writeStateVector = (encoder, sv) => {
7874 writeVarUint(encoder.restEncoder, sv.size);
7875 array_from(sv.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
7876 writeVarUint(encoder.restEncoder, client); // @todo use a special client decoder that is based on mapping
7877 writeVarUint(encoder.restEncoder, clock);
7878 });
7879 return encoder
7880 };
7881
7882 /**
7883 * @param {DSEncoderV1 | DSEncoderV2} encoder
7884 * @param {Doc} doc
7885 *
7886 * @function
7887 */
7888 const writeDocumentStateVector = (encoder, doc) => writeStateVector(encoder, getStateVector(doc.store));
7889
7890 /**
7891 * Encode State as Uint8Array.
7892 *
7893 * @param {Doc|Map<number,number>} doc
7894 * @param {DSEncoderV1 | DSEncoderV2} [encoder]
7895 * @return {Uint8Array}
7896 *
7897 * @function
7898 */
7899 const encodeStateVectorV2 = (doc, encoder = new DSEncoderV2()) => {
7900 if (doc instanceof Map) {
7901 writeStateVector(encoder, doc);
7902 } else {
7903 writeDocumentStateVector(encoder, doc);
7904 }
7905 return encoder.toUint8Array()
7906 };
7907
7908 /**
7909 * Encode State as Uint8Array.
7910 *
7911 * @param {Doc|Map<number,number>} doc
7912 * @return {Uint8Array}
7913 *
7914 * @function
7915 */
7916 const encodeStateVector = doc => encodeStateVectorV2(doc, new DSEncoderV1());
7917
7918 /**
7919 * General event handler implementation.
7920 *
7921 * @template ARG0, ARG1
7922 *
7923 * @private
7924 */
7925 class EventHandler {
7926 constructor () {
7927 /**
7928 * @type {Array<function(ARG0, ARG1):void>}
7929 */
7930 this.l = [];
7931 }
7932 }
7933
7934 /**
7935 * @template ARG0,ARG1
7936 * @returns {EventHandler<ARG0,ARG1>}
7937 *
7938 * @private
7939 * @function
7940 */
7941 const createEventHandler = () => new EventHandler();
7942
7943 /**
7944 * Adds an event listener that is called when
7945 * {@link EventHandler#callEventListeners} is called.
7946 *
7947 * @template ARG0,ARG1
7948 * @param {EventHandler<ARG0,ARG1>} eventHandler
7949 * @param {function(ARG0,ARG1):void} f The event handler.
7950 *
7951 * @private
7952 * @function
7953 */
7954 const addEventHandlerListener = (eventHandler, f) =>
7955 eventHandler.l.push(f);
7956
7957 /**
7958 * Removes an event listener.
7959 *
7960 * @template ARG0,ARG1
7961 * @param {EventHandler<ARG0,ARG1>} eventHandler
7962 * @param {function(ARG0,ARG1):void} f The event handler that was added with
7963 * {@link EventHandler#addEventListener}
7964 *
7965 * @private
7966 * @function
7967 */
7968 const removeEventHandlerListener = (eventHandler, f) => {
7969 const l = eventHandler.l;
7970 const len = l.length;
7971 eventHandler.l = l.filter(g => f !== g);
7972 if (len === eventHandler.l.length) {
7973 console.error('[yjs] Tried to remove event handler that doesn\'t exist.');
7974 }
7975 };
7976
7977 /**
7978 * Call all event listeners that were added via
7979 * {@link EventHandler#addEventListener}.
7980 *
7981 * @template ARG0,ARG1
7982 * @param {EventHandler<ARG0,ARG1>} eventHandler
7983 * @param {ARG0} arg0
7984 * @param {ARG1} arg1
7985 *
7986 * @private
7987 * @function
7988 */
7989 const callEventHandlerListeners = (eventHandler, arg0, arg1) =>
7990 callAll(eventHandler.l, [arg0, arg1]);
7991
7992 class ID {
7993 /**
7994 * @param {number} client client id
7995 * @param {number} clock unique per client id, continuous number
7996 */
7997 constructor (client, clock) {
7998 /**
7999 * Client id
8000 * @type {number}
8001 */
8002 this.client = client;
8003 /**
8004 * unique per client id, continuous number
8005 * @type {number}
8006 */
8007 this.clock = clock;
8008 }
8009 }
8010
8011 /**
8012 * @param {ID | null} a
8013 * @param {ID | null} b
8014 * @return {boolean}
8015 *
8016 * @function
8017 */
8018 const compareIDs = (a, b) => a === b || (a !== null && b !== null && a.client === b.client && a.clock === b.clock);
8019
8020 /**
8021 * @param {number} client
8022 * @param {number} clock
8023 *
8024 * @private
8025 * @function
8026 */
8027 const createID = (client, clock) => new ID(client, clock);
8028
8029 /**
8030 * @param {encoding.Encoder} encoder
8031 * @param {ID} id
8032 *
8033 * @private
8034 * @function
8035 */
8036 const writeID = (encoder, id) => {
8037 encoding.writeVarUint(encoder, id.client);
8038 encoding.writeVarUint(encoder, id.clock);
8039 };
8040
8041 /**
8042 * Read ID.
8043 * * If first varUint read is 0xFFFFFF a RootID is returned.
8044 * * Otherwise an ID is returned
8045 *
8046 * @param {decoding.Decoder} decoder
8047 * @return {ID}
8048 *
8049 * @private
8050 * @function
8051 */
8052 const readID = decoder =>
8053 createID(decoding.readVarUint(decoder), decoding.readVarUint(decoder));
8054
8055 /**
8056 * The top types are mapped from y.share.get(keyname) => type.
8057 * `type` does not store any information about the `keyname`.
8058 * This function finds the correct `keyname` for `type` and throws otherwise.
8059 *
8060 * @param {AbstractType<any>} type
8061 * @return {string}
8062 *
8063 * @private
8064 * @function
8065 */
8066 const findRootTypeKey = type => {
8067 // @ts-ignore _y must be defined, otherwise unexpected case
8068 for (const [key, value] of type.doc.share.entries()) {
8069 if (value === type) {
8070 return key
8071 }
8072 }
8073 throw unexpectedCase()
8074 };
8075
8076 /**
8077 * Check if `parent` is a parent of `child`.
8078 *
8079 * @param {AbstractType<any>} parent
8080 * @param {Item|null} child
8081 * @return {Boolean} Whether `parent` is a parent of `child`.
8082 *
8083 * @private
8084 * @function
8085 */
8086 const yjs_isParentOf = (parent, child) => {
8087 while (child !== null) {
8088 if (child.parent === parent) {
8089 return true
8090 }
8091 child = /** @type {AbstractType<any>} */ (child.parent)._item;
8092 }
8093 return false
8094 };
8095
8096 /**
8097 * Convenient helper to log type information.
8098 *
8099 * Do not use in productive systems as the output can be immense!
8100 *
8101 * @param {AbstractType<any>} type
8102 */
8103 const logType = type => {
8104 const res = [];
8105 let n = type._start;
8106 while (n) {
8107 res.push(n);
8108 n = n.right;
8109 }
8110 console.log('Children: ', res);
8111 console.log('Children content: ', res.filter(m => !m.deleted).map(m => m.content));
8112 };
8113
8114 class PermanentUserData {
8115 /**
8116 * @param {Doc} doc
8117 * @param {YMap<any>} [storeType]
8118 */
8119 constructor (doc, storeType = doc.getMap('users')) {
8120 /**
8121 * @type {Map<string,DeleteSet>}
8122 */
8123 const dss = new Map();
8124 this.yusers = storeType;
8125 this.doc = doc;
8126 /**
8127 * Maps from clientid to userDescription
8128 *
8129 * @type {Map<number,string>}
8130 */
8131 this.clients = new Map();
8132 this.dss = dss;
8133 /**
8134 * @param {YMap<any>} user
8135 * @param {string} userDescription
8136 */
8137 const initUser = (user, userDescription) => {
8138 /**
8139 * @type {YArray<Uint8Array>}
8140 */
8141 const ds = user.get('ds');
8142 const ids = user.get('ids');
8143 const addClientId = /** @param {number} clientid */ clientid => this.clients.set(clientid, userDescription);
8144 ds.observe(/** @param {YArrayEvent<any>} event */ event => {
8145 event.changes.added.forEach(item => {
8146 item.content.getContent().forEach(encodedDs => {
8147 if (encodedDs instanceof Uint8Array) {
8148 this.dss.set(userDescription, mergeDeleteSets([this.dss.get(userDescription) || createDeleteSet(), readDeleteSet(new DSDecoderV1(decoding.createDecoder(encodedDs)))]));
8149 }
8150 });
8151 });
8152 });
8153 this.dss.set(userDescription, mergeDeleteSets(ds.map(encodedDs => readDeleteSet(new DSDecoderV1(decoding.createDecoder(encodedDs))))));
8154 ids.observe(/** @param {YArrayEvent<any>} event */ event =>
8155 event.changes.added.forEach(item => item.content.getContent().forEach(addClientId))
8156 );
8157 ids.forEach(addClientId);
8158 };
8159 // observe users
8160 storeType.observe(event => {
8161 event.keysChanged.forEach(userDescription =>
8162 initUser(storeType.get(userDescription), userDescription)
8163 );
8164 });
8165 // add intial data
8166 storeType.forEach(initUser);
8167 }
8168
8169 /**
8170 * @param {Doc} doc
8171 * @param {number} clientid
8172 * @param {string} userDescription
8173 * @param {Object} conf
8174 * @param {function(Transaction, DeleteSet):boolean} [conf.filter]
8175 */
8176 setUserMapping (doc, clientid, userDescription, { filter = () => true } = {}) {
8177 const users = this.yusers;
8178 let user = users.get(userDescription);
8179 if (!user) {
8180 user = new YMap();
8181 user.set('ids', new YArray());
8182 user.set('ds', new YArray());
8183 users.set(userDescription, user);
8184 }
8185 user.get('ids').push([clientid]);
8186 users.observe(_event => {
8187 setTimeout(() => {
8188 const userOverwrite = users.get(userDescription);
8189 if (userOverwrite !== user) {
8190 // user was overwritten, port all data over to the next user object
8191 // @todo Experiment with Y.Sets here
8192 user = userOverwrite;
8193 // @todo iterate over old type
8194 this.clients.forEach((_userDescription, clientid) => {
8195 if (userDescription === _userDescription) {
8196 user.get('ids').push([clientid]);
8197 }
8198 });
8199 const encoder = new DSEncoderV1();
8200 const ds = this.dss.get(userDescription);
8201 if (ds) {
8202 writeDeleteSet(encoder, ds);
8203 user.get('ds').push([encoder.toUint8Array()]);
8204 }
8205 }
8206 }, 0);
8207 });
8208 doc.on('afterTransaction', /** @param {Transaction} transaction */ transaction => {
8209 setTimeout(() => {
8210 const yds = user.get('ds');
8211 const ds = transaction.deleteSet;
8212 if (transaction.local && ds.clients.size > 0 && filter(transaction, ds)) {
8213 const encoder = new DSEncoderV1();
8214 writeDeleteSet(encoder, ds);
8215 yds.push([encoder.toUint8Array()]);
8216 }
8217 });
8218 });
8219 }
8220
8221 /**
8222 * @param {number} clientid
8223 * @return {any}
8224 */
8225 getUserByClientId (clientid) {
8226 return this.clients.get(clientid) || null
8227 }
8228
8229 /**
8230 * @param {ID} id
8231 * @return {string | null}
8232 */
8233 getUserByDeletedId (id) {
8234 for (const [userDescription, ds] of this.dss.entries()) {
8235 if (isDeleted(ds, id)) {
8236 return userDescription
8237 }
8238 }
8239 return null
8240 }
8241 }
8242
8243 /**
8244 * A relative position is based on the Yjs model and is not affected by document changes.
8245 * E.g. If you place a relative position before a certain character, it will always point to this character.
8246 * If you place a relative position at the end of a type, it will always point to the end of the type.
8247 *
8248 * A numeric position is often unsuited for user selections, because it does not change when content is inserted
8249 * before or after.
8250 *
8251 * ```Insert(0, 'x')('a|bc') = 'xa|bc'``` Where | is the relative position.
8252 *
8253 * One of the properties must be defined.
8254 *
8255 * @example
8256 * // Current cursor position is at position 10
8257 * const relativePosition = createRelativePositionFromIndex(yText, 10)
8258 * // modify yText
8259 * yText.insert(0, 'abc')
8260 * yText.delete(3, 10)
8261 * // Compute the cursor position
8262 * const absolutePosition = createAbsolutePositionFromRelativePosition(y, relativePosition)
8263 * absolutePosition.type === yText // => true
8264 * console.log('cursor location is ' + absolutePosition.index) // => cursor location is 3
8265 *
8266 */
8267 class RelativePosition {
8268 /**
8269 * @param {ID|null} type
8270 * @param {string|null} tname
8271 * @param {ID|null} item
8272 * @param {number} assoc
8273 */
8274 constructor (type, tname, item, assoc = 0) {
8275 /**
8276 * @type {ID|null}
8277 */
8278 this.type = type;
8279 /**
8280 * @type {string|null}
8281 */
8282 this.tname = tname;
8283 /**
8284 * @type {ID | null}
8285 */
8286 this.item = item;
8287 /**
8288 * A relative position is associated to a specific character. By default
8289 * assoc >= 0, the relative position is associated to the character
8290 * after the meant position.
8291 * I.e. position 1 in 'ab' is associated to character 'b'.
8292 *
8293 * If assoc < 0, then the relative position is associated to the caharacter
8294 * before the meant position.
8295 *
8296 * @type {number}
8297 */
8298 this.assoc = assoc;
8299 }
8300 }
8301
8302 /**
8303 * @param {RelativePosition} rpos
8304 * @return {any}
8305 */
8306 const relativePositionToJSON = rpos => {
8307 const json = {};
8308 if (rpos.type) {
8309 json.type = rpos.type;
8310 }
8311 if (rpos.tname) {
8312 json.tname = rpos.tname;
8313 }
8314 if (rpos.item) {
8315 json.item = rpos.item;
8316 }
8317 if (rpos.assoc != null) {
8318 json.assoc = rpos.assoc;
8319 }
8320 return json
8321 };
8322
8323 /**
8324 * @param {any} json
8325 * @return {RelativePosition}
8326 *
8327 * @function
8328 */
8329 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);
8330
8331 class AbsolutePosition {
8332 /**
8333 * @param {AbstractType<any>} type
8334 * @param {number} index
8335 * @param {number} [assoc]
8336 */
8337 constructor (type, index, assoc = 0) {
8338 /**
8339 * @type {AbstractType<any>}
8340 */
8341 this.type = type;
8342 /**
8343 * @type {number}
8344 */
8345 this.index = index;
8346 this.assoc = assoc;
8347 }
8348 }
8349
8350 /**
8351 * @param {AbstractType<any>} type
8352 * @param {number} index
8353 * @param {number} [assoc]
8354 *
8355 * @function
8356 */
8357 const createAbsolutePosition = (type, index, assoc = 0) => new AbsolutePosition(type, index, assoc);
8358
8359 /**
8360 * @param {AbstractType<any>} type
8361 * @param {ID|null} item
8362 * @param {number} [assoc]
8363 *
8364 * @function
8365 */
8366 const createRelativePosition = (type, item, assoc) => {
8367 let typeid = null;
8368 let tname = null;
8369 if (type._item === null) {
8370 tname = findRootTypeKey(type);
8371 } else {
8372 typeid = createID(type._item.id.client, type._item.id.clock);
8373 }
8374 return new RelativePosition(typeid, tname, item, assoc)
8375 };
8376
8377 /**
8378 * Create a relativePosition based on a absolute position.
8379 *
8380 * @param {AbstractType<any>} type The base type (e.g. YText or YArray).
8381 * @param {number} index The absolute position.
8382 * @param {number} [assoc]
8383 * @return {RelativePosition}
8384 *
8385 * @function
8386 */
8387 const createRelativePositionFromTypeIndex = (type, index, assoc = 0) => {
8388 let t = type._start;
8389 if (assoc < 0) {
8390 // associated to the left character or the beginning of a type, increment index if possible.
8391 if (index === 0) {
8392 return createRelativePosition(type, null, assoc)
8393 }
8394 index--;
8395 }
8396 while (t !== null) {
8397 if (!t.deleted && t.countable) {
8398 if (t.length > index) {
8399 // case 1: found position somewhere in the linked list
8400 return createRelativePosition(type, createID(t.id.client, t.id.clock + index), assoc)
8401 }
8402 index -= t.length;
8403 }
8404 if (t.right === null && assoc < 0) {
8405 // left-associated position, return last available id
8406 return createRelativePosition(type, t.lastId, assoc)
8407 }
8408 t = t.right;
8409 }
8410 return createRelativePosition(type, null, assoc)
8411 };
8412
8413 /**
8414 * @param {encoding.Encoder} encoder
8415 * @param {RelativePosition} rpos
8416 *
8417 * @function
8418 */
8419 const writeRelativePosition = (encoder, rpos) => {
8420 const { type, tname, item, assoc } = rpos;
8421 if (item !== null) {
8422 encoding.writeVarUint(encoder, 0);
8423 writeID(encoder, item);
8424 } else if (tname !== null) {
8425 // case 2: found position at the end of the list and type is stored in y.share
8426 encoding.writeUint8(encoder, 1);
8427 encoding.writeVarString(encoder, tname);
8428 } else if (type !== null) {
8429 // case 3: found position at the end of the list and type is attached to an item
8430 encoding.writeUint8(encoder, 2);
8431 writeID(encoder, type);
8432 } else {
8433 throw error.unexpectedCase()
8434 }
8435 encoding.writeVarInt(encoder, assoc);
8436 return encoder
8437 };
8438
8439 /**
8440 * @param {RelativePosition} rpos
8441 * @return {Uint8Array}
8442 */
8443 const encodeRelativePosition = rpos => {
8444 const encoder = encoding.createEncoder();
8445 writeRelativePosition(encoder, rpos);
8446 return encoding.toUint8Array(encoder)
8447 };
8448
8449 /**
8450 * @param {decoding.Decoder} decoder
8451 * @return {RelativePosition}
8452 *
8453 * @function
8454 */
8455 const readRelativePosition = decoder => {
8456 let type = null;
8457 let tname = null;
8458 let itemID = null;
8459 switch (decoding.readVarUint(decoder)) {
8460 case 0:
8461 // case 1: found position somewhere in the linked list
8462 itemID = readID(decoder);
8463 break
8464 case 1:
8465 // case 2: found position at the end of the list and type is stored in y.share
8466 tname = decoding.readVarString(decoder);
8467 break
8468 case 2: {
8469 // case 3: found position at the end of the list and type is attached to an item
8470 type = readID(decoder);
8471 }
8472 }
8473 const assoc = decoding.hasContent(decoder) ? decoding.readVarInt(decoder) : 0;
8474 return new RelativePosition(type, tname, itemID, assoc)
8475 };
8476
8477 /**
8478 * @param {Uint8Array} uint8Array
8479 * @return {RelativePosition}
8480 */
8481 const decodeRelativePosition = uint8Array => readRelativePosition(decoding.createDecoder(uint8Array));
8482
8483 /**
8484 * @param {RelativePosition} rpos
8485 * @param {Doc} doc
8486 * @return {AbsolutePosition|null}
8487 *
8488 * @function
8489 */
8490 const createAbsolutePositionFromRelativePosition = (rpos, doc) => {
8491 const store = doc.store;
8492 const rightID = rpos.item;
8493 const typeID = rpos.type;
8494 const tname = rpos.tname;
8495 const assoc = rpos.assoc;
8496 let type = null;
8497 let index = 0;
8498 if (rightID !== null) {
8499 if (getState(store, rightID.client) <= rightID.clock) {
8500 return null
8501 }
8502 const res = followRedone(store, rightID);
8503 const right = res.item;
8504 if (!(right instanceof Item)) {
8505 return null
8506 }
8507 type = /** @type {AbstractType<any>} */ (right.parent);
8508 if (type._item === null || !type._item.deleted) {
8509 index = (right.deleted || !right.countable) ? 0 : (res.diff + (assoc >= 0 ? 0 : 1)); // adjust position based on left association if necessary
8510 let n = right.left;
8511 while (n !== null) {
8512 if (!n.deleted && n.countable) {
8513 index += n.length;
8514 }
8515 n = n.left;
8516 }
8517 }
8518 } else {
8519 if (tname !== null) {
8520 type = doc.get(tname);
8521 } else if (typeID !== null) {
8522 if (getState(store, typeID.client) <= typeID.clock) {
8523 // type does not exist yet
8524 return null
8525 }
8526 const { item } = followRedone(store, typeID);
8527 if (item instanceof Item && item.content instanceof ContentType) {
8528 type = item.content.type;
8529 } else {
8530 // struct is garbage collected
8531 return null
8532 }
8533 } else {
8534 throw error.unexpectedCase()
8535 }
8536 if (assoc >= 0) {
8537 index = type._length;
8538 } else {
8539 index = 0;
8540 }
8541 }
8542 return createAbsolutePosition(type, index, rpos.assoc)
8543 };
8544
8545 /**
8546 * @param {RelativePosition|null} a
8547 * @param {RelativePosition|null} b
8548 * @return {boolean}
8549 *
8550 * @function
8551 */
8552 const compareRelativePositions = (a, b) => a === b || (
8553 a !== null && b !== null && a.tname === b.tname && compareIDs(a.item, b.item) && compareIDs(a.type, b.type) && a.assoc === b.assoc
8554 );
8555
8556 class Snapshot {
8557 /**
8558 * @param {DeleteSet} ds
8559 * @param {Map<number,number>} sv state map
8560 */
8561 constructor (ds, sv) {
8562 /**
8563 * @type {DeleteSet}
8564 */
8565 this.ds = ds;
8566 /**
8567 * State Map
8568 * @type {Map<number,number>}
8569 */
8570 this.sv = sv;
8571 }
8572 }
8573
8574 /**
8575 * @param {Snapshot} snap1
8576 * @param {Snapshot} snap2
8577 * @return {boolean}
8578 */
8579 const equalSnapshots = (snap1, snap2) => {
8580 const ds1 = snap1.ds.clients;
8581 const ds2 = snap2.ds.clients;
8582 const sv1 = snap1.sv;
8583 const sv2 = snap2.sv;
8584 if (sv1.size !== sv2.size || ds1.size !== ds2.size) {
8585 return false
8586 }
8587 for (const [key, value] of sv1.entries()) {
8588 if (sv2.get(key) !== value) {
8589 return false
8590 }
8591 }
8592 for (const [client, dsitems1] of ds1.entries()) {
8593 const dsitems2 = ds2.get(client) || [];
8594 if (dsitems1.length !== dsitems2.length) {
8595 return false
8596 }
8597 for (let i = 0; i < dsitems1.length; i++) {
8598 const dsitem1 = dsitems1[i];
8599 const dsitem2 = dsitems2[i];
8600 if (dsitem1.clock !== dsitem2.clock || dsitem1.len !== dsitem2.len) {
8601 return false
8602 }
8603 }
8604 }
8605 return true
8606 };
8607
8608 /**
8609 * @param {Snapshot} snapshot
8610 * @param {DSEncoderV1 | DSEncoderV2} [encoder]
8611 * @return {Uint8Array}
8612 */
8613 const encodeSnapshotV2 = (snapshot, encoder = new DSEncoderV2()) => {
8614 writeDeleteSet(encoder, snapshot.ds);
8615 writeStateVector(encoder, snapshot.sv);
8616 return encoder.toUint8Array()
8617 };
8618
8619 /**
8620 * @param {Snapshot} snapshot
8621 * @return {Uint8Array}
8622 */
8623 const encodeSnapshot = snapshot => encodeSnapshotV2(snapshot, new DSEncoderV1());
8624
8625 /**
8626 * @param {Uint8Array} buf
8627 * @param {DSDecoderV1 | DSDecoderV2} [decoder]
8628 * @return {Snapshot}
8629 */
8630 const decodeSnapshotV2 = (buf, decoder = new DSDecoderV2(decoding.createDecoder(buf))) => {
8631 return new Snapshot(readDeleteSet(decoder), readStateVector(decoder))
8632 };
8633
8634 /**
8635 * @param {Uint8Array} buf
8636 * @return {Snapshot}
8637 */
8638 const decodeSnapshot = buf => decodeSnapshotV2(buf, new DSDecoderV1(decoding.createDecoder(buf)));
8639
8640 /**
8641 * @param {DeleteSet} ds
8642 * @param {Map<number,number>} sm
8643 * @return {Snapshot}
8644 */
8645 const createSnapshot = (ds, sm) => new Snapshot(ds, sm);
8646
8647 const emptySnapshot = createSnapshot(createDeleteSet(), new Map());
8648
8649 /**
8650 * @param {Doc} doc
8651 * @return {Snapshot}
8652 */
8653 const snapshot = doc => createSnapshot(createDeleteSetFromStructStore(doc.store), getStateVector(doc.store));
8654
8655 /**
8656 * @param {Item} item
8657 * @param {Snapshot|undefined} snapshot
8658 *
8659 * @protected
8660 * @function
8661 */
8662 const isVisible = (item, snapshot) => snapshot === undefined
8663 ? !item.deleted
8664 : snapshot.sv.has(item.id.client) && (snapshot.sv.get(item.id.client) || 0) > item.id.clock && !isDeleted(snapshot.ds, item.id);
8665
8666 /**
8667 * @param {Transaction} transaction
8668 * @param {Snapshot} snapshot
8669 */
8670 const splitSnapshotAffectedStructs = (transaction, snapshot) => {
8671 const meta = setIfUndefined(transaction.meta, splitSnapshotAffectedStructs, set_create);
8672 const store = transaction.doc.store;
8673 // check if we already split for this snapshot
8674 if (!meta.has(snapshot)) {
8675 snapshot.sv.forEach((clock, client) => {
8676 if (clock < getState(store, client)) {
8677 getItemCleanStart(transaction, createID(client, clock));
8678 }
8679 });
8680 iterateDeletedStructs(transaction, snapshot.ds, _item => {});
8681 meta.add(snapshot);
8682 }
8683 };
8684
8685 /**
8686 * @example
8687 * const ydoc = new Y.Doc({ gc: false })
8688 * ydoc.getText().insert(0, 'world!')
8689 * const snapshot = Y.snapshot(ydoc)
8690 * ydoc.getText().insert(0, 'hello ')
8691 * const restored = Y.createDocFromSnapshot(ydoc, snapshot)
8692 * assert(restored.getText().toString() === 'world!')
8693 *
8694 * @param {Doc} originDoc
8695 * @param {Snapshot} snapshot
8696 * @param {Doc} [newDoc] Optionally, you may define the Yjs document that receives the data from originDoc
8697 * @return {Doc}
8698 */
8699 const createDocFromSnapshot = (originDoc, snapshot, newDoc = new Doc()) => {
8700 if (originDoc.gc) {
8701 // we should not try to restore a GC-ed document, because some of the restored items might have their content deleted
8702 throw new Error('Garbage-collection must be disabled in `originDoc`!')
8703 }
8704 const { sv, ds } = snapshot;
8705
8706 const encoder = new UpdateEncoderV2();
8707 originDoc.transact(transaction => {
8708 let size = 0;
8709 sv.forEach(clock => {
8710 if (clock > 0) {
8711 size++;
8712 }
8713 });
8714 encoding.writeVarUint(encoder.restEncoder, size);
8715 // splitting the structs before writing them to the encoder
8716 for (const [client, clock] of sv) {
8717 if (clock === 0) {
8718 continue
8719 }
8720 if (clock < getState(originDoc.store, client)) {
8721 getItemCleanStart(transaction, createID(client, clock));
8722 }
8723 const structs = originDoc.store.clients.get(client) || [];
8724 const lastStructIndex = findIndexSS(structs, clock - 1);
8725 // write # encoded structs
8726 encoding.writeVarUint(encoder.restEncoder, lastStructIndex + 1);
8727 encoder.writeClient(client);
8728 // first clock written is 0
8729 encoding.writeVarUint(encoder.restEncoder, 0);
8730 for (let i = 0; i <= lastStructIndex; i++) {
8731 structs[i].write(encoder, 0);
8732 }
8733 }
8734 writeDeleteSet(encoder, ds);
8735 });
8736
8737 applyUpdateV2(newDoc, encoder.toUint8Array(), 'snapshot');
8738 return newDoc
8739 };
8740
8741 /**
8742 * @param {Snapshot} snapshot
8743 * @param {Uint8Array} update
8744 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
8745 */
8746 const snapshotContainsUpdateV2 = (snapshot, update, YDecoder = UpdateDecoderV2) => {
8747 const updateDecoder = new YDecoder(decoding.createDecoder(update));
8748 const lazyDecoder = new LazyStructReader(updateDecoder, false);
8749 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
8750 if ((snapshot.sv.get(curr.id.client) || 0) < curr.id.clock + curr.length) {
8751 return false
8752 }
8753 }
8754 const mergedDS = mergeDeleteSets([snapshot.ds, readDeleteSet(updateDecoder)]);
8755 return equalDeleteSets(snapshot.ds, mergedDS)
8756 };
8757
8758 /**
8759 * @param {Snapshot} snapshot
8760 * @param {Uint8Array} update
8761 */
8762 const snapshotContainsUpdate = (snapshot, update) => snapshotContainsUpdateV2(snapshot, update, UpdateDecoderV1);
8763
8764 class StructStore {
8765 constructor () {
8766 /**
8767 * @type {Map<number,Array<GC|Item>>}
8768 */
8769 this.clients = new Map();
8770 /**
8771 * @type {null | { missing: Map<number, number>, update: Uint8Array }}
8772 */
8773 this.pendingStructs = null;
8774 /**
8775 * @type {null | Uint8Array}
8776 */
8777 this.pendingDs = null;
8778 }
8779 }
8780
8781 /**
8782 * Return the states as a Map<client,clock>.
8783 * Note that clock refers to the next expected clock id.
8784 *
8785 * @param {StructStore} store
8786 * @return {Map<number,number>}
8787 *
8788 * @public
8789 * @function
8790 */
8791 const getStateVector = store => {
8792 const sm = new Map();
8793 store.clients.forEach((structs, client) => {
8794 const struct = structs[structs.length - 1];
8795 sm.set(client, struct.id.clock + struct.length);
8796 });
8797 return sm
8798 };
8799
8800 /**
8801 * @param {StructStore} store
8802 * @param {number} client
8803 * @return {number}
8804 *
8805 * @public
8806 * @function
8807 */
8808 const getState = (store, client) => {
8809 const structs = store.clients.get(client);
8810 if (structs === undefined) {
8811 return 0
8812 }
8813 const lastStruct = structs[structs.length - 1];
8814 return lastStruct.id.clock + lastStruct.length
8815 };
8816
8817 /**
8818 * @param {StructStore} store
8819 * @param {GC|Item} struct
8820 *
8821 * @private
8822 * @function
8823 */
8824 const addStruct = (store, struct) => {
8825 let structs = store.clients.get(struct.id.client);
8826 if (structs === undefined) {
8827 structs = [];
8828 store.clients.set(struct.id.client, structs);
8829 } else {
8830 const lastStruct = structs[structs.length - 1];
8831 if (lastStruct.id.clock + lastStruct.length !== struct.id.clock) {
8832 throw unexpectedCase()
8833 }
8834 }
8835 structs.push(struct);
8836 };
8837
8838 /**
8839 * Perform a binary search on a sorted array
8840 * @param {Array<Item|GC>} structs
8841 * @param {number} clock
8842 * @return {number}
8843 *
8844 * @private
8845 * @function
8846 */
8847 const findIndexSS = (structs, clock) => {
8848 let left = 0;
8849 let right = structs.length - 1;
8850 let mid = structs[right];
8851 let midclock = mid.id.clock;
8852 if (midclock === clock) {
8853 return right
8854 }
8855 // @todo does it even make sense to pivot the search?
8856 // If a good split misses, it might actually increase the time to find the correct item.
8857 // Currently, the only advantage is that search with pivoting might find the item on the first try.
8858 let midindex = floor((clock / (midclock + mid.length - 1)) * right); // pivoting the search
8859 while (left <= right) {
8860 mid = structs[midindex];
8861 midclock = mid.id.clock;
8862 if (midclock <= clock) {
8863 if (clock < midclock + mid.length) {
8864 return midindex
8865 }
8866 left = midindex + 1;
8867 } else {
8868 right = midindex - 1;
8869 }
8870 midindex = floor((left + right) / 2);
8871 }
8872 // Always check state before looking for a struct in StructStore
8873 // Therefore the case of not finding a struct is unexpected
8874 throw unexpectedCase()
8875 };
8876
8877 /**
8878 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8879 *
8880 * @param {StructStore} store
8881 * @param {ID} id
8882 * @return {GC|Item}
8883 *
8884 * @private
8885 * @function
8886 */
8887 const find = (store, id) => {
8888 /**
8889 * @type {Array<GC|Item>}
8890 */
8891 // @ts-ignore
8892 const structs = store.clients.get(id.client);
8893 return structs[findIndexSS(structs, id.clock)]
8894 };
8895
8896 /**
8897 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8898 * @private
8899 * @function
8900 */
8901 const getItem = /** @type {function(StructStore,ID):Item} */ (find);
8902
8903 /**
8904 * @param {Transaction} transaction
8905 * @param {Array<Item|GC>} structs
8906 * @param {number} clock
8907 */
8908 const findIndexCleanStart = (transaction, structs, clock) => {
8909 const index = findIndexSS(structs, clock);
8910 const struct = structs[index];
8911 if (struct.id.clock < clock && struct instanceof Item) {
8912 structs.splice(index + 1, 0, splitItem(transaction, struct, clock - struct.id.clock));
8913 return index + 1
8914 }
8915 return index
8916 };
8917
8918 /**
8919 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8920 *
8921 * @param {Transaction} transaction
8922 * @param {ID} id
8923 * @return {Item}
8924 *
8925 * @private
8926 * @function
8927 */
8928 const getItemCleanStart = (transaction, id) => {
8929 const structs = /** @type {Array<Item>} */ (transaction.doc.store.clients.get(id.client));
8930 return structs[findIndexCleanStart(transaction, structs, id.clock)]
8931 };
8932
8933 /**
8934 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8935 *
8936 * @param {Transaction} transaction
8937 * @param {StructStore} store
8938 * @param {ID} id
8939 * @return {Item}
8940 *
8941 * @private
8942 * @function
8943 */
8944 const getItemCleanEnd = (transaction, store, id) => {
8945 /**
8946 * @type {Array<Item>}
8947 */
8948 // @ts-ignore
8949 const structs = store.clients.get(id.client);
8950 const index = findIndexSS(structs, id.clock);
8951 const struct = structs[index];
8952 if (id.clock !== struct.id.clock + struct.length - 1 && struct.constructor !== GC) {
8953 structs.splice(index + 1, 0, splitItem(transaction, struct, id.clock - struct.id.clock + 1));
8954 }
8955 return struct
8956 };
8957
8958 /**
8959 * Replace `item` with `newitem` in store
8960 * @param {StructStore} store
8961 * @param {GC|Item} struct
8962 * @param {GC|Item} newStruct
8963 *
8964 * @private
8965 * @function
8966 */
8967 const replaceStruct = (store, struct, newStruct) => {
8968 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(struct.id.client));
8969 structs[findIndexSS(structs, struct.id.clock)] = newStruct;
8970 };
8971
8972 /**
8973 * Iterate over a range of structs
8974 *
8975 * @param {Transaction} transaction
8976 * @param {Array<Item|GC>} structs
8977 * @param {number} clockStart Inclusive start
8978 * @param {number} len
8979 * @param {function(GC|Item):void} f
8980 *
8981 * @function
8982 */
8983 const iterateStructs = (transaction, structs, clockStart, len, f) => {
8984 if (len === 0) {
8985 return
8986 }
8987 const clockEnd = clockStart + len;
8988 let index = findIndexCleanStart(transaction, structs, clockStart);
8989 let struct;
8990 do {
8991 struct = structs[index++];
8992 if (clockEnd < struct.id.clock + struct.length) {
8993 findIndexCleanStart(transaction, structs, clockEnd);
8994 }
8995 f(struct);
8996 } while (index < structs.length && structs[index].id.clock < clockEnd)
8997 };
8998
8999 /**
9000 * A transaction is created for every change on the Yjs model. It is possible
9001 * to bundle changes on the Yjs model in a single transaction to
9002 * minimize the number on messages sent and the number of observer calls.
9003 * If possible the user of this library should bundle as many changes as
9004 * possible. Here is an example to illustrate the advantages of bundling:
9005 *
9006 * @example
9007 * const map = y.define('map', YMap)
9008 * // Log content when change is triggered
9009 * map.observe(() => {
9010 * console.log('change triggered')
9011 * })
9012 * // Each change on the map type triggers a log message:
9013 * map.set('a', 0) // => "change triggered"
9014 * map.set('b', 0) // => "change triggered"
9015 * // When put in a transaction, it will trigger the log after the transaction:
9016 * y.transact(() => {
9017 * map.set('a', 1)
9018 * map.set('b', 1)
9019 * }) // => "change triggered"
9020 *
9021 * @public
9022 */
9023 class Transaction {
9024 /**
9025 * @param {Doc} doc
9026 * @param {any} origin
9027 * @param {boolean} local
9028 */
9029 constructor (doc, origin, local) {
9030 /**
9031 * The Yjs instance.
9032 * @type {Doc}
9033 */
9034 this.doc = doc;
9035 /**
9036 * Describes the set of deleted items by ids
9037 * @type {DeleteSet}
9038 */
9039 this.deleteSet = new DeleteSet();
9040 /**
9041 * Holds the state before the transaction started.
9042 * @type {Map<Number,Number>}
9043 */
9044 this.beforeState = getStateVector(doc.store);
9045 /**
9046 * Holds the state after the transaction.
9047 * @type {Map<Number,Number>}
9048 */
9049 this.afterState = new Map();
9050 /**
9051 * All types that were directly modified (property added or child
9052 * inserted/deleted). New types are not included in this Set.
9053 * Maps from type to parentSubs (`item.parentSub = null` for YArray)
9054 * @type {Map<AbstractType<YEvent<any>>,Set<String|null>>}
9055 */
9056 this.changed = new Map();
9057 /**
9058 * Stores the events for the types that observe also child elements.
9059 * It is mainly used by `observeDeep`.
9060 * @type {Map<AbstractType<YEvent<any>>,Array<YEvent<any>>>}
9061 */
9062 this.changedParentTypes = new Map();
9063 /**
9064 * @type {Array<AbstractStruct>}
9065 */
9066 this._mergeStructs = [];
9067 /**
9068 * @type {any}
9069 */
9070 this.origin = origin;
9071 /**
9072 * Stores meta information on the transaction
9073 * @type {Map<any,any>}
9074 */
9075 this.meta = new Map();
9076 /**
9077 * Whether this change originates from this doc.
9078 * @type {boolean}
9079 */
9080 this.local = local;
9081 /**
9082 * @type {Set<Doc>}
9083 */
9084 this.subdocsAdded = new Set();
9085 /**
9086 * @type {Set<Doc>}
9087 */
9088 this.subdocsRemoved = new Set();
9089 /**
9090 * @type {Set<Doc>}
9091 */
9092 this.subdocsLoaded = new Set();
9093 /**
9094 * @type {boolean}
9095 */
9096 this._needFormattingCleanup = false;
9097 }
9098 }
9099
9100 /**
9101 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
9102 * @param {Transaction} transaction
9103 * @return {boolean} Whether data was written.
9104 */
9105 const writeUpdateMessageFromTransaction = (encoder, transaction) => {
9106 if (transaction.deleteSet.clients.size === 0 && !any(transaction.afterState, (clock, client) => transaction.beforeState.get(client) !== clock)) {
9107 return false
9108 }
9109 sortAndMergeDeleteSet(transaction.deleteSet);
9110 writeStructsFromTransaction(encoder, transaction);
9111 writeDeleteSet(encoder, transaction.deleteSet);
9112 return true
9113 };
9114
9115 /**
9116 * If `type.parent` was added in current transaction, `type` technically
9117 * did not change, it was just added and we should not fire events for `type`.
9118 *
9119 * @param {Transaction} transaction
9120 * @param {AbstractType<YEvent<any>>} type
9121 * @param {string|null} parentSub
9122 */
9123 const addChangedTypeToTransaction = (transaction, type, parentSub) => {
9124 const item = type._item;
9125 if (item === null || (item.id.clock < (transaction.beforeState.get(item.id.client) || 0) && !item.deleted)) {
9126 setIfUndefined(transaction.changed, type, set_create).add(parentSub);
9127 }
9128 };
9129
9130 /**
9131 * @param {Array<AbstractStruct>} structs
9132 * @param {number} pos
9133 * @return {number} # of merged structs
9134 */
9135 const tryToMergeWithLefts = (structs, pos) => {
9136 let right = structs[pos];
9137 let left = structs[pos - 1];
9138 let i = pos;
9139 for (; i > 0; right = left, left = structs[--i - 1]) {
9140 if (left.deleted === right.deleted && left.constructor === right.constructor) {
9141 if (left.mergeWith(right)) {
9142 if (right instanceof Item && right.parentSub !== null && /** @type {AbstractType<any>} */ (right.parent)._map.get(right.parentSub) === right) {
9143 /** @type {AbstractType<any>} */ (right.parent)._map.set(right.parentSub, /** @type {Item} */ (left));
9144 }
9145 continue
9146 }
9147 }
9148 break
9149 }
9150 const merged = pos - i;
9151 if (merged) {
9152 // remove all merged structs from the array
9153 structs.splice(pos + 1 - merged, merged);
9154 }
9155 return merged
9156 };
9157
9158 /**
9159 * @param {DeleteSet} ds
9160 * @param {StructStore} store
9161 * @param {function(Item):boolean} gcFilter
9162 */
9163 const tryGcDeleteSet = (ds, store, gcFilter) => {
9164 for (const [client, deleteItems] of ds.clients.entries()) {
9165 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9166 for (let di = deleteItems.length - 1; di >= 0; di--) {
9167 const deleteItem = deleteItems[di];
9168 const endDeleteItemClock = deleteItem.clock + deleteItem.len;
9169 for (
9170 let si = findIndexSS(structs, deleteItem.clock), struct = structs[si];
9171 si < structs.length && struct.id.clock < endDeleteItemClock;
9172 struct = structs[++si]
9173 ) {
9174 const struct = structs[si];
9175 if (deleteItem.clock + deleteItem.len <= struct.id.clock) {
9176 break
9177 }
9178 if (struct instanceof Item && struct.deleted && !struct.keep && gcFilter(struct)) {
9179 struct.gc(store, false);
9180 }
9181 }
9182 }
9183 }
9184 };
9185
9186 /**
9187 * @param {DeleteSet} ds
9188 * @param {StructStore} store
9189 */
9190 const tryMergeDeleteSet = (ds, store) => {
9191 // try to merge deleted / gc'd items
9192 // merge from right to left for better efficiecy and so we don't miss any merge targets
9193 ds.clients.forEach((deleteItems, client) => {
9194 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9195 for (let di = deleteItems.length - 1; di >= 0; di--) {
9196 const deleteItem = deleteItems[di];
9197 // start with merging the item next to the last deleted item
9198 const mostRightIndexToCheck = min(structs.length - 1, 1 + findIndexSS(structs, deleteItem.clock + deleteItem.len - 1));
9199 for (
9200 let si = mostRightIndexToCheck, struct = structs[si];
9201 si > 0 && struct.id.clock >= deleteItem.clock;
9202 struct = structs[si]
9203 ) {
9204 si -= 1 + tryToMergeWithLefts(structs, si);
9205 }
9206 }
9207 });
9208 };
9209
9210 /**
9211 * @param {DeleteSet} ds
9212 * @param {StructStore} store
9213 * @param {function(Item):boolean} gcFilter
9214 */
9215 const tryGc = (ds, store, gcFilter) => {
9216 tryGcDeleteSet(ds, store, gcFilter);
9217 tryMergeDeleteSet(ds, store);
9218 };
9219
9220 /**
9221 * @param {Array<Transaction>} transactionCleanups
9222 * @param {number} i
9223 */
9224 const cleanupTransactions = (transactionCleanups, i) => {
9225 if (i < transactionCleanups.length) {
9226 const transaction = transactionCleanups[i];
9227 const doc = transaction.doc;
9228 const store = doc.store;
9229 const ds = transaction.deleteSet;
9230 const mergeStructs = transaction._mergeStructs;
9231 try {
9232 sortAndMergeDeleteSet(ds);
9233 transaction.afterState = getStateVector(transaction.doc.store);
9234 doc.emit('beforeObserverCalls', [transaction, doc]);
9235 /**
9236 * An array of event callbacks.
9237 *
9238 * Each callback is called even if the other ones throw errors.
9239 *
9240 * @type {Array<function():void>}
9241 */
9242 const fs = [];
9243 // observe events on changed types
9244 transaction.changed.forEach((subs, itemtype) =>
9245 fs.push(() => {
9246 if (itemtype._item === null || !itemtype._item.deleted) {
9247 itemtype._callObserver(transaction, subs);
9248 }
9249 })
9250 );
9251 fs.push(() => {
9252 // deep observe events
9253 transaction.changedParentTypes.forEach((events, type) => {
9254 // We need to think about the possibility that the user transforms the
9255 // Y.Doc in the event.
9256 if (type._dEH.l.length > 0 && (type._item === null || !type._item.deleted)) {
9257 events = events
9258 .filter(event =>
9259 event.target._item === null || !event.target._item.deleted
9260 );
9261 events
9262 .forEach(event => {
9263 event.currentTarget = type;
9264 // path is relative to the current target
9265 event._path = null;
9266 });
9267 // sort events by path length so that top-level events are fired first.
9268 events
9269 .sort((event1, event2) => event1.path.length - event2.path.length);
9270 // We don't need to check for events.length
9271 // because we know it has at least one element
9272 callEventHandlerListeners(type._dEH, events, transaction);
9273 }
9274 });
9275 });
9276 fs.push(() => doc.emit('afterTransaction', [transaction, doc]));
9277 callAll(fs, []);
9278 if (transaction._needFormattingCleanup) {
9279 cleanupYTextAfterTransaction(transaction);
9280 }
9281 } finally {
9282 // Replace deleted items with ItemDeleted / GC.
9283 // This is where content is actually remove from the Yjs Doc.
9284 if (doc.gc) {
9285 tryGcDeleteSet(ds, store, doc.gcFilter);
9286 }
9287 tryMergeDeleteSet(ds, store);
9288
9289 // on all affected store.clients props, try to merge
9290 transaction.afterState.forEach((clock, client) => {
9291 const beforeClock = transaction.beforeState.get(client) || 0;
9292 if (beforeClock !== clock) {
9293 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9294 // we iterate from right to left so we can safely remove entries
9295 const firstChangePos = max(findIndexSS(structs, beforeClock), 1);
9296 for (let i = structs.length - 1; i >= firstChangePos;) {
9297 i -= 1 + tryToMergeWithLefts(structs, i);
9298 }
9299 }
9300 });
9301 // try to merge mergeStructs
9302 // @todo: it makes more sense to transform mergeStructs to a DS, sort it, and merge from right to left
9303 // but at the moment DS does not handle duplicates
9304 for (let i = mergeStructs.length - 1; i >= 0; i--) {
9305 const { client, clock } = mergeStructs[i].id;
9306 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9307 const replacedStructPos = findIndexSS(structs, clock);
9308 if (replacedStructPos + 1 < structs.length) {
9309 if (tryToMergeWithLefts(structs, replacedStructPos + 1) > 1) {
9310 continue // no need to perform next check, both are already merged
9311 }
9312 }
9313 if (replacedStructPos > 0) {
9314 tryToMergeWithLefts(structs, replacedStructPos);
9315 }
9316 }
9317 if (!transaction.local && transaction.afterState.get(doc.clientID) !== transaction.beforeState.get(doc.clientID)) {
9318 print(ORANGE, BOLD, '[yjs] ', UNBOLD, RED, 'Changed the client-id because another client seems to be using it.');
9319 doc.clientID = generateNewClientId();
9320 }
9321 // @todo Merge all the transactions into one and provide send the data as a single update message
9322 doc.emit('afterTransactionCleanup', [transaction, doc]);
9323 if (doc._observers.has('update')) {
9324 const encoder = new UpdateEncoderV1();
9325 const hasContent = writeUpdateMessageFromTransaction(encoder, transaction);
9326 if (hasContent) {
9327 doc.emit('update', [encoder.toUint8Array(), transaction.origin, doc, transaction]);
9328 }
9329 }
9330 if (doc._observers.has('updateV2')) {
9331 const encoder = new UpdateEncoderV2();
9332 const hasContent = writeUpdateMessageFromTransaction(encoder, transaction);
9333 if (hasContent) {
9334 doc.emit('updateV2', [encoder.toUint8Array(), transaction.origin, doc, transaction]);
9335 }
9336 }
9337 const { subdocsAdded, subdocsLoaded, subdocsRemoved } = transaction;
9338 if (subdocsAdded.size > 0 || subdocsRemoved.size > 0 || subdocsLoaded.size > 0) {
9339 subdocsAdded.forEach(subdoc => {
9340 subdoc.clientID = doc.clientID;
9341 if (subdoc.collectionid == null) {
9342 subdoc.collectionid = doc.collectionid;
9343 }
9344 doc.subdocs.add(subdoc);
9345 });
9346 subdocsRemoved.forEach(subdoc => doc.subdocs.delete(subdoc));
9347 doc.emit('subdocs', [{ loaded: subdocsLoaded, added: subdocsAdded, removed: subdocsRemoved }, doc, transaction]);
9348 subdocsRemoved.forEach(subdoc => subdoc.destroy());
9349 }
9350
9351 if (transactionCleanups.length <= i + 1) {
9352 doc._transactionCleanups = [];
9353 doc.emit('afterAllTransactions', [doc, transactionCleanups]);
9354 } else {
9355 cleanupTransactions(transactionCleanups, i + 1);
9356 }
9357 }
9358 }
9359 };
9360
9361 /**
9362 * Implements the functionality of `y.transact(()=>{..})`
9363 *
9364 * @template T
9365 * @param {Doc} doc
9366 * @param {function(Transaction):T} f
9367 * @param {any} [origin=true]
9368 * @return {T}
9369 *
9370 * @function
9371 */
9372 const transact = (doc, f, origin = null, local = true) => {
9373 const transactionCleanups = doc._transactionCleanups;
9374 let initialCall = false;
9375 /**
9376 * @type {any}
9377 */
9378 let result = null;
9379 if (doc._transaction === null) {
9380 initialCall = true;
9381 doc._transaction = new Transaction(doc, origin, local);
9382 transactionCleanups.push(doc._transaction);
9383 if (transactionCleanups.length === 1) {
9384 doc.emit('beforeAllTransactions', [doc]);
9385 }
9386 doc.emit('beforeTransaction', [doc._transaction, doc]);
9387 }
9388 try {
9389 result = f(doc._transaction);
9390 } finally {
9391 if (initialCall) {
9392 const finishCleanup = doc._transaction === transactionCleanups[0];
9393 doc._transaction = null;
9394 if (finishCleanup) {
9395 // The first transaction ended, now process observer calls.
9396 // Observer call may create new transactions for which we need to call the observers and do cleanup.
9397 // We don't want to nest these calls, so we execute these calls one after
9398 // another.
9399 // Also we need to ensure that all cleanups are called, even if the
9400 // observes throw errors.
9401 // This file is full of hacky try {} finally {} blocks to ensure that an
9402 // event can throw errors and also that the cleanup is called.
9403 cleanupTransactions(transactionCleanups, 0);
9404 }
9405 }
9406 }
9407 return result
9408 };
9409
9410 class StackItem {
9411 /**
9412 * @param {DeleteSet} deletions
9413 * @param {DeleteSet} insertions
9414 */
9415 constructor (deletions, insertions) {
9416 this.insertions = insertions;
9417 this.deletions = deletions;
9418 /**
9419 * Use this to save and restore metadata like selection range
9420 */
9421 this.meta = new Map();
9422 }
9423 }
9424 /**
9425 * @param {Transaction} tr
9426 * @param {UndoManager} um
9427 * @param {StackItem} stackItem
9428 */
9429 const clearUndoManagerStackItem = (tr, um, stackItem) => {
9430 iterateDeletedStructs(tr, stackItem.deletions, item => {
9431 if (item instanceof Item && um.scope.some(type => yjs_isParentOf(type, item))) {
9432 keepItem(item, false);
9433 }
9434 });
9435 };
9436
9437 /**
9438 * @param {UndoManager} undoManager
9439 * @param {Array<StackItem>} stack
9440 * @param {string} eventType
9441 * @return {StackItem?}
9442 */
9443 const popStackItem = (undoManager, stack, eventType) => {
9444 /**
9445 * Whether a change happened
9446 * @type {StackItem?}
9447 */
9448 let result = null;
9449 /**
9450 * Keep a reference to the transaction so we can fire the event with the changedParentTypes
9451 * @type {any}
9452 */
9453 let _tr = null;
9454 const doc = undoManager.doc;
9455 const scope = undoManager.scope;
9456 transact(doc, transaction => {
9457 while (stack.length > 0 && result === null) {
9458 const store = doc.store;
9459 const stackItem = /** @type {StackItem} */ (stack.pop());
9460 /**
9461 * @type {Set<Item>}
9462 */
9463 const itemsToRedo = new Set();
9464 /**
9465 * @type {Array<Item>}
9466 */
9467 const itemsToDelete = [];
9468 let performedChange = false;
9469 iterateDeletedStructs(transaction, stackItem.insertions, struct => {
9470 if (struct instanceof Item) {
9471 if (struct.redone !== null) {
9472 let { item, diff } = followRedone(store, struct.id);
9473 if (diff > 0) {
9474 item = getItemCleanStart(transaction, createID(item.id.client, item.id.clock + diff));
9475 }
9476 struct = item;
9477 }
9478 if (!struct.deleted && scope.some(type => yjs_isParentOf(type, /** @type {Item} */ (struct)))) {
9479 itemsToDelete.push(struct);
9480 }
9481 }
9482 });
9483 iterateDeletedStructs(transaction, stackItem.deletions, struct => {
9484 if (
9485 struct instanceof Item &&
9486 scope.some(type => yjs_isParentOf(type, struct)) &&
9487 // Never redo structs in stackItem.insertions because they were created and deleted in the same capture interval.
9488 !isDeleted(stackItem.insertions, struct.id)
9489 ) {
9490 itemsToRedo.add(struct);
9491 }
9492 });
9493 itemsToRedo.forEach(struct => {
9494 performedChange = redoItem(transaction, struct, itemsToRedo, stackItem.insertions, undoManager.ignoreRemoteMapChanges, undoManager) !== null || performedChange;
9495 });
9496 // We want to delete in reverse order so that children are deleted before
9497 // parents, so we have more information available when items are filtered.
9498 for (let i = itemsToDelete.length - 1; i >= 0; i--) {
9499 const item = itemsToDelete[i];
9500 if (undoManager.deleteFilter(item)) {
9501 item.delete(transaction);
9502 performedChange = true;
9503 }
9504 }
9505 result = performedChange ? stackItem : null;
9506 }
9507 transaction.changed.forEach((subProps, type) => {
9508 // destroy search marker if necessary
9509 if (subProps.has(null) && type._searchMarker) {
9510 type._searchMarker.length = 0;
9511 }
9512 });
9513 _tr = transaction;
9514 }, undoManager);
9515 if (result != null) {
9516 const changedParentTypes = _tr.changedParentTypes;
9517 undoManager.emit('stack-item-popped', [{ stackItem: result, type: eventType, changedParentTypes }, undoManager]);
9518 }
9519 return result
9520 };
9521
9522 /**
9523 * @typedef {Object} UndoManagerOptions
9524 * @property {number} [UndoManagerOptions.captureTimeout=500]
9525 * @property {function(Transaction):boolean} [UndoManagerOptions.captureTransaction] Do not capture changes of a Transaction if result false.
9526 * @property {function(Item):boolean} [UndoManagerOptions.deleteFilter=()=>true] Sometimes
9527 * it is necessary to filter what an Undo/Redo operation can delete. If this
9528 * filter returns false, the type/item won't be deleted even it is in the
9529 * undo/redo scope.
9530 * @property {Set<any>} [UndoManagerOptions.trackedOrigins=new Set([null])]
9531 * @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..).
9532 * @property {Doc} [doc] The document that this UndoManager operates on. Only needed if typeScope is empty.
9533 */
9534
9535 /**
9536 * Fires 'stack-item-added' event when a stack item was added to either the undo- or
9537 * the redo-stack. You may store additional stack information via the
9538 * metadata property on `event.stackItem.meta` (it is a `Map` of metadata properties).
9539 * Fires 'stack-item-popped' event when a stack item was popped from either the
9540 * undo- or the redo-stack. You may restore the saved stack information from `event.stackItem.meta`.
9541 *
9542 * @extends {Observable<'stack-item-added'|'stack-item-popped'|'stack-cleared'|'stack-item-updated'>}
9543 */
9544 class UndoManager extends (/* unused pure expression or super */ null && (Observable)) {
9545 /**
9546 * @param {AbstractType<any>|Array<AbstractType<any>>} typeScope Accepts either a single type, or an array of types
9547 * @param {UndoManagerOptions} options
9548 */
9549 constructor (typeScope, {
9550 captureTimeout = 500,
9551 captureTransaction = _tr => true,
9552 deleteFilter = () => true,
9553 trackedOrigins = new Set([null]),
9554 ignoreRemoteMapChanges = false,
9555 doc = /** @type {Doc} */ (array.isArray(typeScope) ? typeScope[0].doc : typeScope.doc)
9556 } = {}) {
9557 super();
9558 /**
9559 * @type {Array<AbstractType<any>>}
9560 */
9561 this.scope = [];
9562 this.addToScope(typeScope);
9563 this.deleteFilter = deleteFilter;
9564 trackedOrigins.add(this);
9565 this.trackedOrigins = trackedOrigins;
9566 this.captureTransaction = captureTransaction;
9567 /**
9568 * @type {Array<StackItem>}
9569 */
9570 this.undoStack = [];
9571 /**
9572 * @type {Array<StackItem>}
9573 */
9574 this.redoStack = [];
9575 /**
9576 * Whether the client is currently undoing (calling UndoManager.undo)
9577 *
9578 * @type {boolean}
9579 */
9580 this.undoing = false;
9581 this.redoing = false;
9582 this.doc = doc;
9583 this.lastChange = 0;
9584 this.ignoreRemoteMapChanges = ignoreRemoteMapChanges;
9585 this.captureTimeout = captureTimeout;
9586 /**
9587 * @param {Transaction} transaction
9588 */
9589 this.afterTransactionHandler = transaction => {
9590 // Only track certain transactions
9591 if (
9592 !this.captureTransaction(transaction) ||
9593 !this.scope.some(type => transaction.changedParentTypes.has(type)) ||
9594 (!this.trackedOrigins.has(transaction.origin) && (!transaction.origin || !this.trackedOrigins.has(transaction.origin.constructor)))
9595 ) {
9596 return
9597 }
9598 const undoing = this.undoing;
9599 const redoing = this.redoing;
9600 const stack = undoing ? this.redoStack : this.undoStack;
9601 if (undoing) {
9602 this.stopCapturing(); // next undo should not be appended to last stack item
9603 } else if (!redoing) {
9604 // neither undoing nor redoing: delete redoStack
9605 this.clear(false, true);
9606 }
9607 const insertions = new DeleteSet();
9608 transaction.afterState.forEach((endClock, client) => {
9609 const startClock = transaction.beforeState.get(client) || 0;
9610 const len = endClock - startClock;
9611 if (len > 0) {
9612 addToDeleteSet(insertions, client, startClock, len);
9613 }
9614 });
9615 const now = time.getUnixTime();
9616 let didAdd = false;
9617 if (this.lastChange > 0 && now - this.lastChange < this.captureTimeout && stack.length > 0 && !undoing && !redoing) {
9618 // append change to last stack op
9619 const lastOp = stack[stack.length - 1];
9620 lastOp.deletions = mergeDeleteSets([lastOp.deletions, transaction.deleteSet]);
9621 lastOp.insertions = mergeDeleteSets([lastOp.insertions, insertions]);
9622 } else {
9623 // create a new stack op
9624 stack.push(new StackItem(transaction.deleteSet, insertions));
9625 didAdd = true;
9626 }
9627 if (!undoing && !redoing) {
9628 this.lastChange = now;
9629 }
9630 // make sure that deleted structs are not gc'd
9631 iterateDeletedStructs(transaction, transaction.deleteSet, /** @param {Item|GC} item */ item => {
9632 if (item instanceof Item && this.scope.some(type => yjs_isParentOf(type, item))) {
9633 keepItem(item, true);
9634 }
9635 });
9636 const changeEvent = [{ stackItem: stack[stack.length - 1], origin: transaction.origin, type: undoing ? 'redo' : 'undo', changedParentTypes: transaction.changedParentTypes }, this];
9637 if (didAdd) {
9638 this.emit('stack-item-added', changeEvent);
9639 } else {
9640 this.emit('stack-item-updated', changeEvent);
9641 }
9642 };
9643 this.doc.on('afterTransaction', this.afterTransactionHandler);
9644 this.doc.on('destroy', () => {
9645 this.destroy();
9646 });
9647 }
9648
9649 /**
9650 * @param {Array<AbstractType<any>> | AbstractType<any>} ytypes
9651 */
9652 addToScope (ytypes) {
9653 ytypes = array.isArray(ytypes) ? ytypes : [ytypes];
9654 ytypes.forEach(ytype => {
9655 if (this.scope.every(yt => yt !== ytype)) {
9656 this.scope.push(ytype);
9657 }
9658 });
9659 }
9660
9661 /**
9662 * @param {any} origin
9663 */
9664 addTrackedOrigin (origin) {
9665 this.trackedOrigins.add(origin);
9666 }
9667
9668 /**
9669 * @param {any} origin
9670 */
9671 removeTrackedOrigin (origin) {
9672 this.trackedOrigins.delete(origin);
9673 }
9674
9675 clear (clearUndoStack = true, clearRedoStack = true) {
9676 if ((clearUndoStack && this.canUndo()) || (clearRedoStack && this.canRedo())) {
9677 this.doc.transact(tr => {
9678 if (clearUndoStack) {
9679 this.undoStack.forEach(item => clearUndoManagerStackItem(tr, this, item));
9680 this.undoStack = [];
9681 }
9682 if (clearRedoStack) {
9683 this.redoStack.forEach(item => clearUndoManagerStackItem(tr, this, item));
9684 this.redoStack = [];
9685 }
9686 this.emit('stack-cleared', [{ undoStackCleared: clearUndoStack, redoStackCleared: clearRedoStack }]);
9687 });
9688 }
9689 }
9690
9691 /**
9692 * UndoManager merges Undo-StackItem if they are created within time-gap
9693 * smaller than `options.captureTimeout`. Call `um.stopCapturing()` so that the next
9694 * StackItem won't be merged.
9695 *
9696 *
9697 * @example
9698 * // without stopCapturing
9699 * ytext.insert(0, 'a')
9700 * ytext.insert(1, 'b')
9701 * um.undo()
9702 * ytext.toString() // => '' (note that 'ab' was removed)
9703 * // with stopCapturing
9704 * ytext.insert(0, 'a')
9705 * um.stopCapturing()
9706 * ytext.insert(0, 'b')
9707 * um.undo()
9708 * ytext.toString() // => 'a' (note that only 'b' was removed)
9709 *
9710 */
9711 stopCapturing () {
9712 this.lastChange = 0;
9713 }
9714
9715 /**
9716 * Undo last changes on type.
9717 *
9718 * @return {StackItem?} Returns StackItem if a change was applied
9719 */
9720 undo () {
9721 this.undoing = true;
9722 let res;
9723 try {
9724 res = popStackItem(this, this.undoStack, 'undo');
9725 } finally {
9726 this.undoing = false;
9727 }
9728 return res
9729 }
9730
9731 /**
9732 * Redo last undo operation.
9733 *
9734 * @return {StackItem?} Returns StackItem if a change was applied
9735 */
9736 redo () {
9737 this.redoing = true;
9738 let res;
9739 try {
9740 res = popStackItem(this, this.redoStack, 'redo');
9741 } finally {
9742 this.redoing = false;
9743 }
9744 return res
9745 }
9746
9747 /**
9748 * Are undo steps available?
9749 *
9750 * @return {boolean} `true` if undo is possible
9751 */
9752 canUndo () {
9753 return this.undoStack.length > 0
9754 }
9755
9756 /**
9757 * Are redo steps available?
9758 *
9759 * @return {boolean} `true` if redo is possible
9760 */
9761 canRedo () {
9762 return this.redoStack.length > 0
9763 }
9764
9765 destroy () {
9766 this.trackedOrigins.delete(this);
9767 this.doc.off('afterTransaction', this.afterTransactionHandler);
9768 super.destroy();
9769 }
9770 }
9771
9772 /**
9773 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
9774 */
9775 function * lazyStructReaderGenerator (decoder) {
9776 const numOfStateUpdates = readVarUint(decoder.restDecoder);
9777 for (let i = 0; i < numOfStateUpdates; i++) {
9778 const numberOfStructs = readVarUint(decoder.restDecoder);
9779 const client = decoder.readClient();
9780 let clock = readVarUint(decoder.restDecoder);
9781 for (let i = 0; i < numberOfStructs; i++) {
9782 const info = decoder.readInfo();
9783 // @todo use switch instead of ifs
9784 if (info === 10) {
9785 const len = readVarUint(decoder.restDecoder);
9786 yield new Skip(createID(client, clock), len);
9787 clock += len;
9788 } else if ((BITS5 & info) !== 0) {
9789 const cantCopyParentInfo = (info & (BIT7 | BIT8)) === 0;
9790 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
9791 // and we read the next string as parentYKey.
9792 // It indicates how we store/retrieve parent from `y.share`
9793 // @type {string|null}
9794 const struct = new Item(
9795 createID(client, clock),
9796 null, // left
9797 (info & BIT8) === BIT8 ? decoder.readLeftID() : null, // origin
9798 null, // right
9799 (info & BIT7) === BIT7 ? decoder.readRightID() : null, // right origin
9800 // @ts-ignore Force writing a string here.
9801 cantCopyParentInfo ? (decoder.readParentInfo() ? decoder.readString() : decoder.readLeftID()) : null, // parent
9802 cantCopyParentInfo && (info & BIT6) === BIT6 ? decoder.readString() : null, // parentSub
9803 readItemContent(decoder, info) // item content
9804 );
9805 yield struct;
9806 clock += struct.length;
9807 } else {
9808 const len = decoder.readLen();
9809 yield new GC(createID(client, clock), len);
9810 clock += len;
9811 }
9812 }
9813 }
9814 }
9815
9816 class LazyStructReader {
9817 /**
9818 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
9819 * @param {boolean} filterSkips
9820 */
9821 constructor (decoder, filterSkips) {
9822 this.gen = lazyStructReaderGenerator(decoder);
9823 /**
9824 * @type {null | Item | Skip | GC}
9825 */
9826 this.curr = null;
9827 this.done = false;
9828 this.filterSkips = filterSkips;
9829 this.next();
9830 }
9831
9832 /**
9833 * @return {Item | GC | Skip |null}
9834 */
9835 next () {
9836 // ignore "Skip" structs
9837 do {
9838 this.curr = this.gen.next().value || null;
9839 } while (this.filterSkips && this.curr !== null && this.curr.constructor === Skip)
9840 return this.curr
9841 }
9842 }
9843
9844 /**
9845 * @param {Uint8Array} update
9846 *
9847 */
9848 const logUpdate = update => logUpdateV2(update, UpdateDecoderV1);
9849
9850 /**
9851 * @param {Uint8Array} update
9852 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
9853 *
9854 */
9855 const logUpdateV2 = (update, YDecoder = UpdateDecoderV2) => {
9856 const structs = [];
9857 const updateDecoder = new YDecoder(decoding.createDecoder(update));
9858 const lazyDecoder = new LazyStructReader(updateDecoder, false);
9859 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
9860 structs.push(curr);
9861 }
9862 logging.print('Structs: ', structs);
9863 const ds = readDeleteSet(updateDecoder);
9864 logging.print('DeleteSet: ', ds);
9865 };
9866
9867 /**
9868 * @param {Uint8Array} update
9869 *
9870 */
9871 const decodeUpdate = (update) => decodeUpdateV2(update, UpdateDecoderV1);
9872
9873 /**
9874 * @param {Uint8Array} update
9875 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
9876 *
9877 */
9878 const decodeUpdateV2 = (update, YDecoder = UpdateDecoderV2) => {
9879 const structs = [];
9880 const updateDecoder = new YDecoder(decoding.createDecoder(update));
9881 const lazyDecoder = new LazyStructReader(updateDecoder, false);
9882 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
9883 structs.push(curr);
9884 }
9885 return {
9886 structs,
9887 ds: readDeleteSet(updateDecoder)
9888 }
9889 };
9890
9891 class LazyStructWriter {
9892 /**
9893 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
9894 */
9895 constructor (encoder) {
9896 this.currClient = 0;
9897 this.startClock = 0;
9898 this.written = 0;
9899 this.encoder = encoder;
9900 /**
9901 * We want to write operations lazily, but also we need to know beforehand how many operations we want to write for each client.
9902 *
9903 * This kind of meta-information (#clients, #structs-per-client-written) is written to the restEncoder.
9904 *
9905 * We fragment the restEncoder and store a slice of it per-client until we know how many clients there are.
9906 * When we flush (toUint8Array) we write the restEncoder using the fragments and the meta-information.
9907 *
9908 * @type {Array<{ written: number, restEncoder: Uint8Array }>}
9909 */
9910 this.clientStructs = [];
9911 }
9912 }
9913
9914 /**
9915 * @param {Array<Uint8Array>} updates
9916 * @return {Uint8Array}
9917 */
9918 const mergeUpdates = updates => mergeUpdatesV2(updates, UpdateDecoderV1, UpdateEncoderV1);
9919
9920 /**
9921 * @param {Uint8Array} update
9922 * @param {typeof DSEncoderV1 | typeof DSEncoderV2} YEncoder
9923 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} YDecoder
9924 * @return {Uint8Array}
9925 */
9926 const encodeStateVectorFromUpdateV2 = (update, YEncoder = DSEncoderV2, YDecoder = UpdateDecoderV2) => {
9927 const encoder = new YEncoder();
9928 const updateDecoder = new LazyStructReader(new YDecoder(decoding.createDecoder(update)), false);
9929 let curr = updateDecoder.curr;
9930 if (curr !== null) {
9931 let size = 0;
9932 let currClient = curr.id.client;
9933 let stopCounting = curr.id.clock !== 0; // must start at 0
9934 let currClock = stopCounting ? 0 : curr.id.clock + curr.length;
9935 for (; curr !== null; curr = updateDecoder.next()) {
9936 if (currClient !== curr.id.client) {
9937 if (currClock !== 0) {
9938 size++;
9939 // We found a new client
9940 // write what we have to the encoder
9941 encoding.writeVarUint(encoder.restEncoder, currClient);
9942 encoding.writeVarUint(encoder.restEncoder, currClock);
9943 }
9944 currClient = curr.id.client;
9945 currClock = 0;
9946 stopCounting = curr.id.clock !== 0;
9947 }
9948 // we ignore skips
9949 if (curr.constructor === Skip) {
9950 stopCounting = true;
9951 }
9952 if (!stopCounting) {
9953 currClock = curr.id.clock + curr.length;
9954 }
9955 }
9956 // write what we have
9957 if (currClock !== 0) {
9958 size++;
9959 encoding.writeVarUint(encoder.restEncoder, currClient);
9960 encoding.writeVarUint(encoder.restEncoder, currClock);
9961 }
9962 // prepend the size of the state vector
9963 const enc = encoding.createEncoder();
9964 encoding.writeVarUint(enc, size);
9965 encoding.writeBinaryEncoder(enc, encoder.restEncoder);
9966 encoder.restEncoder = enc;
9967 return encoder.toUint8Array()
9968 } else {
9969 encoding.writeVarUint(encoder.restEncoder, 0);
9970 return encoder.toUint8Array()
9971 }
9972 };
9973
9974 /**
9975 * @param {Uint8Array} update
9976 * @return {Uint8Array}
9977 */
9978 const encodeStateVectorFromUpdate = update => encodeStateVectorFromUpdateV2(update, DSEncoderV1, UpdateDecoderV1);
9979
9980 /**
9981 * @param {Uint8Array} update
9982 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} YDecoder
9983 * @return {{ from: Map<number,number>, to: Map<number,number> }}
9984 */
9985 const parseUpdateMetaV2 = (update, YDecoder = UpdateDecoderV2) => {
9986 /**
9987 * @type {Map<number, number>}
9988 */
9989 const from = new Map();
9990 /**
9991 * @type {Map<number, number>}
9992 */
9993 const to = new Map();
9994 const updateDecoder = new LazyStructReader(new YDecoder(decoding.createDecoder(update)), false);
9995 let curr = updateDecoder.curr;
9996 if (curr !== null) {
9997 let currClient = curr.id.client;
9998 let currClock = curr.id.clock;
9999 // write the beginning to `from`
10000 from.set(currClient, currClock);
10001 for (; curr !== null; curr = updateDecoder.next()) {
10002 if (currClient !== curr.id.client) {
10003 // We found a new client
10004 // write the end to `to`
10005 to.set(currClient, currClock);
10006 // write the beginning to `from`
10007 from.set(curr.id.client, curr.id.clock);
10008 // update currClient
10009 currClient = curr.id.client;
10010 }
10011 currClock = curr.id.clock + curr.length;
10012 }
10013 // write the end to `to`
10014 to.set(currClient, currClock);
10015 }
10016 return { from, to }
10017 };
10018
10019 /**
10020 * @param {Uint8Array} update
10021 * @return {{ from: Map<number,number>, to: Map<number,number> }}
10022 */
10023 const parseUpdateMeta = update => parseUpdateMetaV2(update, UpdateDecoderV1);
10024
10025 /**
10026 * This method is intended to slice any kind of struct and retrieve the right part.
10027 * It does not handle side-effects, so it should only be used by the lazy-encoder.
10028 *
10029 * @param {Item | GC | Skip} left
10030 * @param {number} diff
10031 * @return {Item | GC}
10032 */
10033 const sliceStruct = (left, diff) => {
10034 if (left.constructor === GC) {
10035 const { client, clock } = left.id;
10036 return new GC(createID(client, clock + diff), left.length - diff)
10037 } else if (left.constructor === Skip) {
10038 const { client, clock } = left.id;
10039 return new Skip(createID(client, clock + diff), left.length - diff)
10040 } else {
10041 const leftItem = /** @type {Item} */ (left);
10042 const { client, clock } = leftItem.id;
10043 return new Item(
10044 createID(client, clock + diff),
10045 null,
10046 createID(client, clock + diff - 1),
10047 null,
10048 leftItem.rightOrigin,
10049 leftItem.parent,
10050 leftItem.parentSub,
10051 leftItem.content.splice(diff)
10052 )
10053 }
10054 };
10055
10056 /**
10057 *
10058 * This function works similarly to `readUpdateV2`.
10059 *
10060 * @param {Array<Uint8Array>} updates
10061 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
10062 * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder]
10063 * @return {Uint8Array}
10064 */
10065 const mergeUpdatesV2 = (updates, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => {
10066 if (updates.length === 1) {
10067 return updates[0]
10068 }
10069 const updateDecoders = updates.map(update => new YDecoder(createDecoder(update)));
10070 let lazyStructDecoders = updateDecoders.map(decoder => new LazyStructReader(decoder, true));
10071
10072 /**
10073 * @todo we don't need offset because we always slice before
10074 * @type {null | { struct: Item | GC | Skip, offset: number }}
10075 */
10076 let currWrite = null;
10077
10078 const updateEncoder = new YEncoder();
10079 // write structs lazily
10080 const lazyStructEncoder = new LazyStructWriter(updateEncoder);
10081
10082 // Note: We need to ensure that all lazyStructDecoders are fully consumed
10083 // Note: Should merge document updates whenever possible - even from different updates
10084 // Note: Should handle that some operations cannot be applied yet ()
10085
10086 while (true) {
10087 // Write higher clients first ⇒ sort by clientID & clock and remove decoders without content
10088 lazyStructDecoders = lazyStructDecoders.filter(dec => dec.curr !== null);
10089 lazyStructDecoders.sort(
10090 /** @type {function(any,any):number} */ (dec1, dec2) => {
10091 if (dec1.curr.id.client === dec2.curr.id.client) {
10092 const clockDiff = dec1.curr.id.clock - dec2.curr.id.clock;
10093 if (clockDiff === 0) {
10094 // @todo remove references to skip since the structDecoders must filter Skips.
10095 return dec1.curr.constructor === dec2.curr.constructor
10096 ? 0
10097 : dec1.curr.constructor === Skip ? 1 : -1 // we are filtering skips anyway.
10098 } else {
10099 return clockDiff
10100 }
10101 } else {
10102 return dec2.curr.id.client - dec1.curr.id.client
10103 }
10104 }
10105 );
10106 if (lazyStructDecoders.length === 0) {
10107 break
10108 }
10109 const currDecoder = lazyStructDecoders[0];
10110 // write from currDecoder until the next operation is from another client or if filler-struct
10111 // then we need to reorder the decoders and find the next operation to write
10112 const firstClient = /** @type {Item | GC} */ (currDecoder.curr).id.client;
10113
10114 if (currWrite !== null) {
10115 let curr = /** @type {Item | GC | null} */ (currDecoder.curr);
10116 let iterated = false;
10117
10118 // iterate until we find something that we haven't written already
10119 // remember: first the high client-ids are written
10120 while (curr !== null && curr.id.clock + curr.length <= currWrite.struct.id.clock + currWrite.struct.length && curr.id.client >= currWrite.struct.id.client) {
10121 curr = currDecoder.next();
10122 iterated = true;
10123 }
10124 if (
10125 curr === null || // current decoder is empty
10126 curr.id.client !== firstClient || // check whether there is another decoder that has has updates from `firstClient`
10127 (iterated && curr.id.clock > currWrite.struct.id.clock + currWrite.struct.length) // the above while loop was used and we are potentially missing updates
10128 ) {
10129 continue
10130 }
10131
10132 if (firstClient !== currWrite.struct.id.client) {
10133 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10134 currWrite = { struct: curr, offset: 0 };
10135 currDecoder.next();
10136 } else {
10137 if (currWrite.struct.id.clock + currWrite.struct.length < curr.id.clock) {
10138 // @todo write currStruct & set currStruct = Skip(clock = currStruct.id.clock + currStruct.length, length = curr.id.clock - self.clock)
10139 if (currWrite.struct.constructor === Skip) {
10140 // extend existing skip
10141 currWrite.struct.length = curr.id.clock + curr.length - currWrite.struct.id.clock;
10142 } else {
10143 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10144 const diff = curr.id.clock - currWrite.struct.id.clock - currWrite.struct.length;
10145 /**
10146 * @type {Skip}
10147 */
10148 const struct = new Skip(createID(firstClient, currWrite.struct.id.clock + currWrite.struct.length), diff);
10149 currWrite = { struct, offset: 0 };
10150 }
10151 } else { // if (currWrite.struct.id.clock + currWrite.struct.length >= curr.id.clock) {
10152 const diff = currWrite.struct.id.clock + currWrite.struct.length - curr.id.clock;
10153 if (diff > 0) {
10154 if (currWrite.struct.constructor === Skip) {
10155 // prefer to slice Skip because the other struct might contain more information
10156 currWrite.struct.length -= diff;
10157 } else {
10158 curr = sliceStruct(curr, diff);
10159 }
10160 }
10161 if (!currWrite.struct.mergeWith(/** @type {any} */ (curr))) {
10162 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10163 currWrite = { struct: curr, offset: 0 };
10164 currDecoder.next();
10165 }
10166 }
10167 }
10168 } else {
10169 currWrite = { struct: /** @type {Item | GC} */ (currDecoder.curr), offset: 0 };
10170 currDecoder.next();
10171 }
10172 for (
10173 let next = currDecoder.curr;
10174 next !== null && next.id.client === firstClient && next.id.clock === currWrite.struct.id.clock + currWrite.struct.length && next.constructor !== Skip;
10175 next = currDecoder.next()
10176 ) {
10177 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10178 currWrite = { struct: next, offset: 0 };
10179 }
10180 }
10181 if (currWrite !== null) {
10182 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10183 currWrite = null;
10184 }
10185 finishLazyStructWriting(lazyStructEncoder);
10186
10187 const dss = updateDecoders.map(decoder => readDeleteSet(decoder));
10188 const ds = mergeDeleteSets(dss);
10189 writeDeleteSet(updateEncoder, ds);
10190 return updateEncoder.toUint8Array()
10191 };
10192
10193 /**
10194 * @param {Uint8Array} update
10195 * @param {Uint8Array} sv
10196 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
10197 * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder]
10198 */
10199 const diffUpdateV2 = (update, sv, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => {
10200 const state = decodeStateVector(sv);
10201 const encoder = new YEncoder();
10202 const lazyStructWriter = new LazyStructWriter(encoder);
10203 const decoder = new YDecoder(createDecoder(update));
10204 const reader = new LazyStructReader(decoder, false);
10205 while (reader.curr) {
10206 const curr = reader.curr;
10207 const currClient = curr.id.client;
10208 const svClock = state.get(currClient) || 0;
10209 if (reader.curr.constructor === Skip) {
10210 // the first written struct shouldn't be a skip
10211 reader.next();
10212 continue
10213 }
10214 if (curr.id.clock + curr.length > svClock) {
10215 writeStructToLazyStructWriter(lazyStructWriter, curr, max(svClock - curr.id.clock, 0));
10216 reader.next();
10217 while (reader.curr && reader.curr.id.client === currClient) {
10218 writeStructToLazyStructWriter(lazyStructWriter, reader.curr, 0);
10219 reader.next();
10220 }
10221 } else {
10222 // read until something new comes up
10223 while (reader.curr && reader.curr.id.client === currClient && reader.curr.id.clock + reader.curr.length <= svClock) {
10224 reader.next();
10225 }
10226 }
10227 }
10228 finishLazyStructWriting(lazyStructWriter);
10229 // write ds
10230 const ds = readDeleteSet(decoder);
10231 writeDeleteSet(encoder, ds);
10232 return encoder.toUint8Array()
10233 };
10234
10235 /**
10236 * @param {Uint8Array} update
10237 * @param {Uint8Array} sv
10238 */
10239 const diffUpdate = (update, sv) => diffUpdateV2(update, sv, UpdateDecoderV1, UpdateEncoderV1);
10240
10241 /**
10242 * @param {LazyStructWriter} lazyWriter
10243 */
10244 const flushLazyStructWriter = lazyWriter => {
10245 if (lazyWriter.written > 0) {
10246 lazyWriter.clientStructs.push({ written: lazyWriter.written, restEncoder: toUint8Array(lazyWriter.encoder.restEncoder) });
10247 lazyWriter.encoder.restEncoder = createEncoder();
10248 lazyWriter.written = 0;
10249 }
10250 };
10251
10252 /**
10253 * @param {LazyStructWriter} lazyWriter
10254 * @param {Item | GC} struct
10255 * @param {number} offset
10256 */
10257 const writeStructToLazyStructWriter = (lazyWriter, struct, offset) => {
10258 // flush curr if we start another client
10259 if (lazyWriter.written > 0 && lazyWriter.currClient !== struct.id.client) {
10260 flushLazyStructWriter(lazyWriter);
10261 }
10262 if (lazyWriter.written === 0) {
10263 lazyWriter.currClient = struct.id.client;
10264 // write next client
10265 lazyWriter.encoder.writeClient(struct.id.client);
10266 // write startClock
10267 writeVarUint(lazyWriter.encoder.restEncoder, struct.id.clock + offset);
10268 }
10269 struct.write(lazyWriter.encoder, offset);
10270 lazyWriter.written++;
10271 };
10272 /**
10273 * Call this function when we collected all parts and want to
10274 * put all the parts together. After calling this method,
10275 * you can continue using the UpdateEncoder.
10276 *
10277 * @param {LazyStructWriter} lazyWriter
10278 */
10279 const finishLazyStructWriting = (lazyWriter) => {
10280 flushLazyStructWriter(lazyWriter);
10281
10282 // this is a fresh encoder because we called flushCurr
10283 const restEncoder = lazyWriter.encoder.restEncoder;
10284
10285 /**
10286 * Now we put all the fragments together.
10287 * This works similarly to `writeClientsStructs`
10288 */
10289
10290 // write # states that were updated - i.e. the clients
10291 writeVarUint(restEncoder, lazyWriter.clientStructs.length);
10292
10293 for (let i = 0; i < lazyWriter.clientStructs.length; i++) {
10294 const partStructs = lazyWriter.clientStructs[i];
10295 /**
10296 * Works similarly to `writeStructs`
10297 */
10298 // write # encoded structs
10299 writeVarUint(restEncoder, partStructs.written);
10300 // write the rest of the fragment
10301 writeUint8Array(restEncoder, partStructs.restEncoder);
10302 }
10303 };
10304
10305 /**
10306 * @param {Uint8Array} update
10307 * @param {function(Item|GC|Skip):Item|GC|Skip} blockTransformer
10308 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} YDecoder
10309 * @param {typeof UpdateEncoderV2 | typeof UpdateEncoderV1 } YEncoder
10310 */
10311 const convertUpdateFormat = (update, blockTransformer, YDecoder, YEncoder) => {
10312 const updateDecoder = new YDecoder(createDecoder(update));
10313 const lazyDecoder = new LazyStructReader(updateDecoder, false);
10314 const updateEncoder = new YEncoder();
10315 const lazyWriter = new LazyStructWriter(updateEncoder);
10316 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
10317 writeStructToLazyStructWriter(lazyWriter, blockTransformer(curr), 0);
10318 }
10319 finishLazyStructWriting(lazyWriter);
10320 const ds = readDeleteSet(updateDecoder);
10321 writeDeleteSet(updateEncoder, ds);
10322 return updateEncoder.toUint8Array()
10323 };
10324
10325 /**
10326 * @typedef {Object} ObfuscatorOptions
10327 * @property {boolean} [ObfuscatorOptions.formatting=true]
10328 * @property {boolean} [ObfuscatorOptions.subdocs=true]
10329 * @property {boolean} [ObfuscatorOptions.yxml=true] Whether to obfuscate nodeName / hookName
10330 */
10331
10332 /**
10333 * @param {ObfuscatorOptions} obfuscator
10334 */
10335 const createObfuscator = ({ formatting = true, subdocs = true, yxml = true } = {}) => {
10336 let i = 0;
10337 const mapKeyCache = map.create();
10338 const nodeNameCache = map.create();
10339 const formattingKeyCache = map.create();
10340 const formattingValueCache = map.create();
10341 formattingValueCache.set(null, null); // end of a formatting range should always be the end of a formatting range
10342 /**
10343 * @param {Item|GC|Skip} block
10344 * @return {Item|GC|Skip}
10345 */
10346 return block => {
10347 switch (block.constructor) {
10348 case GC:
10349 case Skip:
10350 return block
10351 case Item: {
10352 const item = /** @type {Item} */ (block);
10353 const content = item.content;
10354 switch (content.constructor) {
10355 case ContentDeleted:
10356 break
10357 case ContentType: {
10358 if (yxml) {
10359 const type = /** @type {ContentType} */ (content).type;
10360 if (type instanceof YXmlElement) {
10361 type.nodeName = map.setIfUndefined(nodeNameCache, type.nodeName, () => 'node-' + i);
10362 }
10363 if (type instanceof YXmlHook) {
10364 type.hookName = map.setIfUndefined(nodeNameCache, type.hookName, () => 'hook-' + i);
10365 }
10366 }
10367 break
10368 }
10369 case ContentAny: {
10370 const c = /** @type {ContentAny} */ (content);
10371 c.arr = c.arr.map(() => i);
10372 break
10373 }
10374 case ContentBinary: {
10375 const c = /** @type {ContentBinary} */ (content);
10376 c.content = new Uint8Array([i]);
10377 break
10378 }
10379 case ContentDoc: {
10380 const c = /** @type {ContentDoc} */ (content);
10381 if (subdocs) {
10382 c.opts = {};
10383 c.doc.guid = i + '';
10384 }
10385 break
10386 }
10387 case ContentEmbed: {
10388 const c = /** @type {ContentEmbed} */ (content);
10389 c.embed = {};
10390 break
10391 }
10392 case ContentFormat: {
10393 const c = /** @type {ContentFormat} */ (content);
10394 if (formatting) {
10395 c.key = map.setIfUndefined(formattingKeyCache, c.key, () => i + '');
10396 c.value = map.setIfUndefined(formattingValueCache, c.value, () => ({ i }));
10397 }
10398 break
10399 }
10400 case ContentJSON: {
10401 const c = /** @type {ContentJSON} */ (content);
10402 c.arr = c.arr.map(() => i);
10403 break
10404 }
10405 case ContentString: {
10406 const c = /** @type {ContentString} */ (content);
10407 c.str = string.repeat((i % 10) + '', c.str.length);
10408 break
10409 }
10410 default:
10411 // unknown content type
10412 error.unexpectedCase();
10413 }
10414 if (item.parentSub) {
10415 item.parentSub = map.setIfUndefined(mapKeyCache, item.parentSub, () => i + '');
10416 }
10417 i++;
10418 return block
10419 }
10420 default:
10421 // unknown block-type
10422 error.unexpectedCase();
10423 }
10424 }
10425 };
10426
10427 /**
10428 * This function obfuscates the content of a Yjs update. This is useful to share
10429 * buggy Yjs documents while significantly limiting the possibility that a
10430 * developer can on the user. Note that it might still be possible to deduce
10431 * some information by analyzing the "structure" of the document or by analyzing
10432 * the typing behavior using the CRDT-related metadata that is still kept fully
10433 * intact.
10434 *
10435 * @param {Uint8Array} update
10436 * @param {ObfuscatorOptions} [opts]
10437 */
10438 const obfuscateUpdate = (update, opts) => convertUpdateFormat(update, createObfuscator(opts), UpdateDecoderV1, UpdateEncoderV1);
10439
10440 /**
10441 * @param {Uint8Array} update
10442 * @param {ObfuscatorOptions} [opts]
10443 */
10444 const obfuscateUpdateV2 = (update, opts) => convertUpdateFormat(update, createObfuscator(opts), UpdateDecoderV2, UpdateEncoderV2);
10445
10446 /**
10447 * @param {Uint8Array} update
10448 */
10449 const convertUpdateFormatV1ToV2 = update => convertUpdateFormat(update, f.id, UpdateDecoderV1, UpdateEncoderV2);
10450
10451 /**
10452 * @param {Uint8Array} update
10453 */
10454 const convertUpdateFormatV2ToV1 = update => convertUpdateFormat(update, id, UpdateDecoderV2, UpdateEncoderV1);
10455
10456 const errorComputeChanges = 'You must not compute changes after the event-handler fired.';
10457
10458 /**
10459 * @template {AbstractType<any>} T
10460 * YEvent describes the changes on a YType.
10461 */
10462 class YEvent {
10463 /**
10464 * @param {T} target The changed type.
10465 * @param {Transaction} transaction
10466 */
10467 constructor (target, transaction) {
10468 /**
10469 * The type on which this event was created on.
10470 * @type {T}
10471 */
10472 this.target = target;
10473 /**
10474 * The current target on which the observe callback is called.
10475 * @type {AbstractType<any>}
10476 */
10477 this.currentTarget = target;
10478 /**
10479 * The transaction that triggered this event.
10480 * @type {Transaction}
10481 */
10482 this.transaction = transaction;
10483 /**
10484 * @type {Object|null}
10485 */
10486 this._changes = null;
10487 /**
10488 * @type {null | Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>}
10489 */
10490 this._keys = null;
10491 /**
10492 * @type {null | Array<{ insert?: string | Array<any> | object | AbstractType<any>, retain?: number, delete?: number, attributes?: Object<string, any> }>}
10493 */
10494 this._delta = null;
10495 /**
10496 * @type {Array<string|number>|null}
10497 */
10498 this._path = null;
10499 }
10500
10501 /**
10502 * Computes the path from `y` to the changed type.
10503 *
10504 * @todo v14 should standardize on path: Array<{parent, index}> because that is easier to work with.
10505 *
10506 * The following property holds:
10507 * @example
10508 * let type = y
10509 * event.path.forEach(dir => {
10510 * type = type.get(dir)
10511 * })
10512 * type === event.target // => true
10513 */
10514 get path () {
10515 return this._path || (this._path = getPathTo(this.currentTarget, this.target))
10516 }
10517
10518 /**
10519 * Check if a struct is deleted by this event.
10520 *
10521 * In contrast to change.deleted, this method also returns true if the struct was added and then deleted.
10522 *
10523 * @param {AbstractStruct} struct
10524 * @return {boolean}
10525 */
10526 deletes (struct) {
10527 return isDeleted(this.transaction.deleteSet, struct.id)
10528 }
10529
10530 /**
10531 * @type {Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>}
10532 */
10533 get keys () {
10534 if (this._keys === null) {
10535 if (this.transaction.doc._transactionCleanups.length === 0) {
10536 throw error_create(errorComputeChanges)
10537 }
10538 const keys = new Map();
10539 const target = this.target;
10540 const changed = /** @type Set<string|null> */ (this.transaction.changed.get(target));
10541 changed.forEach(key => {
10542 if (key !== null) {
10543 const item = /** @type {Item} */ (target._map.get(key));
10544 /**
10545 * @type {'delete' | 'add' | 'update'}
10546 */
10547 let action;
10548 let oldValue;
10549 if (this.adds(item)) {
10550 let prev = item.left;
10551 while (prev !== null && this.adds(prev)) {
10552 prev = prev.left;
10553 }
10554 if (this.deletes(item)) {
10555 if (prev !== null && this.deletes(prev)) {
10556 action = 'delete';
10557 oldValue = last(prev.content.getContent());
10558 } else {
10559 return
10560 }
10561 } else {
10562 if (prev !== null && this.deletes(prev)) {
10563 action = 'update';
10564 oldValue = last(prev.content.getContent());
10565 } else {
10566 action = 'add';
10567 oldValue = undefined;
10568 }
10569 }
10570 } else {
10571 if (this.deletes(item)) {
10572 action = 'delete';
10573 oldValue = last(/** @type {Item} */ item.content.getContent());
10574 } else {
10575 return // nop
10576 }
10577 }
10578 keys.set(key, { action, oldValue });
10579 }
10580 });
10581 this._keys = keys;
10582 }
10583 return this._keys
10584 }
10585
10586 /**
10587 * This is a computed property. Note that this can only be safely computed during the
10588 * event call. Computing this property after other changes happened might result in
10589 * unexpected behavior (incorrect computation of deltas). A safe way to collect changes
10590 * is to store the `changes` or the `delta` object. Avoid storing the `transaction` object.
10591 *
10592 * @type {Array<{insert?: string | Array<any> | object | AbstractType<any>, retain?: number, delete?: number, attributes?: Object<string, any>}>}
10593 */
10594 get delta () {
10595 return this.changes.delta
10596 }
10597
10598 /**
10599 * Check if a struct is added by this event.
10600 *
10601 * In contrast to change.deleted, this method also returns true if the struct was added and then deleted.
10602 *
10603 * @param {AbstractStruct} struct
10604 * @return {boolean}
10605 */
10606 adds (struct) {
10607 return struct.id.clock >= (this.transaction.beforeState.get(struct.id.client) || 0)
10608 }
10609
10610 /**
10611 * This is a computed property. Note that this can only be safely computed during the
10612 * event call. Computing this property after other changes happened might result in
10613 * unexpected behavior (incorrect computation of deltas). A safe way to collect changes
10614 * is to store the `changes` or the `delta` object. Avoid storing the `transaction` object.
10615 *
10616 * @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}>}}
10617 */
10618 get changes () {
10619 let changes = this._changes;
10620 if (changes === null) {
10621 if (this.transaction.doc._transactionCleanups.length === 0) {
10622 throw error_create(errorComputeChanges)
10623 }
10624 const target = this.target;
10625 const added = set_create();
10626 const deleted = set_create();
10627 /**
10628 * @type {Array<{insert:Array<any>}|{delete:number}|{retain:number}>}
10629 */
10630 const delta = [];
10631 changes = {
10632 added,
10633 deleted,
10634 delta,
10635 keys: this.keys
10636 };
10637 const changed = /** @type Set<string|null> */ (this.transaction.changed.get(target));
10638 if (changed.has(null)) {
10639 /**
10640 * @type {any}
10641 */
10642 let lastOp = null;
10643 const packOp = () => {
10644 if (lastOp) {
10645 delta.push(lastOp);
10646 }
10647 };
10648 for (let item = target._start; item !== null; item = item.right) {
10649 if (item.deleted) {
10650 if (this.deletes(item) && !this.adds(item)) {
10651 if (lastOp === null || lastOp.delete === undefined) {
10652 packOp();
10653 lastOp = { delete: 0 };
10654 }
10655 lastOp.delete += item.length;
10656 deleted.add(item);
10657 } // else nop
10658 } else {
10659 if (this.adds(item)) {
10660 if (lastOp === null || lastOp.insert === undefined) {
10661 packOp();
10662 lastOp = { insert: [] };
10663 }
10664 lastOp.insert = lastOp.insert.concat(item.content.getContent());
10665 added.add(item);
10666 } else {
10667 if (lastOp === null || lastOp.retain === undefined) {
10668 packOp();
10669 lastOp = { retain: 0 };
10670 }
10671 lastOp.retain += item.length;
10672 }
10673 }
10674 }
10675 if (lastOp !== null && lastOp.retain === undefined) {
10676 packOp();
10677 }
10678 }
10679 this._changes = changes;
10680 }
10681 return /** @type {any} */ (changes)
10682 }
10683 }
10684
10685 /**
10686 * Compute the path from this type to the specified target.
10687 *
10688 * @example
10689 * // `child` should be accessible via `type.get(path[0]).get(path[1])..`
10690 * const path = type.getPathTo(child)
10691 * // assuming `type instanceof YArray`
10692 * console.log(path) // might look like => [2, 'key1']
10693 * child === type.get(path[0]).get(path[1])
10694 *
10695 * @param {AbstractType<any>} parent
10696 * @param {AbstractType<any>} child target
10697 * @return {Array<string|number>} Path to the target
10698 *
10699 * @private
10700 * @function
10701 */
10702 const getPathTo = (parent, child) => {
10703 const path = [];
10704 while (child._item !== null && child !== parent) {
10705 if (child._item.parentSub !== null) {
10706 // parent is map-ish
10707 path.unshift(child._item.parentSub);
10708 } else {
10709 // parent is array-ish
10710 let i = 0;
10711 let c = /** @type {AbstractType<any>} */ (child._item.parent)._start;
10712 while (c !== child._item && c !== null) {
10713 if (!c.deleted) {
10714 i++;
10715 }
10716 c = c.right;
10717 }
10718 path.unshift(i);
10719 }
10720 child = /** @type {AbstractType<any>} */ (child._item.parent);
10721 }
10722 return path
10723 };
10724
10725 const maxSearchMarker = 80;
10726
10727 /**
10728 * A unique timestamp that identifies each marker.
10729 *
10730 * Time is relative,.. this is more like an ever-increasing clock.
10731 *
10732 * @type {number}
10733 */
10734 let globalSearchMarkerTimestamp = 0;
10735
10736 class ArraySearchMarker {
10737 /**
10738 * @param {Item} p
10739 * @param {number} index
10740 */
10741 constructor (p, index) {
10742 p.marker = true;
10743 this.p = p;
10744 this.index = index;
10745 this.timestamp = globalSearchMarkerTimestamp++;
10746 }
10747 }
10748
10749 /**
10750 * @param {ArraySearchMarker} marker
10751 */
10752 const refreshMarkerTimestamp = marker => { marker.timestamp = globalSearchMarkerTimestamp++; };
10753
10754 /**
10755 * This is rather complex so this function is the only thing that should overwrite a marker
10756 *
10757 * @param {ArraySearchMarker} marker
10758 * @param {Item} p
10759 * @param {number} index
10760 */
10761 const overwriteMarker = (marker, p, index) => {
10762 marker.p.marker = false;
10763 marker.p = p;
10764 p.marker = true;
10765 marker.index = index;
10766 marker.timestamp = globalSearchMarkerTimestamp++;
10767 };
10768
10769 /**
10770 * @param {Array<ArraySearchMarker>} searchMarker
10771 * @param {Item} p
10772 * @param {number} index
10773 */
10774 const markPosition = (searchMarker, p, index) => {
10775 if (searchMarker.length >= maxSearchMarker) {
10776 // override oldest marker (we don't want to create more objects)
10777 const marker = searchMarker.reduce((a, b) => a.timestamp < b.timestamp ? a : b);
10778 overwriteMarker(marker, p, index);
10779 return marker
10780 } else {
10781 // create new marker
10782 const pm = new ArraySearchMarker(p, index);
10783 searchMarker.push(pm);
10784 return pm
10785 }
10786 };
10787
10788 /**
10789 * Search marker help us to find positions in the associative array faster.
10790 *
10791 * They speed up the process of finding a position without much bookkeeping.
10792 *
10793 * A maximum of `maxSearchMarker` objects are created.
10794 *
10795 * This function always returns a refreshed marker (updated timestamp)
10796 *
10797 * @param {AbstractType<any>} yarray
10798 * @param {number} index
10799 */
10800 const findMarker = (yarray, index) => {
10801 if (yarray._start === null || index === 0 || yarray._searchMarker === null) {
10802 return null
10803 }
10804 const marker = yarray._searchMarker.length === 0 ? null : yarray._searchMarker.reduce((a, b) => abs(index - a.index) < abs(index - b.index) ? a : b);
10805 let p = yarray._start;
10806 let pindex = 0;
10807 if (marker !== null) {
10808 p = marker.p;
10809 pindex = marker.index;
10810 refreshMarkerTimestamp(marker); // we used it, we might need to use it again
10811 }
10812 // iterate to right if possible
10813 while (p.right !== null && pindex < index) {
10814 if (!p.deleted && p.countable) {
10815 if (index < pindex + p.length) {
10816 break
10817 }
10818 pindex += p.length;
10819 }
10820 p = p.right;
10821 }
10822 // iterate to left if necessary (might be that pindex > index)
10823 while (p.left !== null && pindex > index) {
10824 p = p.left;
10825 if (!p.deleted && p.countable) {
10826 pindex -= p.length;
10827 }
10828 }
10829 // we want to make sure that p can't be merged with left, because that would screw up everything
10830 // in that cas just return what we have (it is most likely the best marker anyway)
10831 // iterate to left until p can't be merged with left
10832 while (p.left !== null && p.left.id.client === p.id.client && p.left.id.clock + p.left.length === p.id.clock) {
10833 p = p.left;
10834 if (!p.deleted && p.countable) {
10835 pindex -= p.length;
10836 }
10837 }
10838
10839 // @todo remove!
10840 // assure position
10841 // {
10842 // let start = yarray._start
10843 // let pos = 0
10844 // while (start !== p) {
10845 // if (!start.deleted && start.countable) {
10846 // pos += start.length
10847 // }
10848 // start = /** @type {Item} */ (start.right)
10849 // }
10850 // if (pos !== pindex) {
10851 // debugger
10852 // throw new Error('Gotcha position fail!')
10853 // }
10854 // }
10855 // if (marker) {
10856 // if (window.lengthes == null) {
10857 // window.lengthes = []
10858 // window.getLengthes = () => window.lengthes.sort((a, b) => a - b)
10859 // }
10860 // window.lengthes.push(marker.index - pindex)
10861 // console.log('distance', marker.index - pindex, 'len', p && p.parent.length)
10862 // }
10863 if (marker !== null && abs(marker.index - pindex) < /** @type {YText|YArray<any>} */ (p.parent).length / maxSearchMarker) {
10864 // adjust existing marker
10865 overwriteMarker(marker, p, pindex);
10866 return marker
10867 } else {
10868 // create new marker
10869 return markPosition(yarray._searchMarker, p, pindex)
10870 }
10871 };
10872
10873 /**
10874 * Update markers when a change happened.
10875 *
10876 * This should be called before doing a deletion!
10877 *
10878 * @param {Array<ArraySearchMarker>} searchMarker
10879 * @param {number} index
10880 * @param {number} len If insertion, len is positive. If deletion, len is negative.
10881 */
10882 const updateMarkerChanges = (searchMarker, index, len) => {
10883 for (let i = searchMarker.length - 1; i >= 0; i--) {
10884 const m = searchMarker[i];
10885 if (len > 0) {
10886 /**
10887 * @type {Item|null}
10888 */
10889 let p = m.p;
10890 p.marker = false;
10891 // Ideally we just want to do a simple position comparison, but this will only work if
10892 // search markers don't point to deleted items for formats.
10893 // Iterate marker to prev undeleted countable position so we know what to do when updating a position
10894 while (p && (p.deleted || !p.countable)) {
10895 p = p.left;
10896 if (p && !p.deleted && p.countable) {
10897 // adjust position. the loop should break now
10898 m.index -= p.length;
10899 }
10900 }
10901 if (p === null || p.marker === true) {
10902 // remove search marker if updated position is null or if position is already marked
10903 searchMarker.splice(i, 1);
10904 continue
10905 }
10906 m.p = p;
10907 p.marker = true;
10908 }
10909 if (index < m.index || (len > 0 && index === m.index)) { // a simple index <= m.index check would actually suffice
10910 m.index = max(index, m.index + len);
10911 }
10912 }
10913 };
10914
10915 /**
10916 * Accumulate all (list) children of a type and return them as an Array.
10917 *
10918 * @param {AbstractType<any>} t
10919 * @return {Array<Item>}
10920 */
10921 const getTypeChildren = t => {
10922 let s = t._start;
10923 const arr = [];
10924 while (s) {
10925 arr.push(s);
10926 s = s.right;
10927 }
10928 return arr
10929 };
10930
10931 /**
10932 * Call event listeners with an event. This will also add an event to all
10933 * parents (for `.observeDeep` handlers).
10934 *
10935 * @template EventType
10936 * @param {AbstractType<EventType>} type
10937 * @param {Transaction} transaction
10938 * @param {EventType} event
10939 */
10940 const callTypeObservers = (type, transaction, event) => {
10941 const changedType = type;
10942 const changedParentTypes = transaction.changedParentTypes;
10943 while (true) {
10944 // @ts-ignore
10945 setIfUndefined(changedParentTypes, type, () => []).push(event);
10946 if (type._item === null) {
10947 break
10948 }
10949 type = /** @type {AbstractType<any>} */ (type._item.parent);
10950 }
10951 callEventHandlerListeners(changedType._eH, event, transaction);
10952 };
10953
10954 /**
10955 * @template EventType
10956 * Abstract Yjs Type class
10957 */
10958 class AbstractType {
10959 constructor () {
10960 /**
10961 * @type {Item|null}
10962 */
10963 this._item = null;
10964 /**
10965 * @type {Map<string,Item>}
10966 */
10967 this._map = new Map();
10968 /**
10969 * @type {Item|null}
10970 */
10971 this._start = null;
10972 /**
10973 * @type {Doc|null}
10974 */
10975 this.doc = null;
10976 this._length = 0;
10977 /**
10978 * Event handlers
10979 * @type {EventHandler<EventType,Transaction>}
10980 */
10981 this._eH = createEventHandler();
10982 /**
10983 * Deep event handlers
10984 * @type {EventHandler<Array<YEvent<any>>,Transaction>}
10985 */
10986 this._dEH = createEventHandler();
10987 /**
10988 * @type {null | Array<ArraySearchMarker>}
10989 */
10990 this._searchMarker = null;
10991 }
10992
10993 /**
10994 * @return {AbstractType<any>|null}
10995 */
10996 get parent () {
10997 return this._item ? /** @type {AbstractType<any>} */ (this._item.parent) : null
10998 }
10999
11000 /**
11001 * Integrate this type into the Yjs instance.
11002 *
11003 * * Save this struct in the os
11004 * * This type is sent to other client
11005 * * Observer functions are fired
11006 *
11007 * @param {Doc} y The Yjs instance
11008 * @param {Item|null} item
11009 */
11010 _integrate (y, item) {
11011 this.doc = y;
11012 this._item = item;
11013 }
11014
11015 /**
11016 * @return {AbstractType<EventType>}
11017 */
11018 _copy () {
11019 throw methodUnimplemented()
11020 }
11021
11022 /**
11023 * @return {AbstractType<EventType>}
11024 */
11025 clone () {
11026 throw methodUnimplemented()
11027 }
11028
11029 /**
11030 * @param {UpdateEncoderV1 | UpdateEncoderV2} _encoder
11031 */
11032 _write (_encoder) { }
11033
11034 /**
11035 * The first non-deleted item
11036 */
11037 get _first () {
11038 let n = this._start;
11039 while (n !== null && n.deleted) {
11040 n = n.right;
11041 }
11042 return n
11043 }
11044
11045 /**
11046 * Creates YEvent and calls all type observers.
11047 * Must be implemented by each type.
11048 *
11049 * @param {Transaction} transaction
11050 * @param {Set<null|string>} _parentSubs Keys changed on this type. `null` if list was modified.
11051 */
11052 _callObserver (transaction, _parentSubs) {
11053 if (!transaction.local && this._searchMarker) {
11054 this._searchMarker.length = 0;
11055 }
11056 }
11057
11058 /**
11059 * Observe all events that are created on this type.
11060 *
11061 * @param {function(EventType, Transaction):void} f Observer function
11062 */
11063 observe (f) {
11064 addEventHandlerListener(this._eH, f);
11065 }
11066
11067 /**
11068 * Observe all events that are created by this type and its children.
11069 *
11070 * @param {function(Array<YEvent<any>>,Transaction):void} f Observer function
11071 */
11072 observeDeep (f) {
11073 addEventHandlerListener(this._dEH, f);
11074 }
11075
11076 /**
11077 * Unregister an observer function.
11078 *
11079 * @param {function(EventType,Transaction):void} f Observer function
11080 */
11081 unobserve (f) {
11082 removeEventHandlerListener(this._eH, f);
11083 }
11084
11085 /**
11086 * Unregister an observer function.
11087 *
11088 * @param {function(Array<YEvent<any>>,Transaction):void} f Observer function
11089 */
11090 unobserveDeep (f) {
11091 removeEventHandlerListener(this._dEH, f);
11092 }
11093
11094 /**
11095 * @abstract
11096 * @return {any}
11097 */
11098 toJSON () {}
11099 }
11100
11101 /**
11102 * @param {AbstractType<any>} type
11103 * @param {number} start
11104 * @param {number} end
11105 * @return {Array<any>}
11106 *
11107 * @private
11108 * @function
11109 */
11110 const typeListSlice = (type, start, end) => {
11111 if (start < 0) {
11112 start = type._length + start;
11113 }
11114 if (end < 0) {
11115 end = type._length + end;
11116 }
11117 let len = end - start;
11118 const cs = [];
11119 let n = type._start;
11120 while (n !== null && len > 0) {
11121 if (n.countable && !n.deleted) {
11122 const c = n.content.getContent();
11123 if (c.length <= start) {
11124 start -= c.length;
11125 } else {
11126 for (let i = start; i < c.length && len > 0; i++) {
11127 cs.push(c[i]);
11128 len--;
11129 }
11130 start = 0;
11131 }
11132 }
11133 n = n.right;
11134 }
11135 return cs
11136 };
11137
11138 /**
11139 * @param {AbstractType<any>} type
11140 * @return {Array<any>}
11141 *
11142 * @private
11143 * @function
11144 */
11145 const typeListToArray = type => {
11146 const cs = [];
11147 let n = type._start;
11148 while (n !== null) {
11149 if (n.countable && !n.deleted) {
11150 const c = n.content.getContent();
11151 for (let i = 0; i < c.length; i++) {
11152 cs.push(c[i]);
11153 }
11154 }
11155 n = n.right;
11156 }
11157 return cs
11158 };
11159
11160 /**
11161 * @param {AbstractType<any>} type
11162 * @param {Snapshot} snapshot
11163 * @return {Array<any>}
11164 *
11165 * @private
11166 * @function
11167 */
11168 const typeListToArraySnapshot = (type, snapshot) => {
11169 const cs = [];
11170 let n = type._start;
11171 while (n !== null) {
11172 if (n.countable && isVisible(n, snapshot)) {
11173 const c = n.content.getContent();
11174 for (let i = 0; i < c.length; i++) {
11175 cs.push(c[i]);
11176 }
11177 }
11178 n = n.right;
11179 }
11180 return cs
11181 };
11182
11183 /**
11184 * Executes a provided function on once on overy element of this YArray.
11185 *
11186 * @param {AbstractType<any>} type
11187 * @param {function(any,number,any):void} f A function to execute on every element of this YArray.
11188 *
11189 * @private
11190 * @function
11191 */
11192 const typeListForEach = (type, f) => {
11193 let index = 0;
11194 let n = type._start;
11195 while (n !== null) {
11196 if (n.countable && !n.deleted) {
11197 const c = n.content.getContent();
11198 for (let i = 0; i < c.length; i++) {
11199 f(c[i], index++, type);
11200 }
11201 }
11202 n = n.right;
11203 }
11204 };
11205
11206 /**
11207 * @template C,R
11208 * @param {AbstractType<any>} type
11209 * @param {function(C,number,AbstractType<any>):R} f
11210 * @return {Array<R>}
11211 *
11212 * @private
11213 * @function
11214 */
11215 const typeListMap = (type, f) => {
11216 /**
11217 * @type {Array<any>}
11218 */
11219 const result = [];
11220 typeListForEach(type, (c, i) => {
11221 result.push(f(c, i, type));
11222 });
11223 return result
11224 };
11225
11226 /**
11227 * @param {AbstractType<any>} type
11228 * @return {IterableIterator<any>}
11229 *
11230 * @private
11231 * @function
11232 */
11233 const typeListCreateIterator = type => {
11234 let n = type._start;
11235 /**
11236 * @type {Array<any>|null}
11237 */
11238 let currentContent = null;
11239 let currentContentIndex = 0;
11240 return {
11241 [Symbol.iterator] () {
11242 return this
11243 },
11244 next: () => {
11245 // find some content
11246 if (currentContent === null) {
11247 while (n !== null && n.deleted) {
11248 n = n.right;
11249 }
11250 // check if we reached the end, no need to check currentContent, because it does not exist
11251 if (n === null) {
11252 return {
11253 done: true,
11254 value: undefined
11255 }
11256 }
11257 // we found n, so we can set currentContent
11258 currentContent = n.content.getContent();
11259 currentContentIndex = 0;
11260 n = n.right; // we used the content of n, now iterate to next
11261 }
11262 const value = currentContent[currentContentIndex++];
11263 // check if we need to empty currentContent
11264 if (currentContent.length <= currentContentIndex) {
11265 currentContent = null;
11266 }
11267 return {
11268 done: false,
11269 value
11270 }
11271 }
11272 }
11273 };
11274
11275 /**
11276 * @param {AbstractType<any>} type
11277 * @param {number} index
11278 * @return {any}
11279 *
11280 * @private
11281 * @function
11282 */
11283 const typeListGet = (type, index) => {
11284 const marker = findMarker(type, index);
11285 let n = type._start;
11286 if (marker !== null) {
11287 n = marker.p;
11288 index -= marker.index;
11289 }
11290 for (; n !== null; n = n.right) {
11291 if (!n.deleted && n.countable) {
11292 if (index < n.length) {
11293 return n.content.getContent()[index]
11294 }
11295 index -= n.length;
11296 }
11297 }
11298 };
11299
11300 /**
11301 * @param {Transaction} transaction
11302 * @param {AbstractType<any>} parent
11303 * @param {Item?} referenceItem
11304 * @param {Array<Object<string,any>|Array<any>|boolean|number|null|string|Uint8Array>} content
11305 *
11306 * @private
11307 * @function
11308 */
11309 const typeListInsertGenericsAfter = (transaction, parent, referenceItem, content) => {
11310 let left = referenceItem;
11311 const doc = transaction.doc;
11312 const ownClientId = doc.clientID;
11313 const store = doc.store;
11314 const right = referenceItem === null ? parent._start : referenceItem.right;
11315 /**
11316 * @type {Array<Object|Array<any>|number|null>}
11317 */
11318 let jsonContent = [];
11319 const packJsonContent = () => {
11320 if (jsonContent.length > 0) {
11321 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentAny(jsonContent));
11322 left.integrate(transaction, 0);
11323 jsonContent = [];
11324 }
11325 };
11326 content.forEach(c => {
11327 if (c === null) {
11328 jsonContent.push(c);
11329 } else {
11330 switch (c.constructor) {
11331 case Number:
11332 case Object:
11333 case Boolean:
11334 case Array:
11335 case String:
11336 jsonContent.push(c);
11337 break
11338 default:
11339 packJsonContent();
11340 switch (c.constructor) {
11341 case Uint8Array:
11342 case ArrayBuffer:
11343 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))));
11344 left.integrate(transaction, 0);
11345 break
11346 case Doc:
11347 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentDoc(/** @type {Doc} */ (c)));
11348 left.integrate(transaction, 0);
11349 break
11350 default:
11351 if (c instanceof AbstractType) {
11352 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentType(c));
11353 left.integrate(transaction, 0);
11354 } else {
11355 throw new Error('Unexpected content type in insert operation')
11356 }
11357 }
11358 }
11359 }
11360 });
11361 packJsonContent();
11362 };
11363
11364 const lengthExceeded = error_create('Length exceeded!');
11365
11366 /**
11367 * @param {Transaction} transaction
11368 * @param {AbstractType<any>} parent
11369 * @param {number} index
11370 * @param {Array<Object<string,any>|Array<any>|number|null|string|Uint8Array>} content
11371 *
11372 * @private
11373 * @function
11374 */
11375 const typeListInsertGenerics = (transaction, parent, index, content) => {
11376 if (index > parent._length) {
11377 throw lengthExceeded
11378 }
11379 if (index === 0) {
11380 if (parent._searchMarker) {
11381 updateMarkerChanges(parent._searchMarker, index, content.length);
11382 }
11383 return typeListInsertGenericsAfter(transaction, parent, null, content)
11384 }
11385 const startIndex = index;
11386 const marker = findMarker(parent, index);
11387 let n = parent._start;
11388 if (marker !== null) {
11389 n = marker.p;
11390 index -= marker.index;
11391 // we need to iterate one to the left so that the algorithm works
11392 if (index === 0) {
11393 // @todo refactor this as it actually doesn't consider formats
11394 n = n.prev; // important! get the left undeleted item so that we can actually decrease index
11395 index += (n && n.countable && !n.deleted) ? n.length : 0;
11396 }
11397 }
11398 for (; n !== null; n = n.right) {
11399 if (!n.deleted && n.countable) {
11400 if (index <= n.length) {
11401 if (index < n.length) {
11402 // insert in-between
11403 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + index));
11404 }
11405 break
11406 }
11407 index -= n.length;
11408 }
11409 }
11410 if (parent._searchMarker) {
11411 updateMarkerChanges(parent._searchMarker, startIndex, content.length);
11412 }
11413 return typeListInsertGenericsAfter(transaction, parent, n, content)
11414 };
11415
11416 /**
11417 * Pushing content is special as we generally want to push after the last item. So we don't have to update
11418 * the serach marker.
11419 *
11420 * @param {Transaction} transaction
11421 * @param {AbstractType<any>} parent
11422 * @param {Array<Object<string,any>|Array<any>|number|null|string|Uint8Array>} content
11423 *
11424 * @private
11425 * @function
11426 */
11427 const typeListPushGenerics = (transaction, parent, content) => {
11428 // Use the marker with the highest index and iterate to the right.
11429 const marker = (parent._searchMarker || []).reduce((maxMarker, currMarker) => currMarker.index > maxMarker.index ? currMarker : maxMarker, { index: 0, p: parent._start });
11430 let n = marker.p;
11431 if (n) {
11432 while (n.right) {
11433 n = n.right;
11434 }
11435 }
11436 return typeListInsertGenericsAfter(transaction, parent, n, content)
11437 };
11438
11439 /**
11440 * @param {Transaction} transaction
11441 * @param {AbstractType<any>} parent
11442 * @param {number} index
11443 * @param {number} length
11444 *
11445 * @private
11446 * @function
11447 */
11448 const typeListDelete = (transaction, parent, index, length) => {
11449 if (length === 0) { return }
11450 const startIndex = index;
11451 const startLength = length;
11452 const marker = findMarker(parent, index);
11453 let n = parent._start;
11454 if (marker !== null) {
11455 n = marker.p;
11456 index -= marker.index;
11457 }
11458 // compute the first item to be deleted
11459 for (; n !== null && index > 0; n = n.right) {
11460 if (!n.deleted && n.countable) {
11461 if (index < n.length) {
11462 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + index));
11463 }
11464 index -= n.length;
11465 }
11466 }
11467 // delete all items until done
11468 while (length > 0 && n !== null) {
11469 if (!n.deleted) {
11470 if (length < n.length) {
11471 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + length));
11472 }
11473 n.delete(transaction);
11474 length -= n.length;
11475 }
11476 n = n.right;
11477 }
11478 if (length > 0) {
11479 throw lengthExceeded
11480 }
11481 if (parent._searchMarker) {
11482 updateMarkerChanges(parent._searchMarker, startIndex, -startLength + length /* in case we remove the above exception */);
11483 }
11484 };
11485
11486 /**
11487 * @param {Transaction} transaction
11488 * @param {AbstractType<any>} parent
11489 * @param {string} key
11490 *
11491 * @private
11492 * @function
11493 */
11494 const typeMapDelete = (transaction, parent, key) => {
11495 const c = parent._map.get(key);
11496 if (c !== undefined) {
11497 c.delete(transaction);
11498 }
11499 };
11500
11501 /**
11502 * @param {Transaction} transaction
11503 * @param {AbstractType<any>} parent
11504 * @param {string} key
11505 * @param {Object|number|null|Array<any>|string|Uint8Array|AbstractType<any>} value
11506 *
11507 * @private
11508 * @function
11509 */
11510 const typeMapSet = (transaction, parent, key, value) => {
11511 const left = parent._map.get(key) || null;
11512 const doc = transaction.doc;
11513 const ownClientId = doc.clientID;
11514 let content;
11515 if (value == null) {
11516 content = new ContentAny([value]);
11517 } else {
11518 switch (value.constructor) {
11519 case Number:
11520 case Object:
11521 case Boolean:
11522 case Array:
11523 case String:
11524 content = new ContentAny([value]);
11525 break
11526 case Uint8Array:
11527 content = new ContentBinary(/** @type {Uint8Array} */ (value));
11528 break
11529 case Doc:
11530 content = new ContentDoc(/** @type {Doc} */ (value));
11531 break
11532 default:
11533 if (value instanceof AbstractType) {
11534 content = new ContentType(value);
11535 } else {
11536 throw new Error('Unexpected content type')
11537 }
11538 }
11539 }
11540 new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, null, null, parent, key, content).integrate(transaction, 0);
11541 };
11542
11543 /**
11544 * @param {AbstractType<any>} parent
11545 * @param {string} key
11546 * @return {Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined}
11547 *
11548 * @private
11549 * @function
11550 */
11551 const typeMapGet = (parent, key) => {
11552 const val = parent._map.get(key);
11553 return val !== undefined && !val.deleted ? val.content.getContent()[val.length - 1] : undefined
11554 };
11555
11556 /**
11557 * @param {AbstractType<any>} parent
11558 * @return {Object<string,Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined>}
11559 *
11560 * @private
11561 * @function
11562 */
11563 const typeMapGetAll = (parent) => {
11564 /**
11565 * @type {Object<string,any>}
11566 */
11567 const res = {};
11568 parent._map.forEach((value, key) => {
11569 if (!value.deleted) {
11570 res[key] = value.content.getContent()[value.length - 1];
11571 }
11572 });
11573 return res
11574 };
11575
11576 /**
11577 * @param {AbstractType<any>} parent
11578 * @param {string} key
11579 * @return {boolean}
11580 *
11581 * @private
11582 * @function
11583 */
11584 const typeMapHas = (parent, key) => {
11585 const val = parent._map.get(key);
11586 return val !== undefined && !val.deleted
11587 };
11588
11589 /**
11590 * @param {AbstractType<any>} parent
11591 * @param {string} key
11592 * @param {Snapshot} snapshot
11593 * @return {Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined}
11594 *
11595 * @private
11596 * @function
11597 */
11598 const typeMapGetSnapshot = (parent, key, snapshot) => {
11599 let v = parent._map.get(key) || null;
11600 while (v !== null && (!snapshot.sv.has(v.id.client) || v.id.clock >= (snapshot.sv.get(v.id.client) || 0))) {
11601 v = v.left;
11602 }
11603 return v !== null && isVisible(v, snapshot) ? v.content.getContent()[v.length - 1] : undefined
11604 };
11605
11606 /**
11607 * @param {Map<string,Item>} map
11608 * @return {IterableIterator<Array<any>>}
11609 *
11610 * @private
11611 * @function
11612 */
11613 const createMapIterator = map => iteratorFilter(map.entries(), /** @param {any} entry */ entry => !entry[1].deleted);
11614
11615 /**
11616 * @module YArray
11617 */
11618
11619 /**
11620 * Event that describes the changes on a YArray
11621 * @template T
11622 * @extends YEvent<YArray<T>>
11623 */
11624 class YArrayEvent extends YEvent {
11625 /**
11626 * @param {YArray<T>} yarray The changed type
11627 * @param {Transaction} transaction The transaction object
11628 */
11629 constructor (yarray, transaction) {
11630 super(yarray, transaction);
11631 this._transaction = transaction;
11632 }
11633 }
11634
11635 /**
11636 * A shared Array implementation.
11637 * @template T
11638 * @extends AbstractType<YArrayEvent<T>>
11639 * @implements {Iterable<T>}
11640 */
11641 class YArray extends AbstractType {
11642 constructor () {
11643 super();
11644 /**
11645 * @type {Array<any>?}
11646 * @private
11647 */
11648 this._prelimContent = [];
11649 /**
11650 * @type {Array<ArraySearchMarker>}
11651 */
11652 this._searchMarker = [];
11653 }
11654
11655 /**
11656 * Construct a new YArray containing the specified items.
11657 * @template {Object<string,any>|Array<any>|number|null|string|Uint8Array} T
11658 * @param {Array<T>} items
11659 * @return {YArray<T>}
11660 */
11661 static from (items) {
11662 /**
11663 * @type {YArray<T>}
11664 */
11665 const a = new YArray();
11666 a.push(items);
11667 return a
11668 }
11669
11670 /**
11671 * Integrate this type into the Yjs instance.
11672 *
11673 * * Save this struct in the os
11674 * * This type is sent to other client
11675 * * Observer functions are fired
11676 *
11677 * @param {Doc} y The Yjs instance
11678 * @param {Item} item
11679 */
11680 _integrate (y, item) {
11681 super._integrate(y, item);
11682 this.insert(0, /** @type {Array<any>} */ (this._prelimContent));
11683 this._prelimContent = null;
11684 }
11685
11686 /**
11687 * @return {YArray<T>}
11688 */
11689 _copy () {
11690 return new YArray()
11691 }
11692
11693 /**
11694 * @return {YArray<T>}
11695 */
11696 clone () {
11697 /**
11698 * @type {YArray<T>}
11699 */
11700 const arr = new YArray();
11701 arr.insert(0, this.toArray().map(el =>
11702 el instanceof AbstractType ? /** @type {typeof el} */ (el.clone()) : el
11703 ));
11704 return arr
11705 }
11706
11707 get length () {
11708 return this._prelimContent === null ? this._length : this._prelimContent.length
11709 }
11710
11711 /**
11712 * Creates YArrayEvent and calls observers.
11713 *
11714 * @param {Transaction} transaction
11715 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
11716 */
11717 _callObserver (transaction, parentSubs) {
11718 super._callObserver(transaction, parentSubs);
11719 callTypeObservers(this, transaction, new YArrayEvent(this, transaction));
11720 }
11721
11722 /**
11723 * Inserts new content at an index.
11724 *
11725 * Important: This function expects an array of content. Not just a content
11726 * object. The reason for this "weirdness" is that inserting several elements
11727 * is very efficient when it is done as a single operation.
11728 *
11729 * @example
11730 * // Insert character 'a' at position 0
11731 * yarray.insert(0, ['a'])
11732 * // Insert numbers 1, 2 at position 1
11733 * yarray.insert(1, [1, 2])
11734 *
11735 * @param {number} index The index to insert content at.
11736 * @param {Array<T>} content The array of content
11737 */
11738 insert (index, content) {
11739 if (this.doc !== null) {
11740 transact(this.doc, transaction => {
11741 typeListInsertGenerics(transaction, this, index, /** @type {any} */ (content));
11742 });
11743 } else {
11744 /** @type {Array<any>} */ (this._prelimContent).splice(index, 0, ...content);
11745 }
11746 }
11747
11748 /**
11749 * Appends content to this YArray.
11750 *
11751 * @param {Array<T>} content Array of content to append.
11752 *
11753 * @todo Use the following implementation in all types.
11754 */
11755 push (content) {
11756 if (this.doc !== null) {
11757 transact(this.doc, transaction => {
11758 typeListPushGenerics(transaction, this, /** @type {any} */ (content));
11759 });
11760 } else {
11761 /** @type {Array<any>} */ (this._prelimContent).push(...content);
11762 }
11763 }
11764
11765 /**
11766 * Preppends content to this YArray.
11767 *
11768 * @param {Array<T>} content Array of content to preppend.
11769 */
11770 unshift (content) {
11771 this.insert(0, content);
11772 }
11773
11774 /**
11775 * Deletes elements starting from an index.
11776 *
11777 * @param {number} index Index at which to start deleting elements
11778 * @param {number} length The number of elements to remove. Defaults to 1.
11779 */
11780 delete (index, length = 1) {
11781 if (this.doc !== null) {
11782 transact(this.doc, transaction => {
11783 typeListDelete(transaction, this, index, length);
11784 });
11785 } else {
11786 /** @type {Array<any>} */ (this._prelimContent).splice(index, length);
11787 }
11788 }
11789
11790 /**
11791 * Returns the i-th element from a YArray.
11792 *
11793 * @param {number} index The index of the element to return from the YArray
11794 * @return {T}
11795 */
11796 get (index) {
11797 return typeListGet(this, index)
11798 }
11799
11800 /**
11801 * Transforms this YArray to a JavaScript Array.
11802 *
11803 * @return {Array<T>}
11804 */
11805 toArray () {
11806 return typeListToArray(this)
11807 }
11808
11809 /**
11810 * Transforms this YArray to a JavaScript Array.
11811 *
11812 * @param {number} [start]
11813 * @param {number} [end]
11814 * @return {Array<T>}
11815 */
11816 slice (start = 0, end = this.length) {
11817 return typeListSlice(this, start, end)
11818 }
11819
11820 /**
11821 * Transforms this Shared Type to a JSON object.
11822 *
11823 * @return {Array<any>}
11824 */
11825 toJSON () {
11826 return this.map(c => c instanceof AbstractType ? c.toJSON() : c)
11827 }
11828
11829 /**
11830 * Returns an Array with the result of calling a provided function on every
11831 * element of this YArray.
11832 *
11833 * @template M
11834 * @param {function(T,number,YArray<T>):M} f Function that produces an element of the new Array
11835 * @return {Array<M>} A new array with each element being the result of the
11836 * callback function
11837 */
11838 map (f) {
11839 return typeListMap(this, /** @type {any} */ (f))
11840 }
11841
11842 /**
11843 * Executes a provided function once on overy element of this YArray.
11844 *
11845 * @param {function(T,number,YArray<T>):void} f A function to execute on every element of this YArray.
11846 */
11847 forEach (f) {
11848 typeListForEach(this, f);
11849 }
11850
11851 /**
11852 * @return {IterableIterator<T>}
11853 */
11854 [Symbol.iterator] () {
11855 return typeListCreateIterator(this)
11856 }
11857
11858 /**
11859 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
11860 */
11861 _write (encoder) {
11862 encoder.writeTypeRef(YArrayRefID);
11863 }
11864 }
11865
11866 /**
11867 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
11868 *
11869 * @private
11870 * @function
11871 */
11872 const readYArray = _decoder => new YArray();
11873
11874 /**
11875 * @template T
11876 * @extends YEvent<YMap<T>>
11877 * Event that describes the changes on a YMap.
11878 */
11879 class YMapEvent extends YEvent {
11880 /**
11881 * @param {YMap<T>} ymap The YArray that changed.
11882 * @param {Transaction} transaction
11883 * @param {Set<any>} subs The keys that changed.
11884 */
11885 constructor (ymap, transaction, subs) {
11886 super(ymap, transaction);
11887 this.keysChanged = subs;
11888 }
11889 }
11890
11891 /**
11892 * @template MapType
11893 * A shared Map implementation.
11894 *
11895 * @extends AbstractType<YMapEvent<MapType>>
11896 * @implements {Iterable<MapType>}
11897 */
11898 class YMap extends AbstractType {
11899 /**
11900 *
11901 * @param {Iterable<readonly [string, any]>=} entries - an optional iterable to initialize the YMap
11902 */
11903 constructor (entries) {
11904 super();
11905 /**
11906 * @type {Map<string,any>?}
11907 * @private
11908 */
11909 this._prelimContent = null;
11910
11911 if (entries === undefined) {
11912 this._prelimContent = new Map();
11913 } else {
11914 this._prelimContent = new Map(entries);
11915 }
11916 }
11917
11918 /**
11919 * Integrate this type into the Yjs instance.
11920 *
11921 * * Save this struct in the os
11922 * * This type is sent to other client
11923 * * Observer functions are fired
11924 *
11925 * @param {Doc} y The Yjs instance
11926 * @param {Item} item
11927 */
11928 _integrate (y, item) {
11929 super._integrate(y, item)
11930 ;/** @type {Map<string, any>} */ (this._prelimContent).forEach((value, key) => {
11931 this.set(key, value);
11932 });
11933 this._prelimContent = null;
11934 }
11935
11936 /**
11937 * @return {YMap<MapType>}
11938 */
11939 _copy () {
11940 return new YMap()
11941 }
11942
11943 /**
11944 * @return {YMap<MapType>}
11945 */
11946 clone () {
11947 /**
11948 * @type {YMap<MapType>}
11949 */
11950 const map = new YMap();
11951 this.forEach((value, key) => {
11952 map.set(key, value instanceof AbstractType ? /** @type {typeof value} */ (value.clone()) : value);
11953 });
11954 return map
11955 }
11956
11957 /**
11958 * Creates YMapEvent and calls observers.
11959 *
11960 * @param {Transaction} transaction
11961 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
11962 */
11963 _callObserver (transaction, parentSubs) {
11964 callTypeObservers(this, transaction, new YMapEvent(this, transaction, parentSubs));
11965 }
11966
11967 /**
11968 * Transforms this Shared Type to a JSON object.
11969 *
11970 * @return {Object<string,any>}
11971 */
11972 toJSON () {
11973 /**
11974 * @type {Object<string,MapType>}
11975 */
11976 const map = {};
11977 this._map.forEach((item, key) => {
11978 if (!item.deleted) {
11979 const v = item.content.getContent()[item.length - 1];
11980 map[key] = v instanceof AbstractType ? v.toJSON() : v;
11981 }
11982 });
11983 return map
11984 }
11985
11986 /**
11987 * Returns the size of the YMap (count of key/value pairs)
11988 *
11989 * @return {number}
11990 */
11991 get size () {
11992 return [...createMapIterator(this._map)].length
11993 }
11994
11995 /**
11996 * Returns the keys for each element in the YMap Type.
11997 *
11998 * @return {IterableIterator<string>}
11999 */
12000 keys () {
12001 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => v[0])
12002 }
12003
12004 /**
12005 * Returns the values for each element in the YMap Type.
12006 *
12007 * @return {IterableIterator<any>}
12008 */
12009 values () {
12010 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => v[1].content.getContent()[v[1].length - 1])
12011 }
12012
12013 /**
12014 * Returns an Iterator of [key, value] pairs
12015 *
12016 * @return {IterableIterator<any>}
12017 */
12018 entries () {
12019 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => [v[0], v[1].content.getContent()[v[1].length - 1]])
12020 }
12021
12022 /**
12023 * Executes a provided function on once on every key-value pair.
12024 *
12025 * @param {function(MapType,string,YMap<MapType>):void} f A function to execute on every element of this YArray.
12026 */
12027 forEach (f) {
12028 this._map.forEach((item, key) => {
12029 if (!item.deleted) {
12030 f(item.content.getContent()[item.length - 1], key, this);
12031 }
12032 });
12033 }
12034
12035 /**
12036 * Returns an Iterator of [key, value] pairs
12037 *
12038 * @return {IterableIterator<any>}
12039 */
12040 [Symbol.iterator] () {
12041 return this.entries()
12042 }
12043
12044 /**
12045 * Remove a specified element from this YMap.
12046 *
12047 * @param {string} key The key of the element to remove.
12048 */
12049 delete (key) {
12050 if (this.doc !== null) {
12051 transact(this.doc, transaction => {
12052 typeMapDelete(transaction, this, key);
12053 });
12054 } else {
12055 /** @type {Map<string, any>} */ (this._prelimContent).delete(key);
12056 }
12057 }
12058
12059 /**
12060 * Adds or updates an element with a specified key and value.
12061 * @template {MapType} VAL
12062 *
12063 * @param {string} key The key of the element to add to this YMap
12064 * @param {VAL} value The value of the element to add
12065 * @return {VAL}
12066 */
12067 set (key, value) {
12068 if (this.doc !== null) {
12069 transact(this.doc, transaction => {
12070 typeMapSet(transaction, this, key, /** @type {any} */ (value));
12071 });
12072 } else {
12073 /** @type {Map<string, any>} */ (this._prelimContent).set(key, value);
12074 }
12075 return value
12076 }
12077
12078 /**
12079 * Returns a specified element from this YMap.
12080 *
12081 * @param {string} key
12082 * @return {MapType|undefined}
12083 */
12084 get (key) {
12085 return /** @type {any} */ (typeMapGet(this, key))
12086 }
12087
12088 /**
12089 * Returns a boolean indicating whether the specified key exists or not.
12090 *
12091 * @param {string} key The key to test.
12092 * @return {boolean}
12093 */
12094 has (key) {
12095 return typeMapHas(this, key)
12096 }
12097
12098 /**
12099 * Removes all elements from this YMap.
12100 */
12101 clear () {
12102 if (this.doc !== null) {
12103 transact(this.doc, transaction => {
12104 this.forEach(function (_value, key, map) {
12105 typeMapDelete(transaction, map, key);
12106 });
12107 });
12108 } else {
12109 /** @type {Map<string, any>} */ (this._prelimContent).clear();
12110 }
12111 }
12112
12113 /**
12114 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
12115 */
12116 _write (encoder) {
12117 encoder.writeTypeRef(YMapRefID);
12118 }
12119 }
12120
12121 /**
12122 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
12123 *
12124 * @private
12125 * @function
12126 */
12127 const readYMap = _decoder => new YMap();
12128
12129 /**
12130 * @param {any} a
12131 * @param {any} b
12132 * @return {boolean}
12133 */
12134 const equalAttrs = (a, b) => a === b || (typeof a === 'object' && typeof b === 'object' && a && b && object_equalFlat(a, b));
12135
12136 class ItemTextListPosition {
12137 /**
12138 * @param {Item|null} left
12139 * @param {Item|null} right
12140 * @param {number} index
12141 * @param {Map<string,any>} currentAttributes
12142 */
12143 constructor (left, right, index, currentAttributes) {
12144 this.left = left;
12145 this.right = right;
12146 this.index = index;
12147 this.currentAttributes = currentAttributes;
12148 }
12149
12150 /**
12151 * Only call this if you know that this.right is defined
12152 */
12153 forward () {
12154 if (this.right === null) {
12155 unexpectedCase();
12156 }
12157 switch (this.right.content.constructor) {
12158 case ContentFormat:
12159 if (!this.right.deleted) {
12160 updateCurrentAttributes(this.currentAttributes, /** @type {ContentFormat} */ (this.right.content));
12161 }
12162 break
12163 default:
12164 if (!this.right.deleted) {
12165 this.index += this.right.length;
12166 }
12167 break
12168 }
12169 this.left = this.right;
12170 this.right = this.right.right;
12171 }
12172 }
12173
12174 /**
12175 * @param {Transaction} transaction
12176 * @param {ItemTextListPosition} pos
12177 * @param {number} count steps to move forward
12178 * @return {ItemTextListPosition}
12179 *
12180 * @private
12181 * @function
12182 */
12183 const findNextPosition = (transaction, pos, count) => {
12184 while (pos.right !== null && count > 0) {
12185 switch (pos.right.content.constructor) {
12186 case ContentFormat:
12187 if (!pos.right.deleted) {
12188 updateCurrentAttributes(pos.currentAttributes, /** @type {ContentFormat} */ (pos.right.content));
12189 }
12190 break
12191 default:
12192 if (!pos.right.deleted) {
12193 if (count < pos.right.length) {
12194 // split right
12195 getItemCleanStart(transaction, createID(pos.right.id.client, pos.right.id.clock + count));
12196 }
12197 pos.index += pos.right.length;
12198 count -= pos.right.length;
12199 }
12200 break
12201 }
12202 pos.left = pos.right;
12203 pos.right = pos.right.right;
12204 // pos.forward() - we don't forward because that would halve the performance because we already do the checks above
12205 }
12206 return pos
12207 };
12208
12209 /**
12210 * @param {Transaction} transaction
12211 * @param {AbstractType<any>} parent
12212 * @param {number} index
12213 * @return {ItemTextListPosition}
12214 *
12215 * @private
12216 * @function
12217 */
12218 const findPosition = (transaction, parent, index) => {
12219 const currentAttributes = new Map();
12220 const marker = findMarker(parent, index);
12221 if (marker) {
12222 const pos = new ItemTextListPosition(marker.p.left, marker.p, marker.index, currentAttributes);
12223 return findNextPosition(transaction, pos, index - marker.index)
12224 } else {
12225 const pos = new ItemTextListPosition(null, parent._start, 0, currentAttributes);
12226 return findNextPosition(transaction, pos, index)
12227 }
12228 };
12229
12230 /**
12231 * Negate applied formats
12232 *
12233 * @param {Transaction} transaction
12234 * @param {AbstractType<any>} parent
12235 * @param {ItemTextListPosition} currPos
12236 * @param {Map<string,any>} negatedAttributes
12237 *
12238 * @private
12239 * @function
12240 */
12241 const insertNegatedAttributes = (transaction, parent, currPos, negatedAttributes) => {
12242 // check if we really need to remove attributes
12243 while (
12244 currPos.right !== null && (
12245 currPos.right.deleted === true || (
12246 currPos.right.content.constructor === ContentFormat &&
12247 equalAttrs(negatedAttributes.get(/** @type {ContentFormat} */ (currPos.right.content).key), /** @type {ContentFormat} */ (currPos.right.content).value)
12248 )
12249 )
12250 ) {
12251 if (!currPos.right.deleted) {
12252 negatedAttributes.delete(/** @type {ContentFormat} */ (currPos.right.content).key);
12253 }
12254 currPos.forward();
12255 }
12256 const doc = transaction.doc;
12257 const ownClientId = doc.clientID;
12258 negatedAttributes.forEach((val, key) => {
12259 const left = currPos.left;
12260 const right = currPos.right;
12261 const nextFormat = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentFormat(key, val));
12262 nextFormat.integrate(transaction, 0);
12263 currPos.right = nextFormat;
12264 currPos.forward();
12265 });
12266 };
12267
12268 /**
12269 * @param {Map<string,any>} currentAttributes
12270 * @param {ContentFormat} format
12271 *
12272 * @private
12273 * @function
12274 */
12275 const updateCurrentAttributes = (currentAttributes, format) => {
12276 const { key, value } = format;
12277 if (value === null) {
12278 currentAttributes.delete(key);
12279 } else {
12280 currentAttributes.set(key, value);
12281 }
12282 };
12283
12284 /**
12285 * @param {ItemTextListPosition} currPos
12286 * @param {Object<string,any>} attributes
12287 *
12288 * @private
12289 * @function
12290 */
12291 const minimizeAttributeChanges = (currPos, attributes) => {
12292 // go right while attributes[right.key] === right.value (or right is deleted)
12293 while (true) {
12294 if (currPos.right === null) {
12295 break
12296 } 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 {
12297 break
12298 }
12299 currPos.forward();
12300 }
12301 };
12302
12303 /**
12304 * @param {Transaction} transaction
12305 * @param {AbstractType<any>} parent
12306 * @param {ItemTextListPosition} currPos
12307 * @param {Object<string,any>} attributes
12308 * @return {Map<string,any>}
12309 *
12310 * @private
12311 * @function
12312 **/
12313 const insertAttributes = (transaction, parent, currPos, attributes) => {
12314 const doc = transaction.doc;
12315 const ownClientId = doc.clientID;
12316 const negatedAttributes = new Map();
12317 // insert format-start items
12318 for (const key in attributes) {
12319 const val = attributes[key];
12320 const currentVal = currPos.currentAttributes.get(key) || null;
12321 if (!equalAttrs(currentVal, val)) {
12322 // save negated attribute (set null if currentVal undefined)
12323 negatedAttributes.set(key, currentVal);
12324 const { left, right } = currPos;
12325 currPos.right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentFormat(key, val));
12326 currPos.right.integrate(transaction, 0);
12327 currPos.forward();
12328 }
12329 }
12330 return negatedAttributes
12331 };
12332
12333 /**
12334 * @param {Transaction} transaction
12335 * @param {AbstractType<any>} parent
12336 * @param {ItemTextListPosition} currPos
12337 * @param {string|object|AbstractType<any>} text
12338 * @param {Object<string,any>} attributes
12339 *
12340 * @private
12341 * @function
12342 **/
12343 const insertText = (transaction, parent, currPos, text, attributes) => {
12344 currPos.currentAttributes.forEach((_val, key) => {
12345 if (attributes[key] === undefined) {
12346 attributes[key] = null;
12347 }
12348 });
12349 const doc = transaction.doc;
12350 const ownClientId = doc.clientID;
12351 minimizeAttributeChanges(currPos, attributes);
12352 const negatedAttributes = insertAttributes(transaction, parent, currPos, attributes);
12353 // insert content
12354 const content = text.constructor === String ? new ContentString(/** @type {string} */ (text)) : (text instanceof AbstractType ? new ContentType(text) : new ContentEmbed(text));
12355 let { left, right, index } = currPos;
12356 if (parent._searchMarker) {
12357 updateMarkerChanges(parent._searchMarker, currPos.index, content.getLength());
12358 }
12359 right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, content);
12360 right.integrate(transaction, 0);
12361 currPos.right = right;
12362 currPos.index = index;
12363 currPos.forward();
12364 insertNegatedAttributes(transaction, parent, currPos, negatedAttributes);
12365 };
12366
12367 /**
12368 * @param {Transaction} transaction
12369 * @param {AbstractType<any>} parent
12370 * @param {ItemTextListPosition} currPos
12371 * @param {number} length
12372 * @param {Object<string,any>} attributes
12373 *
12374 * @private
12375 * @function
12376 */
12377 const formatText = (transaction, parent, currPos, length, attributes) => {
12378 const doc = transaction.doc;
12379 const ownClientId = doc.clientID;
12380 minimizeAttributeChanges(currPos, attributes);
12381 const negatedAttributes = insertAttributes(transaction, parent, currPos, attributes);
12382 // iterate until first non-format or null is found
12383 // delete all formats with attributes[format.key] != null
12384 // also check the attributes after the first non-format as we do not want to insert redundant negated attributes there
12385 // eslint-disable-next-line no-labels
12386 iterationLoop: while (
12387 currPos.right !== null &&
12388 (length > 0 ||
12389 (
12390 negatedAttributes.size > 0 &&
12391 (currPos.right.deleted || currPos.right.content.constructor === ContentFormat)
12392 )
12393 )
12394 ) {
12395 if (!currPos.right.deleted) {
12396 switch (currPos.right.content.constructor) {
12397 case ContentFormat: {
12398 const { key, value } = /** @type {ContentFormat} */ (currPos.right.content);
12399 const attr = attributes[key];
12400 if (attr !== undefined) {
12401 if (equalAttrs(attr, value)) {
12402 negatedAttributes.delete(key);
12403 } else {
12404 if (length === 0) {
12405 // no need to further extend negatedAttributes
12406 // eslint-disable-next-line no-labels
12407 break iterationLoop
12408 }
12409 negatedAttributes.set(key, value);
12410 }
12411 currPos.right.delete(transaction);
12412 } else {
12413 currPos.currentAttributes.set(key, value);
12414 }
12415 break
12416 }
12417 default:
12418 if (length < currPos.right.length) {
12419 getItemCleanStart(transaction, createID(currPos.right.id.client, currPos.right.id.clock + length));
12420 }
12421 length -= currPos.right.length;
12422 break
12423 }
12424 }
12425 currPos.forward();
12426 }
12427 // Quill just assumes that the editor starts with a newline and that it always
12428 // ends with a newline. We only insert that newline when a new newline is
12429 // inserted - i.e when length is bigger than type.length
12430 if (length > 0) {
12431 let newlines = '';
12432 for (; length > 0; length--) {
12433 newlines += '\n';
12434 }
12435 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));
12436 currPos.right.integrate(transaction, 0);
12437 currPos.forward();
12438 }
12439 insertNegatedAttributes(transaction, parent, currPos, negatedAttributes);
12440 };
12441
12442 /**
12443 * Call this function after string content has been deleted in order to
12444 * clean up formatting Items.
12445 *
12446 * @param {Transaction} transaction
12447 * @param {Item} start
12448 * @param {Item|null} curr exclusive end, automatically iterates to the next Content Item
12449 * @param {Map<string,any>} startAttributes
12450 * @param {Map<string,any>} currAttributes
12451 * @return {number} The amount of formatting Items deleted.
12452 *
12453 * @function
12454 */
12455 const cleanupFormattingGap = (transaction, start, curr, startAttributes, currAttributes) => {
12456 /**
12457 * @type {Item|null}
12458 */
12459 let end = start;
12460 /**
12461 * @type {Map<string,ContentFormat>}
12462 */
12463 const endFormats = create();
12464 while (end && (!end.countable || end.deleted)) {
12465 if (!end.deleted && end.content.constructor === ContentFormat) {
12466 const cf = /** @type {ContentFormat} */ (end.content);
12467 endFormats.set(cf.key, cf);
12468 }
12469 end = end.right;
12470 }
12471 let cleanups = 0;
12472 let reachedCurr = false;
12473 while (start !== end) {
12474 if (curr === start) {
12475 reachedCurr = true;
12476 }
12477 if (!start.deleted) {
12478 const content = start.content;
12479 switch (content.constructor) {
12480 case ContentFormat: {
12481 const { key, value } = /** @type {ContentFormat} */ (content);
12482 const startAttrValue = startAttributes.get(key) || null;
12483 if (endFormats.get(key) !== content || startAttrValue === value) {
12484 // Either this format is overwritten or it is not necessary because the attribute already existed.
12485 start.delete(transaction);
12486 cleanups++;
12487 if (!reachedCurr && (currAttributes.get(key) || null) === value && startAttrValue !== value) {
12488 if (startAttrValue === null) {
12489 currAttributes.delete(key);
12490 } else {
12491 currAttributes.set(key, startAttrValue);
12492 }
12493 }
12494 }
12495 if (!reachedCurr && !start.deleted) {
12496 updateCurrentAttributes(currAttributes, /** @type {ContentFormat} */ (content));
12497 }
12498 break
12499 }
12500 }
12501 }
12502 start = /** @type {Item} */ (start.right);
12503 }
12504 return cleanups
12505 };
12506
12507 /**
12508 * @param {Transaction} transaction
12509 * @param {Item | null} item
12510 */
12511 const cleanupContextlessFormattingGap = (transaction, item) => {
12512 // iterate until item.right is null or content
12513 while (item && item.right && (item.right.deleted || !item.right.countable)) {
12514 item = item.right;
12515 }
12516 const attrs = new Set();
12517 // iterate back until a content item is found
12518 while (item && (item.deleted || !item.countable)) {
12519 if (!item.deleted && item.content.constructor === ContentFormat) {
12520 const key = /** @type {ContentFormat} */ (item.content).key;
12521 if (attrs.has(key)) {
12522 item.delete(transaction);
12523 } else {
12524 attrs.add(key);
12525 }
12526 }
12527 item = item.left;
12528 }
12529 };
12530
12531 /**
12532 * This function is experimental and subject to change / be removed.
12533 *
12534 * Ideally, we don't need this function at all. Formatting attributes should be cleaned up
12535 * automatically after each change. This function iterates twice over the complete YText type
12536 * and removes unnecessary formatting attributes. This is also helpful for testing.
12537 *
12538 * This function won't be exported anymore as soon as there is confidence that the YText type works as intended.
12539 *
12540 * @param {YText} type
12541 * @return {number} How many formatting attributes have been cleaned up.
12542 */
12543 const cleanupYTextFormatting = type => {
12544 let res = 0;
12545 transact(/** @type {Doc} */ (type.doc), transaction => {
12546 let start = /** @type {Item} */ (type._start);
12547 let end = type._start;
12548 let startAttributes = create();
12549 const currentAttributes = copy(startAttributes);
12550 while (end) {
12551 if (end.deleted === false) {
12552 switch (end.content.constructor) {
12553 case ContentFormat:
12554 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (end.content));
12555 break
12556 default:
12557 res += cleanupFormattingGap(transaction, start, end, startAttributes, currentAttributes);
12558 startAttributes = copy(currentAttributes);
12559 start = end;
12560 break
12561 }
12562 }
12563 end = end.right;
12564 }
12565 });
12566 return res
12567 };
12568
12569 /**
12570 * This will be called by the transction once the event handlers are called to potentially cleanup
12571 * formatting attributes.
12572 *
12573 * @param {Transaction} transaction
12574 */
12575 const cleanupYTextAfterTransaction = transaction => {
12576 /**
12577 * @type {Set<YText>}
12578 */
12579 const needFullCleanup = new Set();
12580 // check if another formatting item was inserted
12581 const doc = transaction.doc;
12582 for (const [client, afterClock] of transaction.afterState.entries()) {
12583 const clock = transaction.beforeState.get(client) || 0;
12584 if (afterClock === clock) {
12585 continue
12586 }
12587 iterateStructs(transaction, /** @type {Array<Item|GC>} */ (doc.store.clients.get(client)), clock, afterClock, item => {
12588 if (
12589 !item.deleted && /** @type {Item} */ (item).content.constructor === ContentFormat && item.constructor !== GC
12590 ) {
12591 needFullCleanup.add(/** @type {any} */ (item).parent);
12592 }
12593 });
12594 }
12595 // cleanup in a new transaction
12596 transact(doc, (t) => {
12597 iterateDeletedStructs(transaction, transaction.deleteSet, item => {
12598 if (item instanceof GC || !(/** @type {YText} */ (item.parent)._hasFormatting) || needFullCleanup.has(/** @type {YText} */ (item.parent))) {
12599 return
12600 }
12601 const parent = /** @type {YText} */ (item.parent);
12602 if (item.content.constructor === ContentFormat) {
12603 needFullCleanup.add(parent);
12604 } else {
12605 // If no formatting attribute was inserted or deleted, we can make due with contextless
12606 // formatting cleanups.
12607 // Contextless: it is not necessary to compute currentAttributes for the affected position.
12608 cleanupContextlessFormattingGap(t, item);
12609 }
12610 });
12611 // If a formatting item was inserted, we simply clean the whole type.
12612 // We need to compute currentAttributes for the current position anyway.
12613 for (const yText of needFullCleanup) {
12614 cleanupYTextFormatting(yText);
12615 }
12616 });
12617 };
12618
12619 /**
12620 * @param {Transaction} transaction
12621 * @param {ItemTextListPosition} currPos
12622 * @param {number} length
12623 * @return {ItemTextListPosition}
12624 *
12625 * @private
12626 * @function
12627 */
12628 const deleteText = (transaction, currPos, length) => {
12629 const startLength = length;
12630 const startAttrs = copy(currPos.currentAttributes);
12631 const start = currPos.right;
12632 while (length > 0 && currPos.right !== null) {
12633 if (currPos.right.deleted === false) {
12634 switch (currPos.right.content.constructor) {
12635 case ContentType:
12636 case ContentEmbed:
12637 case ContentString:
12638 if (length < currPos.right.length) {
12639 getItemCleanStart(transaction, createID(currPos.right.id.client, currPos.right.id.clock + length));
12640 }
12641 length -= currPos.right.length;
12642 currPos.right.delete(transaction);
12643 break
12644 }
12645 }
12646 currPos.forward();
12647 }
12648 if (start) {
12649 cleanupFormattingGap(transaction, start, currPos.right, startAttrs, currPos.currentAttributes);
12650 }
12651 const parent = /** @type {AbstractType<any>} */ (/** @type {Item} */ (currPos.left || currPos.right).parent);
12652 if (parent._searchMarker) {
12653 updateMarkerChanges(parent._searchMarker, currPos.index, -startLength + length);
12654 }
12655 return currPos
12656 };
12657
12658 /**
12659 * The Quill Delta format represents changes on a text document with
12660 * formatting information. For mor information visit {@link https://quilljs.com/docs/delta/|Quill Delta}
12661 *
12662 * @example
12663 * {
12664 * ops: [
12665 * { insert: 'Gandalf', attributes: { bold: true } },
12666 * { insert: ' the ' },
12667 * { insert: 'Grey', attributes: { color: '#cccccc' } }
12668 * ]
12669 * }
12670 *
12671 */
12672
12673 /**
12674 * Attributes that can be assigned to a selection of text.
12675 *
12676 * @example
12677 * {
12678 * bold: true,
12679 * font-size: '40px'
12680 * }
12681 *
12682 * @typedef {Object} TextAttributes
12683 */
12684
12685 /**
12686 * @extends YEvent<YText>
12687 * Event that describes the changes on a YText type.
12688 */
12689 class YTextEvent extends YEvent {
12690 /**
12691 * @param {YText} ytext
12692 * @param {Transaction} transaction
12693 * @param {Set<any>} subs The keys that changed
12694 */
12695 constructor (ytext, transaction, subs) {
12696 super(ytext, transaction);
12697 /**
12698 * Whether the children changed.
12699 * @type {Boolean}
12700 * @private
12701 */
12702 this.childListChanged = false;
12703 /**
12704 * Set of all changed attributes.
12705 * @type {Set<string>}
12706 */
12707 this.keysChanged = new Set();
12708 subs.forEach((sub) => {
12709 if (sub === null) {
12710 this.childListChanged = true;
12711 } else {
12712 this.keysChanged.add(sub);
12713 }
12714 });
12715 }
12716
12717 /**
12718 * @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}>}}
12719 */
12720 get changes () {
12721 if (this._changes === null) {
12722 /**
12723 * @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}>}}
12724 */
12725 const changes = {
12726 keys: this.keys,
12727 delta: this.delta,
12728 added: new Set(),
12729 deleted: new Set()
12730 };
12731 this._changes = changes;
12732 }
12733 return /** @type {any} */ (this._changes)
12734 }
12735
12736 /**
12737 * Compute the changes in the delta format.
12738 * A {@link https://quilljs.com/docs/delta/|Quill Delta}) that represents the changes on the document.
12739 *
12740 * @type {Array<{insert?:string|object|AbstractType<any>, delete?:number, retain?:number, attributes?: Object<string,any>}>}
12741 *
12742 * @public
12743 */
12744 get delta () {
12745 if (this._delta === null) {
12746 const y = /** @type {Doc} */ (this.target.doc);
12747 /**
12748 * @type {Array<{insert?:string|object|AbstractType<any>, delete?:number, retain?:number, attributes?: Object<string,any>}>}
12749 */
12750 const delta = [];
12751 transact(y, transaction => {
12752 const currentAttributes = new Map(); // saves all current attributes for insert
12753 const oldAttributes = new Map();
12754 let item = this.target._start;
12755 /**
12756 * @type {string?}
12757 */
12758 let action = null;
12759 /**
12760 * @type {Object<string,any>}
12761 */
12762 const attributes = {}; // counts added or removed new attributes for retain
12763 /**
12764 * @type {string|object}
12765 */
12766 let insert = '';
12767 let retain = 0;
12768 let deleteLen = 0;
12769 const addOp = () => {
12770 if (action !== null) {
12771 /**
12772 * @type {any}
12773 */
12774 let op = null;
12775 switch (action) {
12776 case 'delete':
12777 if (deleteLen > 0) {
12778 op = { delete: deleteLen };
12779 }
12780 deleteLen = 0;
12781 break
12782 case 'insert':
12783 if (typeof insert === 'object' || insert.length > 0) {
12784 op = { insert };
12785 if (currentAttributes.size > 0) {
12786 op.attributes = {};
12787 currentAttributes.forEach((value, key) => {
12788 if (value !== null) {
12789 op.attributes[key] = value;
12790 }
12791 });
12792 }
12793 }
12794 insert = '';
12795 break
12796 case 'retain':
12797 if (retain > 0) {
12798 op = { retain };
12799 if (!isEmpty(attributes)) {
12800 op.attributes = object_assign({}, attributes);
12801 }
12802 }
12803 retain = 0;
12804 break
12805 }
12806 if (op) delta.push(op);
12807 action = null;
12808 }
12809 };
12810 while (item !== null) {
12811 switch (item.content.constructor) {
12812 case ContentType:
12813 case ContentEmbed:
12814 if (this.adds(item)) {
12815 if (!this.deletes(item)) {
12816 addOp();
12817 action = 'insert';
12818 insert = item.content.getContent()[0];
12819 addOp();
12820 }
12821 } else if (this.deletes(item)) {
12822 if (action !== 'delete') {
12823 addOp();
12824 action = 'delete';
12825 }
12826 deleteLen += 1;
12827 } else if (!item.deleted) {
12828 if (action !== 'retain') {
12829 addOp();
12830 action = 'retain';
12831 }
12832 retain += 1;
12833 }
12834 break
12835 case ContentString:
12836 if (this.adds(item)) {
12837 if (!this.deletes(item)) {
12838 if (action !== 'insert') {
12839 addOp();
12840 action = 'insert';
12841 }
12842 insert += /** @type {ContentString} */ (item.content).str;
12843 }
12844 } else if (this.deletes(item)) {
12845 if (action !== 'delete') {
12846 addOp();
12847 action = 'delete';
12848 }
12849 deleteLen += item.length;
12850 } else if (!item.deleted) {
12851 if (action !== 'retain') {
12852 addOp();
12853 action = 'retain';
12854 }
12855 retain += item.length;
12856 }
12857 break
12858 case ContentFormat: {
12859 const { key, value } = /** @type {ContentFormat} */ (item.content);
12860 if (this.adds(item)) {
12861 if (!this.deletes(item)) {
12862 const curVal = currentAttributes.get(key) || null;
12863 if (!equalAttrs(curVal, value)) {
12864 if (action === 'retain') {
12865 addOp();
12866 }
12867 if (equalAttrs(value, (oldAttributes.get(key) || null))) {
12868 delete attributes[key];
12869 } else {
12870 attributes[key] = value;
12871 }
12872 } else if (value !== null) {
12873 item.delete(transaction);
12874 }
12875 }
12876 } else if (this.deletes(item)) {
12877 oldAttributes.set(key, value);
12878 const curVal = currentAttributes.get(key) || null;
12879 if (!equalAttrs(curVal, value)) {
12880 if (action === 'retain') {
12881 addOp();
12882 }
12883 attributes[key] = curVal;
12884 }
12885 } else if (!item.deleted) {
12886 oldAttributes.set(key, value);
12887 const attr = attributes[key];
12888 if (attr !== undefined) {
12889 if (!equalAttrs(attr, value)) {
12890 if (action === 'retain') {
12891 addOp();
12892 }
12893 if (value === null) {
12894 delete attributes[key];
12895 } else {
12896 attributes[key] = value;
12897 }
12898 } else if (attr !== null) { // this will be cleaned up automatically by the contextless cleanup function
12899 item.delete(transaction);
12900 }
12901 }
12902 }
12903 if (!item.deleted) {
12904 if (action === 'insert') {
12905 addOp();
12906 }
12907 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (item.content));
12908 }
12909 break
12910 }
12911 }
12912 item = item.right;
12913 }
12914 addOp();
12915 while (delta.length > 0) {
12916 const lastOp = delta[delta.length - 1];
12917 if (lastOp.retain !== undefined && lastOp.attributes === undefined) {
12918 // retain delta's if they don't assign attributes
12919 delta.pop();
12920 } else {
12921 break
12922 }
12923 }
12924 });
12925 this._delta = delta;
12926 }
12927 return /** @type {any} */ (this._delta)
12928 }
12929 }
12930
12931 /**
12932 * Type that represents text with formatting information.
12933 *
12934 * This type replaces y-richtext as this implementation is able to handle
12935 * block formats (format information on a paragraph), embeds (complex elements
12936 * like pictures and videos), and text formats (**bold**, *italic*).
12937 *
12938 * @extends AbstractType<YTextEvent>
12939 */
12940 class YText extends AbstractType {
12941 /**
12942 * @param {String} [string] The initial value of the YText.
12943 */
12944 constructor (string) {
12945 super();
12946 /**
12947 * Array of pending operations on this type
12948 * @type {Array<function():void>?}
12949 */
12950 this._pending = string !== undefined ? [() => this.insert(0, string)] : [];
12951 /**
12952 * @type {Array<ArraySearchMarker>|null}
12953 */
12954 this._searchMarker = [];
12955 /**
12956 * Whether this YText contains formatting attributes.
12957 * This flag is updated when a formatting item is integrated (see ContentFormat.integrate)
12958 */
12959 this._hasFormatting = false;
12960 }
12961
12962 /**
12963 * Number of characters of this text type.
12964 *
12965 * @type {number}
12966 */
12967 get length () {
12968 return this._length
12969 }
12970
12971 /**
12972 * @param {Doc} y
12973 * @param {Item} item
12974 */
12975 _integrate (y, item) {
12976 super._integrate(y, item);
12977 try {
12978 /** @type {Array<function>} */ (this._pending).forEach(f => f());
12979 } catch (e) {
12980 console.error(e);
12981 }
12982 this._pending = null;
12983 }
12984
12985 _copy () {
12986 return new YText()
12987 }
12988
12989 /**
12990 * @return {YText}
12991 */
12992 clone () {
12993 const text = new YText();
12994 text.applyDelta(this.toDelta());
12995 return text
12996 }
12997
12998 /**
12999 * Creates YTextEvent and calls observers.
13000 *
13001 * @param {Transaction} transaction
13002 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
13003 */
13004 _callObserver (transaction, parentSubs) {
13005 super._callObserver(transaction, parentSubs);
13006 const event = new YTextEvent(this, transaction, parentSubs);
13007 callTypeObservers(this, transaction, event);
13008 // If a remote change happened, we try to cleanup potential formatting duplicates.
13009 if (!transaction.local && this._hasFormatting) {
13010 transaction._needFormattingCleanup = true;
13011 }
13012 }
13013
13014 /**
13015 * Returns the unformatted string representation of this YText type.
13016 *
13017 * @public
13018 */
13019 toString () {
13020 let str = '';
13021 /**
13022 * @type {Item|null}
13023 */
13024 let n = this._start;
13025 while (n !== null) {
13026 if (!n.deleted && n.countable && n.content.constructor === ContentString) {
13027 str += /** @type {ContentString} */ (n.content).str;
13028 }
13029 n = n.right;
13030 }
13031 return str
13032 }
13033
13034 /**
13035 * Returns the unformatted string representation of this YText type.
13036 *
13037 * @return {string}
13038 * @public
13039 */
13040 toJSON () {
13041 return this.toString()
13042 }
13043
13044 /**
13045 * Apply a {@link Delta} on this shared YText type.
13046 *
13047 * @param {any} delta The changes to apply on this element.
13048 * @param {object} opts
13049 * @param {boolean} [opts.sanitize] Sanitize input delta. Removes ending newlines if set to true.
13050 *
13051 *
13052 * @public
13053 */
13054 applyDelta (delta, { sanitize = true } = {}) {
13055 if (this.doc !== null) {
13056 transact(this.doc, transaction => {
13057 const currPos = new ItemTextListPosition(null, this._start, 0, new Map());
13058 for (let i = 0; i < delta.length; i++) {
13059 const op = delta[i];
13060 if (op.insert !== undefined) {
13061 // Quill assumes that the content starts with an empty paragraph.
13062 // Yjs/Y.Text assumes that it starts empty. We always hide that
13063 // there is a newline at the end of the content.
13064 // If we omit this step, clients will see a different number of
13065 // paragraphs, but nothing bad will happen.
13066 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;
13067 if (typeof ins !== 'string' || ins.length > 0) {
13068 insertText(transaction, this, currPos, ins, op.attributes || {});
13069 }
13070 } else if (op.retain !== undefined) {
13071 formatText(transaction, this, currPos, op.retain, op.attributes || {});
13072 } else if (op.delete !== undefined) {
13073 deleteText(transaction, currPos, op.delete);
13074 }
13075 }
13076 });
13077 } else {
13078 /** @type {Array<function>} */ (this._pending).push(() => this.applyDelta(delta));
13079 }
13080 }
13081
13082 /**
13083 * Returns the Delta representation of this YText type.
13084 *
13085 * @param {Snapshot} [snapshot]
13086 * @param {Snapshot} [prevSnapshot]
13087 * @param {function('removed' | 'added', ID):any} [computeYChange]
13088 * @return {any} The Delta representation of this type.
13089 *
13090 * @public
13091 */
13092 toDelta (snapshot, prevSnapshot, computeYChange) {
13093 /**
13094 * @type{Array<any>}
13095 */
13096 const ops = [];
13097 const currentAttributes = new Map();
13098 const doc = /** @type {Doc} */ (this.doc);
13099 let str = '';
13100 let n = this._start;
13101 function packStr () {
13102 if (str.length > 0) {
13103 // pack str with attributes to ops
13104 /**
13105 * @type {Object<string,any>}
13106 */
13107 const attributes = {};
13108 let addAttributes = false;
13109 currentAttributes.forEach((value, key) => {
13110 addAttributes = true;
13111 attributes[key] = value;
13112 });
13113 /**
13114 * @type {Object<string,any>}
13115 */
13116 const op = { insert: str };
13117 if (addAttributes) {
13118 op.attributes = attributes;
13119 }
13120 ops.push(op);
13121 str = '';
13122 }
13123 }
13124 const computeDelta = () => {
13125 while (n !== null) {
13126 if (isVisible(n, snapshot) || (prevSnapshot !== undefined && isVisible(n, prevSnapshot))) {
13127 switch (n.content.constructor) {
13128 case ContentString: {
13129 const cur = currentAttributes.get('ychange');
13130 if (snapshot !== undefined && !isVisible(n, snapshot)) {
13131 if (cur === undefined || cur.user !== n.id.client || cur.type !== 'removed') {
13132 packStr();
13133 currentAttributes.set('ychange', computeYChange ? computeYChange('removed', n.id) : { type: 'removed' });
13134 }
13135 } else if (prevSnapshot !== undefined && !isVisible(n, prevSnapshot)) {
13136 if (cur === undefined || cur.user !== n.id.client || cur.type !== 'added') {
13137 packStr();
13138 currentAttributes.set('ychange', computeYChange ? computeYChange('added', n.id) : { type: 'added' });
13139 }
13140 } else if (cur !== undefined) {
13141 packStr();
13142 currentAttributes.delete('ychange');
13143 }
13144 str += /** @type {ContentString} */ (n.content).str;
13145 break
13146 }
13147 case ContentType:
13148 case ContentEmbed: {
13149 packStr();
13150 /**
13151 * @type {Object<string,any>}
13152 */
13153 const op = {
13154 insert: n.content.getContent()[0]
13155 };
13156 if (currentAttributes.size > 0) {
13157 const attrs = /** @type {Object<string,any>} */ ({});
13158 op.attributes = attrs;
13159 currentAttributes.forEach((value, key) => {
13160 attrs[key] = value;
13161 });
13162 }
13163 ops.push(op);
13164 break
13165 }
13166 case ContentFormat:
13167 if (isVisible(n, snapshot)) {
13168 packStr();
13169 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (n.content));
13170 }
13171 break
13172 }
13173 }
13174 n = n.right;
13175 }
13176 packStr();
13177 };
13178 if (snapshot || prevSnapshot) {
13179 // snapshots are merged again after the transaction, so we need to keep the
13180 // transaction alive until we are done
13181 transact(doc, transaction => {
13182 if (snapshot) {
13183 splitSnapshotAffectedStructs(transaction, snapshot);
13184 }
13185 if (prevSnapshot) {
13186 splitSnapshotAffectedStructs(transaction, prevSnapshot);
13187 }
13188 computeDelta();
13189 }, 'cleanup');
13190 } else {
13191 computeDelta();
13192 }
13193 return ops
13194 }
13195
13196 /**
13197 * Insert text at a given index.
13198 *
13199 * @param {number} index The index at which to start inserting.
13200 * @param {String} text The text to insert at the specified position.
13201 * @param {TextAttributes} [attributes] Optionally define some formatting
13202 * information to apply on the inserted
13203 * Text.
13204 * @public
13205 */
13206 insert (index, text, attributes) {
13207 if (text.length <= 0) {
13208 return
13209 }
13210 const y = this.doc;
13211 if (y !== null) {
13212 transact(y, transaction => {
13213 const pos = findPosition(transaction, this, index);
13214 if (!attributes) {
13215 attributes = {};
13216 // @ts-ignore
13217 pos.currentAttributes.forEach((v, k) => { attributes[k] = v; });
13218 }
13219 insertText(transaction, this, pos, text, attributes);
13220 });
13221 } else {
13222 /** @type {Array<function>} */ (this._pending).push(() => this.insert(index, text, attributes));
13223 }
13224 }
13225
13226 /**
13227 * Inserts an embed at a index.
13228 *
13229 * @param {number} index The index to insert the embed at.
13230 * @param {Object | AbstractType<any>} embed The Object that represents the embed.
13231 * @param {TextAttributes} attributes Attribute information to apply on the
13232 * embed
13233 *
13234 * @public
13235 */
13236 insertEmbed (index, embed, attributes = {}) {
13237 const y = this.doc;
13238 if (y !== null) {
13239 transact(y, transaction => {
13240 const pos = findPosition(transaction, this, index);
13241 insertText(transaction, this, pos, embed, attributes);
13242 });
13243 } else {
13244 /** @type {Array<function>} */ (this._pending).push(() => this.insertEmbed(index, embed, attributes));
13245 }
13246 }
13247
13248 /**
13249 * Deletes text starting from an index.
13250 *
13251 * @param {number} index Index at which to start deleting.
13252 * @param {number} length The number of characters to remove. Defaults to 1.
13253 *
13254 * @public
13255 */
13256 delete (index, length) {
13257 if (length === 0) {
13258 return
13259 }
13260 const y = this.doc;
13261 if (y !== null) {
13262 transact(y, transaction => {
13263 deleteText(transaction, findPosition(transaction, this, index), length);
13264 });
13265 } else {
13266 /** @type {Array<function>} */ (this._pending).push(() => this.delete(index, length));
13267 }
13268 }
13269
13270 /**
13271 * Assigns properties to a range of text.
13272 *
13273 * @param {number} index The position where to start formatting.
13274 * @param {number} length The amount of characters to assign properties to.
13275 * @param {TextAttributes} attributes Attribute information to apply on the
13276 * text.
13277 *
13278 * @public
13279 */
13280 format (index, length, attributes) {
13281 if (length === 0) {
13282 return
13283 }
13284 const y = this.doc;
13285 if (y !== null) {
13286 transact(y, transaction => {
13287 const pos = findPosition(transaction, this, index);
13288 if (pos.right === null) {
13289 return
13290 }
13291 formatText(transaction, this, pos, length, attributes);
13292 });
13293 } else {
13294 /** @type {Array<function>} */ (this._pending).push(() => this.format(index, length, attributes));
13295 }
13296 }
13297
13298 /**
13299 * Removes an attribute.
13300 *
13301 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13302 *
13303 * @param {String} attributeName The attribute name that is to be removed.
13304 *
13305 * @public
13306 */
13307 removeAttribute (attributeName) {
13308 if (this.doc !== null) {
13309 transact(this.doc, transaction => {
13310 typeMapDelete(transaction, this, attributeName);
13311 });
13312 } else {
13313 /** @type {Array<function>} */ (this._pending).push(() => this.removeAttribute(attributeName));
13314 }
13315 }
13316
13317 /**
13318 * Sets or updates an attribute.
13319 *
13320 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13321 *
13322 * @param {String} attributeName The attribute name that is to be set.
13323 * @param {any} attributeValue The attribute value that is to be set.
13324 *
13325 * @public
13326 */
13327 setAttribute (attributeName, attributeValue) {
13328 if (this.doc !== null) {
13329 transact(this.doc, transaction => {
13330 typeMapSet(transaction, this, attributeName, attributeValue);
13331 });
13332 } else {
13333 /** @type {Array<function>} */ (this._pending).push(() => this.setAttribute(attributeName, attributeValue));
13334 }
13335 }
13336
13337 /**
13338 * Returns an attribute value that belongs to the attribute name.
13339 *
13340 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13341 *
13342 * @param {String} attributeName The attribute name that identifies the
13343 * queried value.
13344 * @return {any} The queried attribute value.
13345 *
13346 * @public
13347 */
13348 getAttribute (attributeName) {
13349 return /** @type {any} */ (typeMapGet(this, attributeName))
13350 }
13351
13352 /**
13353 * Returns all attribute name/value pairs in a JSON Object.
13354 *
13355 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13356 *
13357 * @return {Object<string, any>} A JSON Object that describes the attributes.
13358 *
13359 * @public
13360 */
13361 getAttributes () {
13362 return typeMapGetAll(this)
13363 }
13364
13365 /**
13366 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
13367 */
13368 _write (encoder) {
13369 encoder.writeTypeRef(YTextRefID);
13370 }
13371 }
13372
13373 /**
13374 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
13375 * @return {YText}
13376 *
13377 * @private
13378 * @function
13379 */
13380 const readYText = _decoder => new YText();
13381
13382 /**
13383 * @module YXml
13384 */
13385
13386 /**
13387 * Define the elements to which a set of CSS queries apply.
13388 * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors}
13389 *
13390 * @example
13391 * query = '.classSelector'
13392 * query = 'nodeSelector'
13393 * query = '#idSelector'
13394 *
13395 * @typedef {string} CSS_Selector
13396 */
13397
13398 /**
13399 * Dom filter function.
13400 *
13401 * @callback domFilter
13402 * @param {string} nodeName The nodeName of the element
13403 * @param {Map} attributes The map of attributes.
13404 * @return {boolean} Whether to include the Dom node in the YXmlElement.
13405 */
13406
13407 /**
13408 * Represents a subset of the nodes of a YXmlElement / YXmlFragment and a
13409 * position within them.
13410 *
13411 * Can be created with {@link YXmlFragment#createTreeWalker}
13412 *
13413 * @public
13414 * @implements {Iterable<YXmlElement|YXmlText|YXmlElement|YXmlHook>}
13415 */
13416 class YXmlTreeWalker {
13417 /**
13418 * @param {YXmlFragment | YXmlElement} root
13419 * @param {function(AbstractType<any>):boolean} [f]
13420 */
13421 constructor (root, f = () => true) {
13422 this._filter = f;
13423 this._root = root;
13424 /**
13425 * @type {Item}
13426 */
13427 this._currentNode = /** @type {Item} */ (root._start);
13428 this._firstCall = true;
13429 }
13430
13431 [Symbol.iterator] () {
13432 return this
13433 }
13434
13435 /**
13436 * Get the next node.
13437 *
13438 * @return {IteratorResult<YXmlElement|YXmlText|YXmlHook>} The next node.
13439 *
13440 * @public
13441 */
13442 next () {
13443 /**
13444 * @type {Item|null}
13445 */
13446 let n = this._currentNode;
13447 let type = n && n.content && /** @type {any} */ (n.content).type;
13448 if (n !== null && (!this._firstCall || n.deleted || !this._filter(type))) { // if first call, we check if we can use the first item
13449 do {
13450 type = /** @type {any} */ (n.content).type;
13451 if (!n.deleted && (type.constructor === YXmlElement || type.constructor === YXmlFragment) && type._start !== null) {
13452 // walk down in the tree
13453 n = type._start;
13454 } else {
13455 // walk right or up in the tree
13456 while (n !== null) {
13457 if (n.right !== null) {
13458 n = n.right;
13459 break
13460 } else if (n.parent === this._root) {
13461 n = null;
13462 } else {
13463 n = /** @type {AbstractType<any>} */ (n.parent)._item;
13464 }
13465 }
13466 }
13467 } while (n !== null && (n.deleted || !this._filter(/** @type {ContentType} */ (n.content).type)))
13468 }
13469 this._firstCall = false;
13470 if (n === null) {
13471 // @ts-ignore
13472 return { value: undefined, done: true }
13473 }
13474 this._currentNode = n;
13475 return { value: /** @type {any} */ (n.content).type, done: false }
13476 }
13477 }
13478
13479 /**
13480 * Represents a list of {@link YXmlElement}.and {@link YXmlText} types.
13481 * A YxmlFragment is similar to a {@link YXmlElement}, but it does not have a
13482 * nodeName and it does not have attributes. Though it can be bound to a DOM
13483 * element - in this case the attributes and the nodeName are not shared.
13484 *
13485 * @public
13486 * @extends AbstractType<YXmlEvent>
13487 */
13488 class YXmlFragment extends AbstractType {
13489 constructor () {
13490 super();
13491 /**
13492 * @type {Array<any>|null}
13493 */
13494 this._prelimContent = [];
13495 }
13496
13497 /**
13498 * @type {YXmlElement|YXmlText|null}
13499 */
13500 get firstChild () {
13501 const first = this._first;
13502 return first ? first.content.getContent()[0] : null
13503 }
13504
13505 /**
13506 * Integrate this type into the Yjs instance.
13507 *
13508 * * Save this struct in the os
13509 * * This type is sent to other client
13510 * * Observer functions are fired
13511 *
13512 * @param {Doc} y The Yjs instance
13513 * @param {Item} item
13514 */
13515 _integrate (y, item) {
13516 super._integrate(y, item);
13517 this.insert(0, /** @type {Array<any>} */ (this._prelimContent));
13518 this._prelimContent = null;
13519 }
13520
13521 _copy () {
13522 return new YXmlFragment()
13523 }
13524
13525 /**
13526 * @return {YXmlFragment}
13527 */
13528 clone () {
13529 const el = new YXmlFragment();
13530 // @ts-ignore
13531 el.insert(0, this.toArray().map(item => item instanceof AbstractType ? item.clone() : item));
13532 return el
13533 }
13534
13535 get length () {
13536 return this._prelimContent === null ? this._length : this._prelimContent.length
13537 }
13538
13539 /**
13540 * Create a subtree of childNodes.
13541 *
13542 * @example
13543 * const walker = elem.createTreeWalker(dom => dom.nodeName === 'div')
13544 * for (let node in walker) {
13545 * // `node` is a div node
13546 * nop(node)
13547 * }
13548 *
13549 * @param {function(AbstractType<any>):boolean} filter Function that is called on each child element and
13550 * returns a Boolean indicating whether the child
13551 * is to be included in the subtree.
13552 * @return {YXmlTreeWalker} A subtree and a position within it.
13553 *
13554 * @public
13555 */
13556 createTreeWalker (filter) {
13557 return new YXmlTreeWalker(this, filter)
13558 }
13559
13560 /**
13561 * Returns the first YXmlElement that matches the query.
13562 * Similar to DOM's {@link querySelector}.
13563 *
13564 * Query support:
13565 * - tagname
13566 * TODO:
13567 * - id
13568 * - attribute
13569 *
13570 * @param {CSS_Selector} query The query on the children.
13571 * @return {YXmlElement|YXmlText|YXmlHook|null} The first element that matches the query or null.
13572 *
13573 * @public
13574 */
13575 querySelector (query) {
13576 query = query.toUpperCase();
13577 // @ts-ignore
13578 const iterator = new YXmlTreeWalker(this, element => element.nodeName && element.nodeName.toUpperCase() === query);
13579 const next = iterator.next();
13580 if (next.done) {
13581 return null
13582 } else {
13583 return next.value
13584 }
13585 }
13586
13587 /**
13588 * Returns all YXmlElements that match the query.
13589 * Similar to Dom's {@link querySelectorAll}.
13590 *
13591 * @todo Does not yet support all queries. Currently only query by tagName.
13592 *
13593 * @param {CSS_Selector} query The query on the children
13594 * @return {Array<YXmlElement|YXmlText|YXmlHook|null>} The elements that match this query.
13595 *
13596 * @public
13597 */
13598 querySelectorAll (query) {
13599 query = query.toUpperCase();
13600 // @ts-ignore
13601 return array_from(new YXmlTreeWalker(this, element => element.nodeName && element.nodeName.toUpperCase() === query))
13602 }
13603
13604 /**
13605 * Creates YXmlEvent and calls observers.
13606 *
13607 * @param {Transaction} transaction
13608 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
13609 */
13610 _callObserver (transaction, parentSubs) {
13611 callTypeObservers(this, transaction, new YXmlEvent(this, parentSubs, transaction));
13612 }
13613
13614 /**
13615 * Get the string representation of all the children of this YXmlFragment.
13616 *
13617 * @return {string} The string representation of all children.
13618 */
13619 toString () {
13620 return typeListMap(this, xml => xml.toString()).join('')
13621 }
13622
13623 /**
13624 * @return {string}
13625 */
13626 toJSON () {
13627 return this.toString()
13628 }
13629
13630 /**
13631 * Creates a Dom Element that mirrors this YXmlElement.
13632 *
13633 * @param {Document} [_document=document] The document object (you must define
13634 * this when calling this method in
13635 * nodejs)
13636 * @param {Object<string, any>} [hooks={}] Optional property to customize how hooks
13637 * are presented in the DOM
13638 * @param {any} [binding] You should not set this property. This is
13639 * used if DomBinding wants to create a
13640 * association to the created DOM type.
13641 * @return {Node} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
13642 *
13643 * @public
13644 */
13645 toDOM (_document = document, hooks = {}, binding) {
13646 const fragment = _document.createDocumentFragment();
13647 if (binding !== undefined) {
13648 binding._createAssociation(fragment, this);
13649 }
13650 typeListForEach(this, xmlType => {
13651 fragment.insertBefore(xmlType.toDOM(_document, hooks, binding), null);
13652 });
13653 return fragment
13654 }
13655
13656 /**
13657 * Inserts new content at an index.
13658 *
13659 * @example
13660 * // Insert character 'a' at position 0
13661 * xml.insert(0, [new Y.XmlText('text')])
13662 *
13663 * @param {number} index The index to insert content at
13664 * @param {Array<YXmlElement|YXmlText>} content The array of content
13665 */
13666 insert (index, content) {
13667 if (this.doc !== null) {
13668 transact(this.doc, transaction => {
13669 typeListInsertGenerics(transaction, this, index, content);
13670 });
13671 } else {
13672 // @ts-ignore _prelimContent is defined because this is not yet integrated
13673 this._prelimContent.splice(index, 0, ...content);
13674 }
13675 }
13676
13677 /**
13678 * Inserts new content at an index.
13679 *
13680 * @example
13681 * // Insert character 'a' at position 0
13682 * xml.insert(0, [new Y.XmlText('text')])
13683 *
13684 * @param {null|Item|YXmlElement|YXmlText} ref The index to insert content at
13685 * @param {Array<YXmlElement|YXmlText>} content The array of content
13686 */
13687 insertAfter (ref, content) {
13688 if (this.doc !== null) {
13689 transact(this.doc, transaction => {
13690 const refItem = (ref && ref instanceof AbstractType) ? ref._item : ref;
13691 typeListInsertGenericsAfter(transaction, this, refItem, content);
13692 });
13693 } else {
13694 const pc = /** @type {Array<any>} */ (this._prelimContent);
13695 const index = ref === null ? 0 : pc.findIndex(el => el === ref) + 1;
13696 if (index === 0 && ref !== null) {
13697 throw error_create('Reference item not found')
13698 }
13699 pc.splice(index, 0, ...content);
13700 }
13701 }
13702
13703 /**
13704 * Deletes elements starting from an index.
13705 *
13706 * @param {number} index Index at which to start deleting elements
13707 * @param {number} [length=1] The number of elements to remove. Defaults to 1.
13708 */
13709 delete (index, length = 1) {
13710 if (this.doc !== null) {
13711 transact(this.doc, transaction => {
13712 typeListDelete(transaction, this, index, length);
13713 });
13714 } else {
13715 // @ts-ignore _prelimContent is defined because this is not yet integrated
13716 this._prelimContent.splice(index, length);
13717 }
13718 }
13719
13720 /**
13721 * Transforms this YArray to a JavaScript Array.
13722 *
13723 * @return {Array<YXmlElement|YXmlText|YXmlHook>}
13724 */
13725 toArray () {
13726 return typeListToArray(this)
13727 }
13728
13729 /**
13730 * Appends content to this YArray.
13731 *
13732 * @param {Array<YXmlElement|YXmlText>} content Array of content to append.
13733 */
13734 push (content) {
13735 this.insert(this.length, content);
13736 }
13737
13738 /**
13739 * Preppends content to this YArray.
13740 *
13741 * @param {Array<YXmlElement|YXmlText>} content Array of content to preppend.
13742 */
13743 unshift (content) {
13744 this.insert(0, content);
13745 }
13746
13747 /**
13748 * Returns the i-th element from a YArray.
13749 *
13750 * @param {number} index The index of the element to return from the YArray
13751 * @return {YXmlElement|YXmlText}
13752 */
13753 get (index) {
13754 return typeListGet(this, index)
13755 }
13756
13757 /**
13758 * Transforms this YArray to a JavaScript Array.
13759 *
13760 * @param {number} [start]
13761 * @param {number} [end]
13762 * @return {Array<YXmlElement|YXmlText>}
13763 */
13764 slice (start = 0, end = this.length) {
13765 return typeListSlice(this, start, end)
13766 }
13767
13768 /**
13769 * Executes a provided function on once on overy child element.
13770 *
13771 * @param {function(YXmlElement|YXmlText,number, typeof self):void} f A function to execute on every element of this YArray.
13772 */
13773 forEach (f) {
13774 typeListForEach(this, f);
13775 }
13776
13777 /**
13778 * Transform the properties of this type to binary and write it to an
13779 * BinaryEncoder.
13780 *
13781 * This is called when this Item is sent to a remote peer.
13782 *
13783 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
13784 */
13785 _write (encoder) {
13786 encoder.writeTypeRef(YXmlFragmentRefID);
13787 }
13788 }
13789
13790 /**
13791 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
13792 * @return {YXmlFragment}
13793 *
13794 * @private
13795 * @function
13796 */
13797 const readYXmlFragment = _decoder => new YXmlFragment();
13798
13799 /**
13800 * @typedef {Object|number|null|Array<any>|string|Uint8Array|AbstractType<any>} ValueTypes
13801 */
13802
13803 /**
13804 * An YXmlElement imitates the behavior of a
13805 * {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}.
13806 *
13807 * * An YXmlElement has attributes (key value pairs)
13808 * * An YXmlElement has childElements that must inherit from YXmlElement
13809 *
13810 * @template {{ [key: string]: ValueTypes }} [KV={ [key: string]: string }]
13811 */
13812 class YXmlElement extends YXmlFragment {
13813 constructor (nodeName = 'UNDEFINED') {
13814 super();
13815 this.nodeName = nodeName;
13816 /**
13817 * @type {Map<string, any>|null}
13818 */
13819 this._prelimAttrs = new Map();
13820 }
13821
13822 /**
13823 * @type {YXmlElement|YXmlText|null}
13824 */
13825 get nextSibling () {
13826 const n = this._item ? this._item.next : null;
13827 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
13828 }
13829
13830 /**
13831 * @type {YXmlElement|YXmlText|null}
13832 */
13833 get prevSibling () {
13834 const n = this._item ? this._item.prev : null;
13835 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
13836 }
13837
13838 /**
13839 * Integrate this type into the Yjs instance.
13840 *
13841 * * Save this struct in the os
13842 * * This type is sent to other client
13843 * * Observer functions are fired
13844 *
13845 * @param {Doc} y The Yjs instance
13846 * @param {Item} item
13847 */
13848 _integrate (y, item) {
13849 super._integrate(y, item)
13850 ;(/** @type {Map<string, any>} */ (this._prelimAttrs)).forEach((value, key) => {
13851 this.setAttribute(key, value);
13852 });
13853 this._prelimAttrs = null;
13854 }
13855
13856 /**
13857 * Creates an Item with the same effect as this Item (without position effect)
13858 *
13859 * @return {YXmlElement}
13860 */
13861 _copy () {
13862 return new YXmlElement(this.nodeName)
13863 }
13864
13865 /**
13866 * @return {YXmlElement<KV>}
13867 */
13868 clone () {
13869 /**
13870 * @type {YXmlElement<KV>}
13871 */
13872 const el = new YXmlElement(this.nodeName);
13873 const attrs = this.getAttributes();
13874 forEach(attrs, (value, key) => {
13875 if (typeof value === 'string') {
13876 el.setAttribute(key, value);
13877 }
13878 });
13879 // @ts-ignore
13880 el.insert(0, this.toArray().map(item => item instanceof AbstractType ? item.clone() : item));
13881 return el
13882 }
13883
13884 /**
13885 * Returns the XML serialization of this YXmlElement.
13886 * The attributes are ordered by attribute-name, so you can easily use this
13887 * method to compare YXmlElements
13888 *
13889 * @return {string} The string representation of this type.
13890 *
13891 * @public
13892 */
13893 toString () {
13894 const attrs = this.getAttributes();
13895 const stringBuilder = [];
13896 const keys = [];
13897 for (const key in attrs) {
13898 keys.push(key);
13899 }
13900 keys.sort();
13901 const keysLen = keys.length;
13902 for (let i = 0; i < keysLen; i++) {
13903 const key = keys[i];
13904 stringBuilder.push(key + '="' + attrs[key] + '"');
13905 }
13906 const nodeName = this.nodeName.toLocaleLowerCase();
13907 const attrsString = stringBuilder.length > 0 ? ' ' + stringBuilder.join(' ') : '';
13908 return `<${nodeName}${attrsString}>${super.toString()}</${nodeName}>`
13909 }
13910
13911 /**
13912 * Removes an attribute from this YXmlElement.
13913 *
13914 * @param {string} attributeName The attribute name that is to be removed.
13915 *
13916 * @public
13917 */
13918 removeAttribute (attributeName) {
13919 if (this.doc !== null) {
13920 transact(this.doc, transaction => {
13921 typeMapDelete(transaction, this, attributeName);
13922 });
13923 } else {
13924 /** @type {Map<string,any>} */ (this._prelimAttrs).delete(attributeName);
13925 }
13926 }
13927
13928 /**
13929 * Sets or updates an attribute.
13930 *
13931 * @template {keyof KV & string} KEY
13932 *
13933 * @param {KEY} attributeName The attribute name that is to be set.
13934 * @param {KV[KEY]} attributeValue The attribute value that is to be set.
13935 *
13936 * @public
13937 */
13938 setAttribute (attributeName, attributeValue) {
13939 if (this.doc !== null) {
13940 transact(this.doc, transaction => {
13941 typeMapSet(transaction, this, attributeName, attributeValue);
13942 });
13943 } else {
13944 /** @type {Map<string, any>} */ (this._prelimAttrs).set(attributeName, attributeValue);
13945 }
13946 }
13947
13948 /**
13949 * Returns an attribute value that belongs to the attribute name.
13950 *
13951 * @template {keyof KV & string} KEY
13952 *
13953 * @param {KEY} attributeName The attribute name that identifies the
13954 * queried value.
13955 * @return {KV[KEY]|undefined} The queried attribute value.
13956 *
13957 * @public
13958 */
13959 getAttribute (attributeName) {
13960 return /** @type {any} */ (typeMapGet(this, attributeName))
13961 }
13962
13963 /**
13964 * Returns whether an attribute exists
13965 *
13966 * @param {string} attributeName The attribute name to check for existence.
13967 * @return {boolean} whether the attribute exists.
13968 *
13969 * @public
13970 */
13971 hasAttribute (attributeName) {
13972 return /** @type {any} */ (typeMapHas(this, attributeName))
13973 }
13974
13975 /**
13976 * Returns all attribute name/value pairs in a JSON Object.
13977 *
13978 * @return {{ [Key in Extract<keyof KV,string>]?: KV[Key]}} A JSON Object that describes the attributes.
13979 *
13980 * @public
13981 */
13982 getAttributes () {
13983 return /** @type {any} */ (typeMapGetAll(this))
13984 }
13985
13986 /**
13987 * Creates a Dom Element that mirrors this YXmlElement.
13988 *
13989 * @param {Document} [_document=document] The document object (you must define
13990 * this when calling this method in
13991 * nodejs)
13992 * @param {Object<string, any>} [hooks={}] Optional property to customize how hooks
13993 * are presented in the DOM
13994 * @param {any} [binding] You should not set this property. This is
13995 * used if DomBinding wants to create a
13996 * association to the created DOM type.
13997 * @return {Node} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
13998 *
13999 * @public
14000 */
14001 toDOM (_document = document, hooks = {}, binding) {
14002 const dom = _document.createElement(this.nodeName);
14003 const attrs = this.getAttributes();
14004 for (const key in attrs) {
14005 const value = attrs[key];
14006 if (typeof value === 'string') {
14007 dom.setAttribute(key, value);
14008 }
14009 }
14010 typeListForEach(this, yxml => {
14011 dom.appendChild(yxml.toDOM(_document, hooks, binding));
14012 });
14013 if (binding !== undefined) {
14014 binding._createAssociation(dom, this);
14015 }
14016 return dom
14017 }
14018
14019 /**
14020 * Transform the properties of this type to binary and write it to an
14021 * BinaryEncoder.
14022 *
14023 * This is called when this Item is sent to a remote peer.
14024 *
14025 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
14026 */
14027 _write (encoder) {
14028 encoder.writeTypeRef(YXmlElementRefID);
14029 encoder.writeKey(this.nodeName);
14030 }
14031 }
14032
14033 /**
14034 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14035 * @return {YXmlElement}
14036 *
14037 * @function
14038 */
14039 const readYXmlElement = decoder => new YXmlElement(decoder.readKey());
14040
14041 /**
14042 * @extends YEvent<YXmlElement|YXmlText|YXmlFragment>
14043 * An Event that describes changes on a YXml Element or Yxml Fragment
14044 */
14045 class YXmlEvent extends YEvent {
14046 /**
14047 * @param {YXmlElement|YXmlText|YXmlFragment} target The target on which the event is created.
14048 * @param {Set<string|null>} subs The set of changed attributes. `null` is included if the
14049 * child list changed.
14050 * @param {Transaction} transaction The transaction instance with wich the
14051 * change was created.
14052 */
14053 constructor (target, subs, transaction) {
14054 super(target, transaction);
14055 /**
14056 * Whether the children changed.
14057 * @type {Boolean}
14058 * @private
14059 */
14060 this.childListChanged = false;
14061 /**
14062 * Set of all changed attributes.
14063 * @type {Set<string>}
14064 */
14065 this.attributesChanged = new Set();
14066 subs.forEach((sub) => {
14067 if (sub === null) {
14068 this.childListChanged = true;
14069 } else {
14070 this.attributesChanged.add(sub);
14071 }
14072 });
14073 }
14074 }
14075
14076 /**
14077 * You can manage binding to a custom type with YXmlHook.
14078 *
14079 * @extends {YMap<any>}
14080 */
14081 class YXmlHook extends YMap {
14082 /**
14083 * @param {string} hookName nodeName of the Dom Node.
14084 */
14085 constructor (hookName) {
14086 super();
14087 /**
14088 * @type {string}
14089 */
14090 this.hookName = hookName;
14091 }
14092
14093 /**
14094 * Creates an Item with the same effect as this Item (without position effect)
14095 */
14096 _copy () {
14097 return new YXmlHook(this.hookName)
14098 }
14099
14100 /**
14101 * @return {YXmlHook}
14102 */
14103 clone () {
14104 const el = new YXmlHook(this.hookName);
14105 this.forEach((value, key) => {
14106 el.set(key, value);
14107 });
14108 return el
14109 }
14110
14111 /**
14112 * Creates a Dom Element that mirrors this YXmlElement.
14113 *
14114 * @param {Document} [_document=document] The document object (you must define
14115 * this when calling this method in
14116 * nodejs)
14117 * @param {Object.<string, any>} [hooks] Optional property to customize how hooks
14118 * are presented in the DOM
14119 * @param {any} [binding] You should not set this property. This is
14120 * used if DomBinding wants to create a
14121 * association to the created DOM type
14122 * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
14123 *
14124 * @public
14125 */
14126 toDOM (_document = document, hooks = {}, binding) {
14127 const hook = hooks[this.hookName];
14128 let dom;
14129 if (hook !== undefined) {
14130 dom = hook.createDom(this);
14131 } else {
14132 dom = document.createElement(this.hookName);
14133 }
14134 dom.setAttribute('data-yjs-hook', this.hookName);
14135 if (binding !== undefined) {
14136 binding._createAssociation(dom, this);
14137 }
14138 return dom
14139 }
14140
14141 /**
14142 * Transform the properties of this type to binary and write it to an
14143 * BinaryEncoder.
14144 *
14145 * This is called when this Item is sent to a remote peer.
14146 *
14147 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
14148 */
14149 _write (encoder) {
14150 encoder.writeTypeRef(YXmlHookRefID);
14151 encoder.writeKey(this.hookName);
14152 }
14153 }
14154
14155 /**
14156 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14157 * @return {YXmlHook}
14158 *
14159 * @private
14160 * @function
14161 */
14162 const readYXmlHook = decoder =>
14163 new YXmlHook(decoder.readKey());
14164
14165 /**
14166 * Represents text in a Dom Element. In the future this type will also handle
14167 * simple formatting information like bold and italic.
14168 */
14169 class YXmlText extends YText {
14170 /**
14171 * @type {YXmlElement|YXmlText|null}
14172 */
14173 get nextSibling () {
14174 const n = this._item ? this._item.next : null;
14175 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
14176 }
14177
14178 /**
14179 * @type {YXmlElement|YXmlText|null}
14180 */
14181 get prevSibling () {
14182 const n = this._item ? this._item.prev : null;
14183 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
14184 }
14185
14186 _copy () {
14187 return new YXmlText()
14188 }
14189
14190 /**
14191 * @return {YXmlText}
14192 */
14193 clone () {
14194 const text = new YXmlText();
14195 text.applyDelta(this.toDelta());
14196 return text
14197 }
14198
14199 /**
14200 * Creates a Dom Element that mirrors this YXmlText.
14201 *
14202 * @param {Document} [_document=document] The document object (you must define
14203 * this when calling this method in
14204 * nodejs)
14205 * @param {Object<string, any>} [hooks] Optional property to customize how hooks
14206 * are presented in the DOM
14207 * @param {any} [binding] You should not set this property. This is
14208 * used if DomBinding wants to create a
14209 * association to the created DOM type.
14210 * @return {Text} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
14211 *
14212 * @public
14213 */
14214 toDOM (_document = document, hooks, binding) {
14215 const dom = _document.createTextNode(this.toString());
14216 if (binding !== undefined) {
14217 binding._createAssociation(dom, this);
14218 }
14219 return dom
14220 }
14221
14222 toString () {
14223 // @ts-ignore
14224 return this.toDelta().map(delta => {
14225 const nestedNodes = [];
14226 for (const nodeName in delta.attributes) {
14227 const attrs = [];
14228 for (const key in delta.attributes[nodeName]) {
14229 attrs.push({ key, value: delta.attributes[nodeName][key] });
14230 }
14231 // sort attributes to get a unique order
14232 attrs.sort((a, b) => a.key < b.key ? -1 : 1);
14233 nestedNodes.push({ nodeName, attrs });
14234 }
14235 // sort node order to get a unique order
14236 nestedNodes.sort((a, b) => a.nodeName < b.nodeName ? -1 : 1);
14237 // now convert to dom string
14238 let str = '';
14239 for (let i = 0; i < nestedNodes.length; i++) {
14240 const node = nestedNodes[i];
14241 str += `<${node.nodeName}`;
14242 for (let j = 0; j < node.attrs.length; j++) {
14243 const attr = node.attrs[j];
14244 str += ` ${attr.key}="${attr.value}"`;
14245 }
14246 str += '>';
14247 }
14248 str += delta.insert;
14249 for (let i = nestedNodes.length - 1; i >= 0; i--) {
14250 str += `</${nestedNodes[i].nodeName}>`;
14251 }
14252 return str
14253 }).join('')
14254 }
14255
14256 /**
14257 * @return {string}
14258 */
14259 toJSON () {
14260 return this.toString()
14261 }
14262
14263 /**
14264 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14265 */
14266 _write (encoder) {
14267 encoder.writeTypeRef(YXmlTextRefID);
14268 }
14269 }
14270
14271 /**
14272 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14273 * @return {YXmlText}
14274 *
14275 * @private
14276 * @function
14277 */
14278 const readYXmlText = decoder => new YXmlText();
14279
14280 class AbstractStruct {
14281 /**
14282 * @param {ID} id
14283 * @param {number} length
14284 */
14285 constructor (id, length) {
14286 this.id = id;
14287 this.length = length;
14288 }
14289
14290 /**
14291 * @type {boolean}
14292 */
14293 get deleted () {
14294 throw methodUnimplemented()
14295 }
14296
14297 /**
14298 * Merge this struct with the item to the right.
14299 * This method is already assuming that `this.id.clock + this.length === this.id.clock`.
14300 * Also this method does *not* remove right from StructStore!
14301 * @param {AbstractStruct} right
14302 * @return {boolean} wether this merged with right
14303 */
14304 mergeWith (right) {
14305 return false
14306 }
14307
14308 /**
14309 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
14310 * @param {number} offset
14311 * @param {number} encodingRef
14312 */
14313 write (encoder, offset, encodingRef) {
14314 throw methodUnimplemented()
14315 }
14316
14317 /**
14318 * @param {Transaction} transaction
14319 * @param {number} offset
14320 */
14321 integrate (transaction, offset) {
14322 throw methodUnimplemented()
14323 }
14324 }
14325
14326 const structGCRefNumber = 0;
14327
14328 /**
14329 * @private
14330 */
14331 class GC extends AbstractStruct {
14332 get deleted () {
14333 return true
14334 }
14335
14336 delete () {}
14337
14338 /**
14339 * @param {GC} right
14340 * @return {boolean}
14341 */
14342 mergeWith (right) {
14343 if (this.constructor !== right.constructor) {
14344 return false
14345 }
14346 this.length += right.length;
14347 return true
14348 }
14349
14350 /**
14351 * @param {Transaction} transaction
14352 * @param {number} offset
14353 */
14354 integrate (transaction, offset) {
14355 if (offset > 0) {
14356 this.id.clock += offset;
14357 this.length -= offset;
14358 }
14359 addStruct(transaction.doc.store, this);
14360 }
14361
14362 /**
14363 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14364 * @param {number} offset
14365 */
14366 write (encoder, offset) {
14367 encoder.writeInfo(structGCRefNumber);
14368 encoder.writeLen(this.length - offset);
14369 }
14370
14371 /**
14372 * @param {Transaction} transaction
14373 * @param {StructStore} store
14374 * @return {null | number}
14375 */
14376 getMissing (transaction, store) {
14377 return null
14378 }
14379 }
14380
14381 class ContentBinary {
14382 /**
14383 * @param {Uint8Array} content
14384 */
14385 constructor (content) {
14386 this.content = content;
14387 }
14388
14389 /**
14390 * @return {number}
14391 */
14392 getLength () {
14393 return 1
14394 }
14395
14396 /**
14397 * @return {Array<any>}
14398 */
14399 getContent () {
14400 return [this.content]
14401 }
14402
14403 /**
14404 * @return {boolean}
14405 */
14406 isCountable () {
14407 return true
14408 }
14409
14410 /**
14411 * @return {ContentBinary}
14412 */
14413 copy () {
14414 return new ContentBinary(this.content)
14415 }
14416
14417 /**
14418 * @param {number} offset
14419 * @return {ContentBinary}
14420 */
14421 splice (offset) {
14422 throw methodUnimplemented()
14423 }
14424
14425 /**
14426 * @param {ContentBinary} right
14427 * @return {boolean}
14428 */
14429 mergeWith (right) {
14430 return false
14431 }
14432
14433 /**
14434 * @param {Transaction} transaction
14435 * @param {Item} item
14436 */
14437 integrate (transaction, item) {}
14438 /**
14439 * @param {Transaction} transaction
14440 */
14441 delete (transaction) {}
14442 /**
14443 * @param {StructStore} store
14444 */
14445 gc (store) {}
14446 /**
14447 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14448 * @param {number} offset
14449 */
14450 write (encoder, offset) {
14451 encoder.writeBuf(this.content);
14452 }
14453
14454 /**
14455 * @return {number}
14456 */
14457 getRef () {
14458 return 3
14459 }
14460 }
14461
14462 /**
14463 * @param {UpdateDecoderV1 | UpdateDecoderV2 } decoder
14464 * @return {ContentBinary}
14465 */
14466 const readContentBinary = decoder => new ContentBinary(decoder.readBuf());
14467
14468 class ContentDeleted {
14469 /**
14470 * @param {number} len
14471 */
14472 constructor (len) {
14473 this.len = len;
14474 }
14475
14476 /**
14477 * @return {number}
14478 */
14479 getLength () {
14480 return this.len
14481 }
14482
14483 /**
14484 * @return {Array<any>}
14485 */
14486 getContent () {
14487 return []
14488 }
14489
14490 /**
14491 * @return {boolean}
14492 */
14493 isCountable () {
14494 return false
14495 }
14496
14497 /**
14498 * @return {ContentDeleted}
14499 */
14500 copy () {
14501 return new ContentDeleted(this.len)
14502 }
14503
14504 /**
14505 * @param {number} offset
14506 * @return {ContentDeleted}
14507 */
14508 splice (offset) {
14509 const right = new ContentDeleted(this.len - offset);
14510 this.len = offset;
14511 return right
14512 }
14513
14514 /**
14515 * @param {ContentDeleted} right
14516 * @return {boolean}
14517 */
14518 mergeWith (right) {
14519 this.len += right.len;
14520 return true
14521 }
14522
14523 /**
14524 * @param {Transaction} transaction
14525 * @param {Item} item
14526 */
14527 integrate (transaction, item) {
14528 addToDeleteSet(transaction.deleteSet, item.id.client, item.id.clock, this.len);
14529 item.markDeleted();
14530 }
14531
14532 /**
14533 * @param {Transaction} transaction
14534 */
14535 delete (transaction) {}
14536 /**
14537 * @param {StructStore} store
14538 */
14539 gc (store) {}
14540 /**
14541 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14542 * @param {number} offset
14543 */
14544 write (encoder, offset) {
14545 encoder.writeLen(this.len - offset);
14546 }
14547
14548 /**
14549 * @return {number}
14550 */
14551 getRef () {
14552 return 1
14553 }
14554 }
14555
14556 /**
14557 * @private
14558 *
14559 * @param {UpdateDecoderV1 | UpdateDecoderV2 } decoder
14560 * @return {ContentDeleted}
14561 */
14562 const readContentDeleted = decoder => new ContentDeleted(decoder.readLen());
14563
14564 /**
14565 * @param {string} guid
14566 * @param {Object<string, any>} opts
14567 */
14568 const createDocFromOpts = (guid, opts) => new Doc({ guid, ...opts, shouldLoad: opts.shouldLoad || opts.autoLoad || false });
14569
14570 /**
14571 * @private
14572 */
14573 class ContentDoc {
14574 /**
14575 * @param {Doc} doc
14576 */
14577 constructor (doc) {
14578 if (doc._item) {
14579 console.error('This document was already integrated as a sub-document. You should create a second instance instead with the same guid.');
14580 }
14581 /**
14582 * @type {Doc}
14583 */
14584 this.doc = doc;
14585 /**
14586 * @type {any}
14587 */
14588 const opts = {};
14589 this.opts = opts;
14590 if (!doc.gc) {
14591 opts.gc = false;
14592 }
14593 if (doc.autoLoad) {
14594 opts.autoLoad = true;
14595 }
14596 if (doc.meta !== null) {
14597 opts.meta = doc.meta;
14598 }
14599 }
14600
14601 /**
14602 * @return {number}
14603 */
14604 getLength () {
14605 return 1
14606 }
14607
14608 /**
14609 * @return {Array<any>}
14610 */
14611 getContent () {
14612 return [this.doc]
14613 }
14614
14615 /**
14616 * @return {boolean}
14617 */
14618 isCountable () {
14619 return true
14620 }
14621
14622 /**
14623 * @return {ContentDoc}
14624 */
14625 copy () {
14626 return new ContentDoc(createDocFromOpts(this.doc.guid, this.opts))
14627 }
14628
14629 /**
14630 * @param {number} offset
14631 * @return {ContentDoc}
14632 */
14633 splice (offset) {
14634 throw methodUnimplemented()
14635 }
14636
14637 /**
14638 * @param {ContentDoc} right
14639 * @return {boolean}
14640 */
14641 mergeWith (right) {
14642 return false
14643 }
14644
14645 /**
14646 * @param {Transaction} transaction
14647 * @param {Item} item
14648 */
14649 integrate (transaction, item) {
14650 // this needs to be reflected in doc.destroy as well
14651 this.doc._item = item;
14652 transaction.subdocsAdded.add(this.doc);
14653 if (this.doc.shouldLoad) {
14654 transaction.subdocsLoaded.add(this.doc);
14655 }
14656 }
14657
14658 /**
14659 * @param {Transaction} transaction
14660 */
14661 delete (transaction) {
14662 if (transaction.subdocsAdded.has(this.doc)) {
14663 transaction.subdocsAdded.delete(this.doc);
14664 } else {
14665 transaction.subdocsRemoved.add(this.doc);
14666 }
14667 }
14668
14669 /**
14670 * @param {StructStore} store
14671 */
14672 gc (store) { }
14673
14674 /**
14675 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14676 * @param {number} offset
14677 */
14678 write (encoder, offset) {
14679 encoder.writeString(this.doc.guid);
14680 encoder.writeAny(this.opts);
14681 }
14682
14683 /**
14684 * @return {number}
14685 */
14686 getRef () {
14687 return 9
14688 }
14689 }
14690
14691 /**
14692 * @private
14693 *
14694 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14695 * @return {ContentDoc}
14696 */
14697 const readContentDoc = decoder => new ContentDoc(createDocFromOpts(decoder.readString(), decoder.readAny()));
14698
14699 /**
14700 * @private
14701 */
14702 class ContentEmbed {
14703 /**
14704 * @param {Object} embed
14705 */
14706 constructor (embed) {
14707 this.embed = embed;
14708 }
14709
14710 /**
14711 * @return {number}
14712 */
14713 getLength () {
14714 return 1
14715 }
14716
14717 /**
14718 * @return {Array<any>}
14719 */
14720 getContent () {
14721 return [this.embed]
14722 }
14723
14724 /**
14725 * @return {boolean}
14726 */
14727 isCountable () {
14728 return true
14729 }
14730
14731 /**
14732 * @return {ContentEmbed}
14733 */
14734 copy () {
14735 return new ContentEmbed(this.embed)
14736 }
14737
14738 /**
14739 * @param {number} offset
14740 * @return {ContentEmbed}
14741 */
14742 splice (offset) {
14743 throw methodUnimplemented()
14744 }
14745
14746 /**
14747 * @param {ContentEmbed} right
14748 * @return {boolean}
14749 */
14750 mergeWith (right) {
14751 return false
14752 }
14753
14754 /**
14755 * @param {Transaction} transaction
14756 * @param {Item} item
14757 */
14758 integrate (transaction, item) {}
14759 /**
14760 * @param {Transaction} transaction
14761 */
14762 delete (transaction) {}
14763 /**
14764 * @param {StructStore} store
14765 */
14766 gc (store) {}
14767 /**
14768 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14769 * @param {number} offset
14770 */
14771 write (encoder, offset) {
14772 encoder.writeJSON(this.embed);
14773 }
14774
14775 /**
14776 * @return {number}
14777 */
14778 getRef () {
14779 return 5
14780 }
14781 }
14782
14783 /**
14784 * @private
14785 *
14786 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14787 * @return {ContentEmbed}
14788 */
14789 const readContentEmbed = decoder => new ContentEmbed(decoder.readJSON());
14790
14791 /**
14792 * @private
14793 */
14794 class ContentFormat {
14795 /**
14796 * @param {string} key
14797 * @param {Object} value
14798 */
14799 constructor (key, value) {
14800 this.key = key;
14801 this.value = value;
14802 }
14803
14804 /**
14805 * @return {number}
14806 */
14807 getLength () {
14808 return 1
14809 }
14810
14811 /**
14812 * @return {Array<any>}
14813 */
14814 getContent () {
14815 return []
14816 }
14817
14818 /**
14819 * @return {boolean}
14820 */
14821 isCountable () {
14822 return false
14823 }
14824
14825 /**
14826 * @return {ContentFormat}
14827 */
14828 copy () {
14829 return new ContentFormat(this.key, this.value)
14830 }
14831
14832 /**
14833 * @param {number} _offset
14834 * @return {ContentFormat}
14835 */
14836 splice (_offset) {
14837 throw methodUnimplemented()
14838 }
14839
14840 /**
14841 * @param {ContentFormat} _right
14842 * @return {boolean}
14843 */
14844 mergeWith (_right) {
14845 return false
14846 }
14847
14848 /**
14849 * @param {Transaction} _transaction
14850 * @param {Item} item
14851 */
14852 integrate (_transaction, item) {
14853 // @todo searchmarker are currently unsupported for rich text documents
14854 const p = /** @type {YText} */ (item.parent);
14855 p._searchMarker = null;
14856 p._hasFormatting = true;
14857 }
14858
14859 /**
14860 * @param {Transaction} transaction
14861 */
14862 delete (transaction) {}
14863 /**
14864 * @param {StructStore} store
14865 */
14866 gc (store) {}
14867 /**
14868 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14869 * @param {number} offset
14870 */
14871 write (encoder, offset) {
14872 encoder.writeKey(this.key);
14873 encoder.writeJSON(this.value);
14874 }
14875
14876 /**
14877 * @return {number}
14878 */
14879 getRef () {
14880 return 6
14881 }
14882 }
14883
14884 /**
14885 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14886 * @return {ContentFormat}
14887 */
14888 const readContentFormat = decoder => new ContentFormat(decoder.readKey(), decoder.readJSON());
14889
14890 /**
14891 * @private
14892 */
14893 class ContentJSON {
14894 /**
14895 * @param {Array<any>} arr
14896 */
14897 constructor (arr) {
14898 /**
14899 * @type {Array<any>}
14900 */
14901 this.arr = arr;
14902 }
14903
14904 /**
14905 * @return {number}
14906 */
14907 getLength () {
14908 return this.arr.length
14909 }
14910
14911 /**
14912 * @return {Array<any>}
14913 */
14914 getContent () {
14915 return this.arr
14916 }
14917
14918 /**
14919 * @return {boolean}
14920 */
14921 isCountable () {
14922 return true
14923 }
14924
14925 /**
14926 * @return {ContentJSON}
14927 */
14928 copy () {
14929 return new ContentJSON(this.arr)
14930 }
14931
14932 /**
14933 * @param {number} offset
14934 * @return {ContentJSON}
14935 */
14936 splice (offset) {
14937 const right = new ContentJSON(this.arr.slice(offset));
14938 this.arr = this.arr.slice(0, offset);
14939 return right
14940 }
14941
14942 /**
14943 * @param {ContentJSON} right
14944 * @return {boolean}
14945 */
14946 mergeWith (right) {
14947 this.arr = this.arr.concat(right.arr);
14948 return true
14949 }
14950
14951 /**
14952 * @param {Transaction} transaction
14953 * @param {Item} item
14954 */
14955 integrate (transaction, item) {}
14956 /**
14957 * @param {Transaction} transaction
14958 */
14959 delete (transaction) {}
14960 /**
14961 * @param {StructStore} store
14962 */
14963 gc (store) {}
14964 /**
14965 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14966 * @param {number} offset
14967 */
14968 write (encoder, offset) {
14969 const len = this.arr.length;
14970 encoder.writeLen(len - offset);
14971 for (let i = offset; i < len; i++) {
14972 const c = this.arr[i];
14973 encoder.writeString(c === undefined ? 'undefined' : JSON.stringify(c));
14974 }
14975 }
14976
14977 /**
14978 * @return {number}
14979 */
14980 getRef () {
14981 return 2
14982 }
14983 }
14984
14985 /**
14986 * @private
14987 *
14988 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14989 * @return {ContentJSON}
14990 */
14991 const readContentJSON = decoder => {
14992 const len = decoder.readLen();
14993 const cs = [];
14994 for (let i = 0; i < len; i++) {
14995 const c = decoder.readString();
14996 if (c === 'undefined') {
14997 cs.push(undefined);
14998 } else {
14999 cs.push(JSON.parse(c));
15000 }
15001 }
15002 return new ContentJSON(cs)
15003 };
15004
15005 class ContentAny {
15006 /**
15007 * @param {Array<any>} arr
15008 */
15009 constructor (arr) {
15010 /**
15011 * @type {Array<any>}
15012 */
15013 this.arr = arr;
15014 }
15015
15016 /**
15017 * @return {number}
15018 */
15019 getLength () {
15020 return this.arr.length
15021 }
15022
15023 /**
15024 * @return {Array<any>}
15025 */
15026 getContent () {
15027 return this.arr
15028 }
15029
15030 /**
15031 * @return {boolean}
15032 */
15033 isCountable () {
15034 return true
15035 }
15036
15037 /**
15038 * @return {ContentAny}
15039 */
15040 copy () {
15041 return new ContentAny(this.arr)
15042 }
15043
15044 /**
15045 * @param {number} offset
15046 * @return {ContentAny}
15047 */
15048 splice (offset) {
15049 const right = new ContentAny(this.arr.slice(offset));
15050 this.arr = this.arr.slice(0, offset);
15051 return right
15052 }
15053
15054 /**
15055 * @param {ContentAny} right
15056 * @return {boolean}
15057 */
15058 mergeWith (right) {
15059 this.arr = this.arr.concat(right.arr);
15060 return true
15061 }
15062
15063 /**
15064 * @param {Transaction} transaction
15065 * @param {Item} item
15066 */
15067 integrate (transaction, item) {}
15068 /**
15069 * @param {Transaction} transaction
15070 */
15071 delete (transaction) {}
15072 /**
15073 * @param {StructStore} store
15074 */
15075 gc (store) {}
15076 /**
15077 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
15078 * @param {number} offset
15079 */
15080 write (encoder, offset) {
15081 const len = this.arr.length;
15082 encoder.writeLen(len - offset);
15083 for (let i = offset; i < len; i++) {
15084 const c = this.arr[i];
15085 encoder.writeAny(c);
15086 }
15087 }
15088
15089 /**
15090 * @return {number}
15091 */
15092 getRef () {
15093 return 8
15094 }
15095 }
15096
15097 /**
15098 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
15099 * @return {ContentAny}
15100 */
15101 const readContentAny = decoder => {
15102 const len = decoder.readLen();
15103 const cs = [];
15104 for (let i = 0; i < len; i++) {
15105 cs.push(decoder.readAny());
15106 }
15107 return new ContentAny(cs)
15108 };
15109
15110 /**
15111 * @private
15112 */
15113 class ContentString {
15114 /**
15115 * @param {string} str
15116 */
15117 constructor (str) {
15118 /**
15119 * @type {string}
15120 */
15121 this.str = str;
15122 }
15123
15124 /**
15125 * @return {number}
15126 */
15127 getLength () {
15128 return this.str.length
15129 }
15130
15131 /**
15132 * @return {Array<any>}
15133 */
15134 getContent () {
15135 return this.str.split('')
15136 }
15137
15138 /**
15139 * @return {boolean}
15140 */
15141 isCountable () {
15142 return true
15143 }
15144
15145 /**
15146 * @return {ContentString}
15147 */
15148 copy () {
15149 return new ContentString(this.str)
15150 }
15151
15152 /**
15153 * @param {number} offset
15154 * @return {ContentString}
15155 */
15156 splice (offset) {
15157 const right = new ContentString(this.str.slice(offset));
15158 this.str = this.str.slice(0, offset);
15159
15160 // Prevent encoding invalid documents because of splitting of surrogate pairs: https://github.com/yjs/yjs/issues/248
15161 const firstCharCode = this.str.charCodeAt(offset - 1);
15162 if (firstCharCode >= 0xD800 && firstCharCode <= 0xDBFF) {
15163 // Last character of the left split is the start of a surrogate utf16/ucs2 pair.
15164 // We don't support splitting of surrogate pairs because this may lead to invalid documents.
15165 // Replace the invalid character with a unicode replacement character (� / U+FFFD)
15166 this.str = this.str.slice(0, offset - 1) + '�';
15167 // replace right as well
15168 right.str = '�' + right.str.slice(1);
15169 }
15170 return right
15171 }
15172
15173 /**
15174 * @param {ContentString} right
15175 * @return {boolean}
15176 */
15177 mergeWith (right) {
15178 this.str += right.str;
15179 return true
15180 }
15181
15182 /**
15183 * @param {Transaction} transaction
15184 * @param {Item} item
15185 */
15186 integrate (transaction, item) {}
15187 /**
15188 * @param {Transaction} transaction
15189 */
15190 delete (transaction) {}
15191 /**
15192 * @param {StructStore} store
15193 */
15194 gc (store) {}
15195 /**
15196 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
15197 * @param {number} offset
15198 */
15199 write (encoder, offset) {
15200 encoder.writeString(offset === 0 ? this.str : this.str.slice(offset));
15201 }
15202
15203 /**
15204 * @return {number}
15205 */
15206 getRef () {
15207 return 4
15208 }
15209 }
15210
15211 /**
15212 * @private
15213 *
15214 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
15215 * @return {ContentString}
15216 */
15217 const readContentString = decoder => new ContentString(decoder.readString());
15218
15219 /**
15220 * @type {Array<function(UpdateDecoderV1 | UpdateDecoderV2):AbstractType<any>>}
15221 * @private
15222 */
15223 const typeRefs = [
15224 readYArray,
15225 readYMap,
15226 readYText,
15227 readYXmlElement,
15228 readYXmlFragment,
15229 readYXmlHook,
15230 readYXmlText
15231 ];
15232
15233 const YArrayRefID = 0;
15234 const YMapRefID = 1;
15235 const YTextRefID = 2;
15236 const YXmlElementRefID = 3;
15237 const YXmlFragmentRefID = 4;
15238 const YXmlHookRefID = 5;
15239 const YXmlTextRefID = 6;
15240
15241 /**
15242 * @private
15243 */
15244 class ContentType {
15245 /**
15246 * @param {AbstractType<any>} type
15247 */
15248 constructor (type) {
15249 /**
15250 * @type {AbstractType<any>}
15251 */
15252 this.type = type;
15253 }
15254
15255 /**
15256 * @return {number}
15257 */
15258 getLength () {
15259 return 1
15260 }
15261
15262 /**
15263 * @return {Array<any>}
15264 */
15265 getContent () {
15266 return [this.type]
15267 }
15268
15269 /**
15270 * @return {boolean}
15271 */
15272 isCountable () {
15273 return true
15274 }
15275
15276 /**
15277 * @return {ContentType}
15278 */
15279 copy () {
15280 return new ContentType(this.type._copy())
15281 }
15282
15283 /**
15284 * @param {number} offset
15285 * @return {ContentType}
15286 */
15287 splice (offset) {
15288 throw methodUnimplemented()
15289 }
15290
15291 /**
15292 * @param {ContentType} right
15293 * @return {boolean}
15294 */
15295 mergeWith (right) {
15296 return false
15297 }
15298
15299 /**
15300 * @param {Transaction} transaction
15301 * @param {Item} item
15302 */
15303 integrate (transaction, item) {
15304 this.type._integrate(transaction.doc, item);
15305 }
15306
15307 /**
15308 * @param {Transaction} transaction
15309 */
15310 delete (transaction) {
15311 let item = this.type._start;
15312 while (item !== null) {
15313 if (!item.deleted) {
15314 item.delete(transaction);
15315 } else if (item.id.clock < (transaction.beforeState.get(item.id.client) || 0)) {
15316 // This will be gc'd later and we want to merge it if possible
15317 // We try to merge all deleted items after each transaction,
15318 // but we have no knowledge about that this needs to be merged
15319 // since it is not in transaction.ds. Hence we add it to transaction._mergeStructs
15320 transaction._mergeStructs.push(item);
15321 }
15322 item = item.right;
15323 }
15324 this.type._map.forEach(item => {
15325 if (!item.deleted) {
15326 item.delete(transaction);
15327 } else if (item.id.clock < (transaction.beforeState.get(item.id.client) || 0)) {
15328 // same as above
15329 transaction._mergeStructs.push(item);
15330 }
15331 });
15332 transaction.changed.delete(this.type);
15333 }
15334
15335 /**
15336 * @param {StructStore} store
15337 */
15338 gc (store) {
15339 let item = this.type._start;
15340 while (item !== null) {
15341 item.gc(store, true);
15342 item = item.right;
15343 }
15344 this.type._start = null;
15345 this.type._map.forEach(/** @param {Item | null} item */ (item) => {
15346 while (item !== null) {
15347 item.gc(store, true);
15348 item = item.left;
15349 }
15350 });
15351 this.type._map = new Map();
15352 }
15353
15354 /**
15355 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
15356 * @param {number} offset
15357 */
15358 write (encoder, offset) {
15359 this.type._write(encoder);
15360 }
15361
15362 /**
15363 * @return {number}
15364 */
15365 getRef () {
15366 return 7
15367 }
15368 }
15369
15370 /**
15371 * @private
15372 *
15373 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
15374 * @return {ContentType}
15375 */
15376 const readContentType = decoder => new ContentType(typeRefs[decoder.readTypeRef()](decoder));
15377
15378 /**
15379 * @todo This should return several items
15380 *
15381 * @param {StructStore} store
15382 * @param {ID} id
15383 * @return {{item:Item, diff:number}}
15384 */
15385 const followRedone = (store, id) => {
15386 /**
15387 * @type {ID|null}
15388 */
15389 let nextID = id;
15390 let diff = 0;
15391 let item;
15392 do {
15393 if (diff > 0) {
15394 nextID = createID(nextID.client, nextID.clock + diff);
15395 }
15396 item = getItem(store, nextID);
15397 diff = nextID.clock - item.id.clock;
15398 nextID = item.redone;
15399 } while (nextID !== null && item instanceof Item)
15400 return {
15401 item, diff
15402 }
15403 };
15404
15405 /**
15406 * Make sure that neither item nor any of its parents is ever deleted.
15407 *
15408 * This property does not persist when storing it into a database or when
15409 * sending it to other peers
15410 *
15411 * @param {Item|null} item
15412 * @param {boolean} keep
15413 */
15414 const keepItem = (item, keep) => {
15415 while (item !== null && item.keep !== keep) {
15416 item.keep = keep;
15417 item = /** @type {AbstractType<any>} */ (item.parent)._item;
15418 }
15419 };
15420
15421 /**
15422 * Split leftItem into two items
15423 * @param {Transaction} transaction
15424 * @param {Item} leftItem
15425 * @param {number} diff
15426 * @return {Item}
15427 *
15428 * @function
15429 * @private
15430 */
15431 const splitItem = (transaction, leftItem, diff) => {
15432 // create rightItem
15433 const { client, clock } = leftItem.id;
15434 const rightItem = new Item(
15435 createID(client, clock + diff),
15436 leftItem,
15437 createID(client, clock + diff - 1),
15438 leftItem.right,
15439 leftItem.rightOrigin,
15440 leftItem.parent,
15441 leftItem.parentSub,
15442 leftItem.content.splice(diff)
15443 );
15444 if (leftItem.deleted) {
15445 rightItem.markDeleted();
15446 }
15447 if (leftItem.keep) {
15448 rightItem.keep = true;
15449 }
15450 if (leftItem.redone !== null) {
15451 rightItem.redone = createID(leftItem.redone.client, leftItem.redone.clock + diff);
15452 }
15453 // update left (do not set leftItem.rightOrigin as it will lead to problems when syncing)
15454 leftItem.right = rightItem;
15455 // update right
15456 if (rightItem.right !== null) {
15457 rightItem.right.left = rightItem;
15458 }
15459 // right is more specific.
15460 transaction._mergeStructs.push(rightItem);
15461 // update parent._map
15462 if (rightItem.parentSub !== null && rightItem.right === null) {
15463 /** @type {AbstractType<any>} */ (rightItem.parent)._map.set(rightItem.parentSub, rightItem);
15464 }
15465 leftItem.length = diff;
15466 return rightItem
15467 };
15468
15469 /**
15470 * @param {Array<StackItem>} stack
15471 * @param {ID} id
15472 */
15473 const isDeletedByUndoStack = (stack, id) => array.some(stack, /** @param {StackItem} s */ s => isDeleted(s.deletions, id));
15474
15475 /**
15476 * Redoes the effect of this operation.
15477 *
15478 * @param {Transaction} transaction The Yjs instance.
15479 * @param {Item} item
15480 * @param {Set<Item>} redoitems
15481 * @param {DeleteSet} itemsToDelete
15482 * @param {boolean} ignoreRemoteMapChanges
15483 * @param {import('../utils/UndoManager.js').UndoManager} um
15484 *
15485 * @return {Item|null}
15486 *
15487 * @private
15488 */
15489 const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) => {
15490 const doc = transaction.doc;
15491 const store = doc.store;
15492 const ownClientID = doc.clientID;
15493 const redone = item.redone;
15494 if (redone !== null) {
15495 return getItemCleanStart(transaction, redone)
15496 }
15497 let parentItem = /** @type {AbstractType<any>} */ (item.parent)._item;
15498 /**
15499 * @type {Item|null}
15500 */
15501 let left = null;
15502 /**
15503 * @type {Item|null}
15504 */
15505 let right;
15506 // make sure that parent is redone
15507 if (parentItem !== null && parentItem.deleted === true) {
15508 // try to undo parent if it will be undone anyway
15509 if (parentItem.redone === null && (!redoitems.has(parentItem) || redoItem(transaction, parentItem, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) === null)) {
15510 return null
15511 }
15512 while (parentItem.redone !== null) {
15513 parentItem = getItemCleanStart(transaction, parentItem.redone);
15514 }
15515 }
15516 const parentType = parentItem === null ? /** @type {AbstractType<any>} */ (item.parent) : /** @type {ContentType} */ (parentItem.content).type;
15517
15518 if (item.parentSub === null) {
15519 // Is an array item. Insert at the old position
15520 left = item.left;
15521 right = item;
15522 // find next cloned_redo items
15523 while (left !== null) {
15524 /**
15525 * @type {Item|null}
15526 */
15527 let leftTrace = left;
15528 // trace redone until parent matches
15529 while (leftTrace !== null && /** @type {AbstractType<any>} */ (leftTrace.parent)._item !== parentItem) {
15530 leftTrace = leftTrace.redone === null ? null : getItemCleanStart(transaction, leftTrace.redone);
15531 }
15532 if (leftTrace !== null && /** @type {AbstractType<any>} */ (leftTrace.parent)._item === parentItem) {
15533 left = leftTrace;
15534 break
15535 }
15536 left = left.left;
15537 }
15538 while (right !== null) {
15539 /**
15540 * @type {Item|null}
15541 */
15542 let rightTrace = right;
15543 // trace redone until parent matches
15544 while (rightTrace !== null && /** @type {AbstractType<any>} */ (rightTrace.parent)._item !== parentItem) {
15545 rightTrace = rightTrace.redone === null ? null : getItemCleanStart(transaction, rightTrace.redone);
15546 }
15547 if (rightTrace !== null && /** @type {AbstractType<any>} */ (rightTrace.parent)._item === parentItem) {
15548 right = rightTrace;
15549 break
15550 }
15551 right = right.right;
15552 }
15553 } else {
15554 right = null;
15555 if (item.right && !ignoreRemoteMapChanges) {
15556 left = item;
15557 // Iterate right while right is in itemsToDelete
15558 // If it is intended to delete right while item is redone, we can expect that item should replace right.
15559 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))) {
15560 left = left.right;
15561 // follow redone
15562 while (left.redone) left = getItemCleanStart(transaction, left.redone);
15563 }
15564 if (left && left.right !== null) {
15565 // It is not possible to redo this item because it conflicts with a
15566 // change from another client
15567 return null
15568 }
15569 } else {
15570 left = parentType._map.get(item.parentSub) || null;
15571 }
15572 }
15573 const nextClock = getState(store, ownClientID);
15574 const nextId = createID(ownClientID, nextClock);
15575 const redoneItem = new Item(
15576 nextId,
15577 left, left && left.lastId,
15578 right, right && right.id,
15579 parentType,
15580 item.parentSub,
15581 item.content.copy()
15582 );
15583 item.redone = nextId;
15584 keepItem(redoneItem, true);
15585 redoneItem.integrate(transaction, 0);
15586 return redoneItem
15587 };
15588
15589 /**
15590 * Abstract class that represents any content.
15591 */
15592 class Item extends AbstractStruct {
15593 /**
15594 * @param {ID} id
15595 * @param {Item | null} left
15596 * @param {ID | null} origin
15597 * @param {Item | null} right
15598 * @param {ID | null} rightOrigin
15599 * @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.
15600 * @param {string | null} parentSub
15601 * @param {AbstractContent} content
15602 */
15603 constructor (id, left, origin, right, rightOrigin, parent, parentSub, content) {
15604 super(id, content.getLength());
15605 /**
15606 * The item that was originally to the left of this item.
15607 * @type {ID | null}
15608 */
15609 this.origin = origin;
15610 /**
15611 * The item that is currently to the left of this item.
15612 * @type {Item | null}
15613 */
15614 this.left = left;
15615 /**
15616 * The item that is currently to the right of this item.
15617 * @type {Item | null}
15618 */
15619 this.right = right;
15620 /**
15621 * The item that was originally to the right of this item.
15622 * @type {ID | null}
15623 */
15624 this.rightOrigin = rightOrigin;
15625 /**
15626 * @type {AbstractType<any>|ID|null}
15627 */
15628 this.parent = parent;
15629 /**
15630 * If the parent refers to this item with some kind of key (e.g. YMap, the
15631 * key is specified here. The key is then used to refer to the list in which
15632 * to insert this item. If `parentSub = null` type._start is the list in
15633 * which to insert to. Otherwise it is `parent._map`.
15634 * @type {String | null}
15635 */
15636 this.parentSub = parentSub;
15637 /**
15638 * If this type's effect is redone this type refers to the type that undid
15639 * this operation.
15640 * @type {ID | null}
15641 */
15642 this.redone = null;
15643 /**
15644 * @type {AbstractContent}
15645 */
15646 this.content = content;
15647 /**
15648 * bit1: keep
15649 * bit2: countable
15650 * bit3: deleted
15651 * bit4: mark - mark node as fast-search-marker
15652 * @type {number} byte
15653 */
15654 this.info = this.content.isCountable() ? BIT2 : 0;
15655 }
15656
15657 /**
15658 * This is used to mark the item as an indexed fast-search marker
15659 *
15660 * @type {boolean}
15661 */
15662 set marker (isMarked) {
15663 if (((this.info & BIT4) > 0) !== isMarked) {
15664 this.info ^= BIT4;
15665 }
15666 }
15667
15668 get marker () {
15669 return (this.info & BIT4) > 0
15670 }
15671
15672 /**
15673 * If true, do not garbage collect this Item.
15674 */
15675 get keep () {
15676 return (this.info & BIT1) > 0
15677 }
15678
15679 set keep (doKeep) {
15680 if (this.keep !== doKeep) {
15681 this.info ^= BIT1;
15682 }
15683 }
15684
15685 get countable () {
15686 return (this.info & BIT2) > 0
15687 }
15688
15689 /**
15690 * Whether this item was deleted or not.
15691 * @type {Boolean}
15692 */
15693 get deleted () {
15694 return (this.info & BIT3) > 0
15695 }
15696
15697 set deleted (doDelete) {
15698 if (this.deleted !== doDelete) {
15699 this.info ^= BIT3;
15700 }
15701 }
15702
15703 markDeleted () {
15704 this.info |= BIT3;
15705 }
15706
15707 /**
15708 * Return the creator clientID of the missing op or define missing items and return null.
15709 *
15710 * @param {Transaction} transaction
15711 * @param {StructStore} store
15712 * @return {null | number}
15713 */
15714 getMissing (transaction, store) {
15715 if (this.origin && this.origin.client !== this.id.client && this.origin.clock >= getState(store, this.origin.client)) {
15716 return this.origin.client
15717 }
15718 if (this.rightOrigin && this.rightOrigin.client !== this.id.client && this.rightOrigin.clock >= getState(store, this.rightOrigin.client)) {
15719 return this.rightOrigin.client
15720 }
15721 if (this.parent && this.parent.constructor === ID && this.id.client !== this.parent.client && this.parent.clock >= getState(store, this.parent.client)) {
15722 return this.parent.client
15723 }
15724
15725 // We have all missing ids, now find the items
15726
15727 if (this.origin) {
15728 this.left = getItemCleanEnd(transaction, store, this.origin);
15729 this.origin = this.left.lastId;
15730 }
15731 if (this.rightOrigin) {
15732 this.right = getItemCleanStart(transaction, this.rightOrigin);
15733 this.rightOrigin = this.right.id;
15734 }
15735 if ((this.left && this.left.constructor === GC) || (this.right && this.right.constructor === GC)) {
15736 this.parent = null;
15737 }
15738 // only set parent if this shouldn't be garbage collected
15739 if (!this.parent) {
15740 if (this.left && this.left.constructor === Item) {
15741 this.parent = this.left.parent;
15742 this.parentSub = this.left.parentSub;
15743 }
15744 if (this.right && this.right.constructor === Item) {
15745 this.parent = this.right.parent;
15746 this.parentSub = this.right.parentSub;
15747 }
15748 } else if (this.parent.constructor === ID) {
15749 const parentItem = getItem(store, this.parent);
15750 if (parentItem.constructor === GC) {
15751 this.parent = null;
15752 } else {
15753 this.parent = /** @type {ContentType} */ (parentItem.content).type;
15754 }
15755 }
15756 return null
15757 }
15758
15759 /**
15760 * @param {Transaction} transaction
15761 * @param {number} offset
15762 */
15763 integrate (transaction, offset) {
15764 if (offset > 0) {
15765 this.id.clock += offset;
15766 this.left = getItemCleanEnd(transaction, transaction.doc.store, createID(this.id.client, this.id.clock - 1));
15767 this.origin = this.left.lastId;
15768 this.content = this.content.splice(offset);
15769 this.length -= offset;
15770 }
15771
15772 if (this.parent) {
15773 if ((!this.left && (!this.right || this.right.left !== null)) || (this.left && this.left.right !== this.right)) {
15774 /**
15775 * @type {Item|null}
15776 */
15777 let left = this.left;
15778
15779 /**
15780 * @type {Item|null}
15781 */
15782 let o;
15783 // set o to the first conflicting item
15784 if (left !== null) {
15785 o = left.right;
15786 } else if (this.parentSub !== null) {
15787 o = /** @type {AbstractType<any>} */ (this.parent)._map.get(this.parentSub) || null;
15788 while (o !== null && o.left !== null) {
15789 o = o.left;
15790 }
15791 } else {
15792 o = /** @type {AbstractType<any>} */ (this.parent)._start;
15793 }
15794 // TODO: use something like DeleteSet here (a tree implementation would be best)
15795 // @todo use global set definitions
15796 /**
15797 * @type {Set<Item>}
15798 */
15799 const conflictingItems = new Set();
15800 /**
15801 * @type {Set<Item>}
15802 */
15803 const itemsBeforeOrigin = new Set();
15804 // Let c in conflictingItems, b in itemsBeforeOrigin
15805 // ***{origin}bbbb{this}{c,b}{c,b}{o}***
15806 // Note that conflictingItems is a subset of itemsBeforeOrigin
15807 while (o !== null && o !== this.right) {
15808 itemsBeforeOrigin.add(o);
15809 conflictingItems.add(o);
15810 if (compareIDs(this.origin, o.origin)) {
15811 // case 1
15812 if (o.id.client < this.id.client) {
15813 left = o;
15814 conflictingItems.clear();
15815 } else if (compareIDs(this.rightOrigin, o.rightOrigin)) {
15816 // this and o are conflicting and point to the same integration points. The id decides which item comes first.
15817 // Since this is to the left of o, we can break here
15818 break
15819 } // else, o might be integrated before an item that this conflicts with. If so, we will find it in the next iterations
15820 } 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.
15821 // case 2
15822 if (!conflictingItems.has(getItem(transaction.doc.store, o.origin))) {
15823 left = o;
15824 conflictingItems.clear();
15825 }
15826 } else {
15827 break
15828 }
15829 o = o.right;
15830 }
15831 this.left = left;
15832 }
15833 // reconnect left/right + update parent map/start if necessary
15834 if (this.left !== null) {
15835 const right = this.left.right;
15836 this.right = right;
15837 this.left.right = this;
15838 } else {
15839 let r;
15840 if (this.parentSub !== null) {
15841 r = /** @type {AbstractType<any>} */ (this.parent)._map.get(this.parentSub) || null;
15842 while (r !== null && r.left !== null) {
15843 r = r.left;
15844 }
15845 } else {
15846 r = /** @type {AbstractType<any>} */ (this.parent)._start
15847 ;/** @type {AbstractType<any>} */ (this.parent)._start = this;
15848 }
15849 this.right = r;
15850 }
15851 if (this.right !== null) {
15852 this.right.left = this;
15853 } else if (this.parentSub !== null) {
15854 // set as current parent value if right === null and this is parentSub
15855 /** @type {AbstractType<any>} */ (this.parent)._map.set(this.parentSub, this);
15856 if (this.left !== null) {
15857 // this is the current attribute value of parent. delete right
15858 this.left.delete(transaction);
15859 }
15860 }
15861 // adjust length of parent
15862 if (this.parentSub === null && this.countable && !this.deleted) {
15863 /** @type {AbstractType<any>} */ (this.parent)._length += this.length;
15864 }
15865 addStruct(transaction.doc.store, this);
15866 this.content.integrate(transaction, this);
15867 // add parent to transaction.changed
15868 addChangedTypeToTransaction(transaction, /** @type {AbstractType<any>} */ (this.parent), this.parentSub);
15869 if ((/** @type {AbstractType<any>} */ (this.parent)._item !== null && /** @type {AbstractType<any>} */ (this.parent)._item.deleted) || (this.parentSub !== null && this.right !== null)) {
15870 // delete if parent is deleted or if this is not the current attribute value of parent
15871 this.delete(transaction);
15872 }
15873 } else {
15874 // parent is not defined. Integrate GC struct instead
15875 new GC(this.id, this.length).integrate(transaction, 0);
15876 }
15877 }
15878
15879 /**
15880 * Returns the next non-deleted item
15881 */
15882 get next () {
15883 let n = this.right;
15884 while (n !== null && n.deleted) {
15885 n = n.right;
15886 }
15887 return n
15888 }
15889
15890 /**
15891 * Returns the previous non-deleted item
15892 */
15893 get prev () {
15894 let n = this.left;
15895 while (n !== null && n.deleted) {
15896 n = n.left;
15897 }
15898 return n
15899 }
15900
15901 /**
15902 * Computes the last content address of this Item.
15903 */
15904 get lastId () {
15905 // allocating ids is pretty costly because of the amount of ids created, so we try to reuse whenever possible
15906 return this.length === 1 ? this.id : createID(this.id.client, this.id.clock + this.length - 1)
15907 }
15908
15909 /**
15910 * Try to merge two items
15911 *
15912 * @param {Item} right
15913 * @return {boolean}
15914 */
15915 mergeWith (right) {
15916 if (
15917 this.constructor === right.constructor &&
15918 compareIDs(right.origin, this.lastId) &&
15919 this.right === right &&
15920 compareIDs(this.rightOrigin, right.rightOrigin) &&
15921 this.id.client === right.id.client &&
15922 this.id.clock + this.length === right.id.clock &&
15923 this.deleted === right.deleted &&
15924 this.redone === null &&
15925 right.redone === null &&
15926 this.content.constructor === right.content.constructor &&
15927 this.content.mergeWith(right.content)
15928 ) {
15929 const searchMarker = /** @type {AbstractType<any>} */ (this.parent)._searchMarker;
15930 if (searchMarker) {
15931 searchMarker.forEach(marker => {
15932 if (marker.p === right) {
15933 // right is going to be "forgotten" so we need to update the marker
15934 marker.p = this;
15935 // adjust marker index
15936 if (!this.deleted && this.countable) {
15937 marker.index -= this.length;
15938 }
15939 }
15940 });
15941 }
15942 if (right.keep) {
15943 this.keep = true;
15944 }
15945 this.right = right.right;
15946 if (this.right !== null) {
15947 this.right.left = this;
15948 }
15949 this.length += right.length;
15950 return true
15951 }
15952 return false
15953 }
15954
15955 /**
15956 * Mark this Item as deleted.
15957 *
15958 * @param {Transaction} transaction
15959 */
15960 delete (transaction) {
15961 if (!this.deleted) {
15962 const parent = /** @type {AbstractType<any>} */ (this.parent);
15963 // adjust the length of parent
15964 if (this.countable && this.parentSub === null) {
15965 parent._length -= this.length;
15966 }
15967 this.markDeleted();
15968 addToDeleteSet(transaction.deleteSet, this.id.client, this.id.clock, this.length);
15969 addChangedTypeToTransaction(transaction, parent, this.parentSub);
15970 this.content.delete(transaction);
15971 }
15972 }
15973
15974 /**
15975 * @param {StructStore} store
15976 * @param {boolean} parentGCd
15977 */
15978 gc (store, parentGCd) {
15979 if (!this.deleted) {
15980 throw unexpectedCase()
15981 }
15982 this.content.gc(store);
15983 if (parentGCd) {
15984 replaceStruct(store, this, new GC(this.id, this.length));
15985 } else {
15986 this.content = new ContentDeleted(this.length);
15987 }
15988 }
15989
15990 /**
15991 * Transform the properties of this type to binary and write it to an
15992 * BinaryEncoder.
15993 *
15994 * This is called when this Item is sent to a remote peer.
15995 *
15996 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
15997 * @param {number} offset
15998 */
15999 write (encoder, offset) {
16000 const origin = offset > 0 ? createID(this.id.client, this.id.clock + offset - 1) : this.origin;
16001 const rightOrigin = this.rightOrigin;
16002 const parentSub = this.parentSub;
16003 const info = (this.content.getRef() & BITS5) |
16004 (origin === null ? 0 : BIT8) | // origin is defined
16005 (rightOrigin === null ? 0 : BIT7) | // right origin is defined
16006 (parentSub === null ? 0 : BIT6); // parentSub is non-null
16007 encoder.writeInfo(info);
16008 if (origin !== null) {
16009 encoder.writeLeftID(origin);
16010 }
16011 if (rightOrigin !== null) {
16012 encoder.writeRightID(rightOrigin);
16013 }
16014 if (origin === null && rightOrigin === null) {
16015 const parent = /** @type {AbstractType<any>} */ (this.parent);
16016 if (parent._item !== undefined) {
16017 const parentItem = parent._item;
16018 if (parentItem === null) {
16019 // parent type on y._map
16020 // find the correct key
16021 const ykey = findRootTypeKey(parent);
16022 encoder.writeParentInfo(true); // write parentYKey
16023 encoder.writeString(ykey);
16024 } else {
16025 encoder.writeParentInfo(false); // write parent id
16026 encoder.writeLeftID(parentItem.id);
16027 }
16028 } else if (parent.constructor === String) { // this edge case was added by differential updates
16029 encoder.writeParentInfo(true); // write parentYKey
16030 encoder.writeString(parent);
16031 } else if (parent.constructor === ID) {
16032 encoder.writeParentInfo(false); // write parent id
16033 encoder.writeLeftID(parent);
16034 } else {
16035 unexpectedCase();
16036 }
16037 if (parentSub !== null) {
16038 encoder.writeString(parentSub);
16039 }
16040 }
16041 this.content.write(encoder, offset);
16042 }
16043 }
16044
16045 /**
16046 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
16047 * @param {number} info
16048 */
16049 const readItemContent = (decoder, info) => contentRefs[info & BITS5](decoder);
16050
16051 /**
16052 * A lookup map for reading Item content.
16053 *
16054 * @type {Array<function(UpdateDecoderV1 | UpdateDecoderV2):AbstractContent>}
16055 */
16056 const contentRefs = [
16057 () => { unexpectedCase(); }, // GC is not ItemContent
16058 readContentDeleted, // 1
16059 readContentJSON, // 2
16060 readContentBinary, // 3
16061 readContentString, // 4
16062 readContentEmbed, // 5
16063 readContentFormat, // 6
16064 readContentType, // 7
16065 readContentAny, // 8
16066 readContentDoc, // 9
16067 () => { unexpectedCase(); } // 10 - Skip is not ItemContent
16068 ];
16069
16070 const structSkipRefNumber = 10;
16071
16072 /**
16073 * @private
16074 */
16075 class Skip extends AbstractStruct {
16076 get deleted () {
16077 return true
16078 }
16079
16080 delete () {}
16081
16082 /**
16083 * @param {Skip} right
16084 * @return {boolean}
16085 */
16086 mergeWith (right) {
16087 if (this.constructor !== right.constructor) {
16088 return false
16089 }
16090 this.length += right.length;
16091 return true
16092 }
16093
16094 /**
16095 * @param {Transaction} transaction
16096 * @param {number} offset
16097 */
16098 integrate (transaction, offset) {
16099 // skip structs cannot be integrated
16100 unexpectedCase();
16101 }
16102
16103 /**
16104 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
16105 * @param {number} offset
16106 */
16107 write (encoder, offset) {
16108 encoder.writeInfo(structSkipRefNumber);
16109 // write as VarUint because Skips can't make use of predictable length-encoding
16110 writeVarUint(encoder.restEncoder, this.length - offset);
16111 }
16112
16113 /**
16114 * @param {Transaction} transaction
16115 * @param {StructStore} store
16116 * @return {null | number}
16117 */
16118 getMissing (transaction, store) {
16119 return null
16120 }
16121 }
16122
16123 /** eslint-env browser */
16124
16125 const glo = /** @type {any} */ (typeof globalThis !== 'undefined'
16126 ? globalThis
16127 : typeof window !== 'undefined'
16128 ? window
16129 // @ts-ignore
16130 : typeof global !== 'undefined' ? global : {});
16131
16132 const importIdentifier = '__ $YJS$ __';
16133
16134 if (glo[importIdentifier] === true) {
16135 /**
16136 * Dear reader of this message. Please take this seriously.
16137 *
16138 * If you see this message, make sure that you only import one version of Yjs. In many cases,
16139 * your package manager installs two versions of Yjs that are used by different packages within your project.
16140 * Another reason for this message is that some parts of your project use the commonjs version of Yjs
16141 * and others use the EcmaScript version of Yjs.
16142 *
16143 * This often leads to issues that are hard to debug. We often need to perform constructor checks,
16144 * e.g. `struct instanceof GC`. If you imported different versions of Yjs, it is impossible for us to
16145 * do the constructor checks anymore - which might break the CRDT algorithm.
16146 *
16147 * https://github.com/yjs/yjs/issues/438
16148 */
16149 console.error('Yjs was already imported. This breaks constructor checks and will lead to issues! - https://github.com/yjs/yjs/issues/438');
16150 }
16151 glo[importIdentifier] = true;
16152
16153
16154 //# sourceMappingURL=yjs.mjs.map
16155
16156 ;// CONCATENATED MODULE: ./packages/sync/build-module/provider.js
16157 /**
16158 * External dependencies
16159 */
16160 // @ts-ignore
16161
16162
16163 /** @typedef {import('./types').ObjectType} ObjectType */
16164 /** @typedef {import('./types').ObjectID} ObjectID */
16165 /** @typedef {import('./types').ObjectConfig} ObjectConfig */
16166 /** @typedef {import('./types').CRDTDoc} CRDTDoc */
16167 /** @typedef {import('./types').ConnectDoc} ConnectDoc */
16168 /** @typedef {import('./types').SyncProvider} SyncProvider */
16169
16170 /**
16171 * Create a sync provider.
16172 *
16173 * @param {ConnectDoc} connectLocal Connect the document to a local database.
16174 * @param {ConnectDoc} connectRemote Connect the document to a remote sync connection.
16175 * @return {SyncProvider} Sync provider.
16176 */
16177 const createSyncProvider = (connectLocal, connectRemote) => {
16178 /**
16179 * @type {Record<string,ObjectConfig>}
16180 */
16181 const config = {};
16182
16183 /**
16184 * @type {Record<string,Record<string,()=>void>>}
16185 */
16186 const listeners = {};
16187
16188 /**
16189 * @type {Record<string,Record<string,CRDTDoc>>}
16190 */
16191 const docs = {};
16192
16193 /**
16194 * Registeres an object type.
16195 *
16196 * @param {ObjectType} objectType Object type to register.
16197 * @param {ObjectConfig} objectConfig Object config.
16198 */
16199 function register(objectType, objectConfig) {
16200 config[objectType] = objectConfig;
16201 }
16202
16203 /**
16204 * Fetch data from local database or remote source.
16205 *
16206 * @param {ObjectType} objectType Object type to load.
16207 * @param {ObjectID} objectId Object ID to load.
16208 * @param {Function} handleChanges Callback to call when data changes.
16209 */
16210 async function bootstrap(objectType, objectId, handleChanges) {
16211 const doc = new Doc();
16212 docs[objectType] = docs[objectType] || {};
16213 docs[objectType][objectId] = doc;
16214 const updateHandler = () => {
16215 const data = config[objectType].fromCRDTDoc(doc);
16216 handleChanges(data);
16217 };
16218 doc.on('update', updateHandler);
16219
16220 // connect to locally saved database.
16221 const destroyLocalConnection = await connectLocal(objectId, objectType, doc);
16222
16223 // Once the database syncing is done, start the remote syncing
16224 if (connectRemote) {
16225 await connectRemote(objectId, objectType, doc);
16226 }
16227 const loadRemotely = config[objectType].fetch;
16228 if (loadRemotely) {
16229 loadRemotely(objectId).then(data => {
16230 doc.transact(() => {
16231 config[objectType].applyChangesToDoc(doc, data);
16232 });
16233 });
16234 }
16235 listeners[objectType] = listeners[objectType] || {};
16236 listeners[objectType][objectId] = () => {
16237 destroyLocalConnection();
16238 doc.off('update', updateHandler);
16239 };
16240 }
16241
16242 /**
16243 * Fetch data from local database or remote source.
16244 *
16245 * @param {ObjectType} objectType Object type to load.
16246 * @param {ObjectID} objectId Object ID to load.
16247 * @param {any} data Updates to make.
16248 */
16249 async function update(objectType, objectId, data) {
16250 const doc = docs[objectType][objectId];
16251 if (!doc) {
16252 throw 'Error doc ' + objectType + ' ' + objectId + ' not found';
16253 }
16254 doc.transact(() => {
16255 config[objectType].applyChangesToDoc(doc, data);
16256 });
16257 }
16258
16259 /**
16260 * Stop updating a document and discard it.
16261 *
16262 * @param {ObjectType} objectType Object type to load.
16263 * @param {ObjectID} objectId Object ID to load.
16264 */
16265 async function discard(objectType, objectId) {
16266 if (listeners?.[objectType]?.[objectId]) {
16267 listeners[objectType][objectId]();
16268 }
16269 }
16270 return {
16271 register,
16272 bootstrap,
16273 update,
16274 discard
16275 };
16276 };
16277
16278 ;// CONCATENATED MODULE: ./node_modules/lib0/indexeddb.js
16279 /* eslint-env browser */
16280
16281 /**
16282 * Helpers to work with IndexedDB.
16283 *
16284 * @module indexeddb
16285 */
16286
16287
16288
16289
16290 /* c8 ignore start */
16291
16292 /**
16293 * IDB Request to Promise transformer
16294 *
16295 * @param {IDBRequest} request
16296 * @return {Promise<any>}
16297 */
16298 const rtop = request => promise_create((resolve, reject) => {
16299 // @ts-ignore
16300 request.onerror = event => reject(new Error(event.target.error))
16301 // @ts-ignore
16302 request.onsuccess = event => resolve(event.target.result)
16303 })
16304
16305 /**
16306 * @param {string} name
16307 * @param {function(IDBDatabase):any} initDB Called when the database is first created
16308 * @return {Promise<IDBDatabase>}
16309 */
16310 const openDB = (name, initDB) => promise_create((resolve, reject) => {
16311 const request = indexedDB.open(name)
16312 /**
16313 * @param {any} event
16314 */
16315 request.onupgradeneeded = event => initDB(event.target.result)
16316 /**
16317 * @param {any} event
16318 */
16319 request.onerror = event => reject(error_create(event.target.error))
16320 /**
16321 * @param {any} event
16322 */
16323 request.onsuccess = event => {
16324 /**
16325 * @type {IDBDatabase}
16326 */
16327 const db = event.target.result
16328 db.onversionchange = () => { db.close() }
16329 if (typeof addEventListener !== 'undefined') {
16330 addEventListener('unload', () => db.close())
16331 }
16332 resolve(db)
16333 }
16334 })
16335
16336 /**
16337 * @param {string} name
16338 */
16339 const deleteDB = name => rtop(indexedDB.deleteDatabase(name))
16340
16341 /**
16342 * @param {IDBDatabase} db
16343 * @param {Array<Array<string>|Array<string|IDBObjectStoreParameters|undefined>>} definitions
16344 */
16345 const createStores = (db, definitions) => definitions.forEach(d =>
16346 // @ts-ignore
16347 db.createObjectStore.apply(db, d)
16348 )
16349
16350 /**
16351 * @param {IDBDatabase} db
16352 * @param {Array<string>} stores
16353 * @param {"readwrite"|"readonly"} [access]
16354 * @return {Array<IDBObjectStore>}
16355 */
16356 const indexeddb_transact = (db, stores, access = 'readwrite') => {
16357 const transaction = db.transaction(stores, access)
16358 return stores.map(store => getStore(transaction, store))
16359 }
16360
16361 /**
16362 * @param {IDBObjectStore} store
16363 * @param {IDBKeyRange} [range]
16364 * @return {Promise<number>}
16365 */
16366 const count = (store, range) =>
16367 rtop(store.count(range))
16368
16369 /**
16370 * @param {IDBObjectStore} store
16371 * @param {String | number | ArrayBuffer | Date | Array<any> } key
16372 * @return {Promise<String | number | ArrayBuffer | Date | Array<any>>}
16373 */
16374 const get = (store, key) =>
16375 rtop(store.get(key))
16376
16377 /**
16378 * @param {IDBObjectStore} store
16379 * @param {String | number | ArrayBuffer | Date | IDBKeyRange | Array<any> } key
16380 */
16381 const del = (store, key) =>
16382 rtop(store.delete(key))
16383
16384 /**
16385 * @param {IDBObjectStore} store
16386 * @param {String | number | ArrayBuffer | Date | boolean} item
16387 * @param {String | number | ArrayBuffer | Date | Array<any>} [key]
16388 */
16389 const put = (store, item, key) =>
16390 rtop(store.put(item, key))
16391
16392 /**
16393 * @param {IDBObjectStore} store
16394 * @param {String | number | ArrayBuffer | Date | boolean} item
16395 * @param {String | number | ArrayBuffer | Date | Array<any>} key
16396 * @return {Promise<any>}
16397 */
16398 const indexeddb_add = (store, item, key) =>
16399 rtop(store.add(item, key))
16400
16401 /**
16402 * @param {IDBObjectStore} store
16403 * @param {String | number | ArrayBuffer | Date} item
16404 * @return {Promise<number>} Returns the generated key
16405 */
16406 const addAutoKey = (store, item) =>
16407 rtop(store.add(item))
16408
16409 /**
16410 * @param {IDBObjectStore} store
16411 * @param {IDBKeyRange} [range]
16412 * @param {number} [limit]
16413 * @return {Promise<Array<any>>}
16414 */
16415 const getAll = (store, range, limit) =>
16416 rtop(store.getAll(range, limit))
16417
16418 /**
16419 * @param {IDBObjectStore} store
16420 * @param {IDBKeyRange} [range]
16421 * @param {number} [limit]
16422 * @return {Promise<Array<any>>}
16423 */
16424 const getAllKeys = (store, range, limit) =>
16425 rtop(store.getAllKeys(range, limit))
16426
16427 /**
16428 * @param {IDBObjectStore} store
16429 * @param {IDBKeyRange|null} query
16430 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction
16431 * @return {Promise<any>}
16432 */
16433 const queryFirst = (store, query, direction) => {
16434 /**
16435 * @type {any}
16436 */
16437 let first = null
16438 return iterateKeys(store, query, key => {
16439 first = key
16440 return false
16441 }, direction).then(() => first)
16442 }
16443
16444 /**
16445 * @param {IDBObjectStore} store
16446 * @param {IDBKeyRange?} [range]
16447 * @return {Promise<any>}
16448 */
16449 const getLastKey = (store, range = null) => queryFirst(store, range, 'prev')
16450
16451 /**
16452 * @param {IDBObjectStore} store
16453 * @param {IDBKeyRange?} [range]
16454 * @return {Promise<any>}
16455 */
16456 const getFirstKey = (store, range = null) => queryFirst(store, range, 'next')
16457
16458 /**
16459 * @typedef KeyValuePair
16460 * @type {Object}
16461 * @property {any} k key
16462 * @property {any} v Value
16463 */
16464
16465 /**
16466 * @param {IDBObjectStore} store
16467 * @param {IDBKeyRange} [range]
16468 * @param {number} [limit]
16469 * @return {Promise<Array<KeyValuePair>>}
16470 */
16471 const getAllKeysValues = (store, range, limit) =>
16472 // @ts-ignore
16473 promise.all([getAllKeys(store, range, limit), getAll(store, range, limit)]).then(([ks, vs]) => ks.map((k, i) => ({ k, v: vs[i] })))
16474
16475 /**
16476 * @param {any} request
16477 * @param {function(IDBCursorWithValue):void|boolean|Promise<void|boolean>} f
16478 * @return {Promise<void>}
16479 */
16480 const iterateOnRequest = (request, f) => promise_create((resolve, reject) => {
16481 request.onerror = reject
16482 /**
16483 * @param {any} event
16484 */
16485 request.onsuccess = async event => {
16486 const cursor = event.target.result
16487 if (cursor === null || (await f(cursor)) === false) {
16488 return resolve()
16489 }
16490 cursor.continue()
16491 }
16492 })
16493
16494 /**
16495 * Iterate on keys and values
16496 * @param {IDBObjectStore} store
16497 * @param {IDBKeyRange|null} keyrange
16498 * @param {function(any,any):void|boolean|Promise<void|boolean>} f Callback that receives (value, key)
16499 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction
16500 */
16501 const iterate = (store, keyrange, f, direction = 'next') =>
16502 iterateOnRequest(store.openCursor(keyrange, direction), cursor => f(cursor.value, cursor.key))
16503
16504 /**
16505 * Iterate on the keys (no values)
16506 *
16507 * @param {IDBObjectStore} store
16508 * @param {IDBKeyRange|null} keyrange
16509 * @param {function(any):void|boolean|Promise<void|boolean>} f callback that receives the key
16510 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction
16511 */
16512 const iterateKeys = (store, keyrange, f, direction = 'next') =>
16513 iterateOnRequest(store.openKeyCursor(keyrange, direction), cursor => f(cursor.key))
16514
16515 /**
16516 * Open store from transaction
16517 * @param {IDBTransaction} t
16518 * @param {String} store
16519 * @returns {IDBObjectStore}
16520 */
16521 const getStore = (t, store) => t.objectStore(store)
16522
16523 /**
16524 * @param {any} lower
16525 * @param {any} upper
16526 * @param {boolean} lowerOpen
16527 * @param {boolean} upperOpen
16528 */
16529 const createIDBKeyRangeBound = (lower, upper, lowerOpen, upperOpen) => IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen)
16530
16531 /**
16532 * @param {any} upper
16533 * @param {boolean} upperOpen
16534 */
16535 const createIDBKeyRangeUpperBound = (upper, upperOpen) => IDBKeyRange.upperBound(upper, upperOpen)
16536
16537 /**
16538 * @param {any} lower
16539 * @param {boolean} lowerOpen
16540 */
16541 const createIDBKeyRangeLowerBound = (lower, lowerOpen) => IDBKeyRange.lowerBound(lower, lowerOpen)
16542
16543 /* c8 ignore stop */
16544
16545 ;// CONCATENATED MODULE: ./node_modules/y-indexeddb/src/y-indexeddb.js
16546
16547
16548
16549
16550
16551 const customStoreName = 'custom'
16552 const updatesStoreName = 'updates'
16553
16554 const PREFERRED_TRIM_SIZE = 500
16555
16556 /**
16557 * @param {IndexeddbPersistence} idbPersistence
16558 * @param {function(IDBObjectStore):void} [beforeApplyUpdatesCallback]
16559 * @param {function(IDBObjectStore):void} [afterApplyUpdatesCallback]
16560 */
16561 const fetchUpdates = (idbPersistence, beforeApplyUpdatesCallback = () => {}, afterApplyUpdatesCallback = () => {}) => {
16562 const [updatesStore] = indexeddb_transact(/** @type {IDBDatabase} */ (idbPersistence.db), [updatesStoreName]) // , 'readonly')
16563 return getAll(updatesStore, createIDBKeyRangeLowerBound(idbPersistence._dbref, false)).then(updates => {
16564 if (!idbPersistence._destroyed) {
16565 beforeApplyUpdatesCallback(updatesStore)
16566 transact(idbPersistence.doc, () => {
16567 updates.forEach(val => applyUpdate(idbPersistence.doc, val))
16568 }, idbPersistence, false)
16569 afterApplyUpdatesCallback(updatesStore)
16570 }
16571 })
16572 .then(() => getLastKey(updatesStore).then(lastKey => { idbPersistence._dbref = lastKey + 1 }))
16573 .then(() => count(updatesStore).then(cnt => { idbPersistence._dbsize = cnt }))
16574 .then(() => updatesStore)
16575 }
16576
16577 /**
16578 * @param {IndexeddbPersistence} idbPersistence
16579 * @param {boolean} forceStore
16580 */
16581 const storeState = (idbPersistence, forceStore = true) =>
16582 fetchUpdates(idbPersistence)
16583 .then(updatesStore => {
16584 if (forceStore || idbPersistence._dbsize >= PREFERRED_TRIM_SIZE) {
16585 addAutoKey(updatesStore, encodeStateAsUpdate(idbPersistence.doc))
16586 .then(() => del(updatesStore, createIDBKeyRangeUpperBound(idbPersistence._dbref, true)))
16587 .then(() => count(updatesStore).then(cnt => { idbPersistence._dbsize = cnt }))
16588 }
16589 })
16590
16591 /**
16592 * @param {string} name
16593 */
16594 const clearDocument = name => idb.deleteDB(name)
16595
16596 /**
16597 * @extends Observable<string>
16598 */
16599 class IndexeddbPersistence extends observable_Observable {
16600 /**
16601 * @param {string} name
16602 * @param {Y.Doc} doc
16603 */
16604 constructor (name, doc) {
16605 super()
16606 this.doc = doc
16607 this.name = name
16608 this._dbref = 0
16609 this._dbsize = 0
16610 this._destroyed = false
16611 /**
16612 * @type {IDBDatabase|null}
16613 */
16614 this.db = null
16615 this.synced = false
16616 this._db = openDB(name, db =>
16617 createStores(db, [
16618 ['updates', { autoIncrement: true }],
16619 ['custom']
16620 ])
16621 )
16622 /**
16623 * @type {Promise<IndexeddbPersistence>}
16624 */
16625 this.whenSynced = promise_create(resolve => this.on('synced', () => resolve(this)))
16626
16627 this._db.then(db => {
16628 this.db = db
16629 /**
16630 * @param {IDBObjectStore} updatesStore
16631 */
16632 const beforeApplyUpdatesCallback = (updatesStore) => addAutoKey(updatesStore, encodeStateAsUpdate(doc))
16633 const afterApplyUpdatesCallback = () => {
16634 if (this._destroyed) return this
16635 this.synced = true
16636 this.emit('synced', [this])
16637 }
16638 fetchUpdates(this, beforeApplyUpdatesCallback, afterApplyUpdatesCallback)
16639 })
16640 /**
16641 * Timeout in ms untill data is merged and persisted in idb.
16642 */
16643 this._storeTimeout = 1000
16644 /**
16645 * @type {any}
16646 */
16647 this._storeTimeoutId = null
16648 /**
16649 * @param {Uint8Array} update
16650 * @param {any} origin
16651 */
16652 this._storeUpdate = (update, origin) => {
16653 if (this.db && origin !== this) {
16654 const [updatesStore] = indexeddb_transact(/** @type {IDBDatabase} */ (this.db), [updatesStoreName])
16655 addAutoKey(updatesStore, update)
16656 if (++this._dbsize >= PREFERRED_TRIM_SIZE) {
16657 // debounce store call
16658 if (this._storeTimeoutId !== null) {
16659 clearTimeout(this._storeTimeoutId)
16660 }
16661 this._storeTimeoutId = setTimeout(() => {
16662 storeState(this, false)
16663 this._storeTimeoutId = null
16664 }, this._storeTimeout)
16665 }
16666 }
16667 }
16668 doc.on('update', this._storeUpdate)
16669 this.destroy = this.destroy.bind(this)
16670 doc.on('destroy', this.destroy)
16671 }
16672
16673 destroy () {
16674 if (this._storeTimeoutId) {
16675 clearTimeout(this._storeTimeoutId)
16676 }
16677 this.doc.off('update', this._storeUpdate)
16678 this.doc.off('destroy', this.destroy)
16679 this._destroyed = true
16680 return this._db.then(db => {
16681 db.close()
16682 })
16683 }
16684
16685 /**
16686 * Destroys this instance and removes all data from indexeddb.
16687 *
16688 * @return {Promise<void>}
16689 */
16690 clearData () {
16691 return this.destroy().then(() => {
16692 deleteDB(this.name)
16693 })
16694 }
16695
16696 /**
16697 * @param {String | number | ArrayBuffer | Date} key
16698 * @return {Promise<String | number | ArrayBuffer | Date | any>}
16699 */
16700 get (key) {
16701 return this._db.then(db => {
16702 const [custom] = indexeddb_transact(db, [customStoreName], 'readonly')
16703 return get(custom, key)
16704 })
16705 }
16706
16707 /**
16708 * @param {String | number | ArrayBuffer | Date} key
16709 * @param {String | number | ArrayBuffer | Date} value
16710 * @return {Promise<String | number | ArrayBuffer | Date>}
16711 */
16712 set (key, value) {
16713 return this._db.then(db => {
16714 const [custom] = indexeddb_transact(db, [customStoreName])
16715 return put(custom, value, key)
16716 })
16717 }
16718
16719 /**
16720 * @param {String | number | ArrayBuffer | Date} key
16721 * @return {Promise<undefined>}
16722 */
16723 del (key) {
16724 return this._db.then(db => {
16725 const [custom] = indexeddb_transact(db, [customStoreName])
16726 return del(custom, key)
16727 })
16728 }
16729 }
16730
16731 ;// CONCATENATED MODULE: ./packages/sync/build-module/connect-indexdb.js
16732 /**
16733 * External dependencies
16734 */
16735 // @ts-ignore
16736
16737
16738 /** @typedef {import('./types').ObjectType} ObjectType */
16739 /** @typedef {import('./types').ObjectID} ObjectID */
16740 /** @typedef {import('./types').CRDTDoc} CRDTDoc */
16741 /** @typedef {import('./types').ConnectDoc} ConnectDoc */
16742 /** @typedef {import('./types').SyncProvider} SyncProvider */
16743
16744 /**
16745 * Connect function to the IndexedDB persistence provider.
16746 *
16747 * @param {ObjectID} objectId The object ID.
16748 * @param {ObjectType} objectType The object type.
16749 * @param {CRDTDoc} doc The CRDT document.
16750 *
16751 * @return {Promise<() => void>} Promise that resolves when the connection is established.
16752 */
16753 function connectIndexDb(objectId, objectType, doc) {
16754 const roomName = `${objectType}-${objectId}`;
16755 const provider = new IndexeddbPersistence(roomName, doc);
16756 return new Promise(resolve => {
16757 provider.on('synced', () => {
16758 resolve(() => provider.destroy());
16759 });
16760 });
16761 }
16762
16763 ;// CONCATENATED MODULE: ./node_modules/lib0/websocket.js
16764 /* eslint-env browser */
16765
16766 /**
16767 * Tiny websocket connection handler.
16768 *
16769 * Implements exponential backoff reconnects, ping/pong, and a nice event system using [lib0/observable].
16770 *
16771 * @module websocket
16772 */
16773
16774
16775
16776
16777
16778 const reconnectTimeoutBase = 1200
16779 const maxReconnectTimeout = 2500
16780 // @todo - this should depend on awareness.outdatedTime
16781 const messageReconnectTimeout = 30000
16782
16783 /**
16784 * @param {WebsocketClient} wsclient
16785 */
16786 const setupWS = (wsclient) => {
16787 if (wsclient.shouldConnect && wsclient.ws === null) {
16788 const websocket = new WebSocket(wsclient.url)
16789 const binaryType = wsclient.binaryType
16790 /**
16791 * @type {any}
16792 */
16793 let pingTimeout = null
16794 if (binaryType) {
16795 websocket.binaryType = binaryType
16796 }
16797 wsclient.ws = websocket
16798 wsclient.connecting = true
16799 wsclient.connected = false
16800 websocket.onmessage = event => {
16801 wsclient.lastMessageReceived = getUnixTime()
16802 const data = event.data
16803 const message = typeof data === 'string' ? JSON.parse(data) : data
16804 if (message && message.type === 'pong') {
16805 clearTimeout(pingTimeout)
16806 pingTimeout = setTimeout(sendPing, messageReconnectTimeout / 2)
16807 }
16808 wsclient.emit('message', [message, wsclient])
16809 }
16810 /**
16811 * @param {any} error
16812 */
16813 const onclose = error => {
16814 if (wsclient.ws !== null) {
16815 wsclient.ws = null
16816 wsclient.connecting = false
16817 if (wsclient.connected) {
16818 wsclient.connected = false
16819 wsclient.emit('disconnect', [{ type: 'disconnect', error }, wsclient])
16820 } else {
16821 wsclient.unsuccessfulReconnects++
16822 }
16823 // Start with no reconnect timeout and increase timeout by
16824 // log10(wsUnsuccessfulReconnects).
16825 // The idea is to increase reconnect timeout slowly and have no reconnect
16826 // timeout at the beginning (log(1) = 0)
16827 setTimeout(setupWS, min(log10(wsclient.unsuccessfulReconnects + 1) * reconnectTimeoutBase, maxReconnectTimeout), wsclient)
16828 }
16829 clearTimeout(pingTimeout)
16830 }
16831 const sendPing = () => {
16832 if (wsclient.ws === websocket) {
16833 wsclient.send({
16834 type: 'ping'
16835 })
16836 }
16837 }
16838 websocket.onclose = () => onclose(null)
16839 websocket.onerror = error => onclose(error)
16840 websocket.onopen = () => {
16841 wsclient.lastMessageReceived = getUnixTime()
16842 wsclient.connecting = false
16843 wsclient.connected = true
16844 wsclient.unsuccessfulReconnects = 0
16845 wsclient.emit('connect', [{ type: 'connect' }, wsclient])
16846 // set ping
16847 pingTimeout = setTimeout(sendPing, messageReconnectTimeout / 2)
16848 }
16849 }
16850 }
16851
16852 /**
16853 * @extends Observable<string>
16854 */
16855 class WebsocketClient extends observable_Observable {
16856 /**
16857 * @param {string} url
16858 * @param {object} opts
16859 * @param {'arraybuffer' | 'blob' | null} [opts.binaryType] Set `ws.binaryType`
16860 */
16861 constructor (url, { binaryType } = {}) {
16862 super()
16863 this.url = url
16864 /**
16865 * @type {WebSocket?}
16866 */
16867 this.ws = null
16868 this.binaryType = binaryType || null
16869 this.connected = false
16870 this.connecting = false
16871 this.unsuccessfulReconnects = 0
16872 this.lastMessageReceived = 0
16873 /**
16874 * Whether to connect to other peers or not
16875 * @type {boolean}
16876 */
16877 this.shouldConnect = true
16878 this._checkInterval = setInterval(() => {
16879 if (this.connected && messageReconnectTimeout < getUnixTime() - this.lastMessageReceived) {
16880 // no message received in a long time - not even your own awareness
16881 // updates (which are updated every 15 seconds)
16882 /** @type {WebSocket} */ (this.ws).close()
16883 }
16884 }, messageReconnectTimeout / 2)
16885 setupWS(this)
16886 }
16887
16888 /**
16889 * @param {any} message
16890 */
16891 send (message) {
16892 if (this.ws) {
16893 this.ws.send(JSON.stringify(message))
16894 }
16895 }
16896
16897 destroy () {
16898 clearInterval(this._checkInterval)
16899 this.disconnect()
16900 super.destroy()
16901 }
16902
16903 disconnect () {
16904 this.shouldConnect = false
16905 if (this.ws !== null) {
16906 this.ws.close()
16907 }
16908 }
16909
16910 connect () {
16911 this.shouldConnect = true
16912 if (!this.connected && this.ws === null) {
16913 setupWS(this)
16914 }
16915 }
16916 }
16917
16918 ;// CONCATENATED MODULE: ./node_modules/lib0/broadcastchannel.js
16919 /* eslint-env browser */
16920
16921 /**
16922 * Helpers for cross-tab communication using broadcastchannel with LocalStorage fallback.
16923 *
16924 * ```js
16925 * // In browser window A:
16926 * broadcastchannel.subscribe('my events', data => console.log(data))
16927 * broadcastchannel.publish('my events', 'Hello world!') // => A: 'Hello world!' fires synchronously in same tab
16928 *
16929 * // In browser window B:
16930 * broadcastchannel.publish('my events', 'hello from tab B') // => A: 'hello from tab B'
16931 * ```
16932 *
16933 * @module broadcastchannel
16934 */
16935
16936 // @todo before next major: use Uint8Array instead as buffer object
16937
16938
16939
16940
16941
16942
16943 /**
16944 * @typedef {Object} Channel
16945 * @property {Set<function(any, any):any>} Channel.subs
16946 * @property {any} Channel.bc
16947 */
16948
16949 /**
16950 * @type {Map<string, Channel>}
16951 */
16952 const channels = new Map()
16953
16954 /* c8 ignore start */
16955 class LocalStoragePolyfill {
16956 /**
16957 * @param {string} room
16958 */
16959 constructor (room) {
16960 this.room = room
16961 /**
16962 * @type {null|function({data:ArrayBuffer}):void}
16963 */
16964 this.onmessage = null
16965 /**
16966 * @param {any} e
16967 */
16968 this._onChange = e => e.key === room && this.onmessage !== null && this.onmessage({ data: fromBase64(e.newValue || '') })
16969 onChange(this._onChange)
16970 }
16971
16972 /**
16973 * @param {ArrayBuffer} buf
16974 */
16975 postMessage (buf) {
16976 varStorage.setItem(this.room, toBase64(createUint8ArrayFromArrayBuffer(buf)))
16977 }
16978
16979 close () {
16980 offChange(this._onChange)
16981 }
16982 }
16983 /* c8 ignore stop */
16984
16985 // Use BroadcastChannel or Polyfill
16986 /* c8 ignore next */
16987 const BC = typeof BroadcastChannel === 'undefined' ? LocalStoragePolyfill : BroadcastChannel
16988
16989 /**
16990 * @param {string} room
16991 * @return {Channel}
16992 */
16993 const getChannel = room =>
16994 setIfUndefined(channels, room, () => {
16995 const subs = set_create()
16996 const bc = new BC(room)
16997 /**
16998 * @param {{data:ArrayBuffer}} e
16999 */
17000 /* c8 ignore next */
17001 bc.onmessage = e => subs.forEach(sub => sub(e.data, 'broadcastchannel'))
17002 return {
17003 bc, subs
17004 }
17005 })
17006
17007 /**
17008 * Subscribe to global `publish` events.
17009 *
17010 * @function
17011 * @param {string} room
17012 * @param {function(any, any):any} f
17013 */
17014 const subscribe = (room, f) => {
17015 getChannel(room).subs.add(f)
17016 return f
17017 }
17018
17019 /**
17020 * Unsubscribe from `publish` global events.
17021 *
17022 * @function
17023 * @param {string} room
17024 * @param {function(any, any):any} f
17025 */
17026 const unsubscribe = (room, f) => {
17027 const channel = getChannel(room)
17028 const unsubscribed = channel.subs.delete(f)
17029 if (unsubscribed && channel.subs.size === 0) {
17030 channel.bc.close()
17031 channels.delete(room)
17032 }
17033 return unsubscribed
17034 }
17035
17036 /**
17037 * Publish data to all subscribers (including subscribers on this tab)
17038 *
17039 * @function
17040 * @param {string} room
17041 * @param {any} data
17042 * @param {any} [origin]
17043 */
17044 const publish = (room, data, origin = null) => {
17045 const c = getChannel(room)
17046 c.bc.postMessage(data)
17047 c.subs.forEach(sub => sub(data, origin))
17048 }
17049
17050 ;// CONCATENATED MODULE: ./node_modules/lib0/mutex.js
17051 /**
17052 * Mutual exclude for JavaScript.
17053 *
17054 * @module mutex
17055 */
17056
17057 /**
17058 * @callback mutex
17059 * @param {function():void} cb Only executed when this mutex is not in the current stack
17060 * @param {function():void} [elseCb] Executed when this mutex is in the current stack
17061 */
17062
17063 /**
17064 * Creates a mutual exclude function with the following property:
17065 *
17066 * ```js
17067 * const mutex = createMutex()
17068 * mutex(() => {
17069 * // This function is immediately executed
17070 * mutex(() => {
17071 * // This function is not executed, as the mutex is already active.
17072 * })
17073 * })
17074 * ```
17075 *
17076 * @return {mutex} A mutual exclude function
17077 * @public
17078 */
17079 const createMutex = () => {
17080 let token = true
17081 return (f, g) => {
17082 if (token) {
17083 token = false
17084 try {
17085 f()
17086 } finally {
17087 token = true
17088 }
17089 } else if (g !== undefined) {
17090 g()
17091 }
17092 }
17093 }
17094
17095 // EXTERNAL MODULE: ./node_modules/simple-peer/simplepeer.min.js
17096 var simplepeer_min = __webpack_require__(2248);
17097 var simplepeer_min_default = /*#__PURE__*/__webpack_require__.n(simplepeer_min);
17098 ;// CONCATENATED MODULE: ./node_modules/y-protocols/sync.js
17099 /**
17100 * @module sync-protocol
17101 */
17102
17103
17104
17105
17106
17107 /**
17108 * @typedef {Map<number, number>} StateMap
17109 */
17110
17111 /**
17112 * Core Yjs defines two message types:
17113 * • YjsSyncStep1: Includes the State Set of the sending client. When received, the client should reply with YjsSyncStep2.
17114 * • YjsSyncStep2: Includes all missing structs and the complete delete set. When received, the client is assured that it
17115 * received all information from the remote client.
17116 *
17117 * In a peer-to-peer network, you may want to introduce a SyncDone message type. Both parties should initiate the connection
17118 * with SyncStep1. When a client received SyncStep2, it should reply with SyncDone. When the local client received both
17119 * SyncStep2 and SyncDone, it is assured that it is synced to the remote client.
17120 *
17121 * In a client-server model, you want to handle this differently: The client should initiate the connection with SyncStep1.
17122 * When the server receives SyncStep1, it should reply with SyncStep2 immediately followed by SyncStep1. The client replies
17123 * with SyncStep2 when it receives SyncStep1. Optionally the server may send a SyncDone after it received SyncStep2, so the
17124 * client knows that the sync is finished. There are two reasons for this more elaborated sync model: 1. This protocol can
17125 * easily be implemented on top of http and websockets. 2. The server shoul only reply to requests, and not initiate them.
17126 * Therefore it is necesarry that the client initiates the sync.
17127 *
17128 * Construction of a message:
17129 * [messageType : varUint, message definition..]
17130 *
17131 * Note: A message does not include information about the room name. This must to be handled by the upper layer protocol!
17132 *
17133 * stringify[messageType] stringifies a message definition (messageType is already read from the bufffer)
17134 */
17135
17136 const messageYjsSyncStep1 = 0
17137 const messageYjsSyncStep2 = 1
17138 const messageYjsUpdate = 2
17139
17140 /**
17141 * Create a sync step 1 message based on the state of the current shared document.
17142 *
17143 * @param {encoding.Encoder} encoder
17144 * @param {Y.Doc} doc
17145 */
17146 const writeSyncStep1 = (encoder, doc) => {
17147 writeVarUint(encoder, messageYjsSyncStep1)
17148 const sv = encodeStateVector(doc)
17149 writeVarUint8Array(encoder, sv)
17150 }
17151
17152 /**
17153 * @param {encoding.Encoder} encoder
17154 * @param {Y.Doc} doc
17155 * @param {Uint8Array} [encodedStateVector]
17156 */
17157 const writeSyncStep2 = (encoder, doc, encodedStateVector) => {
17158 writeVarUint(encoder, messageYjsSyncStep2)
17159 writeVarUint8Array(encoder, encodeStateAsUpdate(doc, encodedStateVector))
17160 }
17161
17162 /**
17163 * Read SyncStep1 message and reply with SyncStep2.
17164 *
17165 * @param {decoding.Decoder} decoder The reply to the received message
17166 * @param {encoding.Encoder} encoder The received message
17167 * @param {Y.Doc} doc
17168 */
17169 const readSyncStep1 = (decoder, encoder, doc) =>
17170 writeSyncStep2(encoder, doc, readVarUint8Array(decoder))
17171
17172 /**
17173 * Read and apply Structs and then DeleteStore to a y instance.
17174 *
17175 * @param {decoding.Decoder} decoder
17176 * @param {Y.Doc} doc
17177 * @param {any} transactionOrigin
17178 */
17179 const readSyncStep2 = (decoder, doc, transactionOrigin) => {
17180 try {
17181 applyUpdate(doc, readVarUint8Array(decoder), transactionOrigin)
17182 } catch (error) {
17183 // This catches errors that are thrown by event handlers
17184 console.error('Caught error while handling a Yjs update', error)
17185 }
17186 }
17187
17188 /**
17189 * @param {encoding.Encoder} encoder
17190 * @param {Uint8Array} update
17191 */
17192 const writeUpdate = (encoder, update) => {
17193 writeVarUint(encoder, messageYjsUpdate)
17194 writeVarUint8Array(encoder, update)
17195 }
17196
17197 /**
17198 * Read and apply Structs and then DeleteStore to a y instance.
17199 *
17200 * @param {decoding.Decoder} decoder
17201 * @param {Y.Doc} doc
17202 * @param {any} transactionOrigin
17203 */
17204 const sync_readUpdate = readSyncStep2
17205
17206 /**
17207 * @param {decoding.Decoder} decoder A message received from another client
17208 * @param {encoding.Encoder} encoder The reply message. Will not be sent if empty.
17209 * @param {Y.Doc} doc
17210 * @param {any} transactionOrigin
17211 */
17212 const readSyncMessage = (decoder, encoder, doc, transactionOrigin) => {
17213 const messageType = readVarUint(decoder)
17214 switch (messageType) {
17215 case messageYjsSyncStep1:
17216 readSyncStep1(decoder, encoder, doc)
17217 break
17218 case messageYjsSyncStep2:
17219 readSyncStep2(decoder, doc, transactionOrigin)
17220 break
17221 case messageYjsUpdate:
17222 sync_readUpdate(decoder, doc, transactionOrigin)
17223 break
17224 default:
17225 throw new Error('Unknown message type')
17226 }
17227 return messageType
17228 }
17229
17230 ;// CONCATENATED MODULE: ./node_modules/y-protocols/awareness.js
17231 /**
17232 * @module awareness-protocol
17233 */
17234
17235
17236
17237
17238
17239
17240
17241 // eslint-disable-line
17242
17243 const outdatedTimeout = 30000
17244
17245 /**
17246 * @typedef {Object} MetaClientState
17247 * @property {number} MetaClientState.clock
17248 * @property {number} MetaClientState.lastUpdated unix timestamp
17249 */
17250
17251 /**
17252 * The Awareness class implements a simple shared state protocol that can be used for non-persistent data like awareness information
17253 * (cursor, username, status, ..). Each client can update its own local state and listen to state changes of
17254 * remote clients. Every client may set a state of a remote peer to `null` to mark the client as offline.
17255 *
17256 * Each client is identified by a unique client id (something we borrow from `doc.clientID`). A client can override
17257 * its own state by propagating a message with an increasing timestamp (`clock`). If such a message is received, it is
17258 * applied if the known state of that client is older than the new state (`clock < newClock`). If a client thinks that
17259 * a remote client is offline, it may propagate a message with
17260 * `{ clock: currentClientClock, state: null, client: remoteClient }`. If such a
17261 * message is received, and the known clock of that client equals the received clock, it will override the state with `null`.
17262 *
17263 * Before a client disconnects, it should propagate a `null` state with an updated clock.
17264 *
17265 * Awareness states must be updated every 30 seconds. Otherwise the Awareness instance will delete the client state.
17266 *
17267 * @extends {Observable<string>}
17268 */
17269 class Awareness extends observable_Observable {
17270 /**
17271 * @param {Y.Doc} doc
17272 */
17273 constructor (doc) {
17274 super()
17275 this.doc = doc
17276 /**
17277 * @type {number}
17278 */
17279 this.clientID = doc.clientID
17280 /**
17281 * Maps from client id to client state
17282 * @type {Map<number, Object<string, any>>}
17283 */
17284 this.states = new Map()
17285 /**
17286 * @type {Map<number, MetaClientState>}
17287 */
17288 this.meta = new Map()
17289 this._checkInterval = /** @type {any} */ (setInterval(() => {
17290 const now = getUnixTime()
17291 if (this.getLocalState() !== null && (outdatedTimeout / 2 <= now - /** @type {{lastUpdated:number}} */ (this.meta.get(this.clientID)).lastUpdated)) {
17292 // renew local clock
17293 this.setLocalState(this.getLocalState())
17294 }
17295 /**
17296 * @type {Array<number>}
17297 */
17298 const remove = []
17299 this.meta.forEach((meta, clientid) => {
17300 if (clientid !== this.clientID && outdatedTimeout <= now - meta.lastUpdated && this.states.has(clientid)) {
17301 remove.push(clientid)
17302 }
17303 })
17304 if (remove.length > 0) {
17305 removeAwarenessStates(this, remove, 'timeout')
17306 }
17307 }, floor(outdatedTimeout / 10)))
17308 doc.on('destroy', () => {
17309 this.destroy()
17310 })
17311 this.setLocalState({})
17312 }
17313
17314 destroy () {
17315 this.emit('destroy', [this])
17316 this.setLocalState(null)
17317 super.destroy()
17318 clearInterval(this._checkInterval)
17319 }
17320
17321 /**
17322 * @return {Object<string,any>|null}
17323 */
17324 getLocalState () {
17325 return this.states.get(this.clientID) || null
17326 }
17327
17328 /**
17329 * @param {Object<string,any>|null} state
17330 */
17331 setLocalState (state) {
17332 const clientID = this.clientID
17333 const currLocalMeta = this.meta.get(clientID)
17334 const clock = currLocalMeta === undefined ? 0 : currLocalMeta.clock + 1
17335 const prevState = this.states.get(clientID)
17336 if (state === null) {
17337 this.states.delete(clientID)
17338 } else {
17339 this.states.set(clientID, state)
17340 }
17341 this.meta.set(clientID, {
17342 clock,
17343 lastUpdated: getUnixTime()
17344 })
17345 const added = []
17346 const updated = []
17347 const filteredUpdated = []
17348 const removed = []
17349 if (state === null) {
17350 removed.push(clientID)
17351 } else if (prevState == null) {
17352 if (state != null) {
17353 added.push(clientID)
17354 }
17355 } else {
17356 updated.push(clientID)
17357 if (!equalityDeep(prevState, state)) {
17358 filteredUpdated.push(clientID)
17359 }
17360 }
17361 if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
17362 this.emit('change', [{ added, updated: filteredUpdated, removed }, 'local'])
17363 }
17364 this.emit('update', [{ added, updated, removed }, 'local'])
17365 }
17366
17367 /**
17368 * @param {string} field
17369 * @param {any} value
17370 */
17371 setLocalStateField (field, value) {
17372 const state = this.getLocalState()
17373 if (state !== null) {
17374 this.setLocalState({
17375 ...state,
17376 [field]: value
17377 })
17378 }
17379 }
17380
17381 /**
17382 * @return {Map<number,Object<string,any>>}
17383 */
17384 getStates () {
17385 return this.states
17386 }
17387 }
17388
17389 /**
17390 * Mark (remote) clients as inactive and remove them from the list of active peers.
17391 * This change will be propagated to remote clients.
17392 *
17393 * @param {Awareness} awareness
17394 * @param {Array<number>} clients
17395 * @param {any} origin
17396 */
17397 const removeAwarenessStates = (awareness, clients, origin) => {
17398 const removed = []
17399 for (let i = 0; i < clients.length; i++) {
17400 const clientID = clients[i]
17401 if (awareness.states.has(clientID)) {
17402 awareness.states.delete(clientID)
17403 if (clientID === awareness.clientID) {
17404 const curMeta = /** @type {MetaClientState} */ (awareness.meta.get(clientID))
17405 awareness.meta.set(clientID, {
17406 clock: curMeta.clock + 1,
17407 lastUpdated: getUnixTime()
17408 })
17409 }
17410 removed.push(clientID)
17411 }
17412 }
17413 if (removed.length > 0) {
17414 awareness.emit('change', [{ added: [], updated: [], removed }, origin])
17415 awareness.emit('update', [{ added: [], updated: [], removed }, origin])
17416 }
17417 }
17418
17419 /**
17420 * @param {Awareness} awareness
17421 * @param {Array<number>} clients
17422 * @return {Uint8Array}
17423 */
17424 const encodeAwarenessUpdate = (awareness, clients, states = awareness.states) => {
17425 const len = clients.length
17426 const encoder = createEncoder()
17427 writeVarUint(encoder, len)
17428 for (let i = 0; i < len; i++) {
17429 const clientID = clients[i]
17430 const state = states.get(clientID) || null
17431 const clock = /** @type {MetaClientState} */ (awareness.meta.get(clientID)).clock
17432 writeVarUint(encoder, clientID)
17433 writeVarUint(encoder, clock)
17434 writeVarString(encoder, JSON.stringify(state))
17435 }
17436 return toUint8Array(encoder)
17437 }
17438
17439 /**
17440 * Modify the content of an awareness update before re-encoding it to an awareness update.
17441 *
17442 * This might be useful when you have a central server that wants to ensure that clients
17443 * cant hijack somebody elses identity.
17444 *
17445 * @param {Uint8Array} update
17446 * @param {function(any):any} modify
17447 * @return {Uint8Array}
17448 */
17449 const modifyAwarenessUpdate = (update, modify) => {
17450 const decoder = decoding.createDecoder(update)
17451 const encoder = encoding.createEncoder()
17452 const len = decoding.readVarUint(decoder)
17453 encoding.writeVarUint(encoder, len)
17454 for (let i = 0; i < len; i++) {
17455 const clientID = decoding.readVarUint(decoder)
17456 const clock = decoding.readVarUint(decoder)
17457 const state = JSON.parse(decoding.readVarString(decoder))
17458 const modifiedState = modify(state)
17459 encoding.writeVarUint(encoder, clientID)
17460 encoding.writeVarUint(encoder, clock)
17461 encoding.writeVarString(encoder, JSON.stringify(modifiedState))
17462 }
17463 return encoding.toUint8Array(encoder)
17464 }
17465
17466 /**
17467 * @param {Awareness} awareness
17468 * @param {Uint8Array} update
17469 * @param {any} origin This will be added to the emitted change event
17470 */
17471 const applyAwarenessUpdate = (awareness, update, origin) => {
17472 const decoder = createDecoder(update)
17473 const timestamp = getUnixTime()
17474 const added = []
17475 const updated = []
17476 const filteredUpdated = []
17477 const removed = []
17478 const len = readVarUint(decoder)
17479 for (let i = 0; i < len; i++) {
17480 const clientID = readVarUint(decoder)
17481 let clock = readVarUint(decoder)
17482 const state = JSON.parse(readVarString(decoder))
17483 const clientMeta = awareness.meta.get(clientID)
17484 const prevState = awareness.states.get(clientID)
17485 const currClock = clientMeta === undefined ? 0 : clientMeta.clock
17486 if (currClock < clock || (currClock === clock && state === null && awareness.states.has(clientID))) {
17487 if (state === null) {
17488 // never let a remote client remove this local state
17489 if (clientID === awareness.clientID && awareness.getLocalState() != null) {
17490 // remote client removed the local state. Do not remote state. Broadcast a message indicating
17491 // that this client still exists by increasing the clock
17492 clock++
17493 } else {
17494 awareness.states.delete(clientID)
17495 }
17496 } else {
17497 awareness.states.set(clientID, state)
17498 }
17499 awareness.meta.set(clientID, {
17500 clock,
17501 lastUpdated: timestamp
17502 })
17503 if (clientMeta === undefined && state !== null) {
17504 added.push(clientID)
17505 } else if (clientMeta !== undefined && state === null) {
17506 removed.push(clientID)
17507 } else if (state !== null) {
17508 if (!equalityDeep(state, prevState)) {
17509 filteredUpdated.push(clientID)
17510 }
17511 updated.push(clientID)
17512 }
17513 }
17514 }
17515 if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
17516 awareness.emit('change', [{
17517 added, updated: filteredUpdated, removed
17518 }, origin])
17519 }
17520 if (added.length > 0 || updated.length > 0 || removed.length > 0) {
17521 awareness.emit('update', [{
17522 added, updated, removed
17523 }, origin])
17524 }
17525 }
17526
17527 ;// CONCATENATED MODULE: ./packages/sync/build-module/y-webrtc/crypto.js
17528 // File copied as is from the y-webrtc package.
17529 /* eslint-disable eslint-comments/disable-enable-pair */
17530 /* eslint-disable eslint-comments/no-unlimited-disable */
17531 /* eslint-disable */
17532 // @ts-nocheck
17533 /* eslint-env browser */
17534
17535
17536
17537
17538
17539
17540
17541 /**
17542 * @param {string} secret
17543 * @param {string} roomName
17544 * @return {PromiseLike<CryptoKey>}
17545 */
17546 const deriveKey = (secret, roomName) => {
17547 const secretBuffer = encodeUtf8(secret).buffer;
17548 const salt = encodeUtf8(roomName).buffer;
17549 return crypto.subtle.importKey('raw', secretBuffer, 'PBKDF2', false, ['deriveKey']).then(keyMaterial => crypto.subtle.deriveKey({
17550 name: 'PBKDF2',
17551 salt,
17552 iterations: 100000,
17553 hash: 'SHA-256'
17554 }, keyMaterial, {
17555 name: 'AES-GCM',
17556 length: 256
17557 }, true, ['encrypt', 'decrypt']));
17558 };
17559
17560 /**
17561 * @param {Uint8Array} data data to be encrypted
17562 * @param {CryptoKey?} key
17563 * @return {PromiseLike<Uint8Array>} encrypted, base64 encoded message
17564 */
17565 const encrypt = (data, key) => {
17566 if (!key) {
17567 return /** @type {PromiseLike<Uint8Array>} */(
17568 resolve(data)
17569 );
17570 }
17571 const iv = crypto.getRandomValues(new Uint8Array(12));
17572 return crypto.subtle.encrypt({
17573 name: 'AES-GCM',
17574 iv
17575 }, key, data).then(cipher => {
17576 const encryptedDataEncoder = createEncoder();
17577 writeVarString(encryptedDataEncoder, 'AES-GCM');
17578 writeVarUint8Array(encryptedDataEncoder, iv);
17579 writeVarUint8Array(encryptedDataEncoder, new Uint8Array(cipher));
17580 return toUint8Array(encryptedDataEncoder);
17581 });
17582 };
17583
17584 /**
17585 * @param {Object} data data to be encrypted
17586 * @param {CryptoKey?} key
17587 * @return {PromiseLike<Uint8Array>} encrypted data, if key is provided
17588 */
17589 const encryptJson = (data, key) => {
17590 const dataEncoder = createEncoder();
17591 writeAny(dataEncoder, data);
17592 return encrypt(toUint8Array(dataEncoder), key);
17593 };
17594
17595 /**
17596 * @param {Uint8Array} data
17597 * @param {CryptoKey?} key
17598 * @return {PromiseLike<Uint8Array>} decrypted buffer
17599 */
17600 const decrypt = (data, key) => {
17601 if (!key) {
17602 return /** @type {PromiseLike<Uint8Array>} */(
17603 resolve(data)
17604 );
17605 }
17606 const dataDecoder = createDecoder(data);
17607 const algorithm = readVarString(dataDecoder);
17608 if (algorithm !== 'AES-GCM') {
17609 reject(error_create('Unknown encryption algorithm'));
17610 }
17611 const iv = readVarUint8Array(dataDecoder);
17612 const cipher = readVarUint8Array(dataDecoder);
17613 return crypto.subtle.decrypt({
17614 name: 'AES-GCM',
17615 iv
17616 }, key, cipher).then(data => new Uint8Array(data));
17617 };
17618
17619 /**
17620 * @param {Uint8Array} data
17621 * @param {CryptoKey?} key
17622 * @return {PromiseLike<Object>} decrypted object
17623 */
17624 const decryptJson = (data, key) => decrypt(data, key).then(decryptedValue => readAny(createDecoder(new Uint8Array(decryptedValue))));
17625
17626 ;// CONCATENATED MODULE: ./packages/sync/build-module/y-webrtc/y-webrtc.js
17627 // File copied as is from the y-webrtc package with only exports
17628 // added to the following vars/functions: signalingConns,rooms, publishSignalingMessage, log.
17629 /* eslint-disable eslint-comments/disable-enable-pair */
17630 /* eslint-disable eslint-comments/no-unlimited-disable */
17631 /* eslint-disable */
17632 // @ts-nocheck
17633
17634
17635
17636
17637
17638
17639
17640
17641
17642
17643
17644
17645
17646
17647 // eslint-disable-line
17648
17649
17650
17651
17652 const y_webrtc_log = logging_createModuleLogger('y-webrtc');
17653 const messageSync = 0;
17654 const messageQueryAwareness = 3;
17655 const messageAwareness = 1;
17656 const messageBcPeerId = 4;
17657
17658 /**
17659 * @type {Map<string, SignalingConn>}
17660 */
17661 const signalingConns = new Map();
17662
17663 /**
17664 * @type {Map<string,Room>}
17665 */
17666 const rooms = new Map();
17667
17668 /**
17669 * @param {Room} room
17670 */
17671 const checkIsSynced = room => {
17672 let synced = true;
17673 room.webrtcConns.forEach(peer => {
17674 if (!peer.synced) {
17675 synced = false;
17676 }
17677 });
17678 if (!synced && room.synced || synced && !room.synced) {
17679 room.synced = synced;
17680 room.provider.emit('synced', [{
17681 synced
17682 }]);
17683 y_webrtc_log('synced ', BOLD, room.name, UNBOLD, ' with all peers');
17684 }
17685 };
17686
17687 /**
17688 * @param {Room} room
17689 * @param {Uint8Array} buf
17690 * @param {function} syncedCallback
17691 * @return {encoding.Encoder?}
17692 */
17693 const readMessage = (room, buf, syncedCallback) => {
17694 const decoder = createDecoder(buf);
17695 const encoder = createEncoder();
17696 const messageType = readVarUint(decoder);
17697 if (room === undefined) {
17698 return null;
17699 }
17700 const awareness = room.awareness;
17701 const doc = room.doc;
17702 let sendReply = false;
17703 switch (messageType) {
17704 case messageSync:
17705 {
17706 writeVarUint(encoder, messageSync);
17707 const syncMessageType = readSyncMessage(decoder, encoder, doc, room);
17708 if (syncMessageType === messageYjsSyncStep2 && !room.synced) {
17709 syncedCallback();
17710 }
17711 if (syncMessageType === messageYjsSyncStep1) {
17712 sendReply = true;
17713 }
17714 break;
17715 }
17716 case messageQueryAwareness:
17717 writeVarUint(encoder, messageAwareness);
17718 writeVarUint8Array(encoder, encodeAwarenessUpdate(awareness, Array.from(awareness.getStates().keys())));
17719 sendReply = true;
17720 break;
17721 case messageAwareness:
17722 applyAwarenessUpdate(awareness, readVarUint8Array(decoder), room);
17723 break;
17724 case messageBcPeerId:
17725 {
17726 const add = readUint8(decoder) === 1;
17727 const peerName = readVarString(decoder);
17728 if (peerName !== room.peerId && (room.bcConns.has(peerName) && !add || !room.bcConns.has(peerName) && add)) {
17729 const removed = [];
17730 const added = [];
17731 if (add) {
17732 room.bcConns.add(peerName);
17733 added.push(peerName);
17734 } else {
17735 room.bcConns.delete(peerName);
17736 removed.push(peerName);
17737 }
17738 room.provider.emit('peers', [{
17739 added,
17740 removed,
17741 webrtcPeers: Array.from(room.webrtcConns.keys()),
17742 bcPeers: Array.from(room.bcConns)
17743 }]);
17744 broadcastBcPeerId(room);
17745 }
17746 break;
17747 }
17748 default:
17749 console.error('Unable to compute message');
17750 return encoder;
17751 }
17752 if (!sendReply) {
17753 // nothing has been written, no answer created
17754 return null;
17755 }
17756 return encoder;
17757 };
17758
17759 /**
17760 * @param {WebrtcConn} peerConn
17761 * @param {Uint8Array} buf
17762 * @return {encoding.Encoder?}
17763 */
17764 const readPeerMessage = (peerConn, buf) => {
17765 const room = peerConn.room;
17766 y_webrtc_log('received message from ', BOLD, peerConn.remotePeerId, GREY, ' (', room.name, ')', UNBOLD, UNCOLOR);
17767 return readMessage(room, buf, () => {
17768 peerConn.synced = true;
17769 y_webrtc_log('synced ', BOLD, room.name, UNBOLD, ' with ', BOLD, peerConn.remotePeerId);
17770 checkIsSynced(room);
17771 });
17772 };
17773
17774 /**
17775 * @param {WebrtcConn} webrtcConn
17776 * @param {encoding.Encoder} encoder
17777 */
17778 const sendWebrtcConn = (webrtcConn, encoder) => {
17779 y_webrtc_log('send message to ', BOLD, webrtcConn.remotePeerId, UNBOLD, GREY, ' (', webrtcConn.room.name, ')', UNCOLOR);
17780 try {
17781 webrtcConn.peer.send(toUint8Array(encoder));
17782 } catch (e) {}
17783 };
17784
17785 /**
17786 * @param {Room} room
17787 * @param {Uint8Array} m
17788 */
17789 const broadcastWebrtcConn = (room, m) => {
17790 y_webrtc_log('broadcast message in ', BOLD, room.name, UNBOLD);
17791 room.webrtcConns.forEach(conn => {
17792 try {
17793 conn.peer.send(m);
17794 } catch (e) {}
17795 });
17796 };
17797 class WebrtcConn {
17798 /**
17799 * @param {SignalingConn} signalingConn
17800 * @param {boolean} initiator
17801 * @param {string} remotePeerId
17802 * @param {Room} room
17803 */
17804 constructor(signalingConn, initiator, remotePeerId, room) {
17805 y_webrtc_log('establishing connection to ', BOLD, remotePeerId);
17806 this.room = room;
17807 this.remotePeerId = remotePeerId;
17808 this.glareToken = undefined;
17809 this.closed = false;
17810 this.connected = false;
17811 this.synced = false;
17812 /**
17813 * @type {any}
17814 */
17815 this.peer = new (simplepeer_min_default())({
17816 initiator,
17817 ...room.provider.peerOpts
17818 });
17819 this.peer.on('signal', signal => {
17820 if (this.glareToken === undefined) {
17821 // add some randomness to the timestamp of the offer
17822 this.glareToken = Date.now() + Math.random();
17823 }
17824 publishSignalingMessage(signalingConn, room, {
17825 to: remotePeerId,
17826 from: room.peerId,
17827 type: 'signal',
17828 token: this.glareToken,
17829 signal
17830 });
17831 });
17832 this.peer.on('connect', () => {
17833 y_webrtc_log('connected to ', BOLD, remotePeerId);
17834 this.connected = true;
17835 // send sync step 1
17836 const provider = room.provider;
17837 const doc = provider.doc;
17838 const awareness = room.awareness;
17839 const encoder = createEncoder();
17840 writeVarUint(encoder, messageSync);
17841 writeSyncStep1(encoder, doc);
17842 sendWebrtcConn(this, encoder);
17843 const awarenessStates = awareness.getStates();
17844 if (awarenessStates.size > 0) {
17845 const encoder = createEncoder();
17846 writeVarUint(encoder, messageAwareness);
17847 writeVarUint8Array(encoder, encodeAwarenessUpdate(awareness, Array.from(awarenessStates.keys())));
17848 sendWebrtcConn(this, encoder);
17849 }
17850 });
17851 this.peer.on('close', () => {
17852 this.connected = false;
17853 this.closed = true;
17854 if (room.webrtcConns.has(this.remotePeerId)) {
17855 room.webrtcConns.delete(this.remotePeerId);
17856 room.provider.emit('peers', [{
17857 removed: [this.remotePeerId],
17858 added: [],
17859 webrtcPeers: Array.from(room.webrtcConns.keys()),
17860 bcPeers: Array.from(room.bcConns)
17861 }]);
17862 }
17863 checkIsSynced(room);
17864 this.peer.destroy();
17865 y_webrtc_log('closed connection to ', BOLD, remotePeerId);
17866 announceSignalingInfo(room);
17867 });
17868 this.peer.on('error', err => {
17869 y_webrtc_log('Error in connection to ', BOLD, remotePeerId, ': ', err);
17870 announceSignalingInfo(room);
17871 });
17872 this.peer.on('data', data => {
17873 const answer = readPeerMessage(this, data);
17874 if (answer !== null) {
17875 sendWebrtcConn(this, answer);
17876 }
17877 });
17878 }
17879 destroy() {
17880 this.peer.destroy();
17881 }
17882 }
17883
17884 /**
17885 * @param {Room} room
17886 * @param {Uint8Array} m
17887 */
17888 const broadcastBcMessage = (room, m) => encrypt(m, room.key).then(data => room.mux(() => publish(room.name, data)));
17889
17890 /**
17891 * @param {Room} room
17892 * @param {Uint8Array} m
17893 */
17894 const broadcastRoomMessage = (room, m) => {
17895 if (room.bcconnected) {
17896 broadcastBcMessage(room, m);
17897 }
17898 broadcastWebrtcConn(room, m);
17899 };
17900
17901 /**
17902 * @param {Room} room
17903 */
17904 const announceSignalingInfo = room => {
17905 signalingConns.forEach(conn => {
17906 // only subscribe if connection is established, otherwise the conn automatically subscribes to all rooms
17907 if (conn.connected) {
17908 conn.send({
17909 type: 'subscribe',
17910 topics: [room.name]
17911 });
17912 if (room.webrtcConns.size < room.provider.maxConns) {
17913 publishSignalingMessage(conn, room, {
17914 type: 'announce',
17915 from: room.peerId
17916 });
17917 }
17918 }
17919 });
17920 };
17921
17922 /**
17923 * @param {Room} room
17924 */
17925 const broadcastBcPeerId = room => {
17926 if (room.provider.filterBcConns) {
17927 // broadcast peerId via broadcastchannel
17928 const encoderPeerIdBc = createEncoder();
17929 writeVarUint(encoderPeerIdBc, messageBcPeerId);
17930 writeUint8(encoderPeerIdBc, 1);
17931 writeVarString(encoderPeerIdBc, room.peerId);
17932 broadcastBcMessage(room, toUint8Array(encoderPeerIdBc));
17933 }
17934 };
17935 class Room {
17936 /**
17937 * @param {Y.Doc} doc
17938 * @param {WebrtcProvider} provider
17939 * @param {string} name
17940 * @param {CryptoKey|null} key
17941 */
17942 constructor(doc, provider, name, key) {
17943 /**
17944 * Do not assume that peerId is unique. This is only meant for sending signaling messages.
17945 *
17946 * @type {string}
17947 */
17948 this.peerId = uuidv4();
17949 this.doc = doc;
17950 /**
17951 * @type {awarenessProtocol.Awareness}
17952 */
17953 this.awareness = provider.awareness;
17954 this.provider = provider;
17955 this.synced = false;
17956 this.name = name;
17957 // @todo make key secret by scoping
17958 this.key = key;
17959 /**
17960 * @type {Map<string, WebrtcConn>}
17961 */
17962 this.webrtcConns = new Map();
17963 /**
17964 * @type {Set<string>}
17965 */
17966 this.bcConns = new Set();
17967 this.mux = createMutex();
17968 this.bcconnected = false;
17969 /**
17970 * @param {ArrayBuffer} data
17971 */
17972 this._bcSubscriber = data => decrypt(new Uint8Array(data), key).then(m => this.mux(() => {
17973 const reply = readMessage(this, m, () => {});
17974 if (reply) {
17975 broadcastBcMessage(this, toUint8Array(reply));
17976 }
17977 }));
17978 /**
17979 * Listens to Yjs updates and sends them to remote peers
17980 *
17981 * @param {Uint8Array} update
17982 * @param {any} origin
17983 */
17984 this._docUpdateHandler = (update, origin) => {
17985 const encoder = createEncoder();
17986 writeVarUint(encoder, messageSync);
17987 writeUpdate(encoder, update);
17988 broadcastRoomMessage(this, toUint8Array(encoder));
17989 };
17990 /**
17991 * Listens to Awareness updates and sends them to remote peers
17992 *
17993 * @param {any} changed
17994 * @param {any} origin
17995 */
17996 this._awarenessUpdateHandler = ({
17997 added,
17998 updated,
17999 removed
18000 }, origin) => {
18001 const changedClients = added.concat(updated).concat(removed);
18002 const encoderAwareness = createEncoder();
18003 writeVarUint(encoderAwareness, messageAwareness);
18004 writeVarUint8Array(encoderAwareness, encodeAwarenessUpdate(this.awareness, changedClients));
18005 broadcastRoomMessage(this, toUint8Array(encoderAwareness));
18006 };
18007 this._beforeUnloadHandler = () => {
18008 removeAwarenessStates(this.awareness, [doc.clientID], 'window unload');
18009 rooms.forEach(room => {
18010 room.disconnect();
18011 });
18012 };
18013 if (typeof window !== 'undefined') {
18014 window.addEventListener('beforeunload', this._beforeUnloadHandler);
18015 } else if (typeof process !== 'undefined') {
18016 process.on('exit', this._beforeUnloadHandler);
18017 }
18018 }
18019 connect() {
18020 this.doc.on('update', this._docUpdateHandler);
18021 this.awareness.on('update', this._awarenessUpdateHandler);
18022 // signal through all available signaling connections
18023 announceSignalingInfo(this);
18024 const roomName = this.name;
18025 subscribe(roomName, this._bcSubscriber);
18026 this.bcconnected = true;
18027 // broadcast peerId via broadcastchannel
18028 broadcastBcPeerId(this);
18029 // write sync step 1
18030 const encoderSync = createEncoder();
18031 writeVarUint(encoderSync, messageSync);
18032 writeSyncStep1(encoderSync, this.doc);
18033 broadcastBcMessage(this, toUint8Array(encoderSync));
18034 // broadcast local state
18035 const encoderState = createEncoder();
18036 writeVarUint(encoderState, messageSync);
18037 writeSyncStep2(encoderState, this.doc);
18038 broadcastBcMessage(this, toUint8Array(encoderState));
18039 // write queryAwareness
18040 const encoderAwarenessQuery = createEncoder();
18041 writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
18042 broadcastBcMessage(this, toUint8Array(encoderAwarenessQuery));
18043 // broadcast local awareness state
18044 const encoderAwarenessState = createEncoder();
18045 writeVarUint(encoderAwarenessState, messageAwareness);
18046 writeVarUint8Array(encoderAwarenessState, encodeAwarenessUpdate(this.awareness, [this.doc.clientID]));
18047 broadcastBcMessage(this, toUint8Array(encoderAwarenessState));
18048 }
18049 disconnect() {
18050 // signal through all available signaling connections
18051 signalingConns.forEach(conn => {
18052 if (conn.connected) {
18053 conn.send({
18054 type: 'unsubscribe',
18055 topics: [this.name]
18056 });
18057 }
18058 });
18059 removeAwarenessStates(this.awareness, [this.doc.clientID], 'disconnect');
18060 // broadcast peerId removal via broadcastchannel
18061 const encoderPeerIdBc = createEncoder();
18062 writeVarUint(encoderPeerIdBc, messageBcPeerId);
18063 writeUint8(encoderPeerIdBc, 0); // remove peerId from other bc peers
18064 writeVarString(encoderPeerIdBc, this.peerId);
18065 broadcastBcMessage(this, toUint8Array(encoderPeerIdBc));
18066 unsubscribe(this.name, this._bcSubscriber);
18067 this.bcconnected = false;
18068 this.doc.off('update', this._docUpdateHandler);
18069 this.awareness.off('update', this._awarenessUpdateHandler);
18070 this.webrtcConns.forEach(conn => conn.destroy());
18071 }
18072 destroy() {
18073 this.disconnect();
18074 if (typeof window !== 'undefined') {
18075 window.removeEventListener('beforeunload', this._beforeUnloadHandler);
18076 } else if (typeof process !== 'undefined') {
18077 process.off('exit', this._beforeUnloadHandler);
18078 }
18079 }
18080 }
18081
18082 /**
18083 * @param {Y.Doc} doc
18084 * @param {WebrtcProvider} provider
18085 * @param {string} name
18086 * @param {CryptoKey|null} key
18087 * @return {Room}
18088 */
18089 const openRoom = (doc, provider, name, key) => {
18090 // there must only be one room
18091 if (rooms.has(name)) {
18092 throw error_create(`A Yjs Doc connected to room "${name}" already exists!`);
18093 }
18094 const room = new Room(doc, provider, name, key);
18095 rooms.set(name, /** @type {Room} */room);
18096 return room;
18097 };
18098
18099 /**
18100 * @param {SignalingConn} conn
18101 * @param {Room} room
18102 * @param {any} data
18103 */
18104 const publishSignalingMessage = (conn, room, data) => {
18105 if (room.key) {
18106 encryptJson(data, room.key).then(data => {
18107 conn.send({
18108 type: 'publish',
18109 topic: room.name,
18110 data: toBase64(data)
18111 });
18112 });
18113 } else {
18114 conn.send({
18115 type: 'publish',
18116 topic: room.name,
18117 data
18118 });
18119 }
18120 };
18121 class SignalingConn extends WebsocketClient {
18122 constructor(url) {
18123 super(url);
18124 /**
18125 * @type {Set<WebrtcProvider>}
18126 */
18127 this.providers = new Set();
18128 this.on('connect', () => {
18129 y_webrtc_log(`connected (${url})`);
18130 const topics = Array.from(rooms.keys());
18131 this.send({
18132 type: 'subscribe',
18133 topics
18134 });
18135 rooms.forEach(room => publishSignalingMessage(this, room, {
18136 type: 'announce',
18137 from: room.peerId
18138 }));
18139 });
18140 this.on('message', m => {
18141 switch (m.type) {
18142 case 'publish':
18143 {
18144 const roomName = m.topic;
18145 const room = rooms.get(roomName);
18146 if (room == null || typeof roomName !== 'string') {
18147 return;
18148 }
18149 const execMessage = data => {
18150 const webrtcConns = room.webrtcConns;
18151 const peerId = room.peerId;
18152 if (data == null || data.from === peerId || data.to !== undefined && data.to !== peerId || room.bcConns.has(data.from)) {
18153 // ignore messages that are not addressed to this conn, or from clients that are connected via broadcastchannel
18154 return;
18155 }
18156 const emitPeerChange = webrtcConns.has(data.from) ? () => {} : () => room.provider.emit('peers', [{
18157 removed: [],
18158 added: [data.from],
18159 webrtcPeers: Array.from(room.webrtcConns.keys()),
18160 bcPeers: Array.from(room.bcConns)
18161 }]);
18162 switch (data.type) {
18163 case 'announce':
18164 if (webrtcConns.size < room.provider.maxConns) {
18165 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(this, true, data.from, room));
18166 emitPeerChange();
18167 }
18168 break;
18169 case 'signal':
18170 if (data.signal.type === 'offer') {
18171 const existingConn = webrtcConns.get(data.from);
18172 if (existingConn) {
18173 const remoteToken = data.token;
18174 const localToken = existingConn.glareToken;
18175 if (localToken && localToken > remoteToken) {
18176 y_webrtc_log('offer rejected: ', data.from);
18177 return;
18178 }
18179 // if we don't reject the offer, we will be accepting it and answering it
18180 existingConn.glareToken = undefined;
18181 }
18182 }
18183 if (data.signal.type === 'answer') {
18184 y_webrtc_log('offer answered by: ', data.from);
18185 const existingConn = webrtcConns.get(data.from);
18186 existingConn.glareToken = undefined;
18187 }
18188 if (data.to === peerId) {
18189 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(this, false, data.from, room)).peer.signal(data.signal);
18190 emitPeerChange();
18191 }
18192 break;
18193 }
18194 };
18195 if (room.key) {
18196 if (typeof m.data === 'string') {
18197 decryptJson(fromBase64(m.data), room.key).then(execMessage);
18198 }
18199 } else {
18200 execMessage(m.data);
18201 }
18202 }
18203 }
18204 });
18205 this.on('disconnect', () => y_webrtc_log(`disconnect (${url})`));
18206 }
18207 }
18208
18209 /**
18210 * @typedef {Object} ProviderOptions
18211 * @property {Array<string>} [signaling]
18212 * @property {string} [password]
18213 * @property {awarenessProtocol.Awareness} [awareness]
18214 * @property {number} [maxConns]
18215 * @property {boolean} [filterBcConns]
18216 * @property {any} [peerOpts]
18217 */
18218
18219 /**
18220 * @extends Observable<string>
18221 */
18222 class WebrtcProvider extends observable_Observable {
18223 /**
18224 * @param {string} roomName
18225 * @param {Y.Doc} doc
18226 * @param {ProviderOptions?} opts
18227 */
18228 constructor(roomName, doc, {
18229 signaling = ['wss://y-webrtc-eu.fly.dev'],
18230 password = null,
18231 awareness = new Awareness(doc),
18232 maxConns = 20 + floor(rand() * 15),
18233 // the random factor reduces the chance that n clients form a cluster
18234 filterBcConns = true,
18235 peerOpts = {} // simple-peer options. See https://github.com/feross/simple-peer#peer--new-peeropts
18236 } = {}) {
18237 super();
18238 this.roomName = roomName;
18239 this.doc = doc;
18240 this.filterBcConns = filterBcConns;
18241 /**
18242 * @type {awarenessProtocol.Awareness}
18243 */
18244 this.awareness = awareness;
18245 this.shouldConnect = false;
18246 this.signalingUrls = signaling;
18247 this.signalingConns = [];
18248 this.maxConns = maxConns;
18249 this.peerOpts = peerOpts;
18250 /**
18251 * @type {PromiseLike<CryptoKey | null>}
18252 */
18253 this.key = password ? deriveKey(password, roomName) : ( /** @type {PromiseLike<null>} */resolve(null));
18254 /**
18255 * @type {Room|null}
18256 */
18257 this.room = null;
18258 this.key.then(key => {
18259 this.room = openRoom(doc, this, roomName, key);
18260 if (this.shouldConnect) {
18261 this.room.connect();
18262 } else {
18263 this.room.disconnect();
18264 }
18265 });
18266 this.connect();
18267 this.destroy = this.destroy.bind(this);
18268 doc.on('destroy', this.destroy);
18269 }
18270
18271 /**
18272 * @type {boolean}
18273 */
18274 get connected() {
18275 return this.room !== null && this.shouldConnect;
18276 }
18277 connect() {
18278 this.shouldConnect = true;
18279 this.signalingUrls.forEach(url => {
18280 const signalingConn = setIfUndefined(signalingConns, url, () => new SignalingConn(url));
18281 this.signalingConns.push(signalingConn);
18282 signalingConn.providers.add(this);
18283 });
18284 if (this.room) {
18285 this.room.connect();
18286 }
18287 }
18288 disconnect() {
18289 this.shouldConnect = false;
18290 this.signalingConns.forEach(conn => {
18291 conn.providers.delete(this);
18292 if (conn.providers.size === 0) {
18293 conn.destroy();
18294 signalingConns.delete(conn.url);
18295 }
18296 });
18297 if (this.room) {
18298 this.room.disconnect();
18299 }
18300 }
18301 destroy() {
18302 this.doc.off('destroy', this.destroy);
18303 // need to wait for key before deleting room
18304 this.key.then(() => {
18305 /** @type {Room} */this.room.destroy();
18306 rooms.delete(this.roomName);
18307 });
18308 super.destroy();
18309 }
18310 }
18311
18312 ;// CONCATENATED MODULE: ./packages/sync/build-module/webrtc-http-stream-signaling.js
18313 /**
18314 * External dependencies
18315 */
18316 /**
18317 * Internal dependencies
18318 */
18319
18320
18321
18322
18323
18324
18325 /**
18326 * WordPress dependencies
18327 */
18328
18329
18330 /**
18331 * Method copied as is from the SignalingConn constructor.
18332 * Setups the needed event handlers for an http signaling connection.
18333 *
18334 * @param {HttpSignalingConn} signalCon The signaling connection.
18335 * @param {string} url The url.
18336 */
18337 function setupSignalEventHandlers(signalCon, url) {
18338 signalCon.on('connect', () => {
18339 y_webrtc_log(`connected (${url})`);
18340 const topics = Array.from(rooms.keys());
18341 signalCon.send({
18342 type: 'subscribe',
18343 topics
18344 });
18345 rooms.forEach(room => publishSignalingMessage(signalCon, room, {
18346 type: 'announce',
18347 from: room.peerId
18348 }));
18349 });
18350 signalCon.on('message', ( /** @type {{ type: any; topic: any; data: string; }} */m) => {
18351 switch (m.type) {
18352 case 'publish':
18353 {
18354 const roomName = m.topic;
18355 const room = rooms.get(roomName);
18356 if (room === null || typeof roomName !== 'string' || room === undefined) {
18357 return;
18358 }
18359 const execMessage = ( /** @type {any} */data) => {
18360 const webrtcConns = room.webrtcConns;
18361 const peerId = room.peerId;
18362 if (data === null || data.from === peerId || data.to !== undefined && data.to !== peerId || room.bcConns.has(data.from)) {
18363 // ignore messages that are not addressed to this conn, or from clients that are connected via broadcastchannel
18364 return;
18365 }
18366 const emitPeerChange = webrtcConns.has(data.from) ? () => {} : () => room.provider.emit('peers', [{
18367 removed: [],
18368 added: [data.from],
18369 webrtcPeers: Array.from(room.webrtcConns.keys()),
18370 bcPeers: Array.from(room.bcConns)
18371 }]);
18372 switch (data.type) {
18373 case 'announce':
18374 if (webrtcConns.size < room.provider.maxConns) {
18375 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(signalCon, true, data.from, room));
18376 emitPeerChange();
18377 }
18378 break;
18379 case 'signal':
18380 if (data.signal.type === 'offer') {
18381 const existingConn = webrtcConns.get(data.from);
18382 if (existingConn) {
18383 const remoteToken = data.token;
18384 const localToken = existingConn.glareToken;
18385 if (localToken && localToken > remoteToken) {
18386 y_webrtc_log('offer rejected: ', data.from);
18387 return;
18388 }
18389 // if we don't reject the offer, we will be accepting it and answering it
18390 existingConn.glareToken = undefined;
18391 }
18392 }
18393 if (data.signal.type === 'answer') {
18394 y_webrtc_log('offer answered by: ', data.from);
18395 const existingConn = webrtcConns.get(data.from);
18396 if (existingConn) {
18397 existingConn.glareToken = undefined;
18398 }
18399 }
18400 if (data.to === peerId) {
18401 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(signalCon, false, data.from, room)).peer.signal(data.signal);
18402 emitPeerChange();
18403 }
18404 break;
18405 }
18406 };
18407 if (room.key) {
18408 if (typeof m.data === 'string') {
18409 decryptJson(fromBase64(m.data), room.key).then(execMessage);
18410 }
18411 } else {
18412 execMessage(m.data);
18413 }
18414 }
18415 }
18416 });
18417 signalCon.on('disconnect', () => y_webrtc_log(`disconnect (${url})`));
18418 }
18419
18420 /**
18421 * Method that instantiates the http signaling connection.
18422 * Tries to implement the same methods a websocket provides using ajax requests
18423 * to send messages and EventSource to retrieve messages.
18424 *
18425 * @param {HttpSignalingConn} httpClient The signaling connection.
18426 */
18427 function setupHttpSignal(httpClient) {
18428 if (httpClient.shouldConnect && httpClient.ws === null) {
18429 // eslint-disable-next-line no-restricted-syntax
18430 const subscriberId = Math.floor(100000 + Math.random() * 900000);
18431 const url = httpClient.url;
18432 const eventSource = new window.EventSource((0,external_wp_url_namespaceObject.addQueryArgs)(url, {
18433 subscriber_id: subscriberId,
18434 action: 'gutenberg_signaling_server'
18435 }));
18436 /**
18437 * @type {any}
18438 */
18439 let pingTimeout = null;
18440 eventSource.onmessage = event => {
18441 httpClient.lastMessageReceived = Date.now();
18442 const data = event.data;
18443 if (data) {
18444 const messages = JSON.parse(data);
18445 if (Array.isArray(messages)) {
18446 messages.forEach(onSingleMessage);
18447 }
18448 }
18449 };
18450 // @ts-ignore
18451 httpClient.ws = eventSource;
18452 httpClient.connecting = true;
18453 httpClient.connected = false;
18454 const onSingleMessage = ( /** @type {any} */message) => {
18455 if (message && message.type === 'pong') {
18456 clearTimeout(pingTimeout);
18457 pingTimeout = setTimeout(sendPing, webrtc_http_stream_signaling_messageReconnectTimeout / 2);
18458 }
18459 httpClient.emit('message', [message, httpClient]);
18460 };
18461
18462 /**
18463 * @param {any} error
18464 */
18465 const onclose = error => {
18466 if (httpClient.ws !== null) {
18467 httpClient.ws.close();
18468 httpClient.ws = null;
18469 httpClient.connecting = false;
18470 if (httpClient.connected) {
18471 httpClient.connected = false;
18472 httpClient.emit('disconnect', [{
18473 type: 'disconnect',
18474 error
18475 }, httpClient]);
18476 } else {
18477 httpClient.unsuccessfulReconnects++;
18478 }
18479 }
18480 clearTimeout(pingTimeout);
18481 };
18482 const sendPing = () => {
18483 if (httpClient.ws && httpClient.ws.readyState === window.EventSource.OPEN) {
18484 httpClient.send({
18485 type: 'ping'
18486 });
18487 }
18488 };
18489 if (httpClient.ws) {
18490 httpClient.ws.onclose = () => {
18491 onclose(null);
18492 };
18493 httpClient.ws.send = function send( /** @type {string} */message) {
18494 window.fetch(url, {
18495 body: new URLSearchParams({
18496 subscriber_id: subscriberId.toString(),
18497 action: 'gutenberg_signaling_server',
18498 message
18499 }),
18500 method: 'POST'
18501 }).catch(() => {
18502 y_webrtc_log('Error sending to server with message: ' + message);
18503 });
18504 };
18505 }
18506 eventSource.onerror = () => {
18507 // Todo: add an error handler
18508 };
18509 eventSource.onopen = () => {
18510 if (httpClient.connected) {
18511 return;
18512 }
18513 if (eventSource.readyState === window.EventSource.OPEN) {
18514 httpClient.lastMessageReceived = Date.now();
18515 httpClient.connecting = false;
18516 httpClient.connected = true;
18517 httpClient.unsuccessfulReconnects = 0;
18518 httpClient.emit('connect', [{
18519 type: 'connect'
18520 }, httpClient]);
18521 // set ping
18522 pingTimeout = setTimeout(sendPing, webrtc_http_stream_signaling_messageReconnectTimeout / 2);
18523 }
18524 };
18525 }
18526 }
18527 const webrtc_http_stream_signaling_messageReconnectTimeout = 30000;
18528
18529 /**
18530 * @augments Observable<string>
18531 */
18532 class HttpSignalingConn extends observable_Observable {
18533 /**
18534 * @param {string} url
18535 */
18536 constructor(url) {
18537 super();
18538
18539 //WebsocketClient from lib0/websocket.js
18540 this.url = url;
18541 /**
18542 * @type {WebSocket?}
18543 */
18544 this.ws = null;
18545 // @ts-ignore
18546 this.binaryType = null; // this.binaryType = binaryType
18547 this.connected = false;
18548 this.connecting = false;
18549 this.unsuccessfulReconnects = 0;
18550 this.lastMessageReceived = 0;
18551 /**
18552 * Whether to connect to other peers or not
18553 *
18554 * @type {boolean}
18555 */
18556 this.shouldConnect = true;
18557 this._checkInterval = setInterval(() => {
18558 if (this.connected && webrtc_http_stream_signaling_messageReconnectTimeout < Date.now() - this.lastMessageReceived && this.ws) {
18559 // no message received in a long time - not even your own awareness
18560 // updates (which are updated every 15 seconds)
18561 this.ws.close();
18562 }
18563 }, webrtc_http_stream_signaling_messageReconnectTimeout / 2);
18564 //setupWS( this );
18565 setupHttpSignal(this);
18566
18567 // From SignalingConn
18568 /**
18569 * @type {Set<WebrtcProvider>}
18570 */
18571 this.providers = new Set();
18572 setupSignalEventHandlers(this, url);
18573 }
18574
18575 /**
18576 * @param {any} message
18577 */
18578 send(message) {
18579 if (this.ws) {
18580 this.ws.send(JSON.stringify(message));
18581 }
18582 }
18583 destroy() {
18584 clearInterval(this._checkInterval);
18585 this.disconnect();
18586 super.destroy();
18587 }
18588 disconnect() {
18589 this.shouldConnect = false;
18590 if (this.ws !== null) {
18591 this.ws.close();
18592 }
18593 }
18594 connect() {
18595 this.shouldConnect = true;
18596 if (!this.connected && this.ws === null) {
18597 setupHttpSignal(this);
18598 }
18599 }
18600 }
18601 class WebrtcProviderWithHttpSignaling extends WebrtcProvider {
18602 connect() {
18603 this.shouldConnect = true;
18604 this.signalingUrls.forEach(( /** @type {string} */url) => {
18605 const signalingConn = setIfUndefined(signalingConns, url,
18606 // Only this conditional logic to create a normal websocket connection or
18607 // an http signaling connection was added to the constructor when compared
18608 // with the base class.
18609 url.startsWith('ws://') || url.startsWith('wss://') ? () => new SignalingConn(url) : () => new HttpSignalingConn(url));
18610 this.signalingConns.push(signalingConn);
18611 signalingConn.providers.add(this);
18612 });
18613 if (this.room) {
18614 this.room.connect();
18615 }
18616 }
18617 }
18618
18619 ;// CONCATENATED MODULE: ./packages/sync/build-module/create-webrtc-connection.js
18620 /**
18621 * External dependencies
18622 */
18623 // import { WebrtcProvider } from 'y-webrtc';
18624
18625 /**
18626 * Internal dependencies
18627 */
18628
18629
18630 /** @typedef {import('./types').ObjectType} ObjectType */
18631 /** @typedef {import('./types').ObjectID} ObjectID */
18632 /** @typedef {import('./types').CRDTDoc} CRDTDoc */
18633
18634 /**
18635 * Function that creates a new WebRTC Connection.
18636 *
18637 * @param {Object} config The object ID.
18638 *
18639 * @param {Array<string>} config.signaling
18640 * @param {string} config.password
18641 * @return {Function} Promise that resolves when the connection is established.
18642 */
18643 function createWebRTCConnection({
18644 signaling,
18645 password
18646 }) {
18647 return function ( /** @type {string} */objectId, /** @type {string} */objectType, /** @type {import("yjs").Doc} */doc) {
18648 const roomName = `${objectType}-${objectId}`;
18649 new WebrtcProviderWithHttpSignaling(roomName, doc, {
18650 signaling,
18651 // @ts-ignore
18652 password
18653 });
18654 return Promise.resolve(() => true);
18655 };
18656 }
18657
18658 ;// CONCATENATED MODULE: ./packages/core-data/build-module/sync.js
18659 /**
18660 * WordPress dependencies
18661 */
18662
18663 let syncProvider;
18664 function getSyncProvider() {
18665 if (!syncProvider) {
18666 syncProvider = createSyncProvider(connectIndexDb, createWebRTCConnection({
18667 signaling: [
18668 //'ws://localhost:4444',
18669 window?.wp?.ajax?.settings?.url],
18670 password: window?.__experimentalCollaborativeEditingSecret
18671 }));
18672 }
18673 return syncProvider;
18674 }
18675
18676 ;// CONCATENATED MODULE: ./packages/core-data/build-module/actions.js
18677 /**
18678 * External dependencies
18679 */
18680
18681
18682
18683 /**
18684 * WordPress dependencies
18685 */
18686
18687
18688
18689
18690 /**
18691 * Internal dependencies
18692 */
18693
18694
18695
18696
18697
18698
18699
18700 /**
18701 * Returns an action object used in signalling that authors have been received.
18702 * Ignored from documentation as it's internal to the data store.
18703 *
18704 * @ignore
18705 *
18706 * @param {string} queryID Query ID.
18707 * @param {Array|Object} users Users received.
18708 *
18709 * @return {Object} Action object.
18710 */
18711 function receiveUserQuery(queryID, users) {
18712 return {
18713 type: 'RECEIVE_USER_QUERY',
18714 users: Array.isArray(users) ? users : [users],
18715 queryID
18716 };
18717 }
18718
18719 /**
18720 * Returns an action used in signalling that the current user has been received.
18721 * Ignored from documentation as it's internal to the data store.
18722 *
18723 * @ignore
18724 *
18725 * @param {Object} currentUser Current user object.
18726 *
18727 * @return {Object} Action object.
18728 */
18729 function receiveCurrentUser(currentUser) {
18730 return {
18731 type: 'RECEIVE_CURRENT_USER',
18732 currentUser
18733 };
18734 }
18735
18736 /**
18737 * Returns an action object used in adding new entities.
18738 *
18739 * @param {Array} entities Entities received.
18740 *
18741 * @return {Object} Action object.
18742 */
18743 function addEntities(entities) {
18744 return {
18745 type: 'ADD_ENTITIES',
18746 entities
18747 };
18748 }
18749
18750 /**
18751 * Returns an action object used in signalling that entity records have been received.
18752 *
18753 * @param {string} kind Kind of the received entity record.
18754 * @param {string} name Name of the received entity record.
18755 * @param {Array|Object} records Records received.
18756 * @param {?Object} query Query Object.
18757 * @param {?boolean} invalidateCache Should invalidate query caches.
18758 * @param {?Object} edits Edits to reset.
18759 * @param {?Object} meta Meta information about pagination.
18760 * @return {Object} Action object.
18761 */
18762 function receiveEntityRecords(kind, name, records, query, invalidateCache = false, edits, meta) {
18763 // Auto drafts should not have titles, but some plugins rely on them so we can't filter this
18764 // on the server.
18765 if (kind === 'postType') {
18766 records = (Array.isArray(records) ? records : [records]).map(record => record.status === 'auto-draft' ? {
18767 ...record,
18768 title: ''
18769 } : record);
18770 }
18771 let action;
18772 if (query) {
18773 action = receiveQueriedItems(records, query, edits, meta);
18774 } else {
18775 action = receiveItems(records, edits, meta);
18776 }
18777 return {
18778 ...action,
18779 kind,
18780 name,
18781 invalidateCache
18782 };
18783 }
18784
18785 /**
18786 * Returns an action object used in signalling that the current theme has been received.
18787 * Ignored from documentation as it's internal to the data store.
18788 *
18789 * @ignore
18790 *
18791 * @param {Object} currentTheme The current theme.
18792 *
18793 * @return {Object} Action object.
18794 */
18795 function receiveCurrentTheme(currentTheme) {
18796 return {
18797 type: 'RECEIVE_CURRENT_THEME',
18798 currentTheme
18799 };
18800 }
18801
18802 /**
18803 * Returns an action object used in signalling that the current global styles id has been received.
18804 * Ignored from documentation as it's internal to the data store.
18805 *
18806 * @ignore
18807 *
18808 * @param {string} currentGlobalStylesId The current global styles id.
18809 *
18810 * @return {Object} Action object.
18811 */
18812 function __experimentalReceiveCurrentGlobalStylesId(currentGlobalStylesId) {
18813 return {
18814 type: 'RECEIVE_CURRENT_GLOBAL_STYLES_ID',
18815 id: currentGlobalStylesId
18816 };
18817 }
18818
18819 /**
18820 * Returns an action object used in signalling that the theme base global styles have been received
18821 * Ignored from documentation as it's internal to the data store.
18822 *
18823 * @ignore
18824 *
18825 * @param {string} stylesheet The theme's identifier
18826 * @param {Object} globalStyles The global styles object.
18827 *
18828 * @return {Object} Action object.
18829 */
18830 function __experimentalReceiveThemeBaseGlobalStyles(stylesheet, globalStyles) {
18831 return {
18832 type: 'RECEIVE_THEME_GLOBAL_STYLES',
18833 stylesheet,
18834 globalStyles
18835 };
18836 }
18837
18838 /**
18839 * Returns an action object used in signalling that the theme global styles variations have been received.
18840 * Ignored from documentation as it's internal to the data store.
18841 *
18842 * @ignore
18843 *
18844 * @param {string} stylesheet The theme's identifier
18845 * @param {Array} variations The global styles variations.
18846 *
18847 * @return {Object} Action object.
18848 */
18849 function __experimentalReceiveThemeGlobalStyleVariations(stylesheet, variations) {
18850 return {
18851 type: 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS',
18852 stylesheet,
18853 variations
18854 };
18855 }
18856
18857 /**
18858 * Returns an action object used in signalling that the index has been received.
18859 *
18860 * @deprecated since WP 5.9, this is not useful anymore, use the selector direclty.
18861 *
18862 * @return {Object} Action object.
18863 */
18864 function receiveThemeSupports() {
18865 external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveThemeSupports", {
18866 since: '5.9'
18867 });
18868 return {
18869 type: 'DO_NOTHING'
18870 };
18871 }
18872
18873 /**
18874 * Returns an action object used in signalling that the theme global styles CPT post revisions have been received.
18875 * Ignored from documentation as it's internal to the data store.
18876 *
18877 * @deprecated since WordPress 6.5.0. Callers should use `dispatch( 'core' ).receiveRevision` instead.
18878 *
18879 * @ignore
18880 *
18881 * @param {number} currentId The post id.
18882 * @param {Array} revisions The global styles revisions.
18883 *
18884 * @return {Object} Action object.
18885 */
18886 function receiveThemeGlobalStyleRevisions(currentId, revisions) {
18887 external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveThemeGlobalStyleRevisions()", {
18888 since: '6.5.0',
18889 alternative: "wp.data.dispatch( 'core' ).receiveRevisions"
18890 });
18891 return {
18892 type: 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS',
18893 currentId,
18894 revisions
18895 };
18896 }
18897
18898 /**
18899 * Returns an action object used in signalling that the preview data for
18900 * a given URl has been received.
18901 * Ignored from documentation as it's internal to the data store.
18902 *
18903 * @ignore
18904 *
18905 * @param {string} url URL to preview the embed for.
18906 * @param {*} preview Preview data.
18907 *
18908 * @return {Object} Action object.
18909 */
18910 function receiveEmbedPreview(url, preview) {
18911 return {
18912 type: 'RECEIVE_EMBED_PREVIEW',
18913 url,
18914 preview
18915 };
18916 }
18917
18918 /**
18919 * Action triggered to delete an entity record.
18920 *
18921 * @param {string} kind Kind of the deleted entity.
18922 * @param {string} name Name of the deleted entity.
18923 * @param {string} recordId Record ID of the deleted entity.
18924 * @param {?Object} query Special query parameters for the
18925 * DELETE API call.
18926 * @param {Object} [options] Delete options.
18927 * @param {Function} [options.__unstableFetch] Internal use only. Function to
18928 * call instead of `apiFetch()`.
18929 * Must return a promise.
18930 * @param {boolean} [options.throwOnError=false] If false, this action suppresses all
18931 * the exceptions. Defaults to false.
18932 */
18933 const deleteEntityRecord = (kind, name, recordId, query, {
18934 __unstableFetch = (external_wp_apiFetch_default()),
18935 throwOnError = false
18936 } = {}) => async ({
18937 dispatch
18938 }) => {
18939 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
18940 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
18941 let error;
18942 let deletedRecord = false;
18943 if (!entityConfig || entityConfig?.__experimentalNoFetch) {
18944 return;
18945 }
18946 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, recordId], {
18947 exclusive: true
18948 });
18949 try {
18950 dispatch({
18951 type: 'DELETE_ENTITY_RECORD_START',
18952 kind,
18953 name,
18954 recordId
18955 });
18956 let hasError = false;
18957 try {
18958 let path = `${entityConfig.baseURL}/${recordId}`;
18959 if (query) {
18960 path = (0,external_wp_url_namespaceObject.addQueryArgs)(path, query);
18961 }
18962 deletedRecord = await __unstableFetch({
18963 path,
18964 method: 'DELETE'
18965 });
18966 await dispatch(removeItems(kind, name, recordId, true));
18967 } catch (_error) {
18968 hasError = true;
18969 error = _error;
18970 }
18971 dispatch({
18972 type: 'DELETE_ENTITY_RECORD_FINISH',
18973 kind,
18974 name,
18975 recordId,
18976 error
18977 });
18978 if (hasError && throwOnError) {
18979 throw error;
18980 }
18981 return deletedRecord;
18982 } finally {
18983 dispatch.__unstableReleaseStoreLock(lock);
18984 }
18985 };
18986
18987 /**
18988 * Returns an action object that triggers an
18989 * edit to an entity record.
18990 *
18991 * @param {string} kind Kind of the edited entity record.
18992 * @param {string} name Name of the edited entity record.
18993 * @param {number|string} recordId Record ID of the edited entity record.
18994 * @param {Object} edits The edits.
18995 * @param {Object} options Options for the edit.
18996 * @param {boolean} [options.undoIgnore] Whether to ignore the edit in undo history or not.
18997 *
18998 * @return {Object} Action object.
18999 */
19000 const editEntityRecord = (kind, name, recordId, edits, options = {}) => ({
19001 select,
19002 dispatch
19003 }) => {
19004 const entityConfig = select.getEntityConfig(kind, name);
19005 if (!entityConfig) {
19006 throw new Error(`The entity being edited (${kind}, ${name}) does not have a loaded config.`);
19007 }
19008 const {
19009 mergedEdits = {}
19010 } = entityConfig;
19011 const record = select.getRawEntityRecord(kind, name, recordId);
19012 const editedRecord = select.getEditedEntityRecord(kind, name, recordId);
19013 const edit = {
19014 kind,
19015 name,
19016 recordId,
19017 // Clear edits when they are equal to their persisted counterparts
19018 // so that the property is not considered dirty.
19019 edits: Object.keys(edits).reduce((acc, key) => {
19020 const recordValue = record[key];
19021 const editedRecordValue = editedRecord[key];
19022 const value = mergedEdits[key] ? {
19023 ...editedRecordValue,
19024 ...edits[key]
19025 } : edits[key];
19026 acc[key] = es6_default()(recordValue, value) ? undefined : value;
19027 return acc;
19028 }, {})
19029 };
19030 if (window.__experimentalEnableSync && entityConfig.syncConfig) {
19031 if (true) {
19032 const objectId = entityConfig.getSyncObjectId(recordId);
19033 getSyncProvider().update(entityConfig.syncObjectType + '--edit', objectId, edit.edits);
19034 }
19035 } else {
19036 if (!options.undoIgnore) {
19037 select.getUndoManager().addRecord([{
19038 id: {
19039 kind,
19040 name,
19041 recordId
19042 },
19043 changes: Object.keys(edits).reduce((acc, key) => {
19044 acc[key] = {
19045 from: editedRecord[key],
19046 to: edits[key]
19047 };
19048 return acc;
19049 }, {})
19050 }], options.isCached);
19051 }
19052 dispatch({
19053 type: 'EDIT_ENTITY_RECORD',
19054 ...edit
19055 });
19056 }
19057 };
19058
19059 /**
19060 * Action triggered to undo the last edit to
19061 * an entity record, if any.
19062 */
19063 const undo = () => ({
19064 select,
19065 dispatch
19066 }) => {
19067 const undoRecord = select.getUndoManager().undo();
19068 if (!undoRecord) {
19069 return;
19070 }
19071 dispatch({
19072 type: 'UNDO',
19073 record: undoRecord
19074 });
19075 };
19076
19077 /**
19078 * Action triggered to redo the last undoed
19079 * edit to an entity record, if any.
19080 */
19081 const redo = () => ({
19082 select,
19083 dispatch
19084 }) => {
19085 const redoRecord = select.getUndoManager().redo();
19086 if (!redoRecord) {
19087 return;
19088 }
19089 dispatch({
19090 type: 'REDO',
19091 record: redoRecord
19092 });
19093 };
19094
19095 /**
19096 * Forces the creation of a new undo level.
19097 *
19098 * @return {Object} Action object.
19099 */
19100 const __unstableCreateUndoLevel = () => ({
19101 select
19102 }) => {
19103 select.getUndoManager().addRecord();
19104 };
19105
19106 /**
19107 * Action triggered to save an entity record.
19108 *
19109 * @param {string} kind Kind of the received entity.
19110 * @param {string} name Name of the received entity.
19111 * @param {Object} record Record to be saved.
19112 * @param {Object} options Saving options.
19113 * @param {boolean} [options.isAutosave=false] Whether this is an autosave.
19114 * @param {Function} [options.__unstableFetch] Internal use only. Function to
19115 * call instead of `apiFetch()`.
19116 * Must return a promise.
19117 * @param {boolean} [options.throwOnError=false] If false, this action suppresses all
19118 * the exceptions. Defaults to false.
19119 */
19120 const saveEntityRecord = (kind, name, record, {
19121 isAutosave = false,
19122 __unstableFetch = (external_wp_apiFetch_default()),
19123 throwOnError = false
19124 } = {}) => async ({
19125 select,
19126 resolveSelect,
19127 dispatch
19128 }) => {
19129 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
19130 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19131 if (!entityConfig || entityConfig?.__experimentalNoFetch) {
19132 return;
19133 }
19134 const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY;
19135 const recordId = record[entityIdKey];
19136 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, recordId || esm_browser_v4()], {
19137 exclusive: true
19138 });
19139 try {
19140 // Evaluate optimized edits.
19141 // (Function edits that should be evaluated on save to avoid expensive computations on every edit.)
19142 for (const [key, value] of Object.entries(record)) {
19143 if (typeof value === 'function') {
19144 const evaluatedValue = value(select.getEditedEntityRecord(kind, name, recordId));
19145 dispatch.editEntityRecord(kind, name, recordId, {
19146 [key]: evaluatedValue
19147 }, {
19148 undoIgnore: true
19149 });
19150 record[key] = evaluatedValue;
19151 }
19152 }
19153 dispatch({
19154 type: 'SAVE_ENTITY_RECORD_START',
19155 kind,
19156 name,
19157 recordId,
19158 isAutosave
19159 });
19160 let updatedRecord;
19161 let error;
19162 let hasError = false;
19163 try {
19164 const path = `${entityConfig.baseURL}${recordId ? '/' + recordId : ''}`;
19165 const persistedRecord = select.getRawEntityRecord(kind, name, recordId);
19166 if (isAutosave) {
19167 // Most of this autosave logic is very specific to posts.
19168 // This is fine for now as it is the only supported autosave,
19169 // but ideally this should all be handled in the back end,
19170 // so the client just sends and receives objects.
19171 const currentUser = select.getCurrentUser();
19172 const currentUserId = currentUser ? currentUser.id : undefined;
19173 const autosavePost = await resolveSelect.getAutosave(persistedRecord.type, persistedRecord.id, currentUserId);
19174 // Autosaves need all expected fields to be present.
19175 // So we fallback to the previous autosave and then
19176 // to the actual persisted entity if the edits don't
19177 // have a value.
19178 let data = {
19179 ...persistedRecord,
19180 ...autosavePost,
19181 ...record
19182 };
19183 data = Object.keys(data).reduce((acc, key) => {
19184 if (['title', 'excerpt', 'content', 'meta'].includes(key)) {
19185 acc[key] = data[key];
19186 }
19187 return acc;
19188 }, {
19189 // Do not update the `status` if we have edited it when auto saving.
19190 // It's very important to let the user explicitly save this change,
19191 // because it can lead to unexpected results. An example would be to
19192 // have a draft post and change the status to publish.
19193 status: data.status === 'auto-draft' ? 'draft' : undefined
19194 });
19195 updatedRecord = await __unstableFetch({
19196 path: `${path}/autosaves`,
19197 method: 'POST',
19198 data
19199 });
19200
19201 // An autosave may be processed by the server as a regular save
19202 // when its update is requested by the author and the post had
19203 // draft or auto-draft status.
19204 if (persistedRecord.id === updatedRecord.id) {
19205 let newRecord = {
19206 ...persistedRecord,
19207 ...data,
19208 ...updatedRecord
19209 };
19210 newRecord = Object.keys(newRecord).reduce((acc, key) => {
19211 // These properties are persisted in autosaves.
19212 if (['title', 'excerpt', 'content'].includes(key)) {
19213 acc[key] = newRecord[key];
19214 } else if (key === 'status') {
19215 // Status is only persisted in autosaves when going from
19216 // "auto-draft" to "draft".
19217 acc[key] = persistedRecord.status === 'auto-draft' && newRecord.status === 'draft' ? newRecord.status : persistedRecord.status;
19218 } else {
19219 // These properties are not persisted in autosaves.
19220 acc[key] = persistedRecord[key];
19221 }
19222 return acc;
19223 }, {});
19224 dispatch.receiveEntityRecords(kind, name, newRecord, undefined, true);
19225 } else {
19226 dispatch.receiveAutosaves(persistedRecord.id, updatedRecord);
19227 }
19228 } else {
19229 let edits = record;
19230 if (entityConfig.__unstablePrePersist) {
19231 edits = {
19232 ...edits,
19233 ...entityConfig.__unstablePrePersist(persistedRecord, edits)
19234 };
19235 }
19236 updatedRecord = await __unstableFetch({
19237 path,
19238 method: recordId ? 'PUT' : 'POST',
19239 data: edits
19240 });
19241 dispatch.receiveEntityRecords(kind, name, updatedRecord, undefined, true, edits);
19242 }
19243 } catch (_error) {
19244 hasError = true;
19245 error = _error;
19246 }
19247 dispatch({
19248 type: 'SAVE_ENTITY_RECORD_FINISH',
19249 kind,
19250 name,
19251 recordId,
19252 error,
19253 isAutosave
19254 });
19255 if (hasError && throwOnError) {
19256 throw error;
19257 }
19258 return updatedRecord;
19259 } finally {
19260 dispatch.__unstableReleaseStoreLock(lock);
19261 }
19262 };
19263
19264 /**
19265 * Runs multiple core-data actions at the same time using one API request.
19266 *
19267 * Example:
19268 *
19269 * ```
19270 * const [ savedRecord, updatedRecord, deletedRecord ] =
19271 * await dispatch( 'core' ).__experimentalBatch( [
19272 * ( { saveEntityRecord } ) => saveEntityRecord( 'root', 'widget', widget ),
19273 * ( { saveEditedEntityRecord } ) => saveEntityRecord( 'root', 'widget', 123 ),
19274 * ( { deleteEntityRecord } ) => deleteEntityRecord( 'root', 'widget', 123, null ),
19275 * ] );
19276 * ```
19277 *
19278 * @param {Array} requests Array of functions which are invoked simultaneously.
19279 * Each function is passed an object containing
19280 * `saveEntityRecord`, `saveEditedEntityRecord`, and
19281 * `deleteEntityRecord`.
19282 *
19283 * @return {(thunkArgs: Object) => Promise} A promise that resolves to an array containing the return
19284 * values of each function given in `requests`.
19285 */
19286 const __experimentalBatch = requests => async ({
19287 dispatch
19288 }) => {
19289 const batch = createBatch();
19290 const api = {
19291 saveEntityRecord(kind, name, record, options) {
19292 return batch.add(add => dispatch.saveEntityRecord(kind, name, record, {
19293 ...options,
19294 __unstableFetch: add
19295 }));
19296 },
19297 saveEditedEntityRecord(kind, name, recordId, options) {
19298 return batch.add(add => dispatch.saveEditedEntityRecord(kind, name, recordId, {
19299 ...options,
19300 __unstableFetch: add
19301 }));
19302 },
19303 deleteEntityRecord(kind, name, recordId, query, options) {
19304 return batch.add(add => dispatch.deleteEntityRecord(kind, name, recordId, query, {
19305 ...options,
19306 __unstableFetch: add
19307 }));
19308 }
19309 };
19310 const resultPromises = requests.map(request => request(api));
19311 const [, ...results] = await Promise.all([batch.run(), ...resultPromises]);
19312 return results;
19313 };
19314
19315 /**
19316 * Action triggered to save an entity record's edits.
19317 *
19318 * @param {string} kind Kind of the entity.
19319 * @param {string} name Name of the entity.
19320 * @param {Object} recordId ID of the record.
19321 * @param {Object} options Saving options.
19322 */
19323 const saveEditedEntityRecord = (kind, name, recordId, options) => async ({
19324 select,
19325 dispatch
19326 }) => {
19327 if (!select.hasEditsForEntityRecord(kind, name, recordId)) {
19328 return;
19329 }
19330 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
19331 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19332 if (!entityConfig) {
19333 return;
19334 }
19335 const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY;
19336 const edits = select.getEntityRecordNonTransientEdits(kind, name, recordId);
19337 const record = {
19338 [entityIdKey]: recordId,
19339 ...edits
19340 };
19341 return await dispatch.saveEntityRecord(kind, name, record, options);
19342 };
19343
19344 /**
19345 * Action triggered to save only specified properties for the entity.
19346 *
19347 * @param {string} kind Kind of the entity.
19348 * @param {string} name Name of the entity.
19349 * @param {Object} recordId ID of the record.
19350 * @param {Array} itemsToSave List of entity properties or property paths to save.
19351 * @param {Object} options Saving options.
19352 */
19353 const __experimentalSaveSpecifiedEntityEdits = (kind, name, recordId, itemsToSave, options) => async ({
19354 select,
19355 dispatch
19356 }) => {
19357 if (!select.hasEditsForEntityRecord(kind, name, recordId)) {
19358 return;
19359 }
19360 const edits = select.getEntityRecordNonTransientEdits(kind, name, recordId);
19361 const editsToSave = {};
19362 for (const item of itemsToSave) {
19363 setNestedValue(editsToSave, item, getNestedValue(edits, item));
19364 }
19365 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
19366 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19367 const entityIdKey = entityConfig?.key || DEFAULT_ENTITY_KEY;
19368
19369 // If a record key is provided then update the existing record.
19370 // This necessitates providing `recordKey` to saveEntityRecord as part of the
19371 // `record` argument (here called `editsToSave`) to stop that action creating
19372 // a new record and instead cause it to update the existing record.
19373 if (recordId) {
19374 editsToSave[entityIdKey] = recordId;
19375 }
19376 return await dispatch.saveEntityRecord(kind, name, editsToSave, options);
19377 };
19378
19379 /**
19380 * Returns an action object used in signalling that Upload permissions have been received.
19381 *
19382 * @deprecated since WP 5.9, use receiveUserPermission instead.
19383 *
19384 * @param {boolean} hasUploadPermissions Does the user have permission to upload files?
19385 *
19386 * @return {Object} Action object.
19387 */
19388 function receiveUploadPermissions(hasUploadPermissions) {
19389 external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveUploadPermissions", {
19390 since: '5.9',
19391 alternative: 'receiveUserPermission'
19392 });
19393 return receiveUserPermission('create/media', hasUploadPermissions);
19394 }
19395
19396 /**
19397 * Returns an action object used in signalling that the current user has
19398 * permission to perform an action on a REST resource.
19399 * Ignored from documentation as it's internal to the data store.
19400 *
19401 * @ignore
19402 *
19403 * @param {string} key A key that represents the action and REST resource.
19404 * @param {boolean} isAllowed Whether or not the user can perform the action.
19405 *
19406 * @return {Object} Action object.
19407 */
19408 function receiveUserPermission(key, isAllowed) {
19409 return {
19410 type: 'RECEIVE_USER_PERMISSION',
19411 key,
19412 isAllowed
19413 };
19414 }
19415
19416 /**
19417 * Returns an action object used in signalling that the autosaves for a
19418 * post have been received.
19419 * Ignored from documentation as it's internal to the data store.
19420 *
19421 * @ignore
19422 *
19423 * @param {number} postId The id of the post that is parent to the autosave.
19424 * @param {Array|Object} autosaves An array of autosaves or singular autosave object.
19425 *
19426 * @return {Object} Action object.
19427 */
19428 function receiveAutosaves(postId, autosaves) {
19429 return {
19430 type: 'RECEIVE_AUTOSAVES',
19431 postId,
19432 autosaves: Array.isArray(autosaves) ? autosaves : [autosaves]
19433 };
19434 }
19435
19436 /**
19437 * Returns an action object signalling that the fallback Navigation
19438 * Menu id has been received.
19439 *
19440 * @param {integer} fallbackId the id of the fallback Navigation Menu
19441 * @return {Object} Action object.
19442 */
19443 function receiveNavigationFallbackId(fallbackId) {
19444 return {
19445 type: 'RECEIVE_NAVIGATION_FALLBACK_ID',
19446 fallbackId
19447 };
19448 }
19449
19450 /**
19451 * Returns an action object used to set the template for a given query.
19452 *
19453 * @param {Object} query The lookup query.
19454 * @param {string} templateId The resolved template id.
19455 *
19456 * @return {Object} Action object.
19457 */
19458 function receiveDefaultTemplateId(query, templateId) {
19459 return {
19460 type: 'RECEIVE_DEFAULT_TEMPLATE',
19461 query,
19462 templateId
19463 };
19464 }
19465
19466 /**
19467 * Action triggered to receive revision items.
19468 *
19469 * @param {string} kind Kind of the received entity record revisions.
19470 * @param {string} name Name of the received entity record revisions.
19471 * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
19472 * @param {Array|Object} records Revisions received.
19473 * @param {?Object} query Query Object.
19474 * @param {?boolean} invalidateCache Should invalidate query caches.
19475 * @param {?Object} meta Meta information about pagination.
19476 */
19477 const receiveRevisions = (kind, name, recordKey, records, query, invalidateCache = false, meta) => async ({
19478 dispatch
19479 }) => {
19480 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
19481 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19482 const key = entityConfig && entityConfig?.revisionKey ? entityConfig.revisionKey : DEFAULT_ENTITY_KEY;
19483 dispatch({
19484 type: 'RECEIVE_ITEM_REVISIONS',
19485 key,
19486 items: Array.isArray(records) ? records : [records],
19487 recordKey,
19488 meta,
19489 query,
19490 kind,
19491 name,
19492 invalidateCache
19493 });
19494 };
19495
19496 ;// CONCATENATED MODULE: ./packages/core-data/build-module/entities.js
19497 /**
19498 * External dependencies
19499 */
19500
19501
19502 /**
19503 * WordPress dependencies
19504 */
19505
19506
19507
19508
19509 /**
19510 * Internal dependencies
19511 */
19512
19513
19514 const DEFAULT_ENTITY_KEY = 'id';
19515 const POST_RAW_ATTRIBUTES = ['title', 'excerpt', 'content'];
19516 const rootEntitiesConfig = [{
19517 label: (0,external_wp_i18n_namespaceObject.__)('Base'),
19518 kind: 'root',
19519 name: '__unstableBase',
19520 baseURL: '/',
19521 baseURLParams: {
19522 _fields: ['description', 'gmt_offset', 'home', 'name', 'site_icon', 'site_icon_url', 'site_logo', 'timezone_string', 'url'].join(',')
19523 },
19524 // The entity doesn't support selecting multiple records.
19525 // The property is maintained for backward compatibility.
19526 plural: '__unstableBases',
19527 syncConfig: {
19528 fetch: async () => {
19529 return external_wp_apiFetch_default()({
19530 path: '/'
19531 });
19532 },
19533 applyChangesToDoc: (doc, changes) => {
19534 const document = doc.getMap('document');
19535 Object.entries(changes).forEach(([key, value]) => {
19536 if (document.get(key) !== value) {
19537 document.set(key, value);
19538 }
19539 });
19540 },
19541 fromCRDTDoc: doc => {
19542 return doc.getMap('document').toJSON();
19543 }
19544 },
19545 syncObjectType: 'root/base',
19546 getSyncObjectId: () => 'index'
19547 }, {
19548 label: (0,external_wp_i18n_namespaceObject.__)('Post Type'),
19549 name: 'postType',
19550 kind: 'root',
19551 key: 'slug',
19552 baseURL: '/wp/v2/types',
19553 baseURLParams: {
19554 context: 'edit'
19555 },
19556 plural: 'postTypes',
19557 syncConfig: {
19558 fetch: async id => {
19559 return external_wp_apiFetch_default()({
19560 path: `/wp/v2/types/${id}?context=edit`
19561 });
19562 },
19563 applyChangesToDoc: (doc, changes) => {
19564 const document = doc.getMap('document');
19565 Object.entries(changes).forEach(([key, value]) => {
19566 if (document.get(key) !== value) {
19567 document.set(key, value);
19568 }
19569 });
19570 },
19571 fromCRDTDoc: doc => {
19572 return doc.getMap('document').toJSON();
19573 }
19574 },
19575 syncObjectType: 'root/postType',
19576 getSyncObjectId: id => id
19577 }, {
19578 name: 'media',
19579 kind: 'root',
19580 baseURL: '/wp/v2/media',
19581 baseURLParams: {
19582 context: 'edit'
19583 },
19584 plural: 'mediaItems',
19585 label: (0,external_wp_i18n_namespaceObject.__)('Media'),
19586 rawAttributes: ['caption', 'title', 'description'],
19587 supportsPagination: true
19588 }, {
19589 name: 'taxonomy',
19590 kind: 'root',
19591 key: 'slug',
19592 baseURL: '/wp/v2/taxonomies',
19593 baseURLParams: {
19594 context: 'edit'
19595 },
19596 plural: 'taxonomies',
19597 label: (0,external_wp_i18n_namespaceObject.__)('Taxonomy')
19598 }, {
19599 name: 'sidebar',
19600 kind: 'root',
19601 baseURL: '/wp/v2/sidebars',
19602 baseURLParams: {
19603 context: 'edit'
19604 },
19605 plural: 'sidebars',
19606 transientEdits: {
19607 blocks: true
19608 },
19609 label: (0,external_wp_i18n_namespaceObject.__)('Widget areas')
19610 }, {
19611 name: 'widget',
19612 kind: 'root',
19613 baseURL: '/wp/v2/widgets',
19614 baseURLParams: {
19615 context: 'edit'
19616 },
19617 plural: 'widgets',
19618 transientEdits: {
19619 blocks: true
19620 },
19621 label: (0,external_wp_i18n_namespaceObject.__)('Widgets')
19622 }, {
19623 name: 'widgetType',
19624 kind: 'root',
19625 baseURL: '/wp/v2/widget-types',
19626 baseURLParams: {
19627 context: 'edit'
19628 },
19629 plural: 'widgetTypes',
19630 label: (0,external_wp_i18n_namespaceObject.__)('Widget types')
19631 }, {
19632 label: (0,external_wp_i18n_namespaceObject.__)('User'),
19633 name: 'user',
19634 kind: 'root',
19635 baseURL: '/wp/v2/users',
19636 baseURLParams: {
19637 context: 'edit'
19638 },
19639 plural: 'users'
19640 }, {
19641 name: 'comment',
19642 kind: 'root',
19643 baseURL: '/wp/v2/comments',
19644 baseURLParams: {
19645 context: 'edit'
19646 },
19647 plural: 'comments',
19648 label: (0,external_wp_i18n_namespaceObject.__)('Comment')
19649 }, {
19650 name: 'menu',
19651 kind: 'root',
19652 baseURL: '/wp/v2/menus',
19653 baseURLParams: {
19654 context: 'edit'
19655 },
19656 plural: 'menus',
19657 label: (0,external_wp_i18n_namespaceObject.__)('Menu')
19658 }, {
19659 name: 'menuItem',
19660 kind: 'root',
19661 baseURL: '/wp/v2/menu-items',
19662 baseURLParams: {
19663 context: 'edit'
19664 },
19665 plural: 'menuItems',
19666 label: (0,external_wp_i18n_namespaceObject.__)('Menu Item'),
19667 rawAttributes: ['title']
19668 }, {
19669 name: 'menuLocation',
19670 kind: 'root',
19671 baseURL: '/wp/v2/menu-locations',
19672 baseURLParams: {
19673 context: 'edit'
19674 },
19675 plural: 'menuLocations',
19676 label: (0,external_wp_i18n_namespaceObject.__)('Menu Location'),
19677 key: 'name'
19678 }, {
19679 label: (0,external_wp_i18n_namespaceObject.__)('Global Styles'),
19680 name: 'globalStyles',
19681 kind: 'root',
19682 baseURL: '/wp/v2/global-styles',
19683 baseURLParams: {
19684 context: 'edit'
19685 },
19686 plural: 'globalStylesVariations',
19687 // Should be different from name.
19688 getTitle: record => record?.title?.rendered || record?.title,
19689 getRevisionsUrl: (parentId, revisionId) => `/wp/v2/global-styles/${parentId}/revisions${revisionId ? '/' + revisionId : ''}`,
19690 supportsPagination: true
19691 }, {
19692 label: (0,external_wp_i18n_namespaceObject.__)('Themes'),
19693 name: 'theme',
19694 kind: 'root',
19695 baseURL: '/wp/v2/themes',
19696 baseURLParams: {
19697 context: 'edit'
19698 },
19699 plural: 'themes',
19700 key: 'stylesheet'
19701 }, {
19702 label: (0,external_wp_i18n_namespaceObject.__)('Plugins'),
19703 name: 'plugin',
19704 kind: 'root',
19705 baseURL: '/wp/v2/plugins',
19706 baseURLParams: {
19707 context: 'edit'
19708 },
19709 plural: 'plugins',
19710 key: 'plugin'
19711 }, {
19712 label: (0,external_wp_i18n_namespaceObject.__)('Status'),
19713 name: 'status',
19714 kind: 'root',
19715 baseURL: '/wp/v2/statuses',
19716 baseURLParams: {
19717 context: 'edit'
19718 },
19719 plural: 'statuses',
19720 key: 'slug'
19721 }];
19722 const additionalEntityConfigLoaders = [{
19723 kind: 'postType',
19724 loadEntities: loadPostTypeEntities
19725 }, {
19726 kind: 'taxonomy',
19727 loadEntities: loadTaxonomyEntities
19728 }, {
19729 kind: 'root',
19730 name: 'site',
19731 plural: 'sites',
19732 loadEntities: loadSiteEntity
19733 }];
19734
19735 /**
19736 * Returns a function to be used to retrieve extra edits to apply before persisting a post type.
19737 *
19738 * @param {Object} persistedRecord Already persisted Post
19739 * @param {Object} edits Edits.
19740 * @return {Object} Updated edits.
19741 */
19742 const prePersistPostType = (persistedRecord, edits) => {
19743 const newEdits = {};
19744 if (persistedRecord?.status === 'auto-draft') {
19745 // Saving an auto-draft should create a draft by default.
19746 if (!edits.status && !newEdits.status) {
19747 newEdits.status = 'draft';
19748 }
19749
19750 // Fix the auto-draft default title.
19751 if ((!edits.title || edits.title === 'Auto Draft') && !newEdits.title && (!persistedRecord?.title || persistedRecord?.title === 'Auto Draft')) {
19752 newEdits.title = '';
19753 }
19754 }
19755 return newEdits;
19756 };
19757 const serialisableBlocksCache = new WeakMap();
19758 function makeBlockAttributesSerializable(attributes) {
19759 const newAttributes = {
19760 ...attributes
19761 };
19762 for (const [key, value] of Object.entries(attributes)) {
19763 if (value instanceof external_wp_richText_namespaceObject.RichTextData) {
19764 newAttributes[key] = value.valueOf();
19765 }
19766 }
19767 return newAttributes;
19768 }
19769 function makeBlocksSerializable(blocks) {
19770 return blocks.map(block => {
19771 const {
19772 innerBlocks,
19773 attributes,
19774 ...rest
19775 } = block;
19776 return {
19777 ...rest,
19778 attributes: makeBlockAttributesSerializable(attributes),
19779 innerBlocks: makeBlocksSerializable(innerBlocks)
19780 };
19781 });
19782 }
19783
19784 /**
19785 * Returns the list of post type entities.
19786 *
19787 * @return {Promise} Entities promise
19788 */
19789 async function loadPostTypeEntities() {
19790 const postTypes = await external_wp_apiFetch_default()({
19791 path: '/wp/v2/types?context=view'
19792 });
19793 return Object.entries(postTypes !== null && postTypes !== void 0 ? postTypes : {}).map(([name, postType]) => {
19794 var _postType$rest_namesp;
19795 const isTemplate = ['wp_template', 'wp_template_part'].includes(name);
19796 const namespace = (_postType$rest_namesp = postType?.rest_namespace) !== null && _postType$rest_namesp !== void 0 ? _postType$rest_namesp : 'wp/v2';
19797 return {
19798 kind: 'postType',
19799 baseURL: `/${namespace}/${postType.rest_base}`,
19800 baseURLParams: {
19801 context: 'edit'
19802 },
19803 name,
19804 label: postType.name,
19805 transientEdits: {
19806 blocks: true,
19807 selection: true
19808 },
19809 mergedEdits: {
19810 meta: true
19811 },
19812 rawAttributes: POST_RAW_ATTRIBUTES,
19813 getTitle: record => {
19814 var _record$slug;
19815 return record?.title?.rendered || record?.title || (isTemplate ? capitalCase((_record$slug = record.slug) !== null && _record$slug !== void 0 ? _record$slug : '') : String(record.id));
19816 },
19817 __unstablePrePersist: isTemplate ? undefined : prePersistPostType,
19818 __unstable_rest_base: postType.rest_base,
19819 syncConfig: {
19820 fetch: async id => {
19821 return external_wp_apiFetch_default()({
19822 path: `/${namespace}/${postType.rest_base}/${id}?context=edit`
19823 });
19824 },
19825 applyChangesToDoc: (doc, changes) => {
19826 const document = doc.getMap('document');
19827 Object.entries(changes).forEach(([key, value]) => {
19828 if (typeof value !== 'function') {
19829 if (key === 'blocks') {
19830 if (!serialisableBlocksCache.has(value)) {
19831 serialisableBlocksCache.set(value, makeBlocksSerializable(value));
19832 }
19833 value = serialisableBlocksCache.get(value);
19834 }
19835 if (document.get(key) !== value) {
19836 document.set(key, value);
19837 }
19838 }
19839 });
19840 },
19841 fromCRDTDoc: doc => {
19842 return doc.getMap('document').toJSON();
19843 }
19844 },
19845 syncObjectType: 'postType/' + postType.name,
19846 getSyncObjectId: id => id,
19847 supportsPagination: true,
19848 getRevisionsUrl: (parentId, revisionId) => `/${namespace}/${postType.rest_base}/${parentId}/revisions${revisionId ? '/' + revisionId : ''}`,
19849 revisionKey: isTemplate ? 'wp_id' : DEFAULT_ENTITY_KEY
19850 };
19851 });
19852 }
19853
19854 /**
19855 * Returns the list of the taxonomies entities.
19856 *
19857 * @return {Promise} Entities promise
19858 */
19859 async function loadTaxonomyEntities() {
19860 const taxonomies = await external_wp_apiFetch_default()({
19861 path: '/wp/v2/taxonomies?context=view'
19862 });
19863 return Object.entries(taxonomies !== null && taxonomies !== void 0 ? taxonomies : {}).map(([name, taxonomy]) => {
19864 var _taxonomy$rest_namesp;
19865 const namespace = (_taxonomy$rest_namesp = taxonomy?.rest_namespace) !== null && _taxonomy$rest_namesp !== void 0 ? _taxonomy$rest_namesp : 'wp/v2';
19866 return {
19867 kind: 'taxonomy',
19868 baseURL: `/${namespace}/${taxonomy.rest_base}`,
19869 baseURLParams: {
19870 context: 'edit'
19871 },
19872 name,
19873 label: taxonomy.name
19874 };
19875 });
19876 }
19877
19878 /**
19879 * Returns the Site entity.
19880 *
19881 * @return {Promise} Entity promise
19882 */
19883 async function loadSiteEntity() {
19884 var _site$schema$properti;
19885 const entity = {
19886 label: (0,external_wp_i18n_namespaceObject.__)('Site'),
19887 name: 'site',
19888 kind: 'root',
19889 baseURL: '/wp/v2/settings',
19890 syncConfig: {
19891 fetch: async () => {
19892 return external_wp_apiFetch_default()({
19893 path: '/wp/v2/settings'
19894 });
19895 },
19896 applyChangesToDoc: (doc, changes) => {
19897 const document = doc.getMap('document');
19898 Object.entries(changes).forEach(([key, value]) => {
19899 if (document.get(key) !== value) {
19900 document.set(key, value);
19901 }
19902 });
19903 },
19904 fromCRDTDoc: doc => {
19905 return doc.getMap('document').toJSON();
19906 }
19907 },
19908 syncObjectType: 'root/site',
19909 getSyncObjectId: () => 'index',
19910 meta: {}
19911 };
19912 const site = await external_wp_apiFetch_default()({
19913 path: entity.baseURL,
19914 method: 'OPTIONS'
19915 });
19916 const labels = {};
19917 Object.entries((_site$schema$properti = site?.schema?.properties) !== null && _site$schema$properti !== void 0 ? _site$schema$properti : {}).forEach(([key, value]) => {
19918 // Ignore properties `title` and `type` keys.
19919 if (typeof value === 'object' && value.title) {
19920 labels[key] = value.title;
19921 }
19922 });
19923 return [{
19924 ...entity,
19925 meta: {
19926 labels
19927 }
19928 }];
19929 }
19930
19931 /**
19932 * Returns the entity's getter method name given its kind and name or plural name.
19933 *
19934 * @example
19935 * ```js
19936 * const nameSingular = getMethodName( 'root', 'theme', 'get' );
19937 * // nameSingular is getRootTheme
19938 *
19939 * const namePlural = getMethodName( 'root', 'themes', 'set' );
19940 * // namePlural is setRootThemes
19941 * ```
19942 *
19943 * @param {string} kind Entity kind.
19944 * @param {string} name Entity name or plural name.
19945 * @param {string} prefix Function prefix.
19946 *
19947 * @return {string} Method name
19948 */
19949 const getMethodName = (kind, name, prefix = 'get') => {
19950 const kindPrefix = kind === 'root' ? '' : pascalCase(kind);
19951 const suffix = pascalCase(name);
19952 return `${prefix}${kindPrefix}${suffix}`;
19953 };
19954 function registerSyncConfigs(configs) {
19955 configs.forEach(({
19956 syncObjectType,
19957 syncConfig
19958 }) => {
19959 getSyncProvider().register(syncObjectType, syncConfig);
19960 const editSyncConfig = {
19961 ...syncConfig
19962 };
19963 delete editSyncConfig.fetch;
19964 getSyncProvider().register(syncObjectType + '--edit', editSyncConfig);
19965 });
19966 }
19967
19968 /**
19969 * Loads the entities into the store.
19970 *
19971 * Note: The `name` argument is used for `root` entities requiring additional server data.
19972 *
19973 * @param {string} kind Kind
19974 * @param {string} name Name
19975 * @return {(thunkArgs: object) => Promise<Array>} Entities
19976 */
19977 const getOrLoadEntitiesConfig = (kind, name) => async ({
19978 select,
19979 dispatch
19980 }) => {
19981 let configs = select.getEntitiesConfig(kind);
19982 const hasConfig = !!select.getEntityConfig(kind, name);
19983 if (configs?.length > 0 && hasConfig) {
19984 if (window.__experimentalEnableSync) {
19985 if (true) {
19986 registerSyncConfigs(configs);
19987 }
19988 }
19989 return configs;
19990 }
19991 const loader = additionalEntityConfigLoaders.find(l => {
19992 if (!name || !l.name) {
19993 return l.kind === kind;
19994 }
19995 return l.kind === kind && l.name === name;
19996 });
19997 if (!loader) {
19998 return [];
19999 }
20000 configs = await loader.loadEntities();
20001 if (window.__experimentalEnableSync) {
20002 if (true) {
20003 registerSyncConfigs(configs);
20004 }
20005 }
20006 dispatch(addEntities(configs));
20007 return configs;
20008 };
20009
20010 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/get-normalized-comma-separable.js
20011 /**
20012 * Given a value which can be specified as one or the other of a comma-separated
20013 * string or an array, returns a value normalized to an array of strings, or
20014 * null if the value cannot be interpreted as either.
20015 *
20016 * @param {string|string[]|*} value
20017 *
20018 * @return {?(string[])} Normalized field value.
20019 */
20020 function getNormalizedCommaSeparable(value) {
20021 if (typeof value === 'string') {
20022 return value.split(',');
20023 } else if (Array.isArray(value)) {
20024 return value;
20025 }
20026 return null;
20027 }
20028 /* harmony default export */ const get_normalized_comma_separable = (getNormalizedCommaSeparable);
20029
20030 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/with-weak-map-cache.js
20031 /**
20032 * Given a function, returns an enhanced function which caches the result and
20033 * tracks in WeakMap. The result is only cached if the original function is
20034 * passed a valid object-like argument (requirement for WeakMap key).
20035 *
20036 * @param {Function} fn Original function.
20037 *
20038 * @return {Function} Enhanced caching function.
20039 */
20040 function withWeakMapCache(fn) {
20041 const cache = new WeakMap();
20042 return key => {
20043 let value;
20044 if (cache.has(key)) {
20045 value = cache.get(key);
20046 } else {
20047 value = fn(key);
20048
20049 // Can reach here if key is not valid for WeakMap, since `has`
20050 // will return false for invalid key. Since `set` will throw,
20051 // ensure that key is valid before setting into cache.
20052 if (key !== null && typeof key === 'object') {
20053 cache.set(key, value);
20054 }
20055 }
20056 return value;
20057 };
20058 }
20059 /* harmony default export */ const with_weak_map_cache = (withWeakMapCache);
20060
20061 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/get-query-parts.js
20062 /**
20063 * WordPress dependencies
20064 */
20065
20066
20067 /**
20068 * Internal dependencies
20069 */
20070
20071
20072 /**
20073 * An object of properties describing a specific query.
20074 *
20075 * @typedef {Object} WPQueriedDataQueryParts
20076 *
20077 * @property {number} page The query page (1-based index, default 1).
20078 * @property {number} perPage Items per page for query (default 10).
20079 * @property {string} stableKey An encoded stable string of all non-
20080 * pagination, non-fields query parameters.
20081 * @property {?(string[])} fields Target subset of fields to derive from
20082 * item objects.
20083 * @property {?(number[])} include Specific item IDs to include.
20084 * @property {string} context Scope under which the request is made;
20085 * determines returned fields in response.
20086 */
20087
20088 /**
20089 * Given a query object, returns an object of parts, including pagination
20090 * details (`page` and `perPage`, or default values). All other properties are
20091 * encoded into a stable (idempotent) `stableKey` value.
20092 *
20093 * @param {Object} query Optional query object.
20094 *
20095 * @return {WPQueriedDataQueryParts} Query parts.
20096 */
20097 function getQueryParts(query) {
20098 /**
20099 * @type {WPQueriedDataQueryParts}
20100 */
20101 const parts = {
20102 stableKey: '',
20103 page: 1,
20104 perPage: 10,
20105 fields: null,
20106 include: null,
20107 context: 'default'
20108 };
20109
20110 // Ensure stable key by sorting keys. Also more efficient for iterating.
20111 const keys = Object.keys(query).sort();
20112 for (let i = 0; i < keys.length; i++) {
20113 const key = keys[i];
20114 let value = query[key];
20115 switch (key) {
20116 case 'page':
20117 parts[key] = Number(value);
20118 break;
20119 case 'per_page':
20120 parts.perPage = Number(value);
20121 break;
20122 case 'context':
20123 parts.context = value;
20124 break;
20125 default:
20126 // While in theory, we could exclude "_fields" from the stableKey
20127 // because two request with different fields have the same results
20128 // We're not able to ensure that because the server can decide to omit
20129 // fields from the response even if we explicitly asked for it.
20130 // Example: Asking for titles in posts without title support.
20131 if (key === '_fields') {
20132 var _getNormalizedCommaSe;
20133 parts.fields = (_getNormalizedCommaSe = get_normalized_comma_separable(value)) !== null && _getNormalizedCommaSe !== void 0 ? _getNormalizedCommaSe : [];
20134 // Make sure to normalize value for `stableKey`
20135 value = parts.fields.join();
20136 }
20137
20138 // Two requests with different include values cannot have same results.
20139 if (key === 'include') {
20140 var _getNormalizedCommaSe2;
20141 if (typeof value === 'number') {
20142 value = value.toString();
20143 }
20144 parts.include = ((_getNormalizedCommaSe2 = get_normalized_comma_separable(value)) !== null && _getNormalizedCommaSe2 !== void 0 ? _getNormalizedCommaSe2 : []).map(Number);
20145 // Normalize value for `stableKey`.
20146 value = parts.include.join();
20147 }
20148
20149 // While it could be any deterministic string, for simplicity's
20150 // sake mimic querystring encoding for stable key.
20151 //
20152 // TODO: For consistency with PHP implementation, addQueryArgs
20153 // should accept a key value pair, which may optimize its
20154 // implementation for our use here, vs. iterating an object
20155 // with only a single key.
20156 parts.stableKey += (parts.stableKey ? '&' : '') + (0,external_wp_url_namespaceObject.addQueryArgs)('', {
20157 [key]: value
20158 }).slice(1);
20159 }
20160 }
20161 return parts;
20162 }
20163 /* harmony default export */ const get_query_parts = (with_weak_map_cache(getQueryParts));
20164
20165 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/reducer.js
20166 /**
20167 * WordPress dependencies
20168 */
20169
20170
20171
20172 /**
20173 * Internal dependencies
20174 */
20175
20176
20177
20178 function getContextFromAction(action) {
20179 const {
20180 query
20181 } = action;
20182 if (!query) {
20183 return 'default';
20184 }
20185 const queryParts = get_query_parts(query);
20186 return queryParts.context;
20187 }
20188
20189 /**
20190 * Returns a merged array of item IDs, given details of the received paginated
20191 * items. The array is sparse-like with `undefined` entries where holes exist.
20192 *
20193 * @param {?Array<number>} itemIds Original item IDs (default empty array).
20194 * @param {number[]} nextItemIds Item IDs to merge.
20195 * @param {number} page Page of items merged.
20196 * @param {number} perPage Number of items per page.
20197 *
20198 * @return {number[]} Merged array of item IDs.
20199 */
20200 function getMergedItemIds(itemIds, nextItemIds, page, perPage) {
20201 var _itemIds$length;
20202 const receivedAllIds = page === 1 && perPage === -1;
20203 if (receivedAllIds) {
20204 return nextItemIds;
20205 }
20206 const nextItemIdsStartIndex = (page - 1) * perPage;
20207
20208 // If later page has already been received, default to the larger known
20209 // size of the existing array, else calculate as extending the existing.
20210 const size = Math.max((_itemIds$length = itemIds?.length) !== null && _itemIds$length !== void 0 ? _itemIds$length : 0, nextItemIdsStartIndex + nextItemIds.length);
20211
20212 // Preallocate array since size is known.
20213 const mergedItemIds = new Array(size);
20214 for (let i = 0; i < size; i++) {
20215 // Preserve existing item ID except for subset of range of next items.
20216 // We need to check against the possible maximum upper boundary because
20217 // a page could receive fewer than what was previously stored.
20218 const isInNextItemsRange = i >= nextItemIdsStartIndex && i < nextItemIdsStartIndex + perPage;
20219 mergedItemIds[i] = isInNextItemsRange ? nextItemIds[i - nextItemIdsStartIndex] : itemIds?.[i];
20220 }
20221 return mergedItemIds;
20222 }
20223
20224 /**
20225 * Helper function to filter out entities with certain IDs.
20226 * Entities are keyed by their ID.
20227 *
20228 * @param {Object} entities Entity objects, keyed by entity ID.
20229 * @param {Array} ids Entity IDs to filter out.
20230 *
20231 * @return {Object} Filtered entities.
20232 */
20233 function removeEntitiesById(entities, ids) {
20234 return Object.fromEntries(Object.entries(entities).filter(([id]) => !ids.some(itemId => {
20235 if (Number.isInteger(itemId)) {
20236 return itemId === +id;
20237 }
20238 return itemId === id;
20239 })));
20240 }
20241
20242 /**
20243 * Reducer tracking items state, keyed by ID. Items are assumed to be normal,
20244 * where identifiers are common across all queries.
20245 *
20246 * @param {Object} state Current state.
20247 * @param {Object} action Dispatched action.
20248 *
20249 * @return {Object} Next state.
20250 */
20251 function items(state = {}, action) {
20252 switch (action.type) {
20253 case 'RECEIVE_ITEMS':
20254 {
20255 const context = getContextFromAction(action);
20256 const key = action.key || DEFAULT_ENTITY_KEY;
20257 return {
20258 ...state,
20259 [context]: {
20260 ...state[context],
20261 ...action.items.reduce((accumulator, value) => {
20262 const itemId = value[key];
20263 accumulator[itemId] = conservativeMapItem(state?.[context]?.[itemId], value);
20264 return accumulator;
20265 }, {})
20266 }
20267 };
20268 }
20269 case 'REMOVE_ITEMS':
20270 return Object.fromEntries(Object.entries(state).map(([itemId, contextState]) => [itemId, removeEntitiesById(contextState, action.itemIds)]));
20271 }
20272 return state;
20273 }
20274
20275 /**
20276 * Reducer tracking item completeness, keyed by ID. A complete item is one for
20277 * which all fields are known. This is used in supporting `_fields` queries,
20278 * where not all properties associated with an entity are necessarily returned.
20279 * In such cases, completeness is used as an indication of whether it would be
20280 * safe to use queried data for a non-`_fields`-limited request.
20281 *
20282 * @param {Object<string,Object<string,boolean>>} state Current state.
20283 * @param {Object} action Dispatched action.
20284 *
20285 * @return {Object<string,Object<string,boolean>>} Next state.
20286 */
20287 function itemIsComplete(state = {}, action) {
20288 switch (action.type) {
20289 case 'RECEIVE_ITEMS':
20290 {
20291 const context = getContextFromAction(action);
20292 const {
20293 query,
20294 key = DEFAULT_ENTITY_KEY
20295 } = action;
20296
20297 // An item is considered complete if it is received without an associated
20298 // fields query. Ideally, this would be implemented in such a way where the
20299 // complete aggregate of all fields would satisfy completeness. Since the
20300 // fields are not consistent across all entities, this would require
20301 // introspection on the REST schema for each entity to know which fields
20302 // compose a complete item for that entity.
20303 const queryParts = query ? get_query_parts(query) : {};
20304 const isCompleteQuery = !query || !Array.isArray(queryParts.fields);
20305 return {
20306 ...state,
20307 [context]: {
20308 ...state[context],
20309 ...action.items.reduce((result, item) => {
20310 const itemId = item[key];
20311
20312 // Defer to completeness if already assigned. Technically the
20313 // data may be outdated if receiving items for a field subset.
20314 result[itemId] = state?.[context]?.[itemId] || isCompleteQuery;
20315 return result;
20316 }, {})
20317 }
20318 };
20319 }
20320 case 'REMOVE_ITEMS':
20321 return Object.fromEntries(Object.entries(state).map(([itemId, contextState]) => [itemId, removeEntitiesById(contextState, action.itemIds)]));
20322 }
20323 return state;
20324 }
20325
20326 /**
20327 * Reducer tracking queries state, keyed by stable query key. Each reducer
20328 * query object includes `itemIds` and `requestingPageByPerPage`.
20329 *
20330 * @param {Object} state Current state.
20331 * @param {Object} action Dispatched action.
20332 *
20333 * @return {Object} Next state.
20334 */
20335 const receiveQueries = (0,external_wp_compose_namespaceObject.compose)([
20336 // Limit to matching action type so we don't attempt to replace action on
20337 // an unhandled action.
20338 if_matching_action(action => 'query' in action),
20339 // Inject query parts into action for use both in `onSubKey` and reducer.
20340 replace_action(action => {
20341 // `ifMatchingAction` still passes on initialization, where state is
20342 // undefined and a query is not assigned. Avoid attempting to parse
20343 // parts. `onSubKey` will omit by lack of `stableKey`.
20344 if (action.query) {
20345 return {
20346 ...action,
20347 ...get_query_parts(action.query)
20348 };
20349 }
20350 return action;
20351 }), on_sub_key('context'),
20352 // Queries shape is shared, but keyed by query `stableKey` part. Original
20353 // reducer tracks only a single query object.
20354 on_sub_key('stableKey')])((state = {}, action) => {
20355 const {
20356 type,
20357 page,
20358 perPage,
20359 key = DEFAULT_ENTITY_KEY
20360 } = action;
20361 if (type !== 'RECEIVE_ITEMS') {
20362 return state;
20363 }
20364 return {
20365 itemIds: getMergedItemIds(state?.itemIds || [], action.items.map(item => item[key]), page, perPage),
20366 meta: action.meta
20367 };
20368 });
20369
20370 /**
20371 * Reducer tracking queries state.
20372 *
20373 * @param {Object} state Current state.
20374 * @param {Object} action Dispatched action.
20375 *
20376 * @return {Object} Next state.
20377 */
20378 const queries = (state = {}, action) => {
20379 switch (action.type) {
20380 case 'RECEIVE_ITEMS':
20381 return receiveQueries(state, action);
20382 case 'REMOVE_ITEMS':
20383 const removedItems = action.itemIds.reduce((result, itemId) => {
20384 result[itemId] = true;
20385 return result;
20386 }, {});
20387 return Object.fromEntries(Object.entries(state).map(([queryGroup, contextQueries]) => [queryGroup, Object.fromEntries(Object.entries(contextQueries).map(([query, queryItems]) => [query, {
20388 ...queryItems,
20389 itemIds: queryItems.itemIds.filter(queryId => !removedItems[queryId])
20390 }]))]));
20391 default:
20392 return state;
20393 }
20394 };
20395 /* harmony default export */ const reducer = ((0,external_wp_data_namespaceObject.combineReducers)({
20396 items,
20397 itemIsComplete,
20398 queries
20399 }));
20400
20401 ;// CONCATENATED MODULE: ./packages/core-data/build-module/reducer.js
20402 /**
20403 * External dependencies
20404 */
20405
20406
20407 /**
20408 * WordPress dependencies
20409 */
20410
20411
20412
20413
20414 /**
20415 * Internal dependencies
20416 */
20417
20418
20419
20420
20421 /** @typedef {import('./types').AnyFunction} AnyFunction */
20422
20423 /**
20424 * Reducer managing terms state. Keyed by taxonomy slug, the value is either
20425 * undefined (if no request has been made for given taxonomy), null (if a
20426 * request is in-flight for given taxonomy), or the array of terms for the
20427 * taxonomy.
20428 *
20429 * @param {Object} state Current state.
20430 * @param {Object} action Dispatched action.
20431 *
20432 * @return {Object} Updated state.
20433 */
20434 function terms(state = {}, action) {
20435 switch (action.type) {
20436 case 'RECEIVE_TERMS':
20437 return {
20438 ...state,
20439 [action.taxonomy]: action.terms
20440 };
20441 }
20442 return state;
20443 }
20444
20445 /**
20446 * Reducer managing authors state. Keyed by id.
20447 *
20448 * @param {Object} state Current state.
20449 * @param {Object} action Dispatched action.
20450 *
20451 * @return {Object} Updated state.
20452 */
20453 function users(state = {
20454 byId: {},
20455 queries: {}
20456 }, action) {
20457 switch (action.type) {
20458 case 'RECEIVE_USER_QUERY':
20459 return {
20460 byId: {
20461 ...state.byId,
20462 // Key users by their ID.
20463 ...action.users.reduce((newUsers, user) => ({
20464 ...newUsers,
20465 [user.id]: user
20466 }), {})
20467 },
20468 queries: {
20469 ...state.queries,
20470 [action.queryID]: action.users.map(user => user.id)
20471 }
20472 };
20473 }
20474 return state;
20475 }
20476
20477 /**
20478 * Reducer managing current user state.
20479 *
20480 * @param {Object} state Current state.
20481 * @param {Object} action Dispatched action.
20482 *
20483 * @return {Object} Updated state.
20484 */
20485 function currentUser(state = {}, action) {
20486 switch (action.type) {
20487 case 'RECEIVE_CURRENT_USER':
20488 return action.currentUser;
20489 }
20490 return state;
20491 }
20492
20493 /**
20494 * Reducer managing taxonomies.
20495 *
20496 * @param {Object} state Current state.
20497 * @param {Object} action Dispatched action.
20498 *
20499 * @return {Object} Updated state.
20500 */
20501 function taxonomies(state = [], action) {
20502 switch (action.type) {
20503 case 'RECEIVE_TAXONOMIES':
20504 return action.taxonomies;
20505 }
20506 return state;
20507 }
20508
20509 /**
20510 * Reducer managing the current theme.
20511 *
20512 * @param {string|undefined} state Current state.
20513 * @param {Object} action Dispatched action.
20514 *
20515 * @return {string|undefined} Updated state.
20516 */
20517 function currentTheme(state = undefined, action) {
20518 switch (action.type) {
20519 case 'RECEIVE_CURRENT_THEME':
20520 return action.currentTheme.stylesheet;
20521 }
20522 return state;
20523 }
20524
20525 /**
20526 * Reducer managing the current global styles id.
20527 *
20528 * @param {string|undefined} state Current state.
20529 * @param {Object} action Dispatched action.
20530 *
20531 * @return {string|undefined} Updated state.
20532 */
20533 function currentGlobalStylesId(state = undefined, action) {
20534 switch (action.type) {
20535 case 'RECEIVE_CURRENT_GLOBAL_STYLES_ID':
20536 return action.id;
20537 }
20538 return state;
20539 }
20540
20541 /**
20542 * Reducer managing the theme base global styles.
20543 *
20544 * @param {Record<string, object>} state Current state.
20545 * @param {Object} action Dispatched action.
20546 *
20547 * @return {Record<string, object>} Updated state.
20548 */
20549 function themeBaseGlobalStyles(state = {}, action) {
20550 switch (action.type) {
20551 case 'RECEIVE_THEME_GLOBAL_STYLES':
20552 return {
20553 ...state,
20554 [action.stylesheet]: action.globalStyles
20555 };
20556 }
20557 return state;
20558 }
20559
20560 /**
20561 * Reducer managing the theme global styles variations.
20562 *
20563 * @param {Record<string, object>} state Current state.
20564 * @param {Object} action Dispatched action.
20565 *
20566 * @return {Record<string, object>} Updated state.
20567 */
20568 function themeGlobalStyleVariations(state = {}, action) {
20569 switch (action.type) {
20570 case 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS':
20571 return {
20572 ...state,
20573 [action.stylesheet]: action.variations
20574 };
20575 }
20576 return state;
20577 }
20578 const withMultiEntityRecordEdits = reducer => (state, action) => {
20579 if (action.type === 'UNDO' || action.type === 'REDO') {
20580 const {
20581 record
20582 } = action;
20583 let newState = state;
20584 record.forEach(({
20585 id: {
20586 kind,
20587 name,
20588 recordId
20589 },
20590 changes
20591 }) => {
20592 newState = reducer(newState, {
20593 type: 'EDIT_ENTITY_RECORD',
20594 kind,
20595 name,
20596 recordId,
20597 edits: Object.entries(changes).reduce((acc, [key, value]) => {
20598 acc[key] = action.type === 'UNDO' ? value.from : value.to;
20599 return acc;
20600 }, {})
20601 });
20602 });
20603 return newState;
20604 }
20605 return reducer(state, action);
20606 };
20607
20608 /**
20609 * Higher Order Reducer for a given entity config. It supports:
20610 *
20611 * - Fetching
20612 * - Editing
20613 * - Saving
20614 *
20615 * @param {Object} entityConfig Entity config.
20616 *
20617 * @return {AnyFunction} Reducer.
20618 */
20619 function entity(entityConfig) {
20620 return (0,external_wp_compose_namespaceObject.compose)([withMultiEntityRecordEdits,
20621 // Limit to matching action type so we don't attempt to replace action on
20622 // an unhandled action.
20623 if_matching_action(action => action.name && action.kind && action.name === entityConfig.name && action.kind === entityConfig.kind),
20624 // Inject the entity config into the action.
20625 replace_action(action => {
20626 return {
20627 key: entityConfig.key || DEFAULT_ENTITY_KEY,
20628 ...action
20629 };
20630 })])((0,external_wp_data_namespaceObject.combineReducers)({
20631 queriedData: reducer,
20632 edits: (state = {}, action) => {
20633 var _action$query$context;
20634 switch (action.type) {
20635 case 'RECEIVE_ITEMS':
20636 const context = (_action$query$context = action?.query?.context) !== null && _action$query$context !== void 0 ? _action$query$context : 'default';
20637 if (context !== 'default') {
20638 return state;
20639 }
20640 const nextState = {
20641 ...state
20642 };
20643 for (const record of action.items) {
20644 const recordId = record[action.key];
20645 const edits = nextState[recordId];
20646 if (!edits) {
20647 continue;
20648 }
20649 const nextEdits = Object.keys(edits).reduce((acc, key) => {
20650 var _record$key$raw;
20651 // If the edited value is still different to the persisted value,
20652 // keep the edited value in edits.
20653 if (
20654 // Edits are the "raw" attribute values, but records may have
20655 // objects with more properties, so we use `get` here for the
20656 // comparison.
20657 !es6_default()(edits[key], (_record$key$raw = record[key]?.raw) !== null && _record$key$raw !== void 0 ? _record$key$raw : record[key]) && (
20658 // Sometimes the server alters the sent value which means
20659 // we need to also remove the edits before the api request.
20660 !action.persistedEdits || !es6_default()(edits[key], action.persistedEdits[key]))) {
20661 acc[key] = edits[key];
20662 }
20663 return acc;
20664 }, {});
20665 if (Object.keys(nextEdits).length) {
20666 nextState[recordId] = nextEdits;
20667 } else {
20668 delete nextState[recordId];
20669 }
20670 }
20671 return nextState;
20672 case 'EDIT_ENTITY_RECORD':
20673 const nextEdits = {
20674 ...state[action.recordId],
20675 ...action.edits
20676 };
20677 Object.keys(nextEdits).forEach(key => {
20678 // Delete cleared edits so that the properties
20679 // are not considered dirty.
20680 if (nextEdits[key] === undefined) {
20681 delete nextEdits[key];
20682 }
20683 });
20684 return {
20685 ...state,
20686 [action.recordId]: nextEdits
20687 };
20688 }
20689 return state;
20690 },
20691 saving: (state = {}, action) => {
20692 switch (action.type) {
20693 case 'SAVE_ENTITY_RECORD_START':
20694 case 'SAVE_ENTITY_RECORD_FINISH':
20695 return {
20696 ...state,
20697 [action.recordId]: {
20698 pending: action.type === 'SAVE_ENTITY_RECORD_START',
20699 error: action.error,
20700 isAutosave: action.isAutosave
20701 }
20702 };
20703 }
20704 return state;
20705 },
20706 deleting: (state = {}, action) => {
20707 switch (action.type) {
20708 case 'DELETE_ENTITY_RECORD_START':
20709 case 'DELETE_ENTITY_RECORD_FINISH':
20710 return {
20711 ...state,
20712 [action.recordId]: {
20713 pending: action.type === 'DELETE_ENTITY_RECORD_START',
20714 error: action.error
20715 }
20716 };
20717 }
20718 return state;
20719 },
20720 revisions: (state = {}, action) => {
20721 // Use the same queriedDataReducer shape for revisions.
20722 if (action.type === 'RECEIVE_ITEM_REVISIONS') {
20723 const recordKey = action.recordKey;
20724 delete action.recordKey;
20725 const newState = reducer(state[recordKey], {
20726 ...action,
20727 type: 'RECEIVE_ITEMS'
20728 });
20729 return {
20730 ...state,
20731 [recordKey]: newState
20732 };
20733 }
20734 if (action.type === 'REMOVE_ITEMS') {
20735 return Object.fromEntries(Object.entries(state).filter(([id]) => !action.itemIds.some(itemId => {
20736 if (Number.isInteger(itemId)) {
20737 return itemId === +id;
20738 }
20739 return itemId === id;
20740 })));
20741 }
20742 return state;
20743 }
20744 }));
20745 }
20746
20747 /**
20748 * Reducer keeping track of the registered entities.
20749 *
20750 * @param {Object} state Current state.
20751 * @param {Object} action Dispatched action.
20752 *
20753 * @return {Object} Updated state.
20754 */
20755 function entitiesConfig(state = rootEntitiesConfig, action) {
20756 switch (action.type) {
20757 case 'ADD_ENTITIES':
20758 return [...state, ...action.entities];
20759 }
20760 return state;
20761 }
20762
20763 /**
20764 * Reducer keeping track of the registered entities config and data.
20765 *
20766 * @param {Object} state Current state.
20767 * @param {Object} action Dispatched action.
20768 *
20769 * @return {Object} Updated state.
20770 */
20771 const entities = (state = {}, action) => {
20772 const newConfig = entitiesConfig(state.config, action);
20773
20774 // Generates a dynamic reducer for the entities.
20775 let entitiesDataReducer = state.reducer;
20776 if (!entitiesDataReducer || newConfig !== state.config) {
20777 const entitiesByKind = newConfig.reduce((acc, record) => {
20778 const {
20779 kind
20780 } = record;
20781 if (!acc[kind]) {
20782 acc[kind] = [];
20783 }
20784 acc[kind].push(record);
20785 return acc;
20786 }, {});
20787 entitiesDataReducer = (0,external_wp_data_namespaceObject.combineReducers)(Object.entries(entitiesByKind).reduce((memo, [kind, subEntities]) => {
20788 const kindReducer = (0,external_wp_data_namespaceObject.combineReducers)(subEntities.reduce((kindMemo, entityConfig) => ({
20789 ...kindMemo,
20790 [entityConfig.name]: entity(entityConfig)
20791 }), {}));
20792 memo[kind] = kindReducer;
20793 return memo;
20794 }, {}));
20795 }
20796 const newData = entitiesDataReducer(state.records, action);
20797 if (newData === state.records && newConfig === state.config && entitiesDataReducer === state.reducer) {
20798 return state;
20799 }
20800 return {
20801 reducer: entitiesDataReducer,
20802 records: newData,
20803 config: newConfig
20804 };
20805 };
20806
20807 /**
20808 * @type {UndoManager}
20809 */
20810 function undoManager(state = createUndoManager()) {
20811 return state;
20812 }
20813 function editsReference(state = {}, action) {
20814 switch (action.type) {
20815 case 'EDIT_ENTITY_RECORD':
20816 case 'UNDO':
20817 case 'REDO':
20818 return {};
20819 }
20820 return state;
20821 }
20822
20823 /**
20824 * Reducer managing embed preview data.
20825 *
20826 * @param {Object} state Current state.
20827 * @param {Object} action Dispatched action.
20828 *
20829 * @return {Object} Updated state.
20830 */
20831 function embedPreviews(state = {}, action) {
20832 switch (action.type) {
20833 case 'RECEIVE_EMBED_PREVIEW':
20834 const {
20835 url,
20836 preview
20837 } = action;
20838 return {
20839 ...state,
20840 [url]: preview
20841 };
20842 }
20843 return state;
20844 }
20845
20846 /**
20847 * State which tracks whether the user can perform an action on a REST
20848 * resource.
20849 *
20850 * @param {Object} state Current state.
20851 * @param {Object} action Dispatched action.
20852 *
20853 * @return {Object} Updated state.
20854 */
20855 function userPermissions(state = {}, action) {
20856 switch (action.type) {
20857 case 'RECEIVE_USER_PERMISSION':
20858 return {
20859 ...state,
20860 [action.key]: action.isAllowed
20861 };
20862 }
20863 return state;
20864 }
20865
20866 /**
20867 * Reducer returning autosaves keyed by their parent's post id.
20868 *
20869 * @param {Object} state Current state.
20870 * @param {Object} action Dispatched action.
20871 *
20872 * @return {Object} Updated state.
20873 */
20874 function autosaves(state = {}, action) {
20875 switch (action.type) {
20876 case 'RECEIVE_AUTOSAVES':
20877 const {
20878 postId,
20879 autosaves: autosavesData
20880 } = action;
20881 return {
20882 ...state,
20883 [postId]: autosavesData
20884 };
20885 }
20886 return state;
20887 }
20888 function blockPatterns(state = [], action) {
20889 switch (action.type) {
20890 case 'RECEIVE_BLOCK_PATTERNS':
20891 return action.patterns;
20892 }
20893 return state;
20894 }
20895 function blockPatternCategories(state = [], action) {
20896 switch (action.type) {
20897 case 'RECEIVE_BLOCK_PATTERN_CATEGORIES':
20898 return action.categories;
20899 }
20900 return state;
20901 }
20902 function userPatternCategories(state = [], action) {
20903 switch (action.type) {
20904 case 'RECEIVE_USER_PATTERN_CATEGORIES':
20905 return action.patternCategories;
20906 }
20907 return state;
20908 }
20909 function navigationFallbackId(state = null, action) {
20910 switch (action.type) {
20911 case 'RECEIVE_NAVIGATION_FALLBACK_ID':
20912 return action.fallbackId;
20913 }
20914 return state;
20915 }
20916
20917 /**
20918 * Reducer managing the theme global styles revisions.
20919 *
20920 * @param {Record<string, object>} state Current state.
20921 * @param {Object} action Dispatched action.
20922 *
20923 * @return {Record<string, object>} Updated state.
20924 */
20925 function themeGlobalStyleRevisions(state = {}, action) {
20926 switch (action.type) {
20927 case 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS':
20928 return {
20929 ...state,
20930 [action.currentId]: action.revisions
20931 };
20932 }
20933 return state;
20934 }
20935
20936 /**
20937 * Reducer managing the template lookup per query.
20938 *
20939 * @param {Record<string, string>} state Current state.
20940 * @param {Object} action Dispatched action.
20941 *
20942 * @return {Record<string, string>} Updated state.
20943 */
20944 function defaultTemplates(state = {}, action) {
20945 switch (action.type) {
20946 case 'RECEIVE_DEFAULT_TEMPLATE':
20947 return {
20948 ...state,
20949 [JSON.stringify(action.query)]: action.templateId
20950 };
20951 }
20952 return state;
20953 }
20954 /* harmony default export */ const build_module_reducer = ((0,external_wp_data_namespaceObject.combineReducers)({
20955 terms,
20956 users,
20957 currentTheme,
20958 currentGlobalStylesId,
20959 currentUser,
20960 themeGlobalStyleVariations,
20961 themeBaseGlobalStyles,
20962 themeGlobalStyleRevisions,
20963 taxonomies,
20964 entities,
20965 editsReference,
20966 undoManager,
20967 embedPreviews,
20968 userPermissions,
20969 autosaves,
20970 blockPatterns,
20971 blockPatternCategories,
20972 userPatternCategories,
20973 navigationFallbackId,
20974 defaultTemplates
20975 }));
20976
20977 // EXTERNAL MODULE: ./node_modules/equivalent-key-map/equivalent-key-map.js
20978 var equivalent_key_map = __webpack_require__(2167);
20979 var equivalent_key_map_default = /*#__PURE__*/__webpack_require__.n(equivalent_key_map);
20980 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/selectors.js
20981 /**
20982 * External dependencies
20983 */
20984
20985
20986 /**
20987 * WordPress dependencies
20988 */
20989
20990
20991 /**
20992 * Internal dependencies
20993 */
20994
20995
20996
20997 /**
20998 * Cache of state keys to EquivalentKeyMap where the inner map tracks queries
20999 * to their resulting items set. WeakMap allows garbage collection on expired
21000 * state references.
21001 *
21002 * @type {WeakMap<Object,EquivalentKeyMap>}
21003 */
21004 const queriedItemsCacheByState = new WeakMap();
21005
21006 /**
21007 * Returns items for a given query, or null if the items are not known.
21008 *
21009 * @param {Object} state State object.
21010 * @param {?Object} query Optional query.
21011 *
21012 * @return {?Array} Query items.
21013 */
21014 function getQueriedItemsUncached(state, query) {
21015 const {
21016 stableKey,
21017 page,
21018 perPage,
21019 include,
21020 fields,
21021 context
21022 } = get_query_parts(query);
21023 let itemIds;
21024 if (state.queries?.[context]?.[stableKey]) {
21025 itemIds = state.queries[context][stableKey].itemIds;
21026 }
21027 if (!itemIds) {
21028 return null;
21029 }
21030 const startOffset = perPage === -1 ? 0 : (page - 1) * perPage;
21031 const endOffset = perPage === -1 ? itemIds.length : Math.min(startOffset + perPage, itemIds.length);
21032 const items = [];
21033 for (let i = startOffset; i < endOffset; i++) {
21034 const itemId = itemIds[i];
21035 if (Array.isArray(include) && !include.includes(itemId)) {
21036 continue;
21037 }
21038 if (itemId === undefined) {
21039 continue;
21040 }
21041 // Having a target item ID doesn't guarantee that this object has been queried.
21042 if (!state.items[context]?.hasOwnProperty(itemId)) {
21043 return null;
21044 }
21045 const item = state.items[context][itemId];
21046 let filteredItem;
21047 if (Array.isArray(fields)) {
21048 filteredItem = {};
21049 for (let f = 0; f < fields.length; f++) {
21050 const field = fields[f].split('.');
21051 let value = item;
21052 field.forEach(fieldName => {
21053 value = value?.[fieldName];
21054 });
21055 setNestedValue(filteredItem, field, value);
21056 }
21057 } else {
21058 // If expecting a complete item, validate that completeness, or
21059 // otherwise abort.
21060 if (!state.itemIsComplete[context]?.[itemId]) {
21061 return null;
21062 }
21063 filteredItem = item;
21064 }
21065 items.push(filteredItem);
21066 }
21067 return items;
21068 }
21069
21070 /**
21071 * Returns items for a given query, or null if the items are not known. Caches
21072 * result both per state (by reference) and per query (by deep equality).
21073 * The caching approach is intended to be durable to query objects which are
21074 * deeply but not referentially equal, since otherwise:
21075 *
21076 * `getQueriedItems( state, {} ) !== getQueriedItems( state, {} )`
21077 *
21078 * @param {Object} state State object.
21079 * @param {?Object} query Optional query.
21080 *
21081 * @return {?Array} Query items.
21082 */
21083 const getQueriedItems = (0,external_wp_data_namespaceObject.createSelector)((state, query = {}) => {
21084 let queriedItemsCache = queriedItemsCacheByState.get(state);
21085 if (queriedItemsCache) {
21086 const queriedItems = queriedItemsCache.get(query);
21087 if (queriedItems !== undefined) {
21088 return queriedItems;
21089 }
21090 } else {
21091 queriedItemsCache = new (equivalent_key_map_default())();
21092 queriedItemsCacheByState.set(state, queriedItemsCache);
21093 }
21094 const items = getQueriedItemsUncached(state, query);
21095 queriedItemsCache.set(query, items);
21096 return items;
21097 });
21098 function getQueriedTotalItems(state, query = {}) {
21099 var _state$queries$contex;
21100 const {
21101 stableKey,
21102 context
21103 } = get_query_parts(query);
21104 return (_state$queries$contex = state.queries?.[context]?.[stableKey]?.meta?.totalItems) !== null && _state$queries$contex !== void 0 ? _state$queries$contex : null;
21105 }
21106 function getQueriedTotalPages(state, query = {}) {
21107 var _state$queries$contex2;
21108 const {
21109 stableKey,
21110 context
21111 } = get_query_parts(query);
21112 return (_state$queries$contex2 = state.queries?.[context]?.[stableKey]?.meta?.totalPages) !== null && _state$queries$contex2 !== void 0 ? _state$queries$contex2 : null;
21113 }
21114
21115 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/is-numeric-id.js
21116 /**
21117 * Checks argument to determine if it's a numeric ID.
21118 * For example, '123' is a numeric ID, but '123abc' is not.
21119 *
21120 * @param {any} id the argument to determine if it's a numeric ID.
21121 * @return {boolean} true if the string is a numeric ID, false otherwise.
21122 */
21123 function isNumericID(id) {
21124 return /^\s*\d+\s*$/.test(id);
21125 }
21126
21127 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/is-raw-attribute.js
21128 /**
21129 * Checks whether the attribute is a "raw" attribute or not.
21130 *
21131 * @param {Object} entity Entity record.
21132 * @param {string} attribute Attribute name.
21133 *
21134 * @return {boolean} Is the attribute raw
21135 */
21136 function isRawAttribute(entity, attribute) {
21137 return (entity.rawAttributes || []).includes(attribute);
21138 }
21139
21140 ;// CONCATENATED MODULE: ./packages/core-data/build-module/selectors.js
21141 /**
21142 * WordPress dependencies
21143 */
21144
21145
21146
21147
21148 /**
21149 * Internal dependencies
21150 */
21151
21152
21153
21154
21155
21156 // This is an incomplete, high-level approximation of the State type.
21157 // It makes the selectors slightly more safe, but is intended to evolve
21158 // into a more detailed representation over time.
21159 // See https://github.com/WordPress/gutenberg/pull/40025#discussion_r865410589 for more context.
21160
21161 /**
21162 * HTTP Query parameters sent with the API request to fetch the entity records.
21163 */
21164
21165 /**
21166 * Arguments for EntityRecord selectors.
21167 */
21168
21169 /**
21170 * Shared reference to an empty object for cases where it is important to avoid
21171 * returning a new object reference on every invocation, as in a connected or
21172 * other pure component which performs `shouldComponentUpdate` check on props.
21173 * This should be used as a last resort, since the normalized data should be
21174 * maintained by the reducer result in state.
21175 */
21176 const EMPTY_OBJECT = {};
21177
21178 /**
21179 * Returns true if a request is in progress for embed preview data, or false
21180 * otherwise.
21181 *
21182 * @param state Data state.
21183 * @param url URL the preview would be for.
21184 *
21185 * @return Whether a request is in progress for an embed preview.
21186 */
21187 const isRequestingEmbedPreview = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, url) => {
21188 return select(STORE_NAME).isResolving('getEmbedPreview', [url]);
21189 });
21190
21191 /**
21192 * Returns all available authors.
21193 *
21194 * @deprecated since 11.3. Callers should use `select( 'core' ).getUsers({ who: 'authors' })` instead.
21195 *
21196 * @param state Data state.
21197 * @param query Optional object of query parameters to
21198 * 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).
21199 * @return Authors list.
21200 */
21201 function getAuthors(state, query) {
21202 external_wp_deprecated_default()("select( 'core' ).getAuthors()", {
21203 since: '5.9',
21204 alternative: "select( 'core' ).getUsers({ who: 'authors' })"
21205 });
21206 const path = (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/users/?who=authors&per_page=100', query);
21207 return getUserQueryResults(state, path);
21208 }
21209
21210 /**
21211 * Returns the current user.
21212 *
21213 * @param state Data state.
21214 *
21215 * @return Current user object.
21216 */
21217 function getCurrentUser(state) {
21218 return state.currentUser;
21219 }
21220
21221 /**
21222 * Returns all the users returned by a query ID.
21223 *
21224 * @param state Data state.
21225 * @param queryID Query ID.
21226 *
21227 * @return Users list.
21228 */
21229 const getUserQueryResults = (0,external_wp_data_namespaceObject.createSelector)((state, queryID) => {
21230 var _state$users$queries$;
21231 const queryResults = (_state$users$queries$ = state.users.queries[queryID]) !== null && _state$users$queries$ !== void 0 ? _state$users$queries$ : [];
21232 return queryResults.map(id => state.users.byId[id]);
21233 }, (state, queryID) => [state.users.queries[queryID], state.users.byId]);
21234
21235 /**
21236 * Returns the loaded entities for the given kind.
21237 *
21238 * @deprecated since WordPress 6.0. Use getEntitiesConfig instead
21239 * @param state Data state.
21240 * @param kind Entity kind.
21241 *
21242 * @return Array of entities with config matching kind.
21243 */
21244 function getEntitiesByKind(state, kind) {
21245 external_wp_deprecated_default()("wp.data.select( 'core' ).getEntitiesByKind()", {
21246 since: '6.0',
21247 alternative: "wp.data.select( 'core' ).getEntitiesConfig()"
21248 });
21249 return getEntitiesConfig(state, kind);
21250 }
21251
21252 /**
21253 * Returns the loaded entities for the given kind.
21254 *
21255 * @param state Data state.
21256 * @param kind Entity kind.
21257 *
21258 * @return Array of entities with config matching kind.
21259 */
21260 const getEntitiesConfig = (0,external_wp_data_namespaceObject.createSelector)((state, kind) => state.entities.config.filter(entity => entity.kind === kind), (state, kind) => state.entities.config);
21261 /**
21262 * Returns the entity config given its kind and name.
21263 *
21264 * @deprecated since WordPress 6.0. Use getEntityConfig instead
21265 * @param state Data state.
21266 * @param kind Entity kind.
21267 * @param name Entity name.
21268 *
21269 * @return Entity config
21270 */
21271 function getEntity(state, kind, name) {
21272 external_wp_deprecated_default()("wp.data.select( 'core' ).getEntity()", {
21273 since: '6.0',
21274 alternative: "wp.data.select( 'core' ).getEntityConfig()"
21275 });
21276 return getEntityConfig(state, kind, name);
21277 }
21278
21279 /**
21280 * Returns the entity config given its kind and name.
21281 *
21282 * @param state Data state.
21283 * @param kind Entity kind.
21284 * @param name Entity name.
21285 *
21286 * @return Entity config
21287 */
21288 function getEntityConfig(state, kind, name) {
21289 return state.entities.config?.find(config => config.kind === kind && config.name === name);
21290 }
21291
21292 /**
21293 * GetEntityRecord is declared as a *callable interface* with
21294 * two signatures to work around the fact that TypeScript doesn't
21295 * allow currying generic functions:
21296 *
21297 * ```ts
21298 * type CurriedState = F extends ( state: any, ...args: infer P ) => infer R
21299 * ? ( ...args: P ) => R
21300 * : F;
21301 * type Selector = <K extends string | number>(
21302 * state: any,
21303 * kind: K,
21304 * key: K extends string ? 'string value' : false
21305 * ) => K;
21306 * type BadlyInferredSignature = CurriedState< Selector >
21307 * // BadlyInferredSignature evaluates to:
21308 * // (kind: string number, key: false | "string value") => string number
21309 * ```
21310 *
21311 * The signature without the state parameter shipped as CurriedSignature
21312 * is used in the return value of `select( coreStore )`.
21313 *
21314 * See https://github.com/WordPress/gutenberg/pull/41578 for more details.
21315 */
21316
21317 /**
21318 * Returns the Entity's record object by key. Returns `null` if the value is not
21319 * yet received, undefined if the value entity is known to not exist, or the
21320 * entity object if it exists and is received.
21321 *
21322 * @param state State tree
21323 * @param kind Entity kind.
21324 * @param name Entity name.
21325 * @param key Record's key
21326 * @param query Optional query. If requesting specific
21327 * 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]".
21328 *
21329 * @return Record.
21330 */
21331 const getEntityRecord = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, key, query) => {
21332 var _query$context;
21333 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21334 if (!queriedState) {
21335 return undefined;
21336 }
21337 const context = (_query$context = query?.context) !== null && _query$context !== void 0 ? _query$context : 'default';
21338 if (query === undefined) {
21339 // If expecting a complete item, validate that completeness.
21340 if (!queriedState.itemIsComplete[context]?.[key]) {
21341 return undefined;
21342 }
21343 return queriedState.items[context][key];
21344 }
21345 const item = queriedState.items[context]?.[key];
21346 if (item && query._fields) {
21347 var _getNormalizedCommaSe;
21348 const filteredItem = {};
21349 const fields = (_getNormalizedCommaSe = get_normalized_comma_separable(query._fields)) !== null && _getNormalizedCommaSe !== void 0 ? _getNormalizedCommaSe : [];
21350 for (let f = 0; f < fields.length; f++) {
21351 const field = fields[f].split('.');
21352 let value = item;
21353 field.forEach(fieldName => {
21354 value = value?.[fieldName];
21355 });
21356 setNestedValue(filteredItem, field, value);
21357 }
21358 return filteredItem;
21359 }
21360 return item;
21361 }, (state, kind, name, recordId, query) => {
21362 var _query$context2;
21363 const context = (_query$context2 = query?.context) !== null && _query$context2 !== void 0 ? _query$context2 : 'default';
21364 return [state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]];
21365 });
21366
21367 /**
21368 * Normalizes `recordKey`s that look like numeric IDs to numbers.
21369 *
21370 * @param args EntityRecordArgs the selector arguments.
21371 * @return EntityRecordArgs the normalized arguments.
21372 */
21373 getEntityRecord.__unstableNormalizeArgs = args => {
21374 const newArgs = [...args];
21375 const recordKey = newArgs?.[2];
21376
21377 // If recordKey looks to be a numeric ID then coerce to number.
21378 newArgs[2] = isNumericID(recordKey) ? Number(recordKey) : recordKey;
21379 return newArgs;
21380 };
21381
21382 /**
21383 * 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.
21384 *
21385 * @param state State tree
21386 * @param kind Entity kind.
21387 * @param name Entity name.
21388 * @param key Record's key
21389 *
21390 * @return Record.
21391 */
21392 function __experimentalGetEntityRecordNoResolver(state, kind, name, key) {
21393 return getEntityRecord(state, kind, name, key);
21394 }
21395
21396 /**
21397 * Returns the entity's record object by key,
21398 * with its attributes mapped to their raw values.
21399 *
21400 * @param state State tree.
21401 * @param kind Entity kind.
21402 * @param name Entity name.
21403 * @param key Record's key.
21404 *
21405 * @return Object with the entity's raw attributes.
21406 */
21407 const getRawEntityRecord = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, key) => {
21408 const record = getEntityRecord(state, kind, name, key);
21409 return record && Object.keys(record).reduce((accumulator, _key) => {
21410 if (isRawAttribute(getEntityConfig(state, kind, name), _key)) {
21411 var _record$_key$raw;
21412 // Because edits are the "raw" attribute values,
21413 // we return those from record selectors to make rendering,
21414 // comparisons, and joins with edits easier.
21415 accumulator[_key] = (_record$_key$raw = record[_key]?.raw) !== null && _record$_key$raw !== void 0 ? _record$_key$raw : record[_key];
21416 } else {
21417 accumulator[_key] = record[_key];
21418 }
21419 return accumulator;
21420 }, {});
21421 }, (state, kind, name, recordId, query) => {
21422 var _query$context3;
21423 const context = (_query$context3 = query?.context) !== null && _query$context3 !== void 0 ? _query$context3 : 'default';
21424 return [state.entities.config, state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]];
21425 });
21426
21427 /**
21428 * Returns true if records have been received for the given set of parameters,
21429 * or false otherwise.
21430 *
21431 * @param state State tree
21432 * @param kind Entity kind.
21433 * @param name Entity name.
21434 * @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".
21435 *
21436 * @return Whether entity records have been received.
21437 */
21438 function hasEntityRecords(state, kind, name, query) {
21439 return Array.isArray(getEntityRecords(state, kind, name, query));
21440 }
21441
21442 /**
21443 * GetEntityRecord is declared as a *callable interface* with
21444 * two signatures to work around the fact that TypeScript doesn't
21445 * allow currying generic functions.
21446 *
21447 * @see GetEntityRecord
21448 * @see https://github.com/WordPress/gutenberg/pull/41578
21449 */
21450
21451 /**
21452 * Returns the Entity's records.
21453 *
21454 * @param state State tree
21455 * @param kind Entity kind.
21456 * @param name Entity name.
21457 * @param query Optional terms query. If requesting specific
21458 * 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".
21459 *
21460 * @return Records.
21461 */
21462 const getEntityRecords = (state, kind, name, query) => {
21463 // Queried data state is prepopulated for all known entities. If this is not
21464 // assigned for the given parameters, then it is known to not exist.
21465 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21466 if (!queriedState) {
21467 return null;
21468 }
21469 return getQueriedItems(queriedState, query);
21470 };
21471
21472 /**
21473 * Returns the Entity's total available records for a given query (ignoring pagination).
21474 *
21475 * @param state State tree
21476 * @param kind Entity kind.
21477 * @param name Entity name.
21478 * @param query Optional terms query. If requesting specific
21479 * 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".
21480 *
21481 * @return number | null.
21482 */
21483 const getEntityRecordsTotalItems = (state, kind, name, query) => {
21484 // Queried data state is prepopulated for all known entities. If this is not
21485 // assigned for the given parameters, then it is known to not exist.
21486 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21487 if (!queriedState) {
21488 return null;
21489 }
21490 return getQueriedTotalItems(queriedState, query);
21491 };
21492
21493 /**
21494 * Returns the number of available pages for the given query.
21495 *
21496 * @param state State tree
21497 * @param kind Entity kind.
21498 * @param name Entity name.
21499 * @param query Optional terms query. If requesting specific
21500 * 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".
21501 *
21502 * @return number | null.
21503 */
21504 const getEntityRecordsTotalPages = (state, kind, name, query) => {
21505 // Queried data state is prepopulated for all known entities. If this is not
21506 // assigned for the given parameters, then it is known to not exist.
21507 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21508 if (!queriedState) {
21509 return null;
21510 }
21511 if (query.per_page === -1) {
21512 return 1;
21513 }
21514 const totalItems = getQueriedTotalItems(queriedState, query);
21515 if (!totalItems) {
21516 return totalItems;
21517 }
21518 // If `per_page` is not set and the query relies on the defaults of the
21519 // REST endpoint, get the info from query's meta.
21520 if (!query.per_page) {
21521 return getQueriedTotalPages(queriedState, query);
21522 }
21523 return Math.ceil(totalItems / query.per_page);
21524 };
21525 /**
21526 * Returns the list of dirty entity records.
21527 *
21528 * @param state State tree.
21529 *
21530 * @return The list of updated records
21531 */
21532 const __experimentalGetDirtyEntityRecords = (0,external_wp_data_namespaceObject.createSelector)(state => {
21533 const {
21534 entities: {
21535 records
21536 }
21537 } = state;
21538 const dirtyRecords = [];
21539 Object.keys(records).forEach(kind => {
21540 Object.keys(records[kind]).forEach(name => {
21541 const primaryKeys = Object.keys(records[kind][name].edits).filter(primaryKey =>
21542 // The entity record must exist (not be deleted),
21543 // and it must have edits.
21544 getEntityRecord(state, kind, name, primaryKey) && hasEditsForEntityRecord(state, kind, name, primaryKey));
21545 if (primaryKeys.length) {
21546 const entityConfig = getEntityConfig(state, kind, name);
21547 primaryKeys.forEach(primaryKey => {
21548 const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey);
21549 dirtyRecords.push({
21550 // We avoid using primaryKey because it's transformed into a string
21551 // when it's used as an object key.
21552 key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined,
21553 title: entityConfig?.getTitle?.(entityRecord) || '',
21554 name,
21555 kind
21556 });
21557 });
21558 }
21559 });
21560 });
21561 return dirtyRecords;
21562 }, state => [state.entities.records]);
21563
21564 /**
21565 * Returns the list of entities currently being saved.
21566 *
21567 * @param state State tree.
21568 *
21569 * @return The list of records being saved.
21570 */
21571 const __experimentalGetEntitiesBeingSaved = (0,external_wp_data_namespaceObject.createSelector)(state => {
21572 const {
21573 entities: {
21574 records
21575 }
21576 } = state;
21577 const recordsBeingSaved = [];
21578 Object.keys(records).forEach(kind => {
21579 Object.keys(records[kind]).forEach(name => {
21580 const primaryKeys = Object.keys(records[kind][name].saving).filter(primaryKey => isSavingEntityRecord(state, kind, name, primaryKey));
21581 if (primaryKeys.length) {
21582 const entityConfig = getEntityConfig(state, kind, name);
21583 primaryKeys.forEach(primaryKey => {
21584 const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey);
21585 recordsBeingSaved.push({
21586 // We avoid using primaryKey because it's transformed into a string
21587 // when it's used as an object key.
21588 key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined,
21589 title: entityConfig?.getTitle?.(entityRecord) || '',
21590 name,
21591 kind
21592 });
21593 });
21594 }
21595 });
21596 });
21597 return recordsBeingSaved;
21598 }, state => [state.entities.records]);
21599
21600 /**
21601 * Returns the specified entity record's edits.
21602 *
21603 * @param state State tree.
21604 * @param kind Entity kind.
21605 * @param name Entity name.
21606 * @param recordId Record ID.
21607 *
21608 * @return The entity record's edits.
21609 */
21610 function getEntityRecordEdits(state, kind, name, recordId) {
21611 return state.entities.records?.[kind]?.[name]?.edits?.[recordId];
21612 }
21613
21614 /**
21615 * Returns the specified entity record's non transient edits.
21616 *
21617 * Transient edits don't create an undo level, and
21618 * are not considered for change detection.
21619 * They are defined in the entity's config.
21620 *
21621 * @param state State tree.
21622 * @param kind Entity kind.
21623 * @param name Entity name.
21624 * @param recordId Record ID.
21625 *
21626 * @return The entity record's non transient edits.
21627 */
21628 const getEntityRecordNonTransientEdits = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, recordId) => {
21629 const {
21630 transientEdits
21631 } = getEntityConfig(state, kind, name) || {};
21632 const edits = getEntityRecordEdits(state, kind, name, recordId) || {};
21633 if (!transientEdits) {
21634 return edits;
21635 }
21636 return Object.keys(edits).reduce((acc, key) => {
21637 if (!transientEdits[key]) {
21638 acc[key] = edits[key];
21639 }
21640 return acc;
21641 }, {});
21642 }, (state, kind, name, recordId) => [state.entities.config, state.entities.records?.[kind]?.[name]?.edits?.[recordId]]);
21643
21644 /**
21645 * Returns true if the specified entity record has edits,
21646 * and false otherwise.
21647 *
21648 * @param state State tree.
21649 * @param kind Entity kind.
21650 * @param name Entity name.
21651 * @param recordId Record ID.
21652 *
21653 * @return Whether the entity record has edits or not.
21654 */
21655 function hasEditsForEntityRecord(state, kind, name, recordId) {
21656 return isSavingEntityRecord(state, kind, name, recordId) || Object.keys(getEntityRecordNonTransientEdits(state, kind, name, recordId)).length > 0;
21657 }
21658
21659 /**
21660 * Returns the specified entity record, merged with its edits.
21661 *
21662 * @param state State tree.
21663 * @param kind Entity kind.
21664 * @param name Entity name.
21665 * @param recordId Record ID.
21666 *
21667 * @return The entity record, merged with its edits.
21668 */
21669 const getEditedEntityRecord = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, recordId) => {
21670 const raw = getRawEntityRecord(state, kind, name, recordId);
21671 const edited = getEntityRecordEdits(state, kind, name, recordId);
21672 // Never return a non-falsy empty object. Unfortunately we can't return
21673 // undefined or null because we were previously returning an empty
21674 // object, so trying to read properties from the result would throw.
21675 // Using false here is a workaround to avoid breaking changes.
21676 if (!raw && !edited) {
21677 return false;
21678 }
21679 return {
21680 ...raw,
21681 ...edited
21682 };
21683 }, (state, kind, name, recordId, query) => {
21684 var _query$context4;
21685 const context = (_query$context4 = query?.context) !== null && _query$context4 !== void 0 ? _query$context4 : 'default';
21686 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]];
21687 });
21688
21689 /**
21690 * Returns true if the specified entity record is autosaving, and false otherwise.
21691 *
21692 * @param state State tree.
21693 * @param kind Entity kind.
21694 * @param name Entity name.
21695 * @param recordId Record ID.
21696 *
21697 * @return Whether the entity record is autosaving or not.
21698 */
21699 function isAutosavingEntityRecord(state, kind, name, recordId) {
21700 var _state$entities$recor;
21701 const {
21702 pending,
21703 isAutosave
21704 } = (_state$entities$recor = state.entities.records?.[kind]?.[name]?.saving?.[recordId]) !== null && _state$entities$recor !== void 0 ? _state$entities$recor : {};
21705 return Boolean(pending && isAutosave);
21706 }
21707
21708 /**
21709 * Returns true if the specified entity record is saving, and false otherwise.
21710 *
21711 * @param state State tree.
21712 * @param kind Entity kind.
21713 * @param name Entity name.
21714 * @param recordId Record ID.
21715 *
21716 * @return Whether the entity record is saving or not.
21717 */
21718 function isSavingEntityRecord(state, kind, name, recordId) {
21719 var _state$entities$recor2;
21720 return (_state$entities$recor2 = state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.pending) !== null && _state$entities$recor2 !== void 0 ? _state$entities$recor2 : false;
21721 }
21722
21723 /**
21724 * Returns true if the specified entity record is deleting, and false otherwise.
21725 *
21726 * @param state State tree.
21727 * @param kind Entity kind.
21728 * @param name Entity name.
21729 * @param recordId Record ID.
21730 *
21731 * @return Whether the entity record is deleting or not.
21732 */
21733 function isDeletingEntityRecord(state, kind, name, recordId) {
21734 var _state$entities$recor3;
21735 return (_state$entities$recor3 = state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.pending) !== null && _state$entities$recor3 !== void 0 ? _state$entities$recor3 : false;
21736 }
21737
21738 /**
21739 * Returns the specified entity record's last save error.
21740 *
21741 * @param state State tree.
21742 * @param kind Entity kind.
21743 * @param name Entity name.
21744 * @param recordId Record ID.
21745 *
21746 * @return The entity record's save error.
21747 */
21748 function getLastEntitySaveError(state, kind, name, recordId) {
21749 return state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.error;
21750 }
21751
21752 /**
21753 * Returns the specified entity record's last delete error.
21754 *
21755 * @param state State tree.
21756 * @param kind Entity kind.
21757 * @param name Entity name.
21758 * @param recordId Record ID.
21759 *
21760 * @return The entity record's save error.
21761 */
21762 function getLastEntityDeleteError(state, kind, name, recordId) {
21763 return state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.error;
21764 }
21765
21766 /**
21767 * Returns the previous edit from the current undo offset
21768 * for the entity records edits history, if any.
21769 *
21770 * @deprecated since 6.3
21771 *
21772 * @param state State tree.
21773 *
21774 * @return The edit.
21775 */
21776 function getUndoEdit(state) {
21777 external_wp_deprecated_default()("select( 'core' ).getUndoEdit()", {
21778 since: '6.3'
21779 });
21780 return undefined;
21781 }
21782
21783 /**
21784 * Returns the next edit from the current undo offset
21785 * for the entity records edits history, if any.
21786 *
21787 * @deprecated since 6.3
21788 *
21789 * @param state State tree.
21790 *
21791 * @return The edit.
21792 */
21793 function getRedoEdit(state) {
21794 external_wp_deprecated_default()("select( 'core' ).getRedoEdit()", {
21795 since: '6.3'
21796 });
21797 return undefined;
21798 }
21799
21800 /**
21801 * Returns true if there is a previous edit from the current undo offset
21802 * for the entity records edits history, and false otherwise.
21803 *
21804 * @param state State tree.
21805 *
21806 * @return Whether there is a previous edit or not.
21807 */
21808 function hasUndo(state) {
21809 return state.undoManager.hasUndo();
21810 }
21811
21812 /**
21813 * Returns true if there is a next edit from the current undo offset
21814 * for the entity records edits history, and false otherwise.
21815 *
21816 * @param state State tree.
21817 *
21818 * @return Whether there is a next edit or not.
21819 */
21820 function hasRedo(state) {
21821 return state.undoManager.hasRedo();
21822 }
21823
21824 /**
21825 * Return the current theme.
21826 *
21827 * @param state Data state.
21828 *
21829 * @return The current theme.
21830 */
21831 function getCurrentTheme(state) {
21832 if (!state.currentTheme) {
21833 return null;
21834 }
21835 return getEntityRecord(state, 'root', 'theme', state.currentTheme);
21836 }
21837
21838 /**
21839 * Return the ID of the current global styles object.
21840 *
21841 * @param state Data state.
21842 *
21843 * @return The current global styles ID.
21844 */
21845 function __experimentalGetCurrentGlobalStylesId(state) {
21846 return state.currentGlobalStylesId;
21847 }
21848
21849 /**
21850 * Return theme supports data in the index.
21851 *
21852 * @param state Data state.
21853 *
21854 * @return Index data.
21855 */
21856 function getThemeSupports(state) {
21857 var _getCurrentTheme$them;
21858 return (_getCurrentTheme$them = getCurrentTheme(state)?.theme_supports) !== null && _getCurrentTheme$them !== void 0 ? _getCurrentTheme$them : EMPTY_OBJECT;
21859 }
21860
21861 /**
21862 * Returns the embed preview for the given URL.
21863 *
21864 * @param state Data state.
21865 * @param url Embedded URL.
21866 *
21867 * @return Undefined if the preview has not been fetched, otherwise, the preview fetched from the embed preview API.
21868 */
21869 function getEmbedPreview(state, url) {
21870 return state.embedPreviews[url];
21871 }
21872
21873 /**
21874 * Determines if the returned preview is an oEmbed link fallback.
21875 *
21876 * WordPress can be configured to return a simple link to a URL if it is not embeddable.
21877 * We need to be able to determine if a URL is embeddable or not, based on what we
21878 * get back from the oEmbed preview API.
21879 *
21880 * @param state Data state.
21881 * @param url Embedded URL.
21882 *
21883 * @return Is the preview for the URL an oEmbed link fallback.
21884 */
21885 function isPreviewEmbedFallback(state, url) {
21886 const preview = state.embedPreviews[url];
21887 const oEmbedLinkCheck = '<a href="' + url + '">' + url + '</a>';
21888 if (!preview) {
21889 return false;
21890 }
21891 return preview.html === oEmbedLinkCheck;
21892 }
21893
21894 /**
21895 * Returns whether the current user can perform the given action on the given
21896 * REST resource.
21897 *
21898 * Calling this may trigger an OPTIONS request to the REST API via the
21899 * `canUser()` resolver.
21900 *
21901 * https://developer.wordpress.org/rest-api/reference/
21902 *
21903 * @param state Data state.
21904 * @param action Action to check. One of: 'create', 'read', 'update', 'delete'.
21905 * @param resource REST resource to check, e.g. 'media' or 'posts'.
21906 * @param id Optional ID of the rest resource to check.
21907 *
21908 * @return Whether or not the user can perform the action,
21909 * or `undefined` if the OPTIONS request is still being made.
21910 */
21911 function canUser(state, action, resource, id) {
21912 const key = [action, resource, id].filter(Boolean).join('/');
21913 return state.userPermissions[key];
21914 }
21915
21916 /**
21917 * Returns whether the current user can edit the given entity.
21918 *
21919 * Calling this may trigger an OPTIONS request to the REST API via the
21920 * `canUser()` resolver.
21921 *
21922 * https://developer.wordpress.org/rest-api/reference/
21923 *
21924 * @param state Data state.
21925 * @param kind Entity kind.
21926 * @param name Entity name.
21927 * @param recordId Record's id.
21928 * @return Whether or not the user can edit,
21929 * or `undefined` if the OPTIONS request is still being made.
21930 */
21931 function canUserEditEntityRecord(state, kind, name, recordId) {
21932 const entityConfig = getEntityConfig(state, kind, name);
21933 if (!entityConfig) {
21934 return false;
21935 }
21936 const resource = entityConfig.__unstable_rest_base;
21937 return canUser(state, 'update', resource, recordId);
21938 }
21939
21940 /**
21941 * Returns the latest autosaves for the post.
21942 *
21943 * May return multiple autosaves since the backend stores one autosave per
21944 * author for each post.
21945 *
21946 * @param state State tree.
21947 * @param postType The type of the parent post.
21948 * @param postId The id of the parent post.
21949 *
21950 * @return An array of autosaves for the post, or undefined if there is none.
21951 */
21952 function getAutosaves(state, postType, postId) {
21953 return state.autosaves[postId];
21954 }
21955
21956 /**
21957 * Returns the autosave for the post and author.
21958 *
21959 * @param state State tree.
21960 * @param postType The type of the parent post.
21961 * @param postId The id of the parent post.
21962 * @param authorId The id of the author.
21963 *
21964 * @return The autosave for the post and author.
21965 */
21966 function getAutosave(state, postType, postId, authorId) {
21967 if (authorId === undefined) {
21968 return;
21969 }
21970 const autosaves = state.autosaves[postId];
21971 return autosaves?.find(autosave => autosave.author === authorId);
21972 }
21973
21974 /**
21975 * Returns true if the REST request for autosaves has completed.
21976 *
21977 * @param state State tree.
21978 * @param postType The type of the parent post.
21979 * @param postId The id of the parent post.
21980 *
21981 * @return True if the REST request was completed. False otherwise.
21982 */
21983 const hasFetchedAutosaves = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, postType, postId) => {
21984 return select(STORE_NAME).hasFinishedResolution('getAutosaves', [postType, postId]);
21985 });
21986
21987 /**
21988 * Returns a new reference when edited values have changed. This is useful in
21989 * inferring where an edit has been made between states by comparison of the
21990 * return values using strict equality.
21991 *
21992 * @example
21993 *
21994 * ```
21995 * const hasEditOccurred = (
21996 * getReferenceByDistinctEdits( beforeState ) !==
21997 * getReferenceByDistinctEdits( afterState )
21998 * );
21999 * ```
22000 *
22001 * @param state Editor state.
22002 *
22003 * @return A value whose reference will change only when an edit occurs.
22004 */
22005 function getReferenceByDistinctEdits(state) {
22006 return state.editsReference;
22007 }
22008
22009 /**
22010 * Retrieve the frontend template used for a given link.
22011 *
22012 * @param state Editor state.
22013 * @param link Link.
22014 *
22015 * @return The template record.
22016 */
22017 function __experimentalGetTemplateForLink(state, link) {
22018 const records = getEntityRecords(state, 'postType', 'wp_template', {
22019 'find-template': link
22020 });
22021 if (records?.length) {
22022 return getEditedEntityRecord(state, 'postType', 'wp_template', records[0].id);
22023 }
22024 return null;
22025 }
22026
22027 /**
22028 * Retrieve the current theme's base global styles
22029 *
22030 * @param state Editor state.
22031 *
22032 * @return The Global Styles object.
22033 */
22034 function __experimentalGetCurrentThemeBaseGlobalStyles(state) {
22035 const currentTheme = getCurrentTheme(state);
22036 if (!currentTheme) {
22037 return null;
22038 }
22039 return state.themeBaseGlobalStyles[currentTheme.stylesheet];
22040 }
22041
22042 /**
22043 * Return the ID of the current global styles object.
22044 *
22045 * @param state Data state.
22046 *
22047 * @return The current global styles ID.
22048 */
22049 function __experimentalGetCurrentThemeGlobalStylesVariations(state) {
22050 const currentTheme = getCurrentTheme(state);
22051 if (!currentTheme) {
22052 return null;
22053 }
22054 return state.themeGlobalStyleVariations[currentTheme.stylesheet];
22055 }
22056
22057 /**
22058 * Retrieve the list of registered block patterns.
22059 *
22060 * @param state Data state.
22061 *
22062 * @return Block pattern list.
22063 */
22064 function getBlockPatterns(state) {
22065 return state.blockPatterns;
22066 }
22067
22068 /**
22069 * Retrieve the list of registered block pattern categories.
22070 *
22071 * @param state Data state.
22072 *
22073 * @return Block pattern category list.
22074 */
22075 function getBlockPatternCategories(state) {
22076 return state.blockPatternCategories;
22077 }
22078
22079 /**
22080 * Retrieve the registered user pattern categories.
22081 *
22082 * @param state Data state.
22083 *
22084 * @return User patterns category array.
22085 */
22086
22087 function getUserPatternCategories(state) {
22088 return state.userPatternCategories;
22089 }
22090
22091 /**
22092 * Returns the revisions of the current global styles theme.
22093 *
22094 * @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.
22095 *
22096 * @param state Data state.
22097 *
22098 * @return The current global styles.
22099 */
22100 function getCurrentThemeGlobalStylesRevisions(state) {
22101 external_wp_deprecated_default()("select( 'core' ).getCurrentThemeGlobalStylesRevisions()", {
22102 since: '6.5.0',
22103 alternative: "select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )"
22104 });
22105 const currentGlobalStylesId = __experimentalGetCurrentGlobalStylesId(state);
22106 if (!currentGlobalStylesId) {
22107 return null;
22108 }
22109 return state.themeGlobalStyleRevisions[currentGlobalStylesId];
22110 }
22111
22112 /**
22113 * Returns the default template use to render a given query.
22114 *
22115 * @param state Data state.
22116 * @param query Query.
22117 *
22118 * @return The default template id for the given query.
22119 */
22120 function getDefaultTemplateId(state, query) {
22121 return state.defaultTemplates[JSON.stringify(query)];
22122 }
22123
22124 /**
22125 * Returns an entity's revisions.
22126 *
22127 * @param state State tree
22128 * @param kind Entity kind.
22129 * @param name Entity name.
22130 * @param recordKey The key of the entity record whose revisions you want to fetch.
22131 * @param query Optional query. If requesting specific
22132 * 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]".
22133 *
22134 * @return Record.
22135 */
22136 const getRevisions = (state, kind, name, recordKey, query) => {
22137 const queriedStateRevisions = state.entities.records?.[kind]?.[name]?.revisions?.[recordKey];
22138 if (!queriedStateRevisions) {
22139 return null;
22140 }
22141 return getQueriedItems(queriedStateRevisions, query);
22142 };
22143
22144 /**
22145 * Returns a single, specific revision of a parent entity.
22146 *
22147 * @param state State tree
22148 * @param kind Entity kind.
22149 * @param name Entity name.
22150 * @param recordKey The key of the entity record whose revisions you want to fetch.
22151 * @param revisionKey The revision's key.
22152 * @param query Optional query. If requesting specific
22153 * 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]".
22154 *
22155 * @return Record.
22156 */
22157 const getRevision = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, recordKey, revisionKey, query) => {
22158 var _query$context5;
22159 const queriedState = state.entities.records?.[kind]?.[name]?.revisions?.[recordKey];
22160 if (!queriedState) {
22161 return undefined;
22162 }
22163 const context = (_query$context5 = query?.context) !== null && _query$context5 !== void 0 ? _query$context5 : 'default';
22164 if (query === undefined) {
22165 // If expecting a complete item, validate that completeness.
22166 if (!queriedState.itemIsComplete[context]?.[revisionKey]) {
22167 return undefined;
22168 }
22169 return queriedState.items[context][revisionKey];
22170 }
22171 const item = queriedState.items[context]?.[revisionKey];
22172 if (item && query._fields) {
22173 var _getNormalizedCommaSe2;
22174 const filteredItem = {};
22175 const fields = (_getNormalizedCommaSe2 = get_normalized_comma_separable(query._fields)) !== null && _getNormalizedCommaSe2 !== void 0 ? _getNormalizedCommaSe2 : [];
22176 for (let f = 0; f < fields.length; f++) {
22177 const field = fields[f].split('.');
22178 let value = item;
22179 field.forEach(fieldName => {
22180 value = value?.[fieldName];
22181 });
22182 setNestedValue(filteredItem, field, value);
22183 }
22184 return filteredItem;
22185 }
22186 return item;
22187 }, (state, kind, name, recordKey, revisionKey, query) => {
22188 var _query$context6;
22189 const context = (_query$context6 = query?.context) !== null && _query$context6 !== void 0 ? _query$context6 : 'default';
22190 return [state.entities.records?.[kind]?.[name]?.revisions?.[recordKey]?.items?.[context]?.[revisionKey], state.entities.records?.[kind]?.[name]?.revisions?.[recordKey]?.itemIsComplete?.[context]?.[revisionKey]];
22191 });
22192
22193 ;// CONCATENATED MODULE: ./packages/core-data/build-module/private-selectors.js
22194 /**
22195 * WordPress dependencies
22196 */
22197
22198
22199 /**
22200 * Internal dependencies
22201 */
22202
22203
22204 /**
22205 * Returns the previous edit from the current undo offset
22206 * for the entity records edits history, if any.
22207 *
22208 * @param state State tree.
22209 *
22210 * @return The undo manager.
22211 */
22212 function getUndoManager(state) {
22213 return state.undoManager;
22214 }
22215
22216 /**
22217 * Retrieve the fallback Navigation.
22218 *
22219 * @param state Data state.
22220 * @return The ID for the fallback Navigation post.
22221 */
22222 function getNavigationFallbackId(state) {
22223 return state.navigationFallbackId;
22224 }
22225 const getBlockPatternsForPostType = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (0,external_wp_data_namespaceObject.createSelector)((state, postType) => select(STORE_NAME).getBlockPatterns().filter(({
22226 postTypes
22227 }) => !postTypes || Array.isArray(postTypes) && postTypes.includes(postType)), () => [select(STORE_NAME).getBlockPatterns()]));
22228
22229 ;// CONCATENATED MODULE: ./node_modules/camel-case/dist.es2015/index.js
22230
22231
22232 function camelCaseTransform(input, index) {
22233 if (index === 0)
22234 return input.toLowerCase();
22235 return pascalCaseTransform(input, index);
22236 }
22237 function camelCaseTransformMerge(input, index) {
22238 if (index === 0)
22239 return input.toLowerCase();
22240 return pascalCaseTransformMerge(input);
22241 }
22242 function camelCase(input, options) {
22243 if (options === void 0) { options = {}; }
22244 return pascalCase(input, __assign({ transform: camelCaseTransform }, options));
22245 }
22246
22247 ;// CONCATENATED MODULE: external ["wp","htmlEntities"]
22248 const external_wp_htmlEntities_namespaceObject = window["wp"]["htmlEntities"];
22249 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/forward-resolver.js
22250 /**
22251 * Higher-order function which forward the resolution to another resolver with the same arguments.
22252 *
22253 * @param {string} resolverName forwarded resolver.
22254 *
22255 * @return {Function} Enhanced resolver.
22256 */
22257 const forwardResolver = resolverName => (...args) => async ({
22258 resolveSelect
22259 }) => {
22260 await resolveSelect[resolverName](...args);
22261 };
22262 /* harmony default export */ const forward_resolver = (forwardResolver);
22263
22264 ;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/__experimental-fetch-link-suggestions.js
22265 /**
22266 * WordPress dependencies
22267 */
22268
22269
22270
22271
22272
22273 /**
22274 * Filters the search by type
22275 *
22276 * @typedef { 'attachment' | 'post' | 'term' | 'post-format' } WPLinkSearchType
22277 */
22278
22279 /**
22280 * A link with an id may be of kind post-type or taxonomy
22281 *
22282 * @typedef { 'post-type' | 'taxonomy' } WPKind
22283 */
22284
22285 /**
22286 * @typedef WPLinkSearchOptions
22287 *
22288 * @property {boolean} [isInitialSuggestions] Displays initial search suggestions, when true.
22289 * @property {WPLinkSearchType} [type] Filters by search type.
22290 * @property {string} [subtype] Slug of the post-type or taxonomy.
22291 * @property {number} [page] Which page of results to return.
22292 * @property {number} [perPage] Search results per page.
22293 */
22294
22295 /**
22296 * @typedef WPLinkSearchResult
22297 *
22298 * @property {number} id Post or term id.
22299 * @property {string} url Link url.
22300 * @property {string} title Title of the link.
22301 * @property {string} type The taxonomy or post type slug or type URL.
22302 * @property {WPKind} [kind] Link kind of post-type or taxonomy
22303 */
22304
22305 /**
22306 * @typedef WPLinkSearchResultAugments
22307 *
22308 * @property {{kind: WPKind}} [meta] Contains kind information.
22309 * @property {WPKind} [subtype] Optional subtype if it exists.
22310 */
22311
22312 /**
22313 * @typedef {WPLinkSearchResult & WPLinkSearchResultAugments} WPLinkSearchResultAugmented
22314 */
22315
22316 /**
22317 * @typedef WPEditorSettings
22318 *
22319 * @property {boolean} [ disablePostFormats ] Disables post formats, when true.
22320 */
22321
22322 /**
22323 * Fetches link suggestions from the API.
22324 *
22325 * @async
22326 * @param {string} search
22327 * @param {WPLinkSearchOptions} [searchOptions]
22328 * @param {WPEditorSettings} [settings]
22329 *
22330 * @example
22331 * ```js
22332 * import { __experimentalFetchLinkSuggestions as fetchLinkSuggestions } from '@wordpress/core-data';
22333 *
22334 * //...
22335 *
22336 * export function initialize( id, settings ) {
22337 *
22338 * settings.__experimentalFetchLinkSuggestions = (
22339 * search,
22340 * searchOptions
22341 * ) => fetchLinkSuggestions( search, searchOptions, settings );
22342 * ```
22343 * @return {Promise< WPLinkSearchResult[] >} List of search suggestions
22344 */
22345 const fetchLinkSuggestions = async (search, searchOptions = {}, settings = {}) => {
22346 const {
22347 isInitialSuggestions = false,
22348 initialSuggestionsSearchOptions = undefined
22349 } = searchOptions;
22350 const {
22351 disablePostFormats = false
22352 } = settings;
22353 let {
22354 type = undefined,
22355 subtype = undefined,
22356 page = undefined,
22357 perPage = isInitialSuggestions ? 3 : 20
22358 } = searchOptions;
22359
22360 /** @type {Promise<WPLinkSearchResult>[]} */
22361 const queries = [];
22362 if (isInitialSuggestions && initialSuggestionsSearchOptions) {
22363 type = initialSuggestionsSearchOptions.type || type;
22364 subtype = initialSuggestionsSearchOptions.subtype || subtype;
22365 page = initialSuggestionsSearchOptions.page || page;
22366 perPage = initialSuggestionsSearchOptions.perPage || perPage;
22367 }
22368 if (!type || type === 'post') {
22369 queries.push(external_wp_apiFetch_default()({
22370 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
22371 search,
22372 page,
22373 per_page: perPage,
22374 type: 'post',
22375 subtype
22376 })
22377 }).then(results => {
22378 return results.map(result => {
22379 return {
22380 ...result,
22381 meta: {
22382 kind: 'post-type',
22383 subtype
22384 }
22385 };
22386 });
22387 }).catch(() => []) // Fail by returning no results.
22388 );
22389 }
22390 if (!type || type === 'term') {
22391 queries.push(external_wp_apiFetch_default()({
22392 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
22393 search,
22394 page,
22395 per_page: perPage,
22396 type: 'term',
22397 subtype
22398 })
22399 }).then(results => {
22400 return results.map(result => {
22401 return {
22402 ...result,
22403 meta: {
22404 kind: 'taxonomy',
22405 subtype
22406 }
22407 };
22408 });
22409 }).catch(() => []) // Fail by returning no results.
22410 );
22411 }
22412 if (!disablePostFormats && (!type || type === 'post-format')) {
22413 queries.push(external_wp_apiFetch_default()({
22414 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
22415 search,
22416 page,
22417 per_page: perPage,
22418 type: 'post-format',
22419 subtype
22420 })
22421 }).then(results => {
22422 return results.map(result => {
22423 return {
22424 ...result,
22425 meta: {
22426 kind: 'taxonomy',
22427 subtype
22428 }
22429 };
22430 });
22431 }).catch(() => []) // Fail by returning no results.
22432 );
22433 }
22434 if (!type || type === 'attachment') {
22435 queries.push(external_wp_apiFetch_default()({
22436 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/media', {
22437 search,
22438 page,
22439 per_page: perPage
22440 })
22441 }).then(results => {
22442 return results.map(result => {
22443 return {
22444 ...result,
22445 meta: {
22446 kind: 'media'
22447 }
22448 };
22449 });
22450 }).catch(() => []) // Fail by returning no results.
22451 );
22452 }
22453 return Promise.all(queries).then(results => {
22454 return results.reduce(( /** @type {WPLinkSearchResult[]} */accumulator, current) => accumulator.concat(current),
22455 // Flatten list.
22456 []).filter(
22457 /**
22458 * @param {{ id: number }} result
22459 */
22460 result => {
22461 return !!result.id;
22462 }).slice(0, perPage).map(( /** @type {WPLinkSearchResultAugmented} */result) => {
22463 const isMedia = result.type === 'attachment';
22464 return {
22465 id: result.id,
22466 // @ts-ignore fix when we make this a TS file
22467 url: isMedia ? result.source_url : result.url,
22468 title: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(isMedia ?
22469 // @ts-ignore fix when we make this a TS file
22470 result.title.rendered : result.title || '') || (0,external_wp_i18n_namespaceObject.__)('(no title)'),
22471 type: result.subtype || result.type,
22472 kind: result?.meta?.kind
22473 };
22474 });
22475 });
22476 };
22477 /* harmony default export */ const _experimental_fetch_link_suggestions = (fetchLinkSuggestions);
22478
22479 ;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/__experimental-fetch-url-data.js
22480 /**
22481 * WordPress dependencies
22482 */
22483
22484
22485
22486 /**
22487 * A simple in-memory cache for requests.
22488 * This avoids repeat HTTP requests which may be beneficial
22489 * for those wishing to preserve low-bandwidth.
22490 */
22491 const CACHE = new Map();
22492
22493 /**
22494 * @typedef WPRemoteUrlData
22495 *
22496 * @property {string} title contents of the remote URL's `<title>` tag.
22497 */
22498
22499 /**
22500 * Fetches data about a remote URL.
22501 * eg: <title> tag, favicon...etc.
22502 *
22503 * @async
22504 * @param {string} url the URL to request details from.
22505 * @param {Object?} options any options to pass to the underlying fetch.
22506 * @example
22507 * ```js
22508 * import { __experimentalFetchUrlData as fetchUrlData } from '@wordpress/core-data';
22509 *
22510 * //...
22511 *
22512 * export function initialize( id, settings ) {
22513 *
22514 * settings.__experimentalFetchUrlData = (
22515 * url
22516 * ) => fetchUrlData( url );
22517 * ```
22518 * @return {Promise< WPRemoteUrlData[] >} Remote URL data.
22519 */
22520 const fetchUrlData = async (url, options = {}) => {
22521 const endpoint = '/wp-block-editor/v1/url-details';
22522 const args = {
22523 url: (0,external_wp_url_namespaceObject.prependHTTP)(url)
22524 };
22525 if (!(0,external_wp_url_namespaceObject.isURL)(url)) {
22526 return Promise.reject(`${url} is not a valid URL.`);
22527 }
22528
22529 // Test for "http" based URL as it is possible for valid
22530 // yet unusable URLs such as `tel:123456` to be passed.
22531 const protocol = (0,external_wp_url_namespaceObject.getProtocol)(url);
22532 if (!protocol || !(0,external_wp_url_namespaceObject.isValidProtocol)(protocol) || !protocol.startsWith('http') || !/^https?:\/\/[^\/\s]/i.test(url)) {
22533 return Promise.reject(`${url} does not have a valid protocol. URLs must be "http" based`);
22534 }
22535 if (CACHE.has(url)) {
22536 return CACHE.get(url);
22537 }
22538 return external_wp_apiFetch_default()({
22539 path: (0,external_wp_url_namespaceObject.addQueryArgs)(endpoint, args),
22540 ...options
22541 }).then(res => {
22542 CACHE.set(url, res);
22543 return res;
22544 });
22545 };
22546 /* harmony default export */ const _experimental_fetch_url_data = (fetchUrlData);
22547
22548 ;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/index.js
22549 /**
22550 * External dependencies
22551 */
22552
22553
22554 /**
22555 * WordPress dependencies
22556 */
22557
22558
22559
22560 async function fetchBlockPatterns() {
22561 const restPatterns = await external_wp_apiFetch_default()({
22562 path: '/wp/v2/block-patterns/patterns'
22563 });
22564 if (!restPatterns) {
22565 return [];
22566 }
22567 return restPatterns.map(pattern => Object.fromEntries(Object.entries(pattern).map(([key, value]) => [camelCase(key), value])));
22568 }
22569
22570 ;// CONCATENATED MODULE: ./packages/core-data/build-module/resolvers.js
22571 /**
22572 * External dependencies
22573 */
22574
22575
22576 /**
22577 * WordPress dependencies
22578 */
22579
22580
22581
22582
22583 /**
22584 * Internal dependencies
22585 */
22586
22587
22588
22589
22590
22591
22592 /**
22593 * Requests authors from the REST API.
22594 *
22595 * @param {Object|undefined} query Optional object of query parameters to
22596 * include with request.
22597 */
22598 const resolvers_getAuthors = query => async ({
22599 dispatch
22600 }) => {
22601 const path = (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/users/?who=authors&per_page=100', query);
22602 const users = await external_wp_apiFetch_default()({
22603 path
22604 });
22605 dispatch.receiveUserQuery(path, users);
22606 };
22607
22608 /**
22609 * Requests the current user from the REST API.
22610 */
22611 const resolvers_getCurrentUser = () => async ({
22612 dispatch
22613 }) => {
22614 const currentUser = await external_wp_apiFetch_default()({
22615 path: '/wp/v2/users/me'
22616 });
22617 dispatch.receiveCurrentUser(currentUser);
22618 };
22619
22620 /**
22621 * Requests an entity's record from the REST API.
22622 *
22623 * @param {string} kind Entity kind.
22624 * @param {string} name Entity name.
22625 * @param {number|string} key Record's key
22626 * @param {Object|undefined} query Optional object of query parameters to
22627 * include with request. If requesting specific
22628 * fields, fields must always include the ID.
22629 */
22630 const resolvers_getEntityRecord = (kind, name, key = '', query) => async ({
22631 select,
22632 dispatch
22633 }) => {
22634 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
22635 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
22636 if (!entityConfig || entityConfig?.__experimentalNoFetch) {
22637 return;
22638 }
22639 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, key], {
22640 exclusive: false
22641 });
22642 try {
22643 // Entity supports configs,
22644 // use the sync algorithm instead of the old fetch behavior.
22645 if (window.__experimentalEnableSync && entityConfig.syncConfig && !query) {
22646 if (true) {
22647 const objectId = entityConfig.getSyncObjectId(key);
22648
22649 // Loads the persisted document.
22650 await getSyncProvider().bootstrap(entityConfig.syncObjectType, objectId, record => {
22651 dispatch.receiveEntityRecords(kind, name, record, query);
22652 });
22653
22654 // Boostraps the edited document as well (and load from peers).
22655 await getSyncProvider().bootstrap(entityConfig.syncObjectType + '--edit', objectId, record => {
22656 dispatch({
22657 type: 'EDIT_ENTITY_RECORD',
22658 kind,
22659 name,
22660 recordId: key,
22661 edits: record,
22662 meta: {
22663 undo: undefined
22664 }
22665 });
22666 });
22667 }
22668 } else {
22669 if (query !== undefined && query._fields) {
22670 // If requesting specific fields, items and query association to said
22671 // records are stored by ID reference. Thus, fields must always include
22672 // the ID.
22673 query = {
22674 ...query,
22675 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.key || DEFAULT_ENTITY_KEY])].join()
22676 };
22677 }
22678
22679 // Disable reason: While true that an early return could leave `path`
22680 // unused, it's important that path is derived using the query prior to
22681 // additional query modifications in the condition below, since those
22682 // modifications are relevant to how the data is tracked in state, and not
22683 // for how the request is made to the REST API.
22684
22685 // eslint-disable-next-line @wordpress/no-unused-vars-before-return
22686 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.baseURL + (key ? '/' + key : ''), {
22687 ...entityConfig.baseURLParams,
22688 ...query
22689 });
22690 if (query !== undefined) {
22691 query = {
22692 ...query,
22693 include: [key]
22694 };
22695
22696 // The resolution cache won't consider query as reusable based on the
22697 // fields, so it's tested here, prior to initiating the REST request,
22698 // and without causing `getEntityRecords` resolution to occur.
22699 const hasRecords = select.hasEntityRecords(kind, name, query);
22700 if (hasRecords) {
22701 return;
22702 }
22703 }
22704 const record = await external_wp_apiFetch_default()({
22705 path
22706 });
22707 dispatch.receiveEntityRecords(kind, name, record, query);
22708 }
22709 } finally {
22710 dispatch.__unstableReleaseStoreLock(lock);
22711 }
22712 };
22713
22714 /**
22715 * Requests an entity's record from the REST API.
22716 */
22717 const resolvers_getRawEntityRecord = forward_resolver('getEntityRecord');
22718
22719 /**
22720 * Requests an entity's record from the REST API.
22721 */
22722 const resolvers_getEditedEntityRecord = forward_resolver('getEntityRecord');
22723
22724 /**
22725 * Requests the entity's records from the REST API.
22726 *
22727 * @param {string} kind Entity kind.
22728 * @param {string} name Entity name.
22729 * @param {Object?} query Query Object. If requesting specific fields, fields
22730 * must always include the ID.
22731 */
22732 const resolvers_getEntityRecords = (kind, name, query = {}) => async ({
22733 dispatch,
22734 registry
22735 }) => {
22736 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
22737 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
22738 if (!entityConfig || entityConfig?.__experimentalNoFetch) {
22739 return;
22740 }
22741 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name], {
22742 exclusive: false
22743 });
22744 try {
22745 if (query._fields) {
22746 // If requesting specific fields, items and query association to said
22747 // records are stored by ID reference. Thus, fields must always include
22748 // the ID.
22749 query = {
22750 ...query,
22751 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.key || DEFAULT_ENTITY_KEY])].join()
22752 };
22753 }
22754 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.baseURL, {
22755 ...entityConfig.baseURLParams,
22756 ...query
22757 });
22758 let records, meta;
22759 if (entityConfig.supportsPagination && query.per_page !== -1) {
22760 const response = await external_wp_apiFetch_default()({
22761 path,
22762 parse: false
22763 });
22764 records = Object.values(await response.json());
22765 meta = {
22766 totalItems: parseInt(response.headers.get('X-WP-Total')),
22767 totalPages: parseInt(response.headers.get('X-WP-TotalPages'))
22768 };
22769 } else {
22770 records = Object.values(await external_wp_apiFetch_default()({
22771 path
22772 }));
22773 }
22774
22775 // If we request fields but the result doesn't contain the fields,
22776 // explicitly set these fields as "undefined"
22777 // that way we consider the query "fulfilled".
22778 if (query._fields) {
22779 records = records.map(record => {
22780 query._fields.split(',').forEach(field => {
22781 if (!record.hasOwnProperty(field)) {
22782 record[field] = undefined;
22783 }
22784 });
22785 return record;
22786 });
22787 }
22788 registry.batch(() => {
22789 dispatch.receiveEntityRecords(kind, name, records, query, false, undefined, meta);
22790
22791 // When requesting all fields, the list of results can be used to
22792 // resolve the `getEntityRecord` selector in addition to `getEntityRecords`.
22793 // See https://github.com/WordPress/gutenberg/pull/26575
22794 if (!query?._fields && !query.context) {
22795 const key = entityConfig.key || DEFAULT_ENTITY_KEY;
22796 const resolutionsArgs = records.filter(record => record[key]).map(record => [kind, name, record[key]]);
22797 dispatch({
22798 type: 'START_RESOLUTIONS',
22799 selectorName: 'getEntityRecord',
22800 args: resolutionsArgs
22801 });
22802 dispatch({
22803 type: 'FINISH_RESOLUTIONS',
22804 selectorName: 'getEntityRecord',
22805 args: resolutionsArgs
22806 });
22807 }
22808 dispatch.__unstableReleaseStoreLock(lock);
22809 });
22810 } catch (e) {
22811 dispatch.__unstableReleaseStoreLock(lock);
22812 }
22813 };
22814 resolvers_getEntityRecords.shouldInvalidate = (action, kind, name) => {
22815 return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && kind === action.kind && name === action.name;
22816 };
22817
22818 /**
22819 * Requests the current theme.
22820 */
22821 const resolvers_getCurrentTheme = () => async ({
22822 dispatch,
22823 resolveSelect
22824 }) => {
22825 const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', {
22826 status: 'active'
22827 });
22828 dispatch.receiveCurrentTheme(activeThemes[0]);
22829 };
22830
22831 /**
22832 * Requests theme supports data from the index.
22833 */
22834 const resolvers_getThemeSupports = forward_resolver('getCurrentTheme');
22835
22836 /**
22837 * Requests a preview from the Embed API.
22838 *
22839 * @param {string} url URL to get the preview for.
22840 */
22841 const resolvers_getEmbedPreview = url => async ({
22842 dispatch
22843 }) => {
22844 try {
22845 const embedProxyResponse = await external_wp_apiFetch_default()({
22846 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/oembed/1.0/proxy', {
22847 url
22848 })
22849 });
22850 dispatch.receiveEmbedPreview(url, embedProxyResponse);
22851 } catch (error) {
22852 // Embed API 404s if the URL cannot be embedded, so we have to catch the error from the apiRequest here.
22853 dispatch.receiveEmbedPreview(url, false);
22854 }
22855 };
22856
22857 /**
22858 * Checks whether the current user can perform the given action on the given
22859 * REST resource.
22860 *
22861 * @param {string} requestedAction Action to check. One of: 'create', 'read', 'update',
22862 * 'delete'.
22863 * @param {string} resource REST resource to check, e.g. 'media' or 'posts'.
22864 * @param {?string} id ID of the rest resource to check.
22865 */
22866 const resolvers_canUser = (requestedAction, resource, id) => async ({
22867 dispatch,
22868 registry
22869 }) => {
22870 const {
22871 hasStartedResolution
22872 } = registry.select(STORE_NAME);
22873 const resourcePath = id ? `${resource}/${id}` : resource;
22874 const retrievedActions = ['create', 'read', 'update', 'delete'];
22875 if (!retrievedActions.includes(requestedAction)) {
22876 throw new Error(`'${requestedAction}' is not a valid action.`);
22877 }
22878
22879 // Prevent resolving the same resource twice.
22880 for (const relatedAction of retrievedActions) {
22881 if (relatedAction === requestedAction) {
22882 continue;
22883 }
22884 const isAlreadyResolving = hasStartedResolution('canUser', [relatedAction, resource, id]);
22885 if (isAlreadyResolving) {
22886 return;
22887 }
22888 }
22889 let response;
22890 try {
22891 response = await external_wp_apiFetch_default()({
22892 path: `/wp/v2/${resourcePath}`,
22893 method: 'OPTIONS',
22894 parse: false
22895 });
22896 } catch (error) {
22897 // Do nothing if our OPTIONS request comes back with an API error (4xx or
22898 // 5xx). The previously determined isAllowed value will remain in the store.
22899 return;
22900 }
22901
22902 // Optional chaining operator is used here because the API requests don't
22903 // return the expected result in the native version. Instead, API requests
22904 // only return the result, without including response properties like the headers.
22905 const allowHeader = response.headers?.get('allow');
22906 const allowedMethods = allowHeader?.allow || allowHeader || '';
22907 const permissions = {};
22908 const methods = {
22909 create: 'POST',
22910 read: 'GET',
22911 update: 'PUT',
22912 delete: 'DELETE'
22913 };
22914 for (const [actionName, methodName] of Object.entries(methods)) {
22915 permissions[actionName] = allowedMethods.includes(methodName);
22916 }
22917 for (const action of retrievedActions) {
22918 dispatch.receiveUserPermission(`${action}/${resourcePath}`, permissions[action]);
22919 }
22920 };
22921
22922 /**
22923 * Checks whether the current user can perform the given action on the given
22924 * REST resource.
22925 *
22926 * @param {string} kind Entity kind.
22927 * @param {string} name Entity name.
22928 * @param {string} recordId Record's id.
22929 */
22930 const resolvers_canUserEditEntityRecord = (kind, name, recordId) => async ({
22931 dispatch
22932 }) => {
22933 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
22934 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
22935 if (!entityConfig) {
22936 return;
22937 }
22938 const resource = entityConfig.__unstable_rest_base;
22939 await dispatch(resolvers_canUser('update', resource, recordId));
22940 };
22941
22942 /**
22943 * Request autosave data from the REST API.
22944 *
22945 * @param {string} postType The type of the parent post.
22946 * @param {number} postId The id of the parent post.
22947 */
22948 const resolvers_getAutosaves = (postType, postId) => async ({
22949 dispatch,
22950 resolveSelect
22951 }) => {
22952 const {
22953 rest_base: restBase,
22954 rest_namespace: restNamespace = 'wp/v2'
22955 } = await resolveSelect.getPostType(postType);
22956 const autosaves = await external_wp_apiFetch_default()({
22957 path: `/${restNamespace}/${restBase}/${postId}/autosaves?context=edit`
22958 });
22959 if (autosaves && autosaves.length) {
22960 dispatch.receiveAutosaves(postId, autosaves);
22961 }
22962 };
22963
22964 /**
22965 * Request autosave data from the REST API.
22966 *
22967 * This resolver exists to ensure the underlying autosaves are fetched via
22968 * `getAutosaves` when a call to the `getAutosave` selector is made.
22969 *
22970 * @param {string} postType The type of the parent post.
22971 * @param {number} postId The id of the parent post.
22972 */
22973 const resolvers_getAutosave = (postType, postId) => async ({
22974 resolveSelect
22975 }) => {
22976 await resolveSelect.getAutosaves(postType, postId);
22977 };
22978
22979 /**
22980 * Retrieve the frontend template used for a given link.
22981 *
22982 * @param {string} link Link.
22983 */
22984 const resolvers_experimentalGetTemplateForLink = link => async ({
22985 dispatch,
22986 resolveSelect
22987 }) => {
22988 let template;
22989 try {
22990 // This is NOT calling a REST endpoint but rather ends up with a response from
22991 // an Ajax function which has a different shape from a WP_REST_Response.
22992 template = await external_wp_apiFetch_default()({
22993 url: (0,external_wp_url_namespaceObject.addQueryArgs)(link, {
22994 '_wp-find-template': true
22995 })
22996 }).then(({
22997 data
22998 }) => data);
22999 } catch (e) {
23000 // For non-FSE themes, it is possible that this request returns an error.
23001 }
23002 if (!template) {
23003 return;
23004 }
23005 const record = await resolveSelect.getEntityRecord('postType', 'wp_template', template.id);
23006 if (record) {
23007 dispatch.receiveEntityRecords('postType', 'wp_template', [record], {
23008 'find-template': link
23009 });
23010 }
23011 };
23012 resolvers_experimentalGetTemplateForLink.shouldInvalidate = action => {
23013 return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && action.kind === 'postType' && action.name === 'wp_template';
23014 };
23015 const resolvers_experimentalGetCurrentGlobalStylesId = () => async ({
23016 dispatch,
23017 resolveSelect
23018 }) => {
23019 const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', {
23020 status: 'active'
23021 });
23022 const globalStylesURL = activeThemes?.[0]?._links?.['wp:user-global-styles']?.[0]?.href;
23023 if (globalStylesURL) {
23024 const globalStylesObject = await external_wp_apiFetch_default()({
23025 url: globalStylesURL
23026 });
23027 dispatch.__experimentalReceiveCurrentGlobalStylesId(globalStylesObject.id);
23028 }
23029 };
23030 const resolvers_experimentalGetCurrentThemeBaseGlobalStyles = () => async ({
23031 resolveSelect,
23032 dispatch
23033 }) => {
23034 const currentTheme = await resolveSelect.getCurrentTheme();
23035 const themeGlobalStyles = await external_wp_apiFetch_default()({
23036 path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}`
23037 });
23038 dispatch.__experimentalReceiveThemeBaseGlobalStyles(currentTheme.stylesheet, themeGlobalStyles);
23039 };
23040 const resolvers_experimentalGetCurrentThemeGlobalStylesVariations = () => async ({
23041 resolveSelect,
23042 dispatch
23043 }) => {
23044 const currentTheme = await resolveSelect.getCurrentTheme();
23045 const variations = await external_wp_apiFetch_default()({
23046 path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}/variations`
23047 });
23048 dispatch.__experimentalReceiveThemeGlobalStyleVariations(currentTheme.stylesheet, variations);
23049 };
23050
23051 /**
23052 * Fetches and returns the revisions of the current global styles theme.
23053 */
23054 const resolvers_getCurrentThemeGlobalStylesRevisions = () => async ({
23055 resolveSelect,
23056 dispatch
23057 }) => {
23058 const globalStylesId = await resolveSelect.__experimentalGetCurrentGlobalStylesId();
23059 const record = globalStylesId ? await resolveSelect.getEntityRecord('root', 'globalStyles', globalStylesId) : undefined;
23060 const revisionsURL = record?._links?.['version-history']?.[0]?.href;
23061 if (revisionsURL) {
23062 const resetRevisions = await external_wp_apiFetch_default()({
23063 url: revisionsURL
23064 });
23065 const revisions = resetRevisions?.map(revision => Object.fromEntries(Object.entries(revision).map(([key, value]) => [camelCase(key), value])));
23066 dispatch.receiveThemeGlobalStyleRevisions(globalStylesId, revisions);
23067 }
23068 };
23069 resolvers_getCurrentThemeGlobalStylesRevisions.shouldInvalidate = action => {
23070 return action.type === 'SAVE_ENTITY_RECORD_FINISH' && action.kind === 'root' && !action.error && action.name === 'globalStyles';
23071 };
23072 const resolvers_getBlockPatterns = () => async ({
23073 dispatch
23074 }) => {
23075 const patterns = await fetchBlockPatterns();
23076 dispatch({
23077 type: 'RECEIVE_BLOCK_PATTERNS',
23078 patterns
23079 });
23080 };
23081 const resolvers_getBlockPatternCategories = () => async ({
23082 dispatch
23083 }) => {
23084 const categories = await external_wp_apiFetch_default()({
23085 path: '/wp/v2/block-patterns/categories'
23086 });
23087 dispatch({
23088 type: 'RECEIVE_BLOCK_PATTERN_CATEGORIES',
23089 categories
23090 });
23091 };
23092 const resolvers_getUserPatternCategories = () => async ({
23093 dispatch,
23094 resolveSelect
23095 }) => {
23096 const patternCategories = await resolveSelect.getEntityRecords('taxonomy', 'wp_pattern_category', {
23097 per_page: -1,
23098 _fields: 'id,name,description,slug',
23099 context: 'view'
23100 });
23101 const mappedPatternCategories = patternCategories?.map(userCategory => ({
23102 ...userCategory,
23103 label: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(userCategory.name),
23104 name: userCategory.slug
23105 })) || [];
23106 dispatch({
23107 type: 'RECEIVE_USER_PATTERN_CATEGORIES',
23108 patternCategories: mappedPatternCategories
23109 });
23110 };
23111 const resolvers_getNavigationFallbackId = () => async ({
23112 dispatch,
23113 select
23114 }) => {
23115 const fallback = await external_wp_apiFetch_default()({
23116 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp-block-editor/v1/navigation-fallback', {
23117 _embed: true
23118 })
23119 });
23120 const record = fallback?._embedded?.self;
23121 dispatch.receiveNavigationFallbackId(fallback?.id);
23122 if (record) {
23123 // If the fallback is already in the store, don't invalidate navigation queries.
23124 // Otherwise, invalidate the cache for the scenario where there were no Navigation
23125 // posts in the state and the fallback created one.
23126 const existingFallbackEntityRecord = select.getEntityRecord('postType', 'wp_navigation', fallback.id);
23127 const invalidateNavigationQueries = !existingFallbackEntityRecord;
23128 dispatch.receiveEntityRecords('postType', 'wp_navigation', record, undefined, invalidateNavigationQueries);
23129
23130 // Resolve to avoid further network requests.
23131 dispatch.finishResolution('getEntityRecord', ['postType', 'wp_navigation', fallback.id]);
23132 }
23133 };
23134 const resolvers_getDefaultTemplateId = query => async ({
23135 dispatch
23136 }) => {
23137 const template = await external_wp_apiFetch_default()({
23138 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/templates/lookup', query)
23139 });
23140 // Endpoint may return an empty object if no template is found.
23141 if (template?.id) {
23142 dispatch.receiveDefaultTemplateId(query, template.id);
23143 }
23144 };
23145
23146 /**
23147 * Requests an entity's revisions from the REST API.
23148 *
23149 * @param {string} kind Entity kind.
23150 * @param {string} name Entity name.
23151 * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
23152 * @param {Object|undefined} query Optional object of query parameters to
23153 * include with request. If requesting specific
23154 * fields, fields must always include the ID.
23155 */
23156 const resolvers_getRevisions = (kind, name, recordKey, query = {}) => async ({
23157 dispatch
23158 }) => {
23159 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
23160 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
23161 if (!entityConfig || entityConfig?.__experimentalNoFetch) {
23162 return;
23163 }
23164 if (query._fields) {
23165 // If requesting specific fields, items and query association to said
23166 // records are stored by ID reference. Thus, fields must always include
23167 // the ID.
23168 query = {
23169 ...query,
23170 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.revisionKey || DEFAULT_ENTITY_KEY])].join()
23171 };
23172 }
23173 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.getRevisionsUrl(recordKey), query);
23174 let records, response;
23175 const meta = {};
23176 const isPaginated = entityConfig.supportsPagination && query.per_page !== -1;
23177 try {
23178 response = await external_wp_apiFetch_default()({
23179 path,
23180 parse: !isPaginated
23181 });
23182 } catch (error) {
23183 // Do nothing if our request comes back with an API error.
23184 return;
23185 }
23186 if (response) {
23187 if (isPaginated) {
23188 records = Object.values(await response.json());
23189 meta.totalItems = parseInt(response.headers.get('X-WP-Total'));
23190 } else {
23191 records = Object.values(response);
23192 }
23193
23194 // If we request fields but the result doesn't contain the fields,
23195 // explicitly set these fields as "undefined"
23196 // that way we consider the query "fulfilled".
23197 if (query._fields) {
23198 records = records.map(record => {
23199 query._fields.split(',').forEach(field => {
23200 if (!record.hasOwnProperty(field)) {
23201 record[field] = undefined;
23202 }
23203 });
23204 return record;
23205 });
23206 }
23207 dispatch.receiveRevisions(kind, name, recordKey, records, query, false, meta);
23208
23209 // When requesting all fields, the list of results can be used to
23210 // resolve the `getRevision` selector in addition to `getRevisions`.
23211 if (!query?._fields && !query.context) {
23212 const key = entityConfig.key || DEFAULT_ENTITY_KEY;
23213 const resolutionsArgs = records.filter(record => record[key]).map(record => [kind, name, recordKey, record[key]]);
23214 dispatch({
23215 type: 'START_RESOLUTIONS',
23216 selectorName: 'getRevision',
23217 args: resolutionsArgs
23218 });
23219 dispatch({
23220 type: 'FINISH_RESOLUTIONS',
23221 selectorName: 'getRevision',
23222 args: resolutionsArgs
23223 });
23224 }
23225 }
23226 };
23227
23228 // Invalidate cache when a new revision is created.
23229 resolvers_getRevisions.shouldInvalidate = (action, kind, name, recordKey) => action.type === 'SAVE_ENTITY_RECORD_FINISH' && name === action.name && kind === action.kind && !action.error && recordKey === action.recordId;
23230
23231 /**
23232 * Requests a specific Entity revision from the REST API.
23233 *
23234 * @param {string} kind Entity kind.
23235 * @param {string} name Entity name.
23236 * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
23237 * @param {number|string} revisionKey The revision's key.
23238 * @param {Object|undefined} query Optional object of query parameters to
23239 * include with request. If requesting specific
23240 * fields, fields must always include the ID.
23241 */
23242 const resolvers_getRevision = (kind, name, recordKey, revisionKey, query) => async ({
23243 dispatch
23244 }) => {
23245 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
23246 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
23247 if (!entityConfig || entityConfig?.__experimentalNoFetch) {
23248 return;
23249 }
23250 if (query !== undefined && query._fields) {
23251 // If requesting specific fields, items and query association to said
23252 // records are stored by ID reference. Thus, fields must always include
23253 // the ID.
23254 query = {
23255 ...query,
23256 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.revisionKey || DEFAULT_ENTITY_KEY])].join()
23257 };
23258 }
23259 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.getRevisionsUrl(recordKey, revisionKey), query);
23260 let record;
23261 try {
23262 record = await external_wp_apiFetch_default()({
23263 path
23264 });
23265 } catch (error) {
23266 // Do nothing if our request comes back with an API error.
23267 return;
23268 }
23269 if (record) {
23270 dispatch.receiveRevisions(kind, name, recordKey, record, query);
23271 }
23272 };
23273
23274 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/utils.js
23275 function deepCopyLocksTreePath(tree, path) {
23276 const newTree = {
23277 ...tree
23278 };
23279 let currentNode = newTree;
23280 for (const branchName of path) {
23281 currentNode.children = {
23282 ...currentNode.children,
23283 [branchName]: {
23284 locks: [],
23285 children: {},
23286 ...currentNode.children[branchName]
23287 }
23288 };
23289 currentNode = currentNode.children[branchName];
23290 }
23291 return newTree;
23292 }
23293 function getNode(tree, path) {
23294 let currentNode = tree;
23295 for (const branchName of path) {
23296 const nextNode = currentNode.children[branchName];
23297 if (!nextNode) {
23298 return null;
23299 }
23300 currentNode = nextNode;
23301 }
23302 return currentNode;
23303 }
23304 function* iteratePath(tree, path) {
23305 let currentNode = tree;
23306 yield currentNode;
23307 for (const branchName of path) {
23308 const nextNode = currentNode.children[branchName];
23309 if (!nextNode) {
23310 break;
23311 }
23312 yield nextNode;
23313 currentNode = nextNode;
23314 }
23315 }
23316 function* iterateDescendants(node) {
23317 const stack = Object.values(node.children);
23318 while (stack.length) {
23319 const childNode = stack.pop();
23320 yield childNode;
23321 stack.push(...Object.values(childNode.children));
23322 }
23323 }
23324 function hasConflictingLock({
23325 exclusive
23326 }, locks) {
23327 if (exclusive && locks.length) {
23328 return true;
23329 }
23330 if (!exclusive && locks.filter(lock => lock.exclusive).length) {
23331 return true;
23332 }
23333 return false;
23334 }
23335
23336 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/reducer.js
23337 /**
23338 * Internal dependencies
23339 */
23340
23341 const DEFAULT_STATE = {
23342 requests: [],
23343 tree: {
23344 locks: [],
23345 children: {}
23346 }
23347 };
23348
23349 /**
23350 * Reducer returning locks.
23351 *
23352 * @param {Object} state Current state.
23353 * @param {Object} action Dispatched action.
23354 *
23355 * @return {Object} Updated state.
23356 */
23357 function locks(state = DEFAULT_STATE, action) {
23358 switch (action.type) {
23359 case 'ENQUEUE_LOCK_REQUEST':
23360 {
23361 const {
23362 request
23363 } = action;
23364 return {
23365 ...state,
23366 requests: [request, ...state.requests]
23367 };
23368 }
23369 case 'GRANT_LOCK_REQUEST':
23370 {
23371 const {
23372 lock,
23373 request
23374 } = action;
23375 const {
23376 store,
23377 path
23378 } = request;
23379 const storePath = [store, ...path];
23380 const newTree = deepCopyLocksTreePath(state.tree, storePath);
23381 const node = getNode(newTree, storePath);
23382 node.locks = [...node.locks, lock];
23383 return {
23384 ...state,
23385 requests: state.requests.filter(r => r !== request),
23386 tree: newTree
23387 };
23388 }
23389 case 'RELEASE_LOCK':
23390 {
23391 const {
23392 lock
23393 } = action;
23394 const storePath = [lock.store, ...lock.path];
23395 const newTree = deepCopyLocksTreePath(state.tree, storePath);
23396 const node = getNode(newTree, storePath);
23397 node.locks = node.locks.filter(l => l !== lock);
23398 return {
23399 ...state,
23400 tree: newTree
23401 };
23402 }
23403 }
23404 return state;
23405 }
23406
23407 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/selectors.js
23408 /**
23409 * Internal dependencies
23410 */
23411
23412 function getPendingLockRequests(state) {
23413 return state.requests;
23414 }
23415 function isLockAvailable(state, store, path, {
23416 exclusive
23417 }) {
23418 const storePath = [store, ...path];
23419 const locks = state.tree;
23420
23421 // Validate all parents and the node itself
23422 for (const node of iteratePath(locks, storePath)) {
23423 if (hasConflictingLock({
23424 exclusive
23425 }, node.locks)) {
23426 return false;
23427 }
23428 }
23429
23430 // iteratePath terminates early if path is unreachable, let's
23431 // re-fetch the node and check it exists in the tree.
23432 const node = getNode(locks, storePath);
23433 if (!node) {
23434 return true;
23435 }
23436
23437 // Validate all nested nodes
23438 for (const descendant of iterateDescendants(node)) {
23439 if (hasConflictingLock({
23440 exclusive
23441 }, descendant.locks)) {
23442 return false;
23443 }
23444 }
23445 return true;
23446 }
23447
23448 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/engine.js
23449 /**
23450 * Internal dependencies
23451 */
23452
23453
23454 function createLocks() {
23455 let state = locks(undefined, {
23456 type: '@@INIT'
23457 });
23458 function processPendingLockRequests() {
23459 for (const request of getPendingLockRequests(state)) {
23460 const {
23461 store,
23462 path,
23463 exclusive,
23464 notifyAcquired
23465 } = request;
23466 if (isLockAvailable(state, store, path, {
23467 exclusive
23468 })) {
23469 const lock = {
23470 store,
23471 path,
23472 exclusive
23473 };
23474 state = locks(state, {
23475 type: 'GRANT_LOCK_REQUEST',
23476 lock,
23477 request
23478 });
23479 notifyAcquired(lock);
23480 }
23481 }
23482 }
23483 function acquire(store, path, exclusive) {
23484 return new Promise(resolve => {
23485 state = locks(state, {
23486 type: 'ENQUEUE_LOCK_REQUEST',
23487 request: {
23488 store,
23489 path,
23490 exclusive,
23491 notifyAcquired: resolve
23492 }
23493 });
23494 processPendingLockRequests();
23495 });
23496 }
23497 function release(lock) {
23498 state = locks(state, {
23499 type: 'RELEASE_LOCK',
23500 lock
23501 });
23502 processPendingLockRequests();
23503 }
23504 return {
23505 acquire,
23506 release
23507 };
23508 }
23509
23510 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/actions.js
23511 /**
23512 * Internal dependencies
23513 */
23514
23515 function createLocksActions() {
23516 const locks = createLocks();
23517 function __unstableAcquireStoreLock(store, path, {
23518 exclusive
23519 }) {
23520 return () => locks.acquire(store, path, exclusive);
23521 }
23522 function __unstableReleaseStoreLock(lock) {
23523 return () => locks.release(lock);
23524 }
23525 return {
23526 __unstableAcquireStoreLock,
23527 __unstableReleaseStoreLock
23528 };
23529 }
23530
23531 ;// CONCATENATED MODULE: external ["wp","privateApis"]
23532 const external_wp_privateApis_namespaceObject = window["wp"]["privateApis"];
23533 ;// CONCATENATED MODULE: ./packages/core-data/build-module/private-apis.js
23534 /**
23535 * WordPress dependencies
23536 */
23537
23538 const {
23539 lock,
23540 unlock
23541 } = (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');
23542
23543 ;// CONCATENATED MODULE: external ["wp","element"]
23544 const external_wp_element_namespaceObject = window["wp"]["element"];
23545 ;// CONCATENATED MODULE: external ["wp","blocks"]
23546 const external_wp_blocks_namespaceObject = window["wp"]["blocks"];
23547 ;// CONCATENATED MODULE: external ["wp","blockEditor"]
23548 const external_wp_blockEditor_namespaceObject = window["wp"]["blockEditor"];
23549 ;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/get-rich-text-values-cached.js
23550 /**
23551 * WordPress dependencies
23552 */
23553
23554
23555 /**
23556 * Internal dependencies
23557 */
23558
23559
23560 // TODO: The following line should have been:
23561 //
23562 // const unlockedApis = unlock( blockEditorPrivateApis );
23563 //
23564 // But there are hidden circular dependencies in RNMobile code, specifically in
23565 // certain native components in the `components` package that depend on
23566 // `block-editor`. What follows is a workaround that defers the `unlock` call
23567 // to prevent native code from failing.
23568 //
23569 // Fix once https://github.com/WordPress/gutenberg/issues/52692 is closed.
23570 let unlockedApis;
23571 const cache = new WeakMap();
23572 function getRichTextValuesCached(block) {
23573 if (!unlockedApis) {
23574 unlockedApis = unlock(external_wp_blockEditor_namespaceObject.privateApis);
23575 }
23576 if (!cache.has(block)) {
23577 const values = unlockedApis.getRichTextValues([block]);
23578 cache.set(block, values);
23579 }
23580 return cache.get(block);
23581 }
23582
23583 ;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/get-footnotes-order.js
23584 /**
23585 * Internal dependencies
23586 */
23587
23588 const get_footnotes_order_cache = new WeakMap();
23589 function getBlockFootnotesOrder(block) {
23590 if (!get_footnotes_order_cache.has(block)) {
23591 const order = [];
23592 for (const value of getRichTextValuesCached(block)) {
23593 if (!value) {
23594 continue;
23595 }
23596
23597 // replacements is a sparse array, use forEach to skip empty slots.
23598 value.replacements.forEach(({
23599 type,
23600 attributes
23601 }) => {
23602 if (type === 'core/footnote') {
23603 order.push(attributes['data-fn']);
23604 }
23605 });
23606 }
23607 get_footnotes_order_cache.set(block, order);
23608 }
23609 return get_footnotes_order_cache.get(block);
23610 }
23611 function getFootnotesOrder(blocks) {
23612 // We can only separate getting order from blocks at the root level. For
23613 // deeper inner blocks, this will not work since it's possible to have both
23614 // inner blocks and block attributes, so order needs to be computed from the
23615 // Edit functions as a whole.
23616 return blocks.flatMap(getBlockFootnotesOrder);
23617 }
23618
23619 ;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/index.js
23620 /**
23621 * WordPress dependencies
23622 */
23623
23624
23625 /**
23626 * Internal dependencies
23627 */
23628
23629 let oldFootnotes = {};
23630 function updateFootnotesFromMeta(blocks, meta) {
23631 const output = {
23632 blocks
23633 };
23634 if (!meta) {
23635 return output;
23636 }
23637
23638 // If meta.footnotes is empty, it means the meta is not registered.
23639 if (meta.footnotes === undefined) {
23640 return output;
23641 }
23642 const newOrder = getFootnotesOrder(blocks);
23643 const footnotes = meta.footnotes ? JSON.parse(meta.footnotes) : [];
23644 const currentOrder = footnotes.map(fn => fn.id);
23645 if (currentOrder.join('') === newOrder.join('')) {
23646 return output;
23647 }
23648 const newFootnotes = newOrder.map(fnId => footnotes.find(fn => fn.id === fnId) || oldFootnotes[fnId] || {
23649 id: fnId,
23650 content: ''
23651 });
23652 function updateAttributes(attributes) {
23653 // Only attempt to update attributes, if attributes is an object.
23654 if (!attributes || Array.isArray(attributes) || typeof attributes !== 'object') {
23655 return attributes;
23656 }
23657 attributes = {
23658 ...attributes
23659 };
23660 for (const key in attributes) {
23661 const value = attributes[key];
23662 if (Array.isArray(value)) {
23663 attributes[key] = value.map(updateAttributes);
23664 continue;
23665 }
23666
23667 // To do, remove support for string values?
23668 if (typeof value !== 'string' && !(value instanceof external_wp_richText_namespaceObject.RichTextData)) {
23669 continue;
23670 }
23671 const richTextValue = typeof value === 'string' ? external_wp_richText_namespaceObject.RichTextData.fromHTMLString(value) : new external_wp_richText_namespaceObject.RichTextData(value);
23672 richTextValue.replacements.forEach(replacement => {
23673 if (replacement.type === 'core/footnote') {
23674 const id = replacement.attributes['data-fn'];
23675 const index = newOrder.indexOf(id);
23676 // The innerHTML contains the count wrapped in a link.
23677 const countValue = (0,external_wp_richText_namespaceObject.create)({
23678 html: replacement.innerHTML
23679 });
23680 countValue.text = String(index + 1);
23681 countValue.formats = Array.from({
23682 length: countValue.text.length
23683 }, () => countValue.formats[0]);
23684 countValue.replacements = Array.from({
23685 length: countValue.text.length
23686 }, () => countValue.replacements[0]);
23687 replacement.innerHTML = (0,external_wp_richText_namespaceObject.toHTMLString)({
23688 value: countValue
23689 });
23690 }
23691 });
23692 attributes[key] = typeof value === 'string' ? richTextValue.toHTMLString() : richTextValue;
23693 }
23694 return attributes;
23695 }
23696 function updateBlocksAttributes(__blocks) {
23697 return __blocks.map(block => {
23698 return {
23699 ...block,
23700 attributes: updateAttributes(block.attributes),
23701 innerBlocks: updateBlocksAttributes(block.innerBlocks)
23702 };
23703 });
23704 }
23705
23706 // We need to go through all block attributes deeply and update the
23707 // footnote anchor numbering (textContent) to match the new order.
23708 const newBlocks = updateBlocksAttributes(blocks);
23709 oldFootnotes = {
23710 ...oldFootnotes,
23711 ...footnotes.reduce((acc, fn) => {
23712 if (!newOrder.includes(fn.id)) {
23713 acc[fn.id] = fn;
23714 }
23715 return acc;
23716 }, {})
23717 };
23718 return {
23719 meta: {
23720 ...meta,
23721 footnotes: JSON.stringify(newFootnotes)
23722 },
23723 blocks: newBlocks
23724 };
23725 }
23726
23727 ;// CONCATENATED MODULE: external "ReactJSXRuntime"
23728 const external_ReactJSXRuntime_namespaceObject = window["ReactJSXRuntime"];
23729 ;// CONCATENATED MODULE: ./packages/core-data/build-module/entity-provider.js
23730 /**
23731 * WordPress dependencies
23732 */
23733
23734
23735
23736
23737 /**
23738 * Internal dependencies
23739 */
23740
23741
23742
23743 /** @typedef {import('@wordpress/blocks').WPBlock} WPBlock */
23744
23745 const EMPTY_ARRAY = [];
23746 const EntityContext = (0,external_wp_element_namespaceObject.createContext)({});
23747
23748 /**
23749 * Context provider component for providing
23750 * an entity for a specific entity.
23751 *
23752 * @param {Object} props The component's props.
23753 * @param {string} props.kind The entity kind.
23754 * @param {string} props.type The entity name.
23755 * @param {number} props.id The entity ID.
23756 * @param {*} props.children The children to wrap.
23757 *
23758 * @return {Object} The provided children, wrapped with
23759 * the entity's context provider.
23760 */
23761 function EntityProvider({
23762 kind,
23763 type: name,
23764 id,
23765 children
23766 }) {
23767 const parent = (0,external_wp_element_namespaceObject.useContext)(EntityContext);
23768 const childContext = (0,external_wp_element_namespaceObject.useMemo)(() => ({
23769 ...parent,
23770 [kind]: {
23771 ...parent?.[kind],
23772 [name]: id
23773 }
23774 }), [parent, kind, name, id]);
23775 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(EntityContext.Provider, {
23776 value: childContext,
23777 children: children
23778 });
23779 }
23780
23781 /**
23782 * Hook that returns the ID for the nearest
23783 * provided entity of the specified type.
23784 *
23785 * @param {string} kind The entity kind.
23786 * @param {string} name The entity name.
23787 */
23788 function useEntityId(kind, name) {
23789 const context = (0,external_wp_element_namespaceObject.useContext)(EntityContext);
23790 return context?.[kind]?.[name];
23791 }
23792
23793 /**
23794 * Hook that returns the value and a setter for the
23795 * specified property of the nearest provided
23796 * entity of the specified type.
23797 *
23798 * @param {string} kind The entity kind.
23799 * @param {string} name The entity name.
23800 * @param {string} prop The property name.
23801 * @param {string} [_id] An entity ID to use instead of the context-provided one.
23802 *
23803 * @return {[*, Function, *]} An array where the first item is the
23804 * property value, the second is the
23805 * setter and the third is the full value
23806 * object from REST API containing more
23807 * information like `raw`, `rendered` and
23808 * `protected` props.
23809 */
23810 function useEntityProp(kind, name, prop, _id) {
23811 const providerId = useEntityId(kind, name);
23812 const id = _id !== null && _id !== void 0 ? _id : providerId;
23813 const {
23814 value,
23815 fullValue
23816 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
23817 const {
23818 getEntityRecord,
23819 getEditedEntityRecord
23820 } = select(STORE_NAME);
23821 const record = getEntityRecord(kind, name, id); // Trigger resolver.
23822 const editedRecord = getEditedEntityRecord(kind, name, id);
23823 return record && editedRecord ? {
23824 value: editedRecord[prop],
23825 fullValue: record[prop]
23826 } : {};
23827 }, [kind, name, id, prop]);
23828 const {
23829 editEntityRecord
23830 } = (0,external_wp_data_namespaceObject.useDispatch)(STORE_NAME);
23831 const setValue = (0,external_wp_element_namespaceObject.useCallback)(newValue => {
23832 editEntityRecord(kind, name, id, {
23833 [prop]: newValue
23834 });
23835 }, [editEntityRecord, kind, name, id, prop]);
23836 return [value, setValue, fullValue];
23837 }
23838 const parsedBlocksCache = new WeakMap();
23839
23840 /**
23841 * Hook that returns block content getters and setters for
23842 * the nearest provided entity of the specified type.
23843 *
23844 * The return value has the shape `[ blocks, onInput, onChange ]`.
23845 * `onInput` is for block changes that don't create undo levels
23846 * or dirty the post, non-persistent changes, and `onChange` is for
23847 * persistent changes. They map directly to the props of a
23848 * `BlockEditorProvider` and are intended to be used with it,
23849 * or similar components or hooks.
23850 *
23851 * @param {string} kind The entity kind.
23852 * @param {string} name The entity name.
23853 * @param {Object} options
23854 * @param {string} [options.id] An entity ID to use instead of the context-provided one.
23855 *
23856 * @return {[WPBlock[], Function, Function]} The block array and setters.
23857 */
23858 function useEntityBlockEditor(kind, name, {
23859 id: _id
23860 } = {}) {
23861 const providerId = useEntityId(kind, name);
23862 const id = _id !== null && _id !== void 0 ? _id : providerId;
23863 const {
23864 getEntityRecord,
23865 getEntityRecordEdits
23866 } = (0,external_wp_data_namespaceObject.useSelect)(STORE_NAME);
23867 const {
23868 content,
23869 editedBlocks,
23870 meta
23871 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
23872 if (!id) {
23873 return {};
23874 }
23875 const {
23876 getEditedEntityRecord
23877 } = select(STORE_NAME);
23878 const editedRecord = getEditedEntityRecord(kind, name, id);
23879 return {
23880 editedBlocks: editedRecord.blocks,
23881 content: editedRecord.content,
23882 meta: editedRecord.meta
23883 };
23884 }, [kind, name, id]);
23885 const {
23886 __unstableCreateUndoLevel,
23887 editEntityRecord
23888 } = (0,external_wp_data_namespaceObject.useDispatch)(STORE_NAME);
23889 const blocks = (0,external_wp_element_namespaceObject.useMemo)(() => {
23890 if (!id) {
23891 return undefined;
23892 }
23893 if (editedBlocks) {
23894 return editedBlocks;
23895 }
23896 if (!content || typeof content !== 'string') {
23897 return EMPTY_ARRAY;
23898 }
23899
23900 // If there's an edit, cache the parsed blocks by the edit.
23901 // If not, cache by the original enity record.
23902 const edits = getEntityRecordEdits(kind, name, id);
23903 const isUnedited = !edits || !Object.keys(edits).length;
23904 const cackeKey = isUnedited ? getEntityRecord(kind, name, id) : edits;
23905 let _blocks = parsedBlocksCache.get(cackeKey);
23906 if (!_blocks) {
23907 _blocks = (0,external_wp_blocks_namespaceObject.parse)(content);
23908 parsedBlocksCache.set(cackeKey, _blocks);
23909 }
23910 return _blocks;
23911 }, [kind, name, id, editedBlocks, content, getEntityRecord, getEntityRecordEdits]);
23912 const updateFootnotes = (0,external_wp_element_namespaceObject.useCallback)(_blocks => updateFootnotesFromMeta(_blocks, meta), [meta]);
23913 const onChange = (0,external_wp_element_namespaceObject.useCallback)((newBlocks, options) => {
23914 const noChange = blocks === newBlocks;
23915 if (noChange) {
23916 return __unstableCreateUndoLevel(kind, name, id);
23917 }
23918 const {
23919 selection,
23920 ...rest
23921 } = options;
23922
23923 // We create a new function here on every persistent edit
23924 // to make sure the edit makes the post dirty and creates
23925 // a new undo level.
23926 const edits = {
23927 selection,
23928 content: ({
23929 blocks: blocksForSerialization = []
23930 }) => (0,external_wp_blocks_namespaceObject.__unstableSerializeAndClean)(blocksForSerialization),
23931 ...updateFootnotes(newBlocks)
23932 };
23933 editEntityRecord(kind, name, id, edits, {
23934 isCached: false,
23935 ...rest
23936 });
23937 }, [kind, name, id, blocks, updateFootnotes, __unstableCreateUndoLevel, editEntityRecord]);
23938 const onInput = (0,external_wp_element_namespaceObject.useCallback)((newBlocks, options) => {
23939 const {
23940 selection,
23941 ...rest
23942 } = options;
23943 const footnotesChanges = updateFootnotes(newBlocks);
23944 const edits = {
23945 selection,
23946 ...footnotesChanges
23947 };
23948 editEntityRecord(kind, name, id, edits, {
23949 isCached: true,
23950 ...rest
23951 });
23952 }, [kind, name, id, updateFootnotes, editEntityRecord]);
23953 return [blocks, onInput, onChange];
23954 }
23955
23956 ;// CONCATENATED MODULE: ./node_modules/memize/dist/index.js
23957 /**
23958 * Memize options object.
23959 *
23960 * @typedef MemizeOptions
23961 *
23962 * @property {number} [maxSize] Maximum size of the cache.
23963 */
23964
23965 /**
23966 * Internal cache entry.
23967 *
23968 * @typedef MemizeCacheNode
23969 *
23970 * @property {?MemizeCacheNode|undefined} [prev] Previous node.
23971 * @property {?MemizeCacheNode|undefined} [next] Next node.
23972 * @property {Array<*>} args Function arguments for cache
23973 * entry.
23974 * @property {*} val Function result.
23975 */
23976
23977 /**
23978 * Properties of the enhanced function for controlling cache.
23979 *
23980 * @typedef MemizeMemoizedFunction
23981 *
23982 * @property {()=>void} clear Clear the cache.
23983 */
23984
23985 /**
23986 * Accepts a function to be memoized, and returns a new memoized function, with
23987 * optional options.
23988 *
23989 * @template {(...args: any[]) => any} F
23990 *
23991 * @param {F} fn Function to memoize.
23992 * @param {MemizeOptions} [options] Options object.
23993 *
23994 * @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function.
23995 */
23996 function memize(fn, options) {
23997 var size = 0;
23998
23999 /** @type {?MemizeCacheNode|undefined} */
24000 var head;
24001
24002 /** @type {?MemizeCacheNode|undefined} */
24003 var tail;
24004
24005 options = options || {};
24006
24007 function memoized(/* ...args */) {
24008 var node = head,
24009 len = arguments.length,
24010 args,
24011 i;
24012
24013 searchCache: while (node) {
24014 // Perform a shallow equality test to confirm that whether the node
24015 // under test is a candidate for the arguments passed. Two arrays
24016 // are shallowly equal if their length matches and each entry is
24017 // strictly equal between the two sets. Avoid abstracting to a
24018 // function which could incur an arguments leaking deoptimization.
24019
24020 // Check whether node arguments match arguments length
24021 if (node.args.length !== arguments.length) {
24022 node = node.next;
24023 continue;
24024 }
24025
24026 // Check whether node arguments match arguments values
24027 for (i = 0; i < len; i++) {
24028 if (node.args[i] !== arguments[i]) {
24029 node = node.next;
24030 continue searchCache;
24031 }
24032 }
24033
24034 // At this point we can assume we've found a match
24035
24036 // Surface matched node to head if not already
24037 if (node !== head) {
24038 // As tail, shift to previous. Must only shift if not also
24039 // head, since if both head and tail, there is no previous.
24040 if (node === tail) {
24041 tail = node.prev;
24042 }
24043
24044 // Adjust siblings to point to each other. If node was tail,
24045 // this also handles new tail's empty `next` assignment.
24046 /** @type {MemizeCacheNode} */ (node.prev).next = node.next;
24047 if (node.next) {
24048 node.next.prev = node.prev;
24049 }
24050
24051 node.next = head;
24052 node.prev = null;
24053 /** @type {MemizeCacheNode} */ (head).prev = node;
24054 head = node;
24055 }
24056
24057 // Return immediately
24058 return node.val;
24059 }
24060
24061 // No cached value found. Continue to insertion phase:
24062
24063 // Create a copy of arguments (avoid leaking deoptimization)
24064 args = new Array(len);
24065 for (i = 0; i < len; i++) {
24066 args[i] = arguments[i];
24067 }
24068
24069 node = {
24070 args: args,
24071
24072 // Generate the result from original function
24073 val: fn.apply(null, args),
24074 };
24075
24076 // Don't need to check whether node is already head, since it would
24077 // have been returned above already if it was
24078
24079 // Shift existing head down list
24080 if (head) {
24081 head.prev = node;
24082 node.next = head;
24083 } else {
24084 // If no head, follows that there's no tail (at initial or reset)
24085 tail = node;
24086 }
24087
24088 // Trim tail if we're reached max size and are pending cache insertion
24089 if (size === /** @type {MemizeOptions} */ (options).maxSize) {
24090 tail = /** @type {MemizeCacheNode} */ (tail).prev;
24091 /** @type {MemizeCacheNode} */ (tail).next = null;
24092 } else {
24093 size++;
24094 }
24095
24096 head = node;
24097
24098 return node.val;
24099 }
24100
24101 memoized.clear = function () {
24102 head = null;
24103 tail = null;
24104 size = 0;
24105 };
24106
24107 // Ignore reason: There's not a clear solution to create an intersection of
24108 // the function with additional properties, where the goal is to retain the
24109 // function signature of the incoming argument and add control properties
24110 // on the return value.
24111
24112 // @ts-ignore
24113 return memoized;
24114 }
24115
24116
24117
24118 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/memoize.js
24119 /**
24120 * External dependencies
24121 */
24122
24123
24124 // re-export due to restrictive esModuleInterop setting
24125 /* harmony default export */ const memoize = (memize);
24126
24127 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/constants.js
24128 let Status = /*#__PURE__*/function (Status) {
24129 Status["Idle"] = "IDLE";
24130 Status["Resolving"] = "RESOLVING";
24131 Status["Error"] = "ERROR";
24132 Status["Success"] = "SUCCESS";
24133 return Status;
24134 }({});
24135
24136 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-query-select.js
24137 /**
24138 * WordPress dependencies
24139 */
24140
24141
24142 /**
24143 * Internal dependencies
24144 */
24145
24146
24147 const META_SELECTORS = ['getIsResolving', 'hasStartedResolution', 'hasFinishedResolution', 'isResolving', 'getCachedResolvers'];
24148 /**
24149 * Like useSelect, but the selectors return objects containing
24150 * both the original data AND the resolution info.
24151 *
24152 * @since 6.1.0 Introduced in WordPress core.
24153 * @private
24154 *
24155 * @param {Function} mapQuerySelect see useSelect
24156 * @param {Array} deps see useSelect
24157 *
24158 * @example
24159 * ```js
24160 * import { useQuerySelect } from '@wordpress/data';
24161 * import { store as coreDataStore } from '@wordpress/core-data';
24162 *
24163 * function PageTitleDisplay( { id } ) {
24164 * const { data: page, isResolving } = useQuerySelect( ( query ) => {
24165 * return query( coreDataStore ).getEntityRecord( 'postType', 'page', id )
24166 * }, [ id ] );
24167 *
24168 * if ( isResolving ) {
24169 * return 'Loading...';
24170 * }
24171 *
24172 * return page.title;
24173 * }
24174 *
24175 * // Rendered in the application:
24176 * // <PageTitleDisplay id={ 10 } />
24177 * ```
24178 *
24179 * In the above example, when `PageTitleDisplay` is rendered into an
24180 * application, the page and the resolution details will be retrieved from
24181 * the store state using the `mapSelect` callback on `useQuerySelect`.
24182 *
24183 * If the id prop changes then any page in the state for that id is
24184 * retrieved. If the id prop doesn't change and other props are passed in
24185 * that do change, the title will not change because the dependency is just
24186 * the id.
24187 * @see useSelect
24188 *
24189 * @return {QuerySelectResponse} Queried data.
24190 */
24191 function useQuerySelect(mapQuerySelect, deps) {
24192 return (0,external_wp_data_namespaceObject.useSelect)((select, registry) => {
24193 const resolve = store => enrichSelectors(select(store));
24194 return mapQuerySelect(resolve, registry);
24195 }, deps);
24196 }
24197 /**
24198 * Transform simple selectors into ones that return an object with the
24199 * original return value AND the resolution info.
24200 *
24201 * @param {Object} selectors Selectors to enrich
24202 * @return {EnrichedSelectors} Enriched selectors
24203 */
24204 const enrichSelectors = memoize(selectors => {
24205 const resolvers = {};
24206 for (const selectorName in selectors) {
24207 if (META_SELECTORS.includes(selectorName)) {
24208 continue;
24209 }
24210 Object.defineProperty(resolvers, selectorName, {
24211 get: () => (...args) => {
24212 const data = selectors[selectorName](...args);
24213 const resolutionStatus = selectors.getResolutionState(selectorName, args)?.status;
24214 let status;
24215 switch (resolutionStatus) {
24216 case 'resolving':
24217 status = Status.Resolving;
24218 break;
24219 case 'finished':
24220 status = Status.Success;
24221 break;
24222 case 'error':
24223 status = Status.Error;
24224 break;
24225 case undefined:
24226 status = Status.Idle;
24227 break;
24228 }
24229 return {
24230 data,
24231 status,
24232 isResolving: status === Status.Resolving,
24233 hasStarted: status !== Status.Idle,
24234 hasResolved: status === Status.Success || status === Status.Error
24235 };
24236 }
24237 });
24238 }
24239 return resolvers;
24240 });
24241
24242 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-entity-record.js
24243 /**
24244 * WordPress dependencies
24245 */
24246
24247
24248
24249
24250 /**
24251 * Internal dependencies
24252 */
24253
24254
24255 const use_entity_record_EMPTY_OBJECT = {};
24256
24257 /**
24258 * Resolves the specified entity record.
24259 *
24260 * @since 6.1.0 Introduced in WordPress core.
24261 *
24262 * @param kind Kind of the entity, e.g. `root` or a `postType`. See rootEntitiesConfig in ../entities.ts for a list of available kinds.
24263 * @param name Name of the entity, e.g. `plugin` or a `post`. See rootEntitiesConfig in ../entities.ts for a list of available names.
24264 * @param recordId ID of the requested entity record.
24265 * @param options Optional hook options.
24266 * @example
24267 * ```js
24268 * import { useEntityRecord } from '@wordpress/core-data';
24269 *
24270 * function PageTitleDisplay( { id } ) {
24271 * const { record, isResolving } = useEntityRecord( 'postType', 'page', id );
24272 *
24273 * if ( isResolving ) {
24274 * return 'Loading...';
24275 * }
24276 *
24277 * return record.title;
24278 * }
24279 *
24280 * // Rendered in the application:
24281 * // <PageTitleDisplay id={ 1 } />
24282 * ```
24283 *
24284 * In the above example, when `PageTitleDisplay` is rendered into an
24285 * application, the page and the resolution details will be retrieved from
24286 * the store state using `getEntityRecord()`, or resolved if missing.
24287 *
24288 * @example
24289 * ```js
24290 * import { useCallback } from 'react';
24291 * import { useDispatch } from '@wordpress/data';
24292 * import { __ } from '@wordpress/i18n';
24293 * import { TextControl } from '@wordpress/components';
24294 * import { store as noticeStore } from '@wordpress/notices';
24295 * import { useEntityRecord } from '@wordpress/core-data';
24296 *
24297 * function PageRenameForm( { id } ) {
24298 * const page = useEntityRecord( 'postType', 'page', id );
24299 * const { createSuccessNotice, createErrorNotice } =
24300 * useDispatch( noticeStore );
24301 *
24302 * const setTitle = useCallback( ( title ) => {
24303 * page.edit( { title } );
24304 * }, [ page.edit ] );
24305 *
24306 * if ( page.isResolving ) {
24307 * return 'Loading...';
24308 * }
24309 *
24310 * async function onRename( event ) {
24311 * event.preventDefault();
24312 * try {
24313 * await page.save();
24314 * createSuccessNotice( __( 'Page renamed.' ), {
24315 * type: 'snackbar',
24316 * } );
24317 * } catch ( error ) {
24318 * createErrorNotice( error.message, { type: 'snackbar' } );
24319 * }
24320 * }
24321 *
24322 * return (
24323 * <form onSubmit={ onRename }>
24324 * <TextControl
24325 * label={ __( 'Name' ) }
24326 * value={ page.editedRecord.title }
24327 * onChange={ setTitle }
24328 * />
24329 * <button type="submit">{ __( 'Save' ) }</button>
24330 * </form>
24331 * );
24332 * }
24333 *
24334 * // Rendered in the application:
24335 * // <PageRenameForm id={ 1 } />
24336 * ```
24337 *
24338 * In the above example, updating and saving the page title is handled
24339 * via the `edit()` and `save()` mutation helpers provided by
24340 * `useEntityRecord()`;
24341 *
24342 * @return Entity record data.
24343 * @template RecordType
24344 */
24345 function useEntityRecord(kind, name, recordId, options = {
24346 enabled: true
24347 }) {
24348 const {
24349 editEntityRecord,
24350 saveEditedEntityRecord
24351 } = (0,external_wp_data_namespaceObject.useDispatch)(store);
24352 const mutations = (0,external_wp_element_namespaceObject.useMemo)(() => ({
24353 edit: (record, editOptions = {}) => editEntityRecord(kind, name, recordId, record, editOptions),
24354 save: (saveOptions = {}) => saveEditedEntityRecord(kind, name, recordId, {
24355 throwOnError: true,
24356 ...saveOptions
24357 })
24358 }), [editEntityRecord, kind, name, recordId, saveEditedEntityRecord]);
24359 const {
24360 editedRecord,
24361 hasEdits,
24362 edits
24363 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
24364 if (!options.enabled) {
24365 return {
24366 editedRecord: use_entity_record_EMPTY_OBJECT,
24367 hasEdits: false,
24368 edits: use_entity_record_EMPTY_OBJECT
24369 };
24370 }
24371 return {
24372 editedRecord: select(store).getEditedEntityRecord(kind, name, recordId),
24373 hasEdits: select(store).hasEditsForEntityRecord(kind, name, recordId),
24374 edits: select(store).getEntityRecordNonTransientEdits(kind, name, recordId)
24375 };
24376 }, [kind, name, recordId, options.enabled]);
24377 const {
24378 data: record,
24379 ...querySelectRest
24380 } = useQuerySelect(query => {
24381 if (!options.enabled) {
24382 return {
24383 data: null
24384 };
24385 }
24386 return query(store).getEntityRecord(kind, name, recordId);
24387 }, [kind, name, recordId, options.enabled]);
24388 return {
24389 record,
24390 editedRecord,
24391 hasEdits,
24392 edits,
24393 ...querySelectRest,
24394 ...mutations
24395 };
24396 }
24397 function __experimentalUseEntityRecord(kind, name, recordId, options) {
24398 external_wp_deprecated_default()(`wp.data.__experimentalUseEntityRecord`, {
24399 alternative: 'wp.data.useEntityRecord',
24400 since: '6.1'
24401 });
24402 return useEntityRecord(kind, name, recordId, options);
24403 }
24404
24405 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-entity-records.js
24406 /**
24407 * WordPress dependencies
24408 */
24409
24410
24411
24412
24413 /**
24414 * Internal dependencies
24415 */
24416
24417
24418 const use_entity_records_EMPTY_ARRAY = [];
24419
24420 /**
24421 * Resolves the specified entity records.
24422 *
24423 * @since 6.1.0 Introduced in WordPress core.
24424 *
24425 * @param kind Kind of the entity, e.g. `root` or a `postType`. See rootEntitiesConfig in ../entities.ts for a list of available kinds.
24426 * @param name Name of the entity, e.g. `plugin` or a `post`. See rootEntitiesConfig in ../entities.ts for a list of available names.
24427 * @param queryArgs Optional HTTP query description for how to fetch the data, passed to the requested API endpoint.
24428 * @param options Optional hook options.
24429 * @example
24430 * ```js
24431 * import { useEntityRecords } from '@wordpress/core-data';
24432 *
24433 * function PageTitlesList() {
24434 * const { records, isResolving } = useEntityRecords( 'postType', 'page' );
24435 *
24436 * if ( isResolving ) {
24437 * return 'Loading...';
24438 * }
24439 *
24440 * return (
24441 * <ul>
24442 * {records.map(( page ) => (
24443 * <li>{ page.title }</li>
24444 * ))}
24445 * </ul>
24446 * );
24447 * }
24448 *
24449 * // Rendered in the application:
24450 * // <PageTitlesList />
24451 * ```
24452 *
24453 * In the above example, when `PageTitlesList` is rendered into an
24454 * application, the list of records and the resolution details will be retrieved from
24455 * the store state using `getEntityRecords()`, or resolved if missing.
24456 *
24457 * @return Entity records data.
24458 * @template RecordType
24459 */
24460 function useEntityRecords(kind, name, queryArgs = {}, options = {
24461 enabled: true
24462 }) {
24463 // Serialize queryArgs to a string that can be safely used as a React dep.
24464 // We can't just pass queryArgs as one of the deps, because if it is passed
24465 // as an object literal, then it will be a different object on each call even
24466 // if the values remain the same.
24467 const queryAsString = (0,external_wp_url_namespaceObject.addQueryArgs)('', queryArgs);
24468 const {
24469 data: records,
24470 ...rest
24471 } = useQuerySelect(query => {
24472 if (!options.enabled) {
24473 return {
24474 // Avoiding returning a new reference on every execution.
24475 data: use_entity_records_EMPTY_ARRAY
24476 };
24477 }
24478 return query(store).getEntityRecords(kind, name, queryArgs);
24479 }, [kind, name, queryAsString, options.enabled]);
24480 const {
24481 totalItems,
24482 totalPages
24483 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
24484 if (!options.enabled) {
24485 return {
24486 totalItems: null,
24487 totalPages: null
24488 };
24489 }
24490 return {
24491 totalItems: select(store).getEntityRecordsTotalItems(kind, name, queryArgs),
24492 totalPages: select(store).getEntityRecordsTotalPages(kind, name, queryArgs)
24493 };
24494 }, [kind, name, queryAsString, options.enabled]);
24495 return {
24496 records,
24497 totalItems,
24498 totalPages,
24499 ...rest
24500 };
24501 }
24502 function __experimentalUseEntityRecords(kind, name, queryArgs, options) {
24503 external_wp_deprecated_default()(`wp.data.__experimentalUseEntityRecords`, {
24504 alternative: 'wp.data.useEntityRecords',
24505 since: '6.1'
24506 });
24507 return useEntityRecords(kind, name, queryArgs, options);
24508 }
24509
24510 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-resource-permissions.js
24511 /**
24512 * WordPress dependencies
24513 */
24514
24515
24516 /**
24517 * Internal dependencies
24518 */
24519
24520
24521
24522
24523 /**
24524 * Is the data resolved by now?
24525 */
24526
24527 /**
24528 * Resolves resource permissions.
24529 *
24530 * @since 6.1.0 Introduced in WordPress core.
24531 *
24532 * @param resource The resource in question, e.g. media.
24533 * @param id ID of a specific resource entry, if needed, e.g. 10.
24534 *
24535 * @example
24536 * ```js
24537 * import { useResourcePermissions } from '@wordpress/core-data';
24538 *
24539 * function PagesList() {
24540 * const { canCreate, isResolving } = useResourcePermissions( 'pages' );
24541 *
24542 * if ( isResolving ) {
24543 * return 'Loading ...';
24544 * }
24545 *
24546 * return (
24547 * <div>
24548 * {canCreate ? (<button>+ Create a new page</button>) : false}
24549 * // ...
24550 * </div>
24551 * );
24552 * }
24553 *
24554 * // Rendered in the application:
24555 * // <PagesList />
24556 * ```
24557 *
24558 * @example
24559 * ```js
24560 * import { useResourcePermissions } from '@wordpress/core-data';
24561 *
24562 * function Page({ pageId }) {
24563 * const {
24564 * canCreate,
24565 * canUpdate,
24566 * canDelete,
24567 * isResolving
24568 * } = useResourcePermissions( 'pages', pageId );
24569 *
24570 * if ( isResolving ) {
24571 * return 'Loading ...';
24572 * }
24573 *
24574 * return (
24575 * <div>
24576 * {canCreate ? (<button>+ Create a new page</button>) : false}
24577 * {canUpdate ? (<button>Edit page</button>) : false}
24578 * {canDelete ? (<button>Delete page</button>) : false}
24579 * // ...
24580 * </div>
24581 * );
24582 * }
24583 *
24584 * // Rendered in the application:
24585 * // <Page pageId={ 15 } />
24586 * ```
24587 *
24588 * In the above example, when `PagesList` is rendered into an
24589 * application, the appropriate permissions and the resolution details will be retrieved from
24590 * the store state using `canUser()`, or resolved if missing.
24591 *
24592 * @return Entity records data.
24593 * @template IdType
24594 */
24595 function useResourcePermissions(resource, id) {
24596 return useQuerySelect(resolve => {
24597 const {
24598 canUser
24599 } = resolve(store);
24600 const create = canUser('create', resource);
24601 if (!id) {
24602 const read = canUser('read', resource);
24603 const isResolving = create.isResolving || read.isResolving;
24604 const hasResolved = create.hasResolved && read.hasResolved;
24605 let status = Status.Idle;
24606 if (isResolving) {
24607 status = Status.Resolving;
24608 } else if (hasResolved) {
24609 status = Status.Success;
24610 }
24611 return {
24612 status,
24613 isResolving,
24614 hasResolved,
24615 canCreate: create.hasResolved && create.data,
24616 canRead: read.hasResolved && read.data
24617 };
24618 }
24619 const read = canUser('read', resource, id);
24620 const update = canUser('update', resource, id);
24621 const _delete = canUser('delete', resource, id);
24622 const isResolving = read.isResolving || create.isResolving || update.isResolving || _delete.isResolving;
24623 const hasResolved = read.hasResolved && create.hasResolved && update.hasResolved && _delete.hasResolved;
24624 let status = Status.Idle;
24625 if (isResolving) {
24626 status = Status.Resolving;
24627 } else if (hasResolved) {
24628 status = Status.Success;
24629 }
24630 return {
24631 status,
24632 isResolving,
24633 hasResolved,
24634 canRead: hasResolved && read.data,
24635 canCreate: hasResolved && create.data,
24636 canUpdate: hasResolved && update.data,
24637 canDelete: hasResolved && _delete.data
24638 };
24639 }, [resource, id]);
24640 }
24641 function __experimentalUseResourcePermissions(resource, id) {
24642 external_wp_deprecated_default()(`wp.data.__experimentalUseResourcePermissions`, {
24643 alternative: 'wp.data.useResourcePermissions',
24644 since: '6.1'
24645 });
24646 return useResourcePermissions(resource, id);
24647 }
24648
24649 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/index.js
24650
24651
24652
24653
24654 ;// CONCATENATED MODULE: ./packages/core-data/build-module/index.js
24655 /**
24656 * WordPress dependencies
24657 */
24658
24659
24660 /**
24661 * Internal dependencies
24662 */
24663
24664
24665
24666
24667
24668
24669
24670
24671
24672
24673 // The entity selectors/resolvers and actions are shortcuts to their generic equivalents
24674 // (getEntityRecord, getEntityRecords, updateEntityRecord, updateEntityRecords)
24675 // Instead of getEntityRecord, the consumer could use more user-friendly named selector: getPostType, getTaxonomy...
24676 // The "kind" and the "name" of the entity are combined to generate these shortcuts.
24677 const build_module_entitiesConfig = [...rootEntitiesConfig, ...additionalEntityConfigLoaders.filter(config => !!config.name)];
24678 const entitySelectors = build_module_entitiesConfig.reduce((result, entity) => {
24679 const {
24680 kind,
24681 name,
24682 plural
24683 } = entity;
24684 result[getMethodName(kind, name)] = (state, key, query) => getEntityRecord(state, kind, name, key, query);
24685 if (plural) {
24686 result[getMethodName(kind, plural, 'get')] = (state, query) => getEntityRecords(state, kind, name, query);
24687 }
24688 return result;
24689 }, {});
24690 const entityResolvers = build_module_entitiesConfig.reduce((result, entity) => {
24691 const {
24692 kind,
24693 name,
24694 plural
24695 } = entity;
24696 result[getMethodName(kind, name)] = (key, query) => resolvers_getEntityRecord(kind, name, key, query);
24697 if (plural) {
24698 const pluralMethodName = getMethodName(kind, plural, 'get');
24699 result[pluralMethodName] = (...args) => resolvers_getEntityRecords(kind, name, ...args);
24700 result[pluralMethodName].shouldInvalidate = action => resolvers_getEntityRecords.shouldInvalidate(action, kind, name);
24701 }
24702 return result;
24703 }, {});
24704 const entityActions = build_module_entitiesConfig.reduce((result, entity) => {
24705 const {
24706 kind,
24707 name
24708 } = entity;
24709 result[getMethodName(kind, name, 'save')] = (record, options) => saveEntityRecord(kind, name, record, options);
24710 result[getMethodName(kind, name, 'delete')] = (key, query, options) => deleteEntityRecord(kind, name, key, query, options);
24711 return result;
24712 }, {});
24713 const storeConfig = () => ({
24714 reducer: build_module_reducer,
24715 actions: {
24716 ...build_module_actions_namespaceObject,
24717 ...entityActions,
24718 ...createLocksActions()
24719 },
24720 selectors: {
24721 ...build_module_selectors_namespaceObject,
24722 ...entitySelectors
24723 },
24724 resolvers: {
24725 ...resolvers_namespaceObject,
24726 ...entityResolvers
24727 }
24728 });
24729
24730 /**
24731 * Store definition for the code data namespace.
24732 *
24733 * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore
24734 */
24735 const store = (0,external_wp_data_namespaceObject.createReduxStore)(STORE_NAME, storeConfig());
24736 unlock(store).registerPrivateSelectors(private_selectors_namespaceObject);
24737 (0,external_wp_data_namespaceObject.register)(store); // Register store after unlocking private selectors to allow resolvers to use them.
24738
24739
24740
24741
24742
24743
24744
24745 })();
24746
24747 (window.wp = window.wp || {}).coreData = __webpack_exports__;
24748 /******/ })()
24749 ;