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

24,832 lines 794.8 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 */ fetchLinkSuggestions),
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 */ use_resource_permissions)
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", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
1173 function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
1174 function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
1175 function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
1176 function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
1177 function fulfill(value) { resume("next", value); }
1178 function reject(value) { resume("throw", value); }
1179 function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
1180 }
1181
1182 function __asyncDelegator(o) {
1183 var i, p;
1184 return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
1185 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; }
1186 }
1187
1188 function __asyncValues(o) {
1189 if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
1190 var m = o[Symbol.asyncIterator], i;
1191 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);
1192 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); }); }; }
1193 function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
1194 }
1195
1196 function __makeTemplateObject(cooked, raw) {
1197 if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
1198 return cooked;
1199 };
1200
1201 var __setModuleDefault = Object.create ? (function(o, v) {
1202 Object.defineProperty(o, "default", { enumerable: true, value: v });
1203 }) : function(o, v) {
1204 o["default"] = v;
1205 };
1206
1207 function __importStar(mod) {
1208 if (mod && mod.__esModule) return mod;
1209 var result = {};
1210 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
1211 __setModuleDefault(result, mod);
1212 return result;
1213 }
1214
1215 function __importDefault(mod) {
1216 return (mod && mod.__esModule) ? mod : { default: mod };
1217 }
1218
1219 function __classPrivateFieldGet(receiver, state, kind, f) {
1220 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
1221 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");
1222 return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
1223 }
1224
1225 function __classPrivateFieldSet(receiver, state, value, kind, f) {
1226 if (kind === "m") throw new TypeError("Private method is not writable");
1227 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
1228 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");
1229 return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
1230 }
1231
1232 function __classPrivateFieldIn(state, receiver) {
1233 if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object");
1234 return typeof state === "function" ? receiver === state : state.has(receiver);
1235 }
1236
1237 function __addDisposableResource(env, value, async) {
1238 if (value !== null && value !== void 0) {
1239 if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
1240 var dispose, inner;
1241 if (async) {
1242 if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
1243 dispose = value[Symbol.asyncDispose];
1244 }
1245 if (dispose === void 0) {
1246 if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
1247 dispose = value[Symbol.dispose];
1248 if (async) inner = dispose;
1249 }
1250 if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
1251 if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
1252 env.stack.push({ value: value, dispose: dispose, async: async });
1253 }
1254 else if (async) {
1255 env.stack.push({ async: true });
1256 }
1257 return value;
1258 }
1259
1260 var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1261 var e = new Error(message);
1262 return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1263 };
1264
1265 function __disposeResources(env) {
1266 function fail(e) {
1267 env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
1268 env.hasError = true;
1269 }
1270 function next() {
1271 while (env.stack.length) {
1272 var rec = env.stack.pop();
1273 try {
1274 var result = rec.dispose && rec.dispose.call(rec.value);
1275 if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
1276 }
1277 catch (e) {
1278 fail(e);
1279 }
1280 }
1281 if (env.hasError) throw env.error;
1282 }
1283 return next();
1284 }
1285
1286 /* harmony default export */ const tslib_es6 = ({
1287 __extends,
1288 __assign,
1289 __rest,
1290 __decorate,
1291 __param,
1292 __metadata,
1293 __awaiter,
1294 __generator,
1295 __createBinding,
1296 __exportStar,
1297 __values,
1298 __read,
1299 __spread,
1300 __spreadArrays,
1301 __spreadArray,
1302 __await,
1303 __asyncGenerator,
1304 __asyncDelegator,
1305 __asyncValues,
1306 __makeTemplateObject,
1307 __importStar,
1308 __importDefault,
1309 __classPrivateFieldGet,
1310 __classPrivateFieldSet,
1311 __classPrivateFieldIn,
1312 __addDisposableResource,
1313 __disposeResources,
1314 });
1315
1316 ;// CONCATENATED MODULE: ./node_modules/lower-case/dist.es2015/index.js
1317 /**
1318 * Source: ftp://ftp.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt
1319 */
1320 var SUPPORTED_LOCALE = {
1321 tr: {
1322 regexp: /\u0130|\u0049|\u0049\u0307/g,
1323 map: {
1324 İ: "\u0069",
1325 I: "\u0131",
1326 İ: "\u0069",
1327 },
1328 },
1329 az: {
1330 regexp: /\u0130/g,
1331 map: {
1332 İ: "\u0069",
1333 I: "\u0131",
1334 İ: "\u0069",
1335 },
1336 },
1337 lt: {
1338 regexp: /\u0049|\u004A|\u012E|\u00CC|\u00CD|\u0128/g,
1339 map: {
1340 I: "\u0069\u0307",
1341 J: "\u006A\u0307",
1342 Į: "\u012F\u0307",
1343 Ì: "\u0069\u0307\u0300",
1344 Í: "\u0069\u0307\u0301",
1345 Ĩ: "\u0069\u0307\u0303",
1346 },
1347 },
1348 };
1349 /**
1350 * Localized lower case.
1351 */
1352 function localeLowerCase(str, locale) {
1353 var lang = SUPPORTED_LOCALE[locale.toLowerCase()];
1354 if (lang)
1355 return lowerCase(str.replace(lang.regexp, function (m) { return lang.map[m]; }));
1356 return lowerCase(str);
1357 }
1358 /**
1359 * Lower case as a function.
1360 */
1361 function lowerCase(str) {
1362 return str.toLowerCase();
1363 }
1364
1365 ;// CONCATENATED MODULE: ./node_modules/no-case/dist.es2015/index.js
1366
1367 // Support camel case ("camelCase" -> "camel Case" and "CAMELCase" -> "CAMEL Case").
1368 var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g];
1369 // Remove all non-word characters.
1370 var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;
1371 /**
1372 * Normalize the string into something other libraries can manipulate easier.
1373 */
1374 function noCase(input, options) {
1375 if (options === void 0) { options = {}; }
1376 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;
1377 var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0");
1378 var start = 0;
1379 var end = result.length;
1380 // Trim the delimiter from around the output string.
1381 while (result.charAt(start) === "\0")
1382 start++;
1383 while (result.charAt(end - 1) === "\0")
1384 end--;
1385 // Transform each token independently.
1386 return result.slice(start, end).split("\0").map(transform).join(delimiter);
1387 }
1388 /**
1389 * Replace `re` in the input string with the replacement value.
1390 */
1391 function replace(input, re, value) {
1392 if (re instanceof RegExp)
1393 return input.replace(re, value);
1394 return re.reduce(function (input, re) { return input.replace(re, value); }, input);
1395 }
1396
1397 ;// CONCATENATED MODULE: ./node_modules/upper-case-first/dist.es2015/index.js
1398 /**
1399 * Upper case the first character of an input string.
1400 */
1401 function upperCaseFirst(input) {
1402 return input.charAt(0).toUpperCase() + input.substr(1);
1403 }
1404
1405 ;// CONCATENATED MODULE: ./node_modules/capital-case/dist.es2015/index.js
1406
1407
1408
1409 function capitalCaseTransform(input) {
1410 return upperCaseFirst(input.toLowerCase());
1411 }
1412 function capitalCase(input, options) {
1413 if (options === void 0) { options = {}; }
1414 return noCase(input, __assign({ delimiter: " ", transform: capitalCaseTransform }, options));
1415 }
1416
1417 ;// CONCATENATED MODULE: ./node_modules/pascal-case/dist.es2015/index.js
1418
1419
1420 function pascalCaseTransform(input, index) {
1421 var firstChar = input.charAt(0);
1422 var lowerChars = input.substr(1).toLowerCase();
1423 if (index > 0 && firstChar >= "0" && firstChar <= "9") {
1424 return "_" + firstChar + lowerChars;
1425 }
1426 return "" + firstChar.toUpperCase() + lowerChars;
1427 }
1428 function dist_es2015_pascalCaseTransformMerge(input) {
1429 return input.charAt(0).toUpperCase() + input.slice(1).toLowerCase();
1430 }
1431 function pascalCase(input, options) {
1432 if (options === void 0) { options = {}; }
1433 return noCase(input, __assign({ delimiter: "", transform: pascalCaseTransform }, options));
1434 }
1435
1436 ;// CONCATENATED MODULE: external ["wp","apiFetch"]
1437 const external_wp_apiFetch_namespaceObject = window["wp"]["apiFetch"];
1438 var external_wp_apiFetch_default = /*#__PURE__*/__webpack_require__.n(external_wp_apiFetch_namespaceObject);
1439 ;// CONCATENATED MODULE: external ["wp","i18n"]
1440 const external_wp_i18n_namespaceObject = window["wp"]["i18n"];
1441 ;// CONCATENATED MODULE: external ["wp","richText"]
1442 const external_wp_richText_namespaceObject = window["wp"]["richText"];
1443 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/rng.js
1444 // Unique ID creation requires a high quality random # generator. In the browser we therefore
1445 // require the crypto API and do not support built-in fallback to lower quality random number
1446 // generators (like Math.random()).
1447 var rng_getRandomValues;
1448 var rnds8 = new Uint8Array(16);
1449 function rng() {
1450 // lazy load so that environments that need to polyfill have a chance to do so
1451 if (!rng_getRandomValues) {
1452 // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also,
1453 // find the complete implementation of crypto (msCrypto) on IE11.
1454 rng_getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto);
1455
1456 if (!rng_getRandomValues) {
1457 throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
1458 }
1459 }
1460
1461 return rng_getRandomValues(rnds8);
1462 }
1463 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/regex.js
1464 /* 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);
1465 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/validate.js
1466
1467
1468 function validate(uuid) {
1469 return typeof uuid === 'string' && regex.test(uuid);
1470 }
1471
1472 /* harmony default export */ const esm_browser_validate = (validate);
1473 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/stringify.js
1474
1475 /**
1476 * Convert array of 16 byte values to UUID string format of the form:
1477 * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
1478 */
1479
1480 var byteToHex = [];
1481
1482 for (var i = 0; i < 256; ++i) {
1483 byteToHex.push((i + 0x100).toString(16).substr(1));
1484 }
1485
1486 function stringify(arr) {
1487 var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
1488 // Note: Be careful editing this code! It's been tuned for performance
1489 // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
1490 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
1491 // of the following:
1492 // - One or more input array values don't map to a hex octet (leading to
1493 // "undefined" in the uuid)
1494 // - Invalid input values for the RFC `version` or `variant` fields
1495
1496 if (!esm_browser_validate(uuid)) {
1497 throw TypeError('Stringified UUID is invalid');
1498 }
1499
1500 return uuid;
1501 }
1502
1503 /* harmony default export */ const esm_browser_stringify = (stringify);
1504 ;// CONCATENATED MODULE: ./packages/core-data/node_modules/uuid/dist/esm-browser/v4.js
1505
1506
1507
1508 function v4(options, buf, offset) {
1509 options = options || {};
1510 var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
1511
1512 rnds[6] = rnds[6] & 0x0f | 0x40;
1513 rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
1514
1515 if (buf) {
1516 offset = offset || 0;
1517
1518 for (var i = 0; i < 16; ++i) {
1519 buf[offset + i] = rnds[i];
1520 }
1521
1522 return buf;
1523 }
1524
1525 return esm_browser_stringify(rnds);
1526 }
1527
1528 /* harmony default export */ const esm_browser_v4 = (v4);
1529 ;// CONCATENATED MODULE: external ["wp","url"]
1530 const external_wp_url_namespaceObject = window["wp"]["url"];
1531 ;// CONCATENATED MODULE: external ["wp","deprecated"]
1532 const external_wp_deprecated_namespaceObject = window["wp"]["deprecated"];
1533 var external_wp_deprecated_default = /*#__PURE__*/__webpack_require__.n(external_wp_deprecated_namespaceObject);
1534 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/set-nested-value.js
1535 /**
1536 * Sets the value at path of object.
1537 * If a portion of path doesn’t exist, it’s created.
1538 * Arrays are created for missing index properties while objects are created
1539 * for all other missing properties.
1540 *
1541 * Path is specified as either:
1542 * - a string of properties, separated by dots, for example: "x.y".
1543 * - an array of properties, for example `[ 'x', 'y' ]`.
1544 *
1545 * This function intentionally mutates the input object.
1546 *
1547 * Inspired by _.set().
1548 *
1549 * @see https://lodash.com/docs/4.17.15#set
1550 *
1551 * @todo Needs to be deduplicated with its copy in `@wordpress/edit-site`.
1552 *
1553 * @param {Object} object Object to modify
1554 * @param {Array|string} path Path of the property to set.
1555 * @param {*} value Value to set.
1556 */
1557 function setNestedValue(object, path, value) {
1558 if (!object || typeof object !== 'object') {
1559 return object;
1560 }
1561 const normalizedPath = Array.isArray(path) ? path : path.split('.');
1562 normalizedPath.reduce((acc, key, idx) => {
1563 if (acc[key] === undefined) {
1564 if (Number.isInteger(normalizedPath[idx + 1])) {
1565 acc[key] = [];
1566 } else {
1567 acc[key] = {};
1568 }
1569 }
1570 if (idx === normalizedPath.length - 1) {
1571 acc[key] = value;
1572 }
1573 return acc[key];
1574 }, object);
1575 return object;
1576 }
1577
1578 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/get-nested-value.js
1579 /**
1580 * Helper util to return a value from a certain path of the object.
1581 * Path is specified as either:
1582 * - a string of properties, separated by dots, for example: "x.y".
1583 * - an array of properties, for example `[ 'x', 'y' ]`.
1584 * You can also specify a default value in case the result is nullish.
1585 *
1586 * @param {Object} object Input object.
1587 * @param {string|Array} path Path to the object property.
1588 * @param {*} defaultValue Default value if the value at the specified path is undefined.
1589 * @return {*} Value of the object property at the specified path.
1590 */
1591 function getNestedValue(object, path, defaultValue) {
1592 if (!object || typeof object !== 'object' || typeof path !== 'string' && !Array.isArray(path)) {
1593 return object;
1594 }
1595 const normalizedPath = Array.isArray(path) ? path : path.split('.');
1596 let value = object;
1597 normalizedPath.forEach(fieldName => {
1598 value = value?.[fieldName];
1599 });
1600 return value !== undefined ? value : defaultValue;
1601 }
1602
1603 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/actions.js
1604 /**
1605 * Returns an action object used in signalling that items have been received.
1606 *
1607 * @param {Array} items Items received.
1608 * @param {?Object} edits Optional edits to reset.
1609 * @param {?Object} meta Meta information about pagination.
1610 *
1611 * @return {Object} Action object.
1612 */
1613 function receiveItems(items, edits, meta) {
1614 return {
1615 type: 'RECEIVE_ITEMS',
1616 items: Array.isArray(items) ? items : [items],
1617 persistedEdits: edits,
1618 meta
1619 };
1620 }
1621
1622 /**
1623 * Returns an action object used in signalling that entity records have been
1624 * deleted and they need to be removed from entities state.
1625 *
1626 * @param {string} kind Kind of the removed entities.
1627 * @param {string} name Name of the removed entities.
1628 * @param {Array|number|string} records Record IDs of the removed entities.
1629 * @param {boolean} invalidateCache Controls whether we want to invalidate the cache.
1630 * @return {Object} Action object.
1631 */
1632 function removeItems(kind, name, records, invalidateCache = false) {
1633 return {
1634 type: 'REMOVE_ITEMS',
1635 itemIds: Array.isArray(records) ? records : [records],
1636 kind,
1637 name,
1638 invalidateCache
1639 };
1640 }
1641
1642 /**
1643 * Returns an action object used in signalling that queried data has been
1644 * received.
1645 *
1646 * @param {Array} items Queried items received.
1647 * @param {?Object} query Optional query object.
1648 * @param {?Object} edits Optional edits to reset.
1649 * @param {?Object} meta Meta information about pagination.
1650 *
1651 * @return {Object} Action object.
1652 */
1653 function receiveQueriedItems(items, query = {}, edits, meta) {
1654 return {
1655 ...receiveItems(items, edits, meta),
1656 query
1657 };
1658 }
1659
1660 ;// CONCATENATED MODULE: ./packages/core-data/build-module/batch/default-processor.js
1661 /**
1662 * WordPress dependencies
1663 */
1664
1665
1666 /**
1667 * Maximum number of requests to place in a single batch request. Obtained by
1668 * sending a preflight OPTIONS request to /batch/v1/.
1669 *
1670 * @type {number?}
1671 */
1672 let maxItems = null;
1673 function chunk(arr, chunkSize) {
1674 const tmp = [...arr];
1675 const cache = [];
1676 while (tmp.length) {
1677 cache.push(tmp.splice(0, chunkSize));
1678 }
1679 return cache;
1680 }
1681
1682 /**
1683 * Default batch processor. Sends its input requests to /batch/v1.
1684 *
1685 * @param {Array} requests List of API requests to perform at once.
1686 *
1687 * @return {Promise} Promise that resolves to a list of objects containing
1688 * either `output` (if that request was successful) or `error`
1689 * (if not ).
1690 */
1691 async function defaultProcessor(requests) {
1692 if (maxItems === null) {
1693 const preflightResponse = await external_wp_apiFetch_default()({
1694 path: '/batch/v1',
1695 method: 'OPTIONS'
1696 });
1697 maxItems = preflightResponse.endpoints[0].args.requests.maxItems;
1698 }
1699 const results = [];
1700
1701 // @ts-ignore We would have crashed or never gotten to this point if we hadn't received the maxItems count.
1702 for (const batchRequests of chunk(requests, maxItems)) {
1703 const batchResponse = await external_wp_apiFetch_default()({
1704 path: '/batch/v1',
1705 method: 'POST',
1706 data: {
1707 validation: 'require-all-validate',
1708 requests: batchRequests.map(request => ({
1709 path: request.path,
1710 body: request.data,
1711 // Rename 'data' to 'body'.
1712 method: request.method,
1713 headers: request.headers
1714 }))
1715 }
1716 });
1717 let batchResults;
1718 if (batchResponse.failed) {
1719 batchResults = batchResponse.responses.map(response => ({
1720 error: response?.body
1721 }));
1722 } else {
1723 batchResults = batchResponse.responses.map(response => {
1724 const result = {};
1725 if (response.status >= 200 && response.status < 300) {
1726 result.output = response.body;
1727 } else {
1728 result.error = response.body;
1729 }
1730 return result;
1731 });
1732 }
1733 results.push(...batchResults);
1734 }
1735 return results;
1736 }
1737
1738 ;// CONCATENATED MODULE: ./packages/core-data/build-module/batch/create-batch.js
1739 /**
1740 * Internal dependencies
1741 */
1742
1743
1744 /**
1745 * Creates a batch, which can be used to combine multiple API requests into one
1746 * API request using the WordPress batch processing API (/v1/batch).
1747 *
1748 * ```
1749 * const batch = createBatch();
1750 * const dunePromise = batch.add( {
1751 * path: '/v1/books',
1752 * method: 'POST',
1753 * data: { title: 'Dune' }
1754 * } );
1755 * const lotrPromise = batch.add( {
1756 * path: '/v1/books',
1757 * method: 'POST',
1758 * data: { title: 'Lord of the Rings' }
1759 * } );
1760 * const isSuccess = await batch.run(); // Sends one POST to /v1/batch.
1761 * if ( isSuccess ) {
1762 * console.log(
1763 * 'Saved two books:',
1764 * await dunePromise,
1765 * await lotrPromise
1766 * );
1767 * }
1768 * ```
1769 *
1770 * @param {Function} [processor] Processor function. Can be used to replace the
1771 * default functionality which is to send an API
1772 * request to /v1/batch. Is given an array of
1773 * inputs and must return a promise that
1774 * resolves to an array of objects containing
1775 * either `output` or `error`.
1776 */
1777 function createBatch(processor = defaultProcessor) {
1778 let lastId = 0;
1779 /** @type {Array<{ input: any; resolve: ( value: any ) => void; reject: ( error: any ) => void }>} */
1780 let queue = [];
1781 const pending = new ObservableSet();
1782 return {
1783 /**
1784 * Adds an input to the batch and returns a promise that is resolved or
1785 * rejected when the input is processed by `batch.run()`.
1786 *
1787 * You may also pass a thunk which allows inputs to be added
1788 * asychronously.
1789 *
1790 * ```
1791 * // Both are allowed:
1792 * batch.add( { path: '/v1/books', ... } );
1793 * batch.add( ( add ) => add( { path: '/v1/books', ... } ) );
1794 * ```
1795 *
1796 * If a thunk is passed, `batch.run()` will pause until either:
1797 *
1798 * - The thunk calls its `add` argument, or;
1799 * - The thunk returns a promise and that promise resolves, or;
1800 * - The thunk returns a non-promise.
1801 *
1802 * @param {any|Function} inputOrThunk Input to add or thunk to execute.
1803 *
1804 * @return {Promise|any} If given an input, returns a promise that
1805 * is resolved or rejected when the batch is
1806 * processed. If given a thunk, returns the return
1807 * value of that thunk.
1808 */
1809 add(inputOrThunk) {
1810 const id = ++lastId;
1811 pending.add(id);
1812 const add = input => new Promise((resolve, reject) => {
1813 queue.push({
1814 input,
1815 resolve,
1816 reject
1817 });
1818 pending.delete(id);
1819 });
1820 if (typeof inputOrThunk === 'function') {
1821 return Promise.resolve(inputOrThunk(add)).finally(() => {
1822 pending.delete(id);
1823 });
1824 }
1825 return add(inputOrThunk);
1826 },
1827 /**
1828 * Runs the batch. This calls `batchProcessor` and resolves or rejects
1829 * all promises returned by `add()`.
1830 *
1831 * @return {Promise<boolean>} A promise that resolves to a boolean that is true
1832 * if the processor returned no errors.
1833 */
1834 async run() {
1835 if (pending.size) {
1836 await new Promise(resolve => {
1837 const unsubscribe = pending.subscribe(() => {
1838 if (!pending.size) {
1839 unsubscribe();
1840 resolve(undefined);
1841 }
1842 });
1843 });
1844 }
1845 let results;
1846 try {
1847 results = await processor(queue.map(({
1848 input
1849 }) => input));
1850 if (results.length !== queue.length) {
1851 throw new Error('run: Array returned by processor must be same size as input array.');
1852 }
1853 } catch (error) {
1854 for (const {
1855 reject
1856 } of queue) {
1857 reject(error);
1858 }
1859 throw error;
1860 }
1861 let isSuccess = true;
1862 results.forEach((result, key) => {
1863 const queueItem = queue[key];
1864 if (result?.error) {
1865 queueItem?.reject(result.error);
1866 isSuccess = false;
1867 } else {
1868 var _result$output;
1869 queueItem?.resolve((_result$output = result?.output) !== null && _result$output !== void 0 ? _result$output : result);
1870 }
1871 });
1872 queue = [];
1873 return isSuccess;
1874 }
1875 };
1876 }
1877 class ObservableSet {
1878 constructor(...args) {
1879 this.set = new Set(...args);
1880 this.subscribers = new Set();
1881 }
1882 get size() {
1883 return this.set.size;
1884 }
1885 add(value) {
1886 this.set.add(value);
1887 this.subscribers.forEach(subscriber => subscriber());
1888 return this;
1889 }
1890 delete(value) {
1891 const isSuccess = this.set.delete(value);
1892 this.subscribers.forEach(subscriber => subscriber());
1893 return isSuccess;
1894 }
1895 subscribe(subscriber) {
1896 this.subscribers.add(subscriber);
1897 return () => {
1898 this.subscribers.delete(subscriber);
1899 };
1900 }
1901 }
1902
1903 ;// CONCATENATED MODULE: ./packages/core-data/build-module/name.js
1904 /**
1905 * The reducer key used by core data in store registration.
1906 * This is defined in a separate file to avoid cycle-dependency
1907 *
1908 * @type {string}
1909 */
1910 const STORE_NAME = 'core';
1911
1912 ;// CONCATENATED MODULE: ./node_modules/lib0/map.js
1913 /**
1914 * Utility module to work with key-value stores.
1915 *
1916 * @module map
1917 */
1918
1919 /**
1920 * Creates a new Map instance.
1921 *
1922 * @function
1923 * @return {Map<any, any>}
1924 *
1925 * @function
1926 */
1927 const create = () => new Map()
1928
1929 /**
1930 * Copy a Map object into a fresh Map object.
1931 *
1932 * @function
1933 * @template X,Y
1934 * @param {Map<X,Y>} m
1935 * @return {Map<X,Y>}
1936 */
1937 const copy = m => {
1938 const r = create()
1939 m.forEach((v, k) => { r.set(k, v) })
1940 return r
1941 }
1942
1943 /**
1944 * Get map property. Create T if property is undefined and set T on map.
1945 *
1946 * ```js
1947 * const listeners = map.setIfUndefined(events, 'eventName', set.create)
1948 * listeners.add(listener)
1949 * ```
1950 *
1951 * @function
1952 * @template V,K
1953 * @template {Map<K,V>} MAP
1954 * @param {MAP} map
1955 * @param {K} key
1956 * @param {function():V} createT
1957 * @return {V}
1958 */
1959 const setIfUndefined = (map, key, createT) => {
1960 let set = map.get(key)
1961 if (set === undefined) {
1962 map.set(key, set = createT())
1963 }
1964 return set
1965 }
1966
1967 /**
1968 * Creates an Array and populates it with the content of all key-value pairs using the `f(value, key)` function.
1969 *
1970 * @function
1971 * @template K
1972 * @template V
1973 * @template R
1974 * @param {Map<K,V>} m
1975 * @param {function(V,K):R} f
1976 * @return {Array<R>}
1977 */
1978 const map_map = (m, f) => {
1979 const res = []
1980 for (const [key, value] of m) {
1981 res.push(f(value, key))
1982 }
1983 return res
1984 }
1985
1986 /**
1987 * Tests whether any key-value pairs pass the test implemented by `f(value, key)`.
1988 *
1989 * @todo should rename to some - similarly to Array.some
1990 *
1991 * @function
1992 * @template K
1993 * @template V
1994 * @param {Map<K,V>} m
1995 * @param {function(V,K):boolean} f
1996 * @return {boolean}
1997 */
1998 const any = (m, f) => {
1999 for (const [key, value] of m) {
2000 if (f(value, key)) {
2001 return true
2002 }
2003 }
2004 return false
2005 }
2006
2007 /**
2008 * Tests whether all key-value pairs pass the test implemented by `f(value, key)`.
2009 *
2010 * @function
2011 * @template K
2012 * @template V
2013 * @param {Map<K,V>} m
2014 * @param {function(V,K):boolean} f
2015 * @return {boolean}
2016 */
2017 const map_all = (m, f) => {
2018 for (const [key, value] of m) {
2019 if (!f(value, key)) {
2020 return false
2021 }
2022 }
2023 return true
2024 }
2025
2026 ;// CONCATENATED MODULE: ./node_modules/lib0/set.js
2027 /**
2028 * Utility module to work with sets.
2029 *
2030 * @module set
2031 */
2032
2033 const set_create = () => new Set()
2034
2035 /**
2036 * @template T
2037 * @param {Set<T>} set
2038 * @return {Array<T>}
2039 */
2040 const toArray = set => Array.from(set)
2041
2042 /**
2043 * @template T
2044 * @param {Set<T>} set
2045 * @return {T}
2046 */
2047 const first = set =>
2048 set.values().next().value || undefined
2049
2050 /**
2051 * @template T
2052 * @param {Iterable<T>} entries
2053 * @return {Set<T>}
2054 */
2055 const from = entries => new Set(entries)
2056
2057 ;// CONCATENATED MODULE: ./node_modules/lib0/array.js
2058 /**
2059 * Utility module to work with Arrays.
2060 *
2061 * @module array
2062 */
2063
2064
2065
2066 /**
2067 * Return the last element of an array. The element must exist
2068 *
2069 * @template L
2070 * @param {ArrayLike<L>} arr
2071 * @return {L}
2072 */
2073 const last = arr => arr[arr.length - 1]
2074
2075 /**
2076 * @template C
2077 * @return {Array<C>}
2078 */
2079 const array_create = () => /** @type {Array<C>} */ ([])
2080
2081 /**
2082 * @template D
2083 * @param {Array<D>} a
2084 * @return {Array<D>}
2085 */
2086 const array_copy = a => /** @type {Array<D>} */ (a.slice())
2087
2088 /**
2089 * Append elements from src to dest
2090 *
2091 * @template M
2092 * @param {Array<M>} dest
2093 * @param {Array<M>} src
2094 */
2095 const appendTo = (dest, src) => {
2096 for (let i = 0; i < src.length; i++) {
2097 dest.push(src[i])
2098 }
2099 }
2100
2101 /**
2102 * Transforms something array-like to an actual Array.
2103 *
2104 * @function
2105 * @template T
2106 * @param {ArrayLike<T>|Iterable<T>} arraylike
2107 * @return {T}
2108 */
2109 const array_from = Array.from
2110
2111 /**
2112 * True iff condition holds on every element in the Array.
2113 *
2114 * @function
2115 * @template ITEM
2116 * @template {ArrayLike<ITEM>} ARR
2117 *
2118 * @param {ARR} arr
2119 * @param {function(ITEM, number, ARR):boolean} f
2120 * @return {boolean}
2121 */
2122 const every = (arr, f) => {
2123 for (let i = 0; i < arr.length; i++) {
2124 if (!f(arr[i], i, arr)) {
2125 return false
2126 }
2127 }
2128 return true
2129 }
2130
2131 /**
2132 * True iff condition holds on some element in the Array.
2133 *
2134 * @function
2135 * @template S
2136 * @template {ArrayLike<S>} ARR
2137 * @param {ARR} arr
2138 * @param {function(S, number, ARR):boolean} f
2139 * @return {boolean}
2140 */
2141 const some = (arr, f) => {
2142 for (let i = 0; i < arr.length; i++) {
2143 if (f(arr[i], i, arr)) {
2144 return true
2145 }
2146 }
2147 return false
2148 }
2149
2150 /**
2151 * @template ELEM
2152 *
2153 * @param {ArrayLike<ELEM>} a
2154 * @param {ArrayLike<ELEM>} b
2155 * @return {boolean}
2156 */
2157 const equalFlat = (a, b) => a.length === b.length && every(a, (item, index) => item === b[index])
2158
2159 /**
2160 * @template ELEM
2161 * @param {Array<Array<ELEM>>} arr
2162 * @return {Array<ELEM>}
2163 */
2164 const flatten = arr => fold(arr, /** @type {Array<ELEM>} */ ([]), (acc, val) => acc.concat(val))
2165
2166 /**
2167 * @template T
2168 * @param {number} len
2169 * @param {function(number, Array<T>):T} f
2170 * @return {Array<T>}
2171 */
2172 const unfold = (len, f) => {
2173 const array = new Array(len)
2174 for (let i = 0; i < len; i++) {
2175 array[i] = f(i, array)
2176 }
2177 return array
2178 }
2179
2180 /**
2181 * @template T
2182 * @template RESULT
2183 * @param {Array<T>} arr
2184 * @param {RESULT} seed
2185 * @param {function(RESULT, T, number):RESULT} folder
2186 */
2187 const fold = (arr, seed, folder) => arr.reduce(folder, seed)
2188
2189 const isArray = Array.isArray
2190
2191 /**
2192 * @template T
2193 * @param {Array<T>} arr
2194 * @return {Array<T>}
2195 */
2196 const unique = arr => array_from(set.from(arr))
2197
2198 /**
2199 * @template T
2200 * @template M
2201 * @param {ArrayLike<T>} arr
2202 * @param {function(T):M} mapper
2203 * @return {Array<T>}
2204 */
2205 const uniqueBy = (arr, mapper) => {
2206 /**
2207 * @type {Set<M>}
2208 */
2209 const happened = set.create()
2210 /**
2211 * @type {Array<T>}
2212 */
2213 const result = []
2214 for (let i = 0; i < arr.length; i++) {
2215 const el = arr[i]
2216 const mapped = mapper(el)
2217 if (!happened.has(mapped)) {
2218 happened.add(mapped)
2219 result.push(el)
2220 }
2221 }
2222 return result
2223 }
2224
2225 /**
2226 * @template {ArrayLike<any>} ARR
2227 * @template {function(ARR extends ArrayLike<infer T> ? T : never, number, ARR):any} MAPPER
2228 * @param {ARR} arr
2229 * @param {MAPPER} mapper
2230 * @return {Array<MAPPER extends function(...any): infer M ? M : never>}
2231 */
2232 const array_map = (arr, mapper) => {
2233 /**
2234 * @type {Array<any>}
2235 */
2236 const res = Array(arr.length)
2237 for (let i = 0; i < arr.length; i++) {
2238 res[i] = mapper(/** @type {any} */ (arr[i]), i, /** @type {any} */ (arr))
2239 }
2240 return /** @type {any} */ (res)
2241 }
2242
2243 ;// CONCATENATED MODULE: ./node_modules/lib0/observable.js
2244 /**
2245 * Observable class prototype.
2246 *
2247 * @module observable
2248 */
2249
2250
2251
2252
2253
2254 /**
2255 * Handles named events.
2256 *
2257 * @template N
2258 */
2259 class observable_Observable {
2260 constructor () {
2261 /**
2262 * Some desc.
2263 * @type {Map<N, any>}
2264 */
2265 this._observers = create()
2266 }
2267
2268 /**
2269 * @param {N} name
2270 * @param {function} f
2271 */
2272 on (name, f) {
2273 setIfUndefined(this._observers, name, set_create).add(f)
2274 }
2275
2276 /**
2277 * @param {N} name
2278 * @param {function} f
2279 */
2280 once (name, f) {
2281 /**
2282 * @param {...any} args
2283 */
2284 const _f = (...args) => {
2285 this.off(name, _f)
2286 f(...args)
2287 }
2288 this.on(name, _f)
2289 }
2290
2291 /**
2292 * @param {N} name
2293 * @param {function} f
2294 */
2295 off (name, f) {
2296 const observers = this._observers.get(name)
2297 if (observers !== undefined) {
2298 observers.delete(f)
2299 if (observers.size === 0) {
2300 this._observers.delete(name)
2301 }
2302 }
2303 }
2304
2305 /**
2306 * Emit a named event. All registered event listeners that listen to the
2307 * specified name will receive the event.
2308 *
2309 * @todo This should catch exceptions
2310 *
2311 * @param {N} name The event name.
2312 * @param {Array<any>} args The arguments that are applied to the event listener.
2313 */
2314 emit (name, args) {
2315 // 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.
2316 return array_from((this._observers.get(name) || create()).values()).forEach(f => f(...args))
2317 }
2318
2319 destroy () {
2320 this._observers = create()
2321 }
2322 }
2323
2324 ;// CONCATENATED MODULE: ./node_modules/lib0/math.js
2325 /**
2326 * Common Math expressions.
2327 *
2328 * @module math
2329 */
2330
2331 const floor = Math.floor
2332 const ceil = Math.ceil
2333 const abs = Math.abs
2334 const imul = Math.imul
2335 const round = Math.round
2336 const log10 = Math.log10
2337 const log2 = Math.log2
2338 const log = Math.log
2339 const sqrt = Math.sqrt
2340
2341 /**
2342 * @function
2343 * @param {number} a
2344 * @param {number} b
2345 * @return {number} The sum of a and b
2346 */
2347 const add = (a, b) => a + b
2348
2349 /**
2350 * @function
2351 * @param {number} a
2352 * @param {number} b
2353 * @return {number} The smaller element of a and b
2354 */
2355 const min = (a, b) => a < b ? a : b
2356
2357 /**
2358 * @function
2359 * @param {number} a
2360 * @param {number} b
2361 * @return {number} The bigger element of a and b
2362 */
2363 const max = (a, b) => a > b ? a : b
2364
2365 const math_isNaN = Number.isNaN
2366
2367 const pow = Math.pow
2368 /**
2369 * Base 10 exponential function. Returns the value of 10 raised to the power of pow.
2370 *
2371 * @param {number} exp
2372 * @return {number}
2373 */
2374 const exp10 = exp => Math.pow(10, exp)
2375
2376 const sign = Math.sign
2377
2378 /**
2379 * @param {number} n
2380 * @return {boolean} Wether n is negative. This function also differentiates between -0 and +0
2381 */
2382 const isNegativeZero = n => n !== 0 ? n < 0 : 1 / n < 0
2383
2384 ;// CONCATENATED MODULE: ./node_modules/lib0/string.js
2385
2386
2387 /**
2388 * Utility module to work with strings.
2389 *
2390 * @module string
2391 */
2392
2393 const fromCharCode = String.fromCharCode
2394 const fromCodePoint = String.fromCodePoint
2395
2396 /**
2397 * The largest utf16 character.
2398 * Corresponds to Uint8Array([255, 255]) or charcodeof(2x2^8)
2399 */
2400 const MAX_UTF16_CHARACTER = fromCharCode(65535)
2401
2402 /**
2403 * @param {string} s
2404 * @return {string}
2405 */
2406 const toLowerCase = s => s.toLowerCase()
2407
2408 const trimLeftRegex = /^\s*/g
2409
2410 /**
2411 * @param {string} s
2412 * @return {string}
2413 */
2414 const trimLeft = s => s.replace(trimLeftRegex, '')
2415
2416 const fromCamelCaseRegex = /([A-Z])/g
2417
2418 /**
2419 * @param {string} s
2420 * @param {string} separator
2421 * @return {string}
2422 */
2423 const fromCamelCase = (s, separator) => trimLeft(s.replace(fromCamelCaseRegex, match => `${separator}${toLowerCase(match)}`))
2424
2425 /**
2426 * Compute the utf8ByteLength
2427 * @param {string} str
2428 * @return {number}
2429 */
2430 const utf8ByteLength = str => unescape(encodeURIComponent(str)).length
2431
2432 /**
2433 * @param {string} str
2434 * @return {Uint8Array}
2435 */
2436 const _encodeUtf8Polyfill = str => {
2437 const encodedString = unescape(encodeURIComponent(str))
2438 const len = encodedString.length
2439 const buf = new Uint8Array(len)
2440 for (let i = 0; i < len; i++) {
2441 buf[i] = /** @type {number} */ (encodedString.codePointAt(i))
2442 }
2443 return buf
2444 }
2445
2446 /* c8 ignore next */
2447 const utf8TextEncoder = /** @type {TextEncoder} */ (typeof TextEncoder !== 'undefined' ? new TextEncoder() : null)
2448
2449 /**
2450 * @param {string} str
2451 * @return {Uint8Array}
2452 */
2453 const _encodeUtf8Native = str => utf8TextEncoder.encode(str)
2454
2455 /**
2456 * @param {string} str
2457 * @return {Uint8Array}
2458 */
2459 /* c8 ignore next */
2460 const encodeUtf8 = utf8TextEncoder ? _encodeUtf8Native : _encodeUtf8Polyfill
2461
2462 /**
2463 * @param {Uint8Array} buf
2464 * @return {string}
2465 */
2466 const _decodeUtf8Polyfill = buf => {
2467 let remainingLen = buf.length
2468 let encodedString = ''
2469 let bufPos = 0
2470 while (remainingLen > 0) {
2471 const nextLen = remainingLen < 10000 ? remainingLen : 10000
2472 const bytes = buf.subarray(bufPos, bufPos + nextLen)
2473 bufPos += nextLen
2474 // Starting with ES5.1 we can supply a generic array-like object as arguments
2475 encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes))
2476 remainingLen -= nextLen
2477 }
2478 return decodeURIComponent(escape(encodedString))
2479 }
2480
2481 /* c8 ignore next */
2482 let utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf-8', { fatal: true, ignoreBOM: true })
2483
2484 /* c8 ignore start */
2485 if (utf8TextDecoder && utf8TextDecoder.decode(new Uint8Array()).length === 1) {
2486 // Safari doesn't handle BOM correctly.
2487 // This fixes a bug in Safari 13.0.5 where it produces a BOM the first time it is called.
2488 // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the first call and
2489 // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the second call
2490 // Another issue is that from then on no BOM chars are recognized anymore
2491 /* c8 ignore next */
2492 utf8TextDecoder = null
2493 }
2494 /* c8 ignore stop */
2495
2496 /**
2497 * @param {Uint8Array} buf
2498 * @return {string}
2499 */
2500 const _decodeUtf8Native = buf => /** @type {TextDecoder} */ (utf8TextDecoder).decode(buf)
2501
2502 /**
2503 * @param {Uint8Array} buf
2504 * @return {string}
2505 */
2506 /* c8 ignore next */
2507 const decodeUtf8 = (/* unused pure expression or super */ null && (utf8TextDecoder ? _decodeUtf8Native : _decodeUtf8Polyfill))
2508
2509 /**
2510 * @param {string} str The initial string
2511 * @param {number} index Starting position
2512 * @param {number} remove Number of characters to remove
2513 * @param {string} insert New content to insert
2514 */
2515 const splice = (str, index, remove, insert = '') => str.slice(0, index) + insert + str.slice(index + remove)
2516
2517 /**
2518 * @param {string} source
2519 * @param {number} n
2520 */
2521 const repeat = (source, n) => array.unfold(n, () => source).join('')
2522
2523 ;// CONCATENATED MODULE: ./node_modules/lib0/conditions.js
2524 /**
2525 * Often used conditions.
2526 *
2527 * @module conditions
2528 */
2529
2530 /**
2531 * @template T
2532 * @param {T|null|undefined} v
2533 * @return {T|null}
2534 */
2535 /* c8 ignore next */
2536 const undefinedToNull = v => v === undefined ? null : v
2537
2538 ;// CONCATENATED MODULE: ./node_modules/lib0/storage.js
2539 /* eslint-env browser */
2540
2541 /**
2542 * Isomorphic variable storage.
2543 *
2544 * Uses LocalStorage in the browser and falls back to in-memory storage.
2545 *
2546 * @module storage
2547 */
2548
2549 /* c8 ignore start */
2550 class VarStoragePolyfill {
2551 constructor () {
2552 this.map = new Map()
2553 }
2554
2555 /**
2556 * @param {string} key
2557 * @param {any} newValue
2558 */
2559 setItem (key, newValue) {
2560 this.map.set(key, newValue)
2561 }
2562
2563 /**
2564 * @param {string} key
2565 */
2566 getItem (key) {
2567 return this.map.get(key)
2568 }
2569 }
2570 /* c8 ignore stop */
2571
2572 /**
2573 * @type {any}
2574 */
2575 let _localStorage = new VarStoragePolyfill()
2576 let usePolyfill = true
2577
2578 /* c8 ignore start */
2579 try {
2580 // if the same-origin rule is violated, accessing localStorage might thrown an error
2581 if (typeof localStorage !== 'undefined') {
2582 _localStorage = localStorage
2583 usePolyfill = false
2584 }
2585 } catch (e) { }
2586 /* c8 ignore stop */
2587
2588 /**
2589 * This is basically localStorage in browser, or a polyfill in nodejs
2590 */
2591 /* c8 ignore next */
2592 const varStorage = _localStorage
2593
2594 /**
2595 * A polyfill for `addEventListener('storage', event => {..})` that does nothing if the polyfill is being used.
2596 *
2597 * @param {function({ key: string, newValue: string, oldValue: string }): void} eventHandler
2598 * @function
2599 */
2600 /* c8 ignore next */
2601 const onChange = eventHandler => usePolyfill || addEventListener('storage', /** @type {any} */ (eventHandler))
2602
2603 /**
2604 * A polyfill for `removeEventListener('storage', event => {..})` that does nothing if the polyfill is being used.
2605 *
2606 * @param {function({ key: string, newValue: string, oldValue: string }): void} eventHandler
2607 * @function
2608 */
2609 /* c8 ignore next */
2610 const offChange = eventHandler => usePolyfill || removeEventListener('storage', /** @type {any} */ (eventHandler))
2611
2612 ;// CONCATENATED MODULE: ./node_modules/lib0/object.js
2613 /**
2614 * Utility functions for working with EcmaScript objects.
2615 *
2616 * @module object
2617 */
2618
2619 /**
2620 * @return {Object<string,any>} obj
2621 */
2622 const object_create = () => Object.create(null)
2623
2624 /**
2625 * Object.assign
2626 */
2627 const object_assign = Object.assign
2628
2629 /**
2630 * @param {Object<string,any>} obj
2631 */
2632 const keys = Object.keys
2633
2634 /**
2635 * @template V
2636 * @param {{[k:string]:V}} obj
2637 * @param {function(V,string):any} f
2638 */
2639 const forEach = (obj, f) => {
2640 for (const key in obj) {
2641 f(obj[key], key)
2642 }
2643 }
2644
2645 /**
2646 * @todo implement mapToArray & map
2647 *
2648 * @template R
2649 * @param {Object<string,any>} obj
2650 * @param {function(any,string):R} f
2651 * @return {Array<R>}
2652 */
2653 const object_map = (obj, f) => {
2654 const results = []
2655 for (const key in obj) {
2656 results.push(f(obj[key], key))
2657 }
2658 return results
2659 }
2660
2661 /**
2662 * @param {Object<string,any>} obj
2663 * @return {number}
2664 */
2665 const object_length = obj => keys(obj).length
2666
2667 /**
2668 * @param {Object<string,any>} obj
2669 * @param {function(any,string):boolean} f
2670 * @return {boolean}
2671 */
2672 const object_some = (obj, f) => {
2673 for (const key in obj) {
2674 if (f(obj[key], key)) {
2675 return true
2676 }
2677 }
2678 return false
2679 }
2680
2681 /**
2682 * @param {Object|undefined} obj
2683 */
2684 const isEmpty = obj => {
2685 // eslint-disable-next-line
2686 for (const _k in obj) {
2687 return false
2688 }
2689 return true
2690 }
2691
2692 /**
2693 * @param {Object<string,any>} obj
2694 * @param {function(any,string):boolean} f
2695 * @return {boolean}
2696 */
2697 const object_every = (obj, f) => {
2698 for (const key in obj) {
2699 if (!f(obj[key], key)) {
2700 return false
2701 }
2702 }
2703 return true
2704 }
2705
2706 /**
2707 * Calls `Object.prototype.hasOwnProperty`.
2708 *
2709 * @param {any} obj
2710 * @param {string|symbol} key
2711 * @return {boolean}
2712 */
2713 const hasProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key)
2714
2715 /**
2716 * @param {Object<string,any>} a
2717 * @param {Object<string,any>} b
2718 * @return {boolean}
2719 */
2720 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))
2721
2722 ;// CONCATENATED MODULE: ./node_modules/lib0/function.js
2723 /**
2724 * Common functions and function call helpers.
2725 *
2726 * @module function
2727 */
2728
2729
2730
2731
2732 /**
2733 * Calls all functions in `fs` with args. Only throws after all functions were called.
2734 *
2735 * @param {Array<function>} fs
2736 * @param {Array<any>} args
2737 */
2738 const callAll = (fs, args, i = 0) => {
2739 try {
2740 for (; i < fs.length; i++) {
2741 fs[i](...args)
2742 }
2743 } finally {
2744 if (i < fs.length) {
2745 callAll(fs, args, i + 1)
2746 }
2747 }
2748 }
2749
2750 const nop = () => {}
2751
2752 /**
2753 * @template T
2754 * @param {function():T} f
2755 * @return {T}
2756 */
2757 const apply = f => f()
2758
2759 /**
2760 * @template A
2761 *
2762 * @param {A} a
2763 * @return {A}
2764 */
2765 const id = a => a
2766
2767 /**
2768 * @template T
2769 *
2770 * @param {T} a
2771 * @param {T} b
2772 * @return {boolean}
2773 */
2774 const equalityStrict = (a, b) => a === b
2775
2776 /**
2777 * @template T
2778 *
2779 * @param {Array<T>|object} a
2780 * @param {Array<T>|object} b
2781 * @return {boolean}
2782 */
2783 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))))
2784
2785 /* c8 ignore start */
2786
2787 /**
2788 * @param {any} a
2789 * @param {any} b
2790 * @return {boolean}
2791 */
2792 const equalityDeep = (a, b) => {
2793 if (a == null || b == null) {
2794 return equalityStrict(a, b)
2795 }
2796 if (a.constructor !== b.constructor) {
2797 return false
2798 }
2799 if (a === b) {
2800 return true
2801 }
2802 switch (a.constructor) {
2803 case ArrayBuffer:
2804 a = new Uint8Array(a)
2805 b = new Uint8Array(b)
2806 // eslint-disable-next-line no-fallthrough
2807 case Uint8Array: {
2808 if (a.byteLength !== b.byteLength) {
2809 return false
2810 }
2811 for (let i = 0; i < a.length; i++) {
2812 if (a[i] !== b[i]) {
2813 return false
2814 }
2815 }
2816 break
2817 }
2818 case Set: {
2819 if (a.size !== b.size) {
2820 return false
2821 }
2822 for (const value of a) {
2823 if (!b.has(value)) {
2824 return false
2825 }
2826 }
2827 break
2828 }
2829 case Map: {
2830 if (a.size !== b.size) {
2831 return false
2832 }
2833 for (const key of a.keys()) {
2834 if (!b.has(key) || !equalityDeep(a.get(key), b.get(key))) {
2835 return false
2836 }
2837 }
2838 break
2839 }
2840 case Object:
2841 if (object_length(a) !== object_length(b)) {
2842 return false
2843 }
2844 for (const key in a) {
2845 if (!hasProperty(a, key) || !equalityDeep(a[key], b[key])) {
2846 return false
2847 }
2848 }
2849 break
2850 case Array:
2851 if (a.length !== b.length) {
2852 return false
2853 }
2854 for (let i = 0; i < a.length; i++) {
2855 if (!equalityDeep(a[i], b[i])) {
2856 return false
2857 }
2858 }
2859 break
2860 default:
2861 return false
2862 }
2863 return true
2864 }
2865
2866 /**
2867 * @template V
2868 * @template {V} OPTS
2869 *
2870 * @param {V} value
2871 * @param {Array<OPTS>} options
2872 */
2873 // @ts-ignore
2874 const isOneOf = (value, options) => options.includes(value)
2875 /* c8 ignore stop */
2876
2877 const function_isArray = isArray
2878
2879 /**
2880 * @param {any} s
2881 * @return {s is String}
2882 */
2883 const isString = (s) => s && s.constructor === String
2884
2885 /**
2886 * @param {any} n
2887 * @return {n is Number}
2888 */
2889 const isNumber = n => n != null && n.constructor === Number
2890
2891 /**
2892 * @template {abstract new (...args: any) => any} TYPE
2893 * @param {any} n
2894 * @param {TYPE} T
2895 * @return {n is InstanceType<TYPE>}
2896 */
2897 const is = (n, T) => n && n.constructor === T
2898
2899 /**
2900 * @template {abstract new (...args: any) => any} TYPE
2901 * @param {TYPE} T
2902 */
2903 const isTemplate = (T) =>
2904 /**
2905 * @param {any} n
2906 * @return {n is InstanceType<TYPE>}
2907 **/
2908 n => n && n.constructor === T
2909
2910 ;// CONCATENATED MODULE: ./node_modules/lib0/environment.js
2911 /**
2912 * Isomorphic module to work access the environment (query params, env variables).
2913 *
2914 * @module map
2915 */
2916
2917
2918
2919
2920
2921
2922
2923 /* c8 ignore next */
2924 // @ts-ignore
2925 const isNode = typeof process !== 'undefined' && process.release &&
2926 /node|io\.js/.test(process.release.name)
2927 /* c8 ignore next */
2928 const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && !isNode
2929 /* c8 ignore next 3 */
2930 const isMac = typeof navigator !== 'undefined'
2931 ? /Mac/.test(navigator.platform)
2932 : false
2933
2934 /**
2935 * @type {Map<string,string>}
2936 */
2937 let params
2938 const args = []
2939
2940 /* c8 ignore start */
2941 const computeParams = () => {
2942 if (params === undefined) {
2943 if (isNode) {
2944 params = create()
2945 const pargs = process.argv
2946 let currParamName = null
2947 for (let i = 0; i < pargs.length; i++) {
2948 const parg = pargs[i]
2949 if (parg[0] === '-') {
2950 if (currParamName !== null) {
2951 params.set(currParamName, '')
2952 }
2953 currParamName = parg
2954 } else {
2955 if (currParamName !== null) {
2956 params.set(currParamName, parg)
2957 currParamName = null
2958 } else {
2959 args.push(parg)
2960 }
2961 }
2962 }
2963 if (currParamName !== null) {
2964 params.set(currParamName, '')
2965 }
2966 // in ReactNative for example this would not be true (unless connected to the Remote Debugger)
2967 } else if (typeof location === 'object') {
2968 params = create(); // eslint-disable-next-line no-undef
2969 (location.search || '?').slice(1).split('&').forEach((kv) => {
2970 if (kv.length !== 0) {
2971 const [key, value] = kv.split('=')
2972 params.set(`--${fromCamelCase(key, '-')}`, value)
2973 params.set(`-${fromCamelCase(key, '-')}`, value)
2974 }
2975 })
2976 } else {
2977 params = create()
2978 }
2979 }
2980 return params
2981 }
2982 /* c8 ignore stop */
2983
2984 /**
2985 * @param {string} name
2986 * @return {boolean}
2987 */
2988 /* c8 ignore next */
2989 const hasParam = (name) => computeParams().has(name)
2990
2991 /**
2992 * @param {string} name
2993 * @param {string} defaultVal
2994 * @return {string}
2995 */
2996 /* c8 ignore next 2 */
2997 const getParam = (name, defaultVal) =>
2998 computeParams().get(name) || defaultVal
2999
3000 /**
3001 * @param {string} name
3002 * @return {string|null}
3003 */
3004 /* c8 ignore next 4 */
3005 const getVariable = (name) =>
3006 isNode
3007 ? undefinedToNull(process.env[name.toUpperCase()])
3008 : undefinedToNull(varStorage.getItem(name))
3009
3010 /**
3011 * @param {string} name
3012 * @return {string|null}
3013 */
3014 /* c8 ignore next 2 */
3015 const getConf = (name) =>
3016 computeParams().get('--' + name) || getVariable(name)
3017
3018 /**
3019 * @param {string} name
3020 * @return {boolean}
3021 */
3022 /* c8 ignore next 2 */
3023 const hasConf = (name) =>
3024 hasParam('--' + name) || getVariable(name) !== null
3025
3026 /* c8 ignore next */
3027 const production = hasConf('production')
3028
3029 /* c8 ignore next 2 */
3030 const forceColor = isNode &&
3031 isOneOf(process.env.FORCE_COLOR, ['true', '1', '2'])
3032
3033 /* c8 ignore start */
3034 const supportsColor = !hasParam('no-colors') &&
3035 (!isNode || process.stdout.isTTY || forceColor) && (
3036 !isNode || hasParam('color') || forceColor ||
3037 getVariable('COLORTERM') !== null ||
3038 (getVariable('TERM') || '').includes('color')
3039 )
3040 /* c8 ignore stop */
3041
3042 ;// CONCATENATED MODULE: ./node_modules/lib0/buffer.js
3043 /**
3044 * Utility functions to work with buffers (Uint8Array).
3045 *
3046 * @module buffer
3047 */
3048
3049
3050
3051
3052
3053
3054
3055
3056 /**
3057 * @param {number} len
3058 */
3059 const createUint8ArrayFromLen = len => new Uint8Array(len)
3060
3061 /**
3062 * Create Uint8Array with initial content from buffer
3063 *
3064 * @param {ArrayBuffer} buffer
3065 * @param {number} byteOffset
3066 * @param {number} length
3067 */
3068 const createUint8ArrayViewFromArrayBuffer = (buffer, byteOffset, length) => new Uint8Array(buffer, byteOffset, length)
3069
3070 /**
3071 * Create Uint8Array with initial content from buffer
3072 *
3073 * @param {ArrayBuffer} buffer
3074 */
3075 const createUint8ArrayFromArrayBuffer = buffer => new Uint8Array(buffer)
3076
3077 /* c8 ignore start */
3078 /**
3079 * @param {Uint8Array} bytes
3080 * @return {string}
3081 */
3082 const toBase64Browser = bytes => {
3083 let s = ''
3084 for (let i = 0; i < bytes.byteLength; i++) {
3085 s += fromCharCode(bytes[i])
3086 }
3087 // eslint-disable-next-line no-undef
3088 return btoa(s)
3089 }
3090 /* c8 ignore stop */
3091
3092 /**
3093 * @param {Uint8Array} bytes
3094 * @return {string}
3095 */
3096 const toBase64Node = bytes => Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64')
3097
3098 /* c8 ignore start */
3099 /**
3100 * @param {string} s
3101 * @return {Uint8Array}
3102 */
3103 const fromBase64Browser = s => {
3104 // eslint-disable-next-line no-undef
3105 const a = atob(s)
3106 const bytes = createUint8ArrayFromLen(a.length)
3107 for (let i = 0; i < a.length; i++) {
3108 bytes[i] = a.charCodeAt(i)
3109 }
3110 return bytes
3111 }
3112 /* c8 ignore stop */
3113
3114 /**
3115 * @param {string} s
3116 */
3117 const fromBase64Node = s => {
3118 const buf = Buffer.from(s, 'base64')
3119 return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)
3120 }
3121
3122 /* c8 ignore next */
3123 const toBase64 = isBrowser ? toBase64Browser : toBase64Node
3124
3125 /* c8 ignore next */
3126 const fromBase64 = isBrowser ? fromBase64Browser : fromBase64Node
3127
3128 /**
3129 * Base64 is always a more efficient choice. This exists for utility purposes only.
3130 *
3131 * @param {Uint8Array} buf
3132 */
3133 const toHexString = buf => array.map(buf, b => b.toString(16).padStart(2, '0')).join('')
3134
3135 /**
3136 * Note: This function expects that the hex doesn't start with 0x..
3137 *
3138 * @param {string} hex
3139 */
3140 const fromHexString = hex => {
3141 const hlen = hex.length
3142 const buf = new Uint8Array(math.ceil(hlen / 2))
3143 for (let i = 0; i < hlen; i += 2) {
3144 buf[buf.length - i / 2 - 1] = Number.parseInt(hex.slice(hlen - i - 2, hlen - i), 16)
3145 }
3146 return buf
3147 }
3148
3149 /**
3150 * Copy the content of an Uint8Array view to a new ArrayBuffer.
3151 *
3152 * @param {Uint8Array} uint8Array
3153 * @return {Uint8Array}
3154 */
3155 const copyUint8Array = uint8Array => {
3156 const newBuf = createUint8ArrayFromLen(uint8Array.byteLength)
3157 newBuf.set(uint8Array)
3158 return newBuf
3159 }
3160
3161 /**
3162 * Encode anything as a UInt8Array. It's a pun on typescripts's `any` type.
3163 * See encoding.writeAny for more information.
3164 *
3165 * @param {any} data
3166 * @return {Uint8Array}
3167 */
3168 const encodeAny = data => {
3169 const encoder = encoding.createEncoder()
3170 encoding.writeAny(encoder, data)
3171 return encoding.toUint8Array(encoder)
3172 }
3173
3174 /**
3175 * Decode an any-encoded value.
3176 *
3177 * @param {Uint8Array} buf
3178 * @return {any}
3179 */
3180 const decodeAny = buf => decoding.readAny(decoding.createDecoder(buf))
3181
3182 /**
3183 * Shift Byte Array {N} bits to the left. Does not expand byte array.
3184 *
3185 * @param {Uint8Array} bs
3186 * @param {number} N should be in the range of [0-7]
3187 */
3188 const shiftNBitsLeft = (bs, N) => {
3189 if (N === 0) return bs
3190 bs = new Uint8Array(bs)
3191 bs[0] <<= N
3192 for (let i = 1; i < bs.length; i++) {
3193 bs[i - 1] |= bs[i] >>> (8 - N)
3194 bs[i] <<= N
3195 }
3196 return bs
3197 }
3198
3199 ;// CONCATENATED MODULE: ./node_modules/lib0/binary.js
3200 /* eslint-env browser */
3201
3202 /**
3203 * Binary data constants.
3204 *
3205 * @module binary
3206 */
3207
3208 /**
3209 * n-th bit activated.
3210 *
3211 * @type {number}
3212 */
3213 const BIT1 = 1
3214 const BIT2 = 2
3215 const BIT3 = 4
3216 const BIT4 = 8
3217 const BIT5 = 16
3218 const BIT6 = 32
3219 const BIT7 = 64
3220 const BIT8 = 128
3221 const BIT9 = 256
3222 const BIT10 = 512
3223 const BIT11 = 1024
3224 const BIT12 = 2048
3225 const BIT13 = 4096
3226 const BIT14 = 8192
3227 const BIT15 = 16384
3228 const BIT16 = 32768
3229 const BIT17 = 65536
3230 const BIT18 = 1 << 17
3231 const BIT19 = 1 << 18
3232 const BIT20 = 1 << 19
3233 const BIT21 = 1 << 20
3234 const BIT22 = 1 << 21
3235 const BIT23 = 1 << 22
3236 const BIT24 = 1 << 23
3237 const BIT25 = 1 << 24
3238 const BIT26 = 1 << 25
3239 const BIT27 = 1 << 26
3240 const BIT28 = 1 << 27
3241 const BIT29 = 1 << 28
3242 const BIT30 = 1 << 29
3243 const BIT31 = 1 << 30
3244 const BIT32 = (/* unused pure expression or super */ null && (1 << 31))
3245
3246 /**
3247 * First n bits activated.
3248 *
3249 * @type {number}
3250 */
3251 const BITS0 = 0
3252 const BITS1 = 1
3253 const BITS2 = 3
3254 const BITS3 = 7
3255 const BITS4 = 15
3256 const BITS5 = 31
3257 const BITS6 = 63
3258 const BITS7 = 127
3259 const BITS8 = 255
3260 const BITS9 = 511
3261 const BITS10 = 1023
3262 const BITS11 = 2047
3263 const BITS12 = 4095
3264 const BITS13 = 8191
3265 const BITS14 = 16383
3266 const BITS15 = 32767
3267 const BITS16 = 65535
3268 const BITS17 = BIT18 - 1
3269 const BITS18 = BIT19 - 1
3270 const BITS19 = BIT20 - 1
3271 const BITS20 = BIT21 - 1
3272 const BITS21 = BIT22 - 1
3273 const BITS22 = BIT23 - 1
3274 const BITS23 = BIT24 - 1
3275 const BITS24 = BIT25 - 1
3276 const BITS25 = BIT26 - 1
3277 const BITS26 = BIT27 - 1
3278 const BITS27 = BIT28 - 1
3279 const BITS28 = BIT29 - 1
3280 const BITS29 = BIT30 - 1
3281 const BITS30 = BIT31 - 1
3282 /**
3283 * @type {number}
3284 */
3285 const BITS31 = 0x7FFFFFFF
3286 /**
3287 * @type {number}
3288 */
3289 const BITS32 = 0xFFFFFFFF
3290
3291 ;// CONCATENATED MODULE: ./node_modules/lib0/number.js
3292 /**
3293 * Utility helpers for working with numbers.
3294 *
3295 * @module number
3296 */
3297
3298
3299
3300
3301 const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER
3302 const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER
3303
3304 const LOWEST_INT32 = (/* unused pure expression or super */ null && (1 << 31))
3305 const HIGHEST_INT32 = BITS31
3306 const HIGHEST_UINT32 = BITS32
3307
3308 /* c8 ignore next */
3309 const isInteger = Number.isInteger || (num => typeof num === 'number' && isFinite(num) && floor(num) === num)
3310 const number_isNaN = Number.isNaN
3311 const number_parseInt = Number.parseInt
3312
3313 /**
3314 * Count the number of "1" bits in an unsigned 32bit number.
3315 *
3316 * Super fun bitcount algorithm by Brian Kernighan.
3317 *
3318 * @param {number} n
3319 */
3320 const countBits = n => {
3321 n &= binary.BITS32
3322 let count = 0
3323 while (n) {
3324 n &= (n - 1)
3325 count++
3326 }
3327 return count
3328 }
3329
3330 ;// CONCATENATED MODULE: ./node_modules/lib0/encoding.js
3331 /**
3332 * Efficient schema-less binary encoding with support for variable length encoding.
3333 *
3334 * Use [lib0/encoding] with [lib0/decoding]. Every encoding function has a corresponding decoding function.
3335 *
3336 * Encodes numbers in little-endian order (least to most significant byte order)
3337 * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
3338 * which is also used in Protocol Buffers.
3339 *
3340 * ```js
3341 * // encoding step
3342 * const encoder = encoding.createEncoder()
3343 * encoding.writeVarUint(encoder, 256)
3344 * encoding.writeVarString(encoder, 'Hello world!')
3345 * const buf = encoding.toUint8Array(encoder)
3346 * ```
3347 *
3348 * ```js
3349 * // decoding step
3350 * const decoder = decoding.createDecoder(buf)
3351 * decoding.readVarUint(decoder) // => 256
3352 * decoding.readVarString(decoder) // => 'Hello world!'
3353 * decoding.hasContent(decoder) // => false - all data is read
3354 * ```
3355 *
3356 * @module encoding
3357 */
3358
3359
3360
3361
3362
3363
3364
3365
3366 /**
3367 * A BinaryEncoder handles the encoding to an Uint8Array.
3368 */
3369 class Encoder {
3370 constructor () {
3371 this.cpos = 0
3372 this.cbuf = new Uint8Array(100)
3373 /**
3374 * @type {Array<Uint8Array>}
3375 */
3376 this.bufs = []
3377 }
3378 }
3379
3380 /**
3381 * @function
3382 * @return {Encoder}
3383 */
3384 const createEncoder = () => new Encoder()
3385
3386 /**
3387 * @param {function(Encoder):void} f
3388 */
3389 const encode = (f) => {
3390 const encoder = createEncoder()
3391 f(encoder)
3392 return toUint8Array(encoder)
3393 }
3394
3395 /**
3396 * The current length of the encoded data.
3397 *
3398 * @function
3399 * @param {Encoder} encoder
3400 * @return {number}
3401 */
3402 const encoding_length = encoder => {
3403 let len = encoder.cpos
3404 for (let i = 0; i < encoder.bufs.length; i++) {
3405 len += encoder.bufs[i].length
3406 }
3407 return len
3408 }
3409
3410 /**
3411 * Check whether encoder is empty.
3412 *
3413 * @function
3414 * @param {Encoder} encoder
3415 * @return {boolean}
3416 */
3417 const hasContent = encoder => encoder.cpos > 0 || encoder.bufs.length > 0
3418
3419 /**
3420 * Transform to Uint8Array.
3421 *
3422 * @function
3423 * @param {Encoder} encoder
3424 * @return {Uint8Array} The created ArrayBuffer.
3425 */
3426 const toUint8Array = encoder => {
3427 const uint8arr = new Uint8Array(encoding_length(encoder))
3428 let curPos = 0
3429 for (let i = 0; i < encoder.bufs.length; i++) {
3430 const d = encoder.bufs[i]
3431 uint8arr.set(d, curPos)
3432 curPos += d.length
3433 }
3434 uint8arr.set(createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos), curPos)
3435 return uint8arr
3436 }
3437
3438 /**
3439 * Verify that it is possible to write `len` bytes wtihout checking. If
3440 * necessary, a new Buffer with the required length is attached.
3441 *
3442 * @param {Encoder} encoder
3443 * @param {number} len
3444 */
3445 const verifyLen = (encoder, len) => {
3446 const bufferLen = encoder.cbuf.length
3447 if (bufferLen - encoder.cpos < len) {
3448 encoder.bufs.push(createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos))
3449 encoder.cbuf = new Uint8Array(max(bufferLen, len) * 2)
3450 encoder.cpos = 0
3451 }
3452 }
3453
3454 /**
3455 * Write one byte to the encoder.
3456 *
3457 * @function
3458 * @param {Encoder} encoder
3459 * @param {number} num The byte that is to be encoded.
3460 */
3461 const write = (encoder, num) => {
3462 const bufferLen = encoder.cbuf.length
3463 if (encoder.cpos === bufferLen) {
3464 encoder.bufs.push(encoder.cbuf)
3465 encoder.cbuf = new Uint8Array(bufferLen * 2)
3466 encoder.cpos = 0
3467 }
3468 encoder.cbuf[encoder.cpos++] = num
3469 }
3470
3471 /**
3472 * Write one byte at a specific position.
3473 * Position must already be written (i.e. encoder.length > pos)
3474 *
3475 * @function
3476 * @param {Encoder} encoder
3477 * @param {number} pos Position to which to write data
3478 * @param {number} num Unsigned 8-bit integer
3479 */
3480 const encoding_set = (encoder, pos, num) => {
3481 let buffer = null
3482 // iterate all buffers and adjust position
3483 for (let i = 0; i < encoder.bufs.length && buffer === null; i++) {
3484 const b = encoder.bufs[i]
3485 if (pos < b.length) {
3486 buffer = b // found buffer
3487 } else {
3488 pos -= b.length
3489 }
3490 }
3491 if (buffer === null) {
3492 // use current buffer
3493 buffer = encoder.cbuf
3494 }
3495 buffer[pos] = num
3496 }
3497
3498 /**
3499 * Write one byte as an unsigned integer.
3500 *
3501 * @function
3502 * @param {Encoder} encoder
3503 * @param {number} num The number that is to be encoded.
3504 */
3505 const writeUint8 = write
3506
3507 /**
3508 * Write one byte as an unsigned Integer at a specific location.
3509 *
3510 * @function
3511 * @param {Encoder} encoder
3512 * @param {number} pos The location where the data will be written.
3513 * @param {number} num The number that is to be encoded.
3514 */
3515 const setUint8 = (/* unused pure expression or super */ null && (encoding_set))
3516
3517 /**
3518 * Write two bytes as an unsigned integer.
3519 *
3520 * @function
3521 * @param {Encoder} encoder
3522 * @param {number} num The number that is to be encoded.
3523 */
3524 const writeUint16 = (encoder, num) => {
3525 write(encoder, num & binary.BITS8)
3526 write(encoder, (num >>> 8) & binary.BITS8)
3527 }
3528 /**
3529 * Write two bytes as an unsigned integer at a specific location.
3530 *
3531 * @function
3532 * @param {Encoder} encoder
3533 * @param {number} pos The location where the data will be written.
3534 * @param {number} num The number that is to be encoded.
3535 */
3536 const setUint16 = (encoder, pos, num) => {
3537 encoding_set(encoder, pos, num & binary.BITS8)
3538 encoding_set(encoder, pos + 1, (num >>> 8) & binary.BITS8)
3539 }
3540
3541 /**
3542 * Write two bytes as an unsigned integer
3543 *
3544 * @function
3545 * @param {Encoder} encoder
3546 * @param {number} num The number that is to be encoded.
3547 */
3548 const writeUint32 = (encoder, num) => {
3549 for (let i = 0; i < 4; i++) {
3550 write(encoder, num & binary.BITS8)
3551 num >>>= 8
3552 }
3553 }
3554
3555 /**
3556 * Write two bytes as an unsigned integer in big endian order.
3557 * (most significant byte first)
3558 *
3559 * @function
3560 * @param {Encoder} encoder
3561 * @param {number} num The number that is to be encoded.
3562 */
3563 const writeUint32BigEndian = (encoder, num) => {
3564 for (let i = 3; i >= 0; i--) {
3565 write(encoder, (num >>> (8 * i)) & binary.BITS8)
3566 }
3567 }
3568
3569 /**
3570 * Write two bytes as an unsigned integer at a specific location.
3571 *
3572 * @function
3573 * @param {Encoder} encoder
3574 * @param {number} pos The location where the data will be written.
3575 * @param {number} num The number that is to be encoded.
3576 */
3577 const setUint32 = (encoder, pos, num) => {
3578 for (let i = 0; i < 4; i++) {
3579 encoding_set(encoder, pos + i, num & binary.BITS8)
3580 num >>>= 8
3581 }
3582 }
3583
3584 /**
3585 * Write a variable length unsigned integer. Max encodable integer is 2^53.
3586 *
3587 * @function
3588 * @param {Encoder} encoder
3589 * @param {number} num The number that is to be encoded.
3590 */
3591 const writeVarUint = (encoder, num) => {
3592 while (num > BITS7) {
3593 write(encoder, BIT8 | (BITS7 & num))
3594 num = floor(num / 128) // shift >>> 7
3595 }
3596 write(encoder, BITS7 & num)
3597 }
3598
3599 /**
3600 * Write a variable length integer.
3601 *
3602 * We use the 7th bit instead for signaling that this is a negative number.
3603 *
3604 * @function
3605 * @param {Encoder} encoder
3606 * @param {number} num The number that is to be encoded.
3607 */
3608 const writeVarInt = (encoder, num) => {
3609 const isNegative = isNegativeZero(num)
3610 if (isNegative) {
3611 num = -num
3612 }
3613 // |- whether to continue reading |- whether is negative |- number
3614 write(encoder, (num > BITS6 ? BIT8 : 0) | (isNegative ? BIT7 : 0) | (BITS6 & num))
3615 num = floor(num / 64) // shift >>> 6
3616 // We don't need to consider the case of num === 0 so we can use a different
3617 // pattern here than above.
3618 while (num > 0) {
3619 write(encoder, (num > BITS7 ? BIT8 : 0) | (BITS7 & num))
3620 num = floor(num / 128) // shift >>> 7
3621 }
3622 }
3623
3624 /**
3625 * A cache to store strings temporarily
3626 */
3627 const _strBuffer = new Uint8Array(30000)
3628 const _maxStrBSize = _strBuffer.length / 3
3629
3630 /**
3631 * Write a variable length string.
3632 *
3633 * @function
3634 * @param {Encoder} encoder
3635 * @param {String} str The string that is to be encoded.
3636 */
3637 const _writeVarStringNative = (encoder, str) => {
3638 if (str.length < _maxStrBSize) {
3639 // We can encode the string into the existing buffer
3640 /* c8 ignore next */
3641 const written = utf8TextEncoder.encodeInto(str, _strBuffer).written || 0
3642 writeVarUint(encoder, written)
3643 for (let i = 0; i < written; i++) {
3644 write(encoder, _strBuffer[i])
3645 }
3646 } else {
3647 writeVarUint8Array(encoder, encodeUtf8(str))
3648 }
3649 }
3650
3651 /**
3652 * Write a variable length string.
3653 *
3654 * @function
3655 * @param {Encoder} encoder
3656 * @param {String} str The string that is to be encoded.
3657 */
3658 const _writeVarStringPolyfill = (encoder, str) => {
3659 const encodedString = unescape(encodeURIComponent(str))
3660 const len = encodedString.length
3661 writeVarUint(encoder, len)
3662 for (let i = 0; i < len; i++) {
3663 write(encoder, /** @type {number} */ (encodedString.codePointAt(i)))
3664 }
3665 }
3666
3667 /**
3668 * Write a variable length string.
3669 *
3670 * @function
3671 * @param {Encoder} encoder
3672 * @param {String} str The string that is to be encoded.
3673 */
3674 /* c8 ignore next */
3675 const writeVarString = (utf8TextEncoder && /** @type {any} */ (utf8TextEncoder).encodeInto) ? _writeVarStringNative : _writeVarStringPolyfill
3676
3677 /**
3678 * Write a string terminated by a special byte sequence. This is not very performant and is
3679 * generally discouraged. However, the resulting byte arrays are lexiographically ordered which
3680 * makes this a nice feature for databases.
3681 *
3682 * The string will be encoded using utf8 and then terminated and escaped using writeTerminatingUint8Array.
3683 *
3684 * @function
3685 * @param {Encoder} encoder
3686 * @param {String} str The string that is to be encoded.
3687 */
3688 const writeTerminatedString = (encoder, str) =>
3689 writeTerminatedUint8Array(encoder, string.encodeUtf8(str))
3690
3691 /**
3692 * Write a terminating Uint8Array. Note that this is not performant and is generally
3693 * discouraged. There are few situations when this is needed.
3694 *
3695 * We use 0x0 as a terminating character. 0x1 serves as an escape character for 0x0 and 0x1.
3696 *
3697 * Example: [0,1,2] is encoded to [1,0,1,1,2,0]. 0x0, and 0x1 needed to be escaped using 0x1. Then
3698 * the result is terminated using the 0x0 character.
3699 *
3700 * This is basically how many systems implement null terminated strings. However, we use an escape
3701 * character 0x1 to avoid issues and potenial attacks on our database (if this is used as a key
3702 * encoder for NoSql databases).
3703 *
3704 * @function
3705 * @param {Encoder} encoder
3706 * @param {Uint8Array} buf The string that is to be encoded.
3707 */
3708 const writeTerminatedUint8Array = (encoder, buf) => {
3709 for (let i = 0; i < buf.length; i++) {
3710 const b = buf[i]
3711 if (b === 0 || b === 1) {
3712 write(encoder, 1)
3713 }
3714 write(encoder, buf[i])
3715 }
3716 write(encoder, 0)
3717 }
3718
3719 /**
3720 * Write the content of another Encoder.
3721 *
3722 * @TODO: can be improved!
3723 * - Note: Should consider that when appending a lot of small Encoders, we should rather clone than referencing the old structure.
3724 * Encoders start with a rather big initial buffer.
3725 *
3726 * @function
3727 * @param {Encoder} encoder The enUint8Arr
3728 * @param {Encoder} append The BinaryEncoder to be written.
3729 */
3730 const writeBinaryEncoder = (encoder, append) => writeUint8Array(encoder, toUint8Array(append))
3731
3732 /**
3733 * Append fixed-length Uint8Array to the encoder.
3734 *
3735 * @function
3736 * @param {Encoder} encoder
3737 * @param {Uint8Array} uint8Array
3738 */
3739 const writeUint8Array = (encoder, uint8Array) => {
3740 const bufferLen = encoder.cbuf.length
3741 const cpos = encoder.cpos
3742 const leftCopyLen = min(bufferLen - cpos, uint8Array.length)
3743 const rightCopyLen = uint8Array.length - leftCopyLen
3744 encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos)
3745 encoder.cpos += leftCopyLen
3746 if (rightCopyLen > 0) {
3747 // Still something to write, write right half..
3748 // Append new buffer
3749 encoder.bufs.push(encoder.cbuf)
3750 // must have at least size of remaining buffer
3751 encoder.cbuf = new Uint8Array(max(bufferLen * 2, rightCopyLen))
3752 // copy array
3753 encoder.cbuf.set(uint8Array.subarray(leftCopyLen))
3754 encoder.cpos = rightCopyLen
3755 }
3756 }
3757
3758 /**
3759 * Append an Uint8Array to Encoder.
3760 *
3761 * @function
3762 * @param {Encoder} encoder
3763 * @param {Uint8Array} uint8Array
3764 */
3765 const writeVarUint8Array = (encoder, uint8Array) => {
3766 writeVarUint(encoder, uint8Array.byteLength)
3767 writeUint8Array(encoder, uint8Array)
3768 }
3769
3770 /**
3771 * Create an DataView of the next `len` bytes. Use it to write data after
3772 * calling this function.
3773 *
3774 * ```js
3775 * // write float32 using DataView
3776 * const dv = writeOnDataView(encoder, 4)
3777 * dv.setFloat32(0, 1.1)
3778 * // read float32 using DataView
3779 * const dv = readFromDataView(encoder, 4)
3780 * dv.getFloat32(0) // => 1.100000023841858 (leaving it to the reader to find out why this is the correct result)
3781 * ```
3782 *
3783 * @param {Encoder} encoder
3784 * @param {number} len
3785 * @return {DataView}
3786 */
3787 const writeOnDataView = (encoder, len) => {
3788 verifyLen(encoder, len)
3789 const dview = new DataView(encoder.cbuf.buffer, encoder.cpos, len)
3790 encoder.cpos += len
3791 return dview
3792 }
3793
3794 /**
3795 * @param {Encoder} encoder
3796 * @param {number} num
3797 */
3798 const writeFloat32 = (encoder, num) => writeOnDataView(encoder, 4).setFloat32(0, num, false)
3799
3800 /**
3801 * @param {Encoder} encoder
3802 * @param {number} num
3803 */
3804 const writeFloat64 = (encoder, num) => writeOnDataView(encoder, 8).setFloat64(0, num, false)
3805
3806 /**
3807 * @param {Encoder} encoder
3808 * @param {bigint} num
3809 */
3810 const writeBigInt64 = (encoder, num) => /** @type {any} */ (writeOnDataView(encoder, 8)).setBigInt64(0, num, false)
3811
3812 /**
3813 * @param {Encoder} encoder
3814 * @param {bigint} num
3815 */
3816 const writeBigUint64 = (encoder, num) => /** @type {any} */ (writeOnDataView(encoder, 8)).setBigUint64(0, num, false)
3817
3818 const floatTestBed = new DataView(new ArrayBuffer(4))
3819 /**
3820 * Check if a number can be encoded as a 32 bit float.
3821 *
3822 * @param {number} num
3823 * @return {boolean}
3824 */
3825 const isFloat32 = num => {
3826 floatTestBed.setFloat32(0, num)
3827 return floatTestBed.getFloat32(0) === num
3828 }
3829
3830 /**
3831 * Encode data with efficient binary format.
3832 *
3833 * Differences to JSON:
3834 * • Transforms data to a binary format (not to a string)
3835 * • Encodes undefined, NaN, and ArrayBuffer (these can't be represented in JSON)
3836 * • Numbers are efficiently encoded either as a variable length integer, as a
3837 * 32 bit float, as a 64 bit float, or as a 64 bit bigint.
3838 *
3839 * Encoding table:
3840 *
3841 * | Data Type | Prefix | Encoding Method | Comment |
3842 * | ------------------- | -------- | ------------------ | ------- |
3843 * | undefined | 127 | | Functions, symbol, and everything that cannot be identified is encoded as undefined |
3844 * | null | 126 | | |
3845 * | integer | 125 | writeVarInt | Only encodes 32 bit signed integers |
3846 * | float32 | 124 | writeFloat32 | |
3847 * | float64 | 123 | writeFloat64 | |
3848 * | bigint | 122 | writeBigInt64 | |
3849 * | boolean (false) | 121 | | True and false are different data types so we save the following byte |
3850 * | boolean (true) | 120 | | - 0b01111000 so the last bit determines whether true or false |
3851 * | string | 119 | writeVarString | |
3852 * | object<string,any> | 118 | custom | Writes {length} then {length} key-value pairs |
3853 * | array<any> | 117 | custom | Writes {length} then {length} json values |
3854 * | Uint8Array | 116 | writeVarUint8Array | We use Uint8Array for any kind of binary data |
3855 *
3856 * Reasons for the decreasing prefix:
3857 * We need the first bit for extendability (later we may want to encode the
3858 * prefix with writeVarUint). The remaining 7 bits are divided as follows:
3859 * [0-30] the beginning of the data range is used for custom purposes
3860 * (defined by the function that uses this library)
3861 * [31-127] the end of the data range is used for data encoding by
3862 * lib0/encoding.js
3863 *
3864 * @param {Encoder} encoder
3865 * @param {undefined|null|number|bigint|boolean|string|Object<string,any>|Array<any>|Uint8Array} data
3866 */
3867 const writeAny = (encoder, data) => {
3868 switch (typeof data) {
3869 case 'string':
3870 // TYPE 119: STRING
3871 write(encoder, 119)
3872 writeVarString(encoder, data)
3873 break
3874 case 'number':
3875 if (isInteger(data) && abs(data) <= BITS31) {
3876 // TYPE 125: INTEGER
3877 write(encoder, 125)
3878 writeVarInt(encoder, data)
3879 } else if (isFloat32(data)) {
3880 // TYPE 124: FLOAT32
3881 write(encoder, 124)
3882 writeFloat32(encoder, data)
3883 } else {
3884 // TYPE 123: FLOAT64
3885 write(encoder, 123)
3886 writeFloat64(encoder, data)
3887 }
3888 break
3889 case 'bigint':
3890 // TYPE 122: BigInt
3891 write(encoder, 122)
3892 writeBigInt64(encoder, data)
3893 break
3894 case 'object':
3895 if (data === null) {
3896 // TYPE 126: null
3897 write(encoder, 126)
3898 } else if (isArray(data)) {
3899 // TYPE 117: Array
3900 write(encoder, 117)
3901 writeVarUint(encoder, data.length)
3902 for (let i = 0; i < data.length; i++) {
3903 writeAny(encoder, data[i])
3904 }
3905 } else if (data instanceof Uint8Array) {
3906 // TYPE 116: ArrayBuffer
3907 write(encoder, 116)
3908 writeVarUint8Array(encoder, data)
3909 } else {
3910 // TYPE 118: Object
3911 write(encoder, 118)
3912 const keys = Object.keys(data)
3913 writeVarUint(encoder, keys.length)
3914 for (let i = 0; i < keys.length; i++) {
3915 const key = keys[i]
3916 writeVarString(encoder, key)
3917 writeAny(encoder, data[key])
3918 }
3919 }
3920 break
3921 case 'boolean':
3922 // TYPE 120/121: boolean (true/false)
3923 write(encoder, data ? 120 : 121)
3924 break
3925 default:
3926 // TYPE 127: undefined
3927 write(encoder, 127)
3928 }
3929 }
3930
3931 /**
3932 * Now come a few stateful encoder that have their own classes.
3933 */
3934
3935 /**
3936 * Basic Run Length Encoder - a basic compression implementation.
3937 *
3938 * 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.
3939 *
3940 * It was originally used for image compression. Cool .. article http://csbruce.com/cbm/transactor/pdfs/trans_v7_i06.pdf
3941 *
3942 * @note T must not be null!
3943 *
3944 * @template T
3945 */
3946 class RleEncoder extends Encoder {
3947 /**
3948 * @param {function(Encoder, T):void} writer
3949 */
3950 constructor (writer) {
3951 super()
3952 /**
3953 * The writer
3954 */
3955 this.w = writer
3956 /**
3957 * Current state
3958 * @type {T|null}
3959 */
3960 this.s = null
3961 this.count = 0
3962 }
3963
3964 /**
3965 * @param {T} v
3966 */
3967 write (v) {
3968 if (this.s === v) {
3969 this.count++
3970 } else {
3971 if (this.count > 0) {
3972 // flush counter, unless this is the first value (count = 0)
3973 writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw
3974 }
3975 this.count = 1
3976 // write first value
3977 this.w(this, v)
3978 this.s = v
3979 }
3980 }
3981 }
3982
3983 /**
3984 * Basic diff decoder using variable length encoding.
3985 *
3986 * Encodes the values [3, 1100, 1101, 1050, 0] to [3, 1097, 1, -51, -1050] using writeVarInt.
3987 */
3988 class IntDiffEncoder extends (/* unused pure expression or super */ null && (Encoder)) {
3989 /**
3990 * @param {number} start
3991 */
3992 constructor (start) {
3993 super()
3994 /**
3995 * Current state
3996 * @type {number}
3997 */
3998 this.s = start
3999 }
4000
4001 /**
4002 * @param {number} v
4003 */
4004 write (v) {
4005 writeVarInt(this, v - this.s)
4006 this.s = v
4007 }
4008 }
4009
4010 /**
4011 * A combination of IntDiffEncoder and RleEncoder.
4012 *
4013 * Basically first writes the IntDiffEncoder and then counts duplicate diffs using RleEncoding.
4014 *
4015 * 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])
4016 */
4017 class RleIntDiffEncoder extends (/* unused pure expression or super */ null && (Encoder)) {
4018 /**
4019 * @param {number} start
4020 */
4021 constructor (start) {
4022 super()
4023 /**
4024 * Current state
4025 * @type {number}
4026 */
4027 this.s = start
4028 this.count = 0
4029 }
4030
4031 /**
4032 * @param {number} v
4033 */
4034 write (v) {
4035 if (this.s === v && this.count > 0) {
4036 this.count++
4037 } else {
4038 if (this.count > 0) {
4039 // flush counter, unless this is the first value (count = 0)
4040 writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw
4041 }
4042 this.count = 1
4043 // write first value
4044 writeVarInt(this, v - this.s)
4045 this.s = v
4046 }
4047 }
4048 }
4049
4050 /**
4051 * @param {UintOptRleEncoder} encoder
4052 */
4053 const flushUintOptRleEncoder = encoder => {
4054 if (encoder.count > 0) {
4055 // flush counter, unless this is the first value (count = 0)
4056 // case 1: just a single value. set sign to positive
4057 // case 2: write several values. set sign to negative to indicate that there is a length coming
4058 writeVarInt(encoder.encoder, encoder.count === 1 ? encoder.s : -encoder.s)
4059 if (encoder.count > 1) {
4060 writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw
4061 }
4062 }
4063 }
4064
4065 /**
4066 * Optimized Rle encoder that does not suffer from the mentioned problem of the basic Rle encoder.
4067 *
4068 * Internally uses VarInt encoder to write unsigned integers. If the input occurs multiple times, we write
4069 * write it as a negative number. The UintOptRleDecoder then understands that it needs to read a count.
4070 *
4071 * Encodes [1,2,3,3,3] as [1,2,-3,3] (once 1, once 2, three times 3)
4072 */
4073 class UintOptRleEncoder {
4074 constructor () {
4075 this.encoder = new Encoder()
4076 /**
4077 * @type {number}
4078 */
4079 this.s = 0
4080 this.count = 0
4081 }
4082
4083 /**
4084 * @param {number} v
4085 */
4086 write (v) {
4087 if (this.s === v) {
4088 this.count++
4089 } else {
4090 flushUintOptRleEncoder(this)
4091 this.count = 1
4092 this.s = v
4093 }
4094 }
4095
4096 toUint8Array () {
4097 flushUintOptRleEncoder(this)
4098 return toUint8Array(this.encoder)
4099 }
4100 }
4101
4102 /**
4103 * Increasing Uint Optimized RLE Encoder
4104 *
4105 * The RLE encoder counts the number of same occurences of the same value.
4106 * The IncUintOptRle encoder counts if the value increases.
4107 * I.e. 7, 8, 9, 10 will be encoded as [-7, 4]. 1, 3, 5 will be encoded
4108 * as [1, 3, 5].
4109 */
4110 class IncUintOptRleEncoder {
4111 constructor () {
4112 this.encoder = new Encoder()
4113 /**
4114 * @type {number}
4115 */
4116 this.s = 0
4117 this.count = 0
4118 }
4119
4120 /**
4121 * @param {number} v
4122 */
4123 write (v) {
4124 if (this.s + this.count === v) {
4125 this.count++
4126 } else {
4127 flushUintOptRleEncoder(this)
4128 this.count = 1
4129 this.s = v
4130 }
4131 }
4132
4133 toUint8Array () {
4134 flushUintOptRleEncoder(this)
4135 return toUint8Array(this.encoder)
4136 }
4137 }
4138
4139 /**
4140 * @param {IntDiffOptRleEncoder} encoder
4141 */
4142 const flushIntDiffOptRleEncoder = encoder => {
4143 if (encoder.count > 0) {
4144 // 31 bit making up the diff | wether to write the counter
4145 // const encodedDiff = encoder.diff << 1 | (encoder.count === 1 ? 0 : 1)
4146 const encodedDiff = encoder.diff * 2 + (encoder.count === 1 ? 0 : 1)
4147 // flush counter, unless this is the first value (count = 0)
4148 // case 1: just a single value. set first bit to positive
4149 // case 2: write several values. set first bit to negative to indicate that there is a length coming
4150 writeVarInt(encoder.encoder, encodedDiff)
4151 if (encoder.count > 1) {
4152 writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw
4153 }
4154 }
4155 }
4156
4157 /**
4158 * A combination of the IntDiffEncoder and the UintOptRleEncoder.
4159 *
4160 * The count approach is similar to the UintDiffOptRleEncoder, but instead of using the negative bitflag, it encodes
4161 * in the LSB whether a count is to be read. Therefore this Encoder only supports 31 bit integers!
4162 *
4163 * Encodes [1, 2, 3, 2] as [3, 1, 6, -1] (more specifically [(1 << 1) | 1, (3 << 0) | 0, -1])
4164 *
4165 * Internally uses variable length encoding. Contrary to normal UintVar encoding, the first byte contains:
4166 * * 1 bit that denotes whether the next value is a count (LSB)
4167 * * 1 bit that denotes whether this value is negative (MSB - 1)
4168 * * 1 bit that denotes whether to continue reading the variable length integer (MSB)
4169 *
4170 * Therefore, only five bits remain to encode diff ranges.
4171 *
4172 * Use this Encoder only when appropriate. In most cases, this is probably a bad idea.
4173 */
4174 class IntDiffOptRleEncoder {
4175 constructor () {
4176 this.encoder = new Encoder()
4177 /**
4178 * @type {number}
4179 */
4180 this.s = 0
4181 this.count = 0
4182 this.diff = 0
4183 }
4184
4185 /**
4186 * @param {number} v
4187 */
4188 write (v) {
4189 if (this.diff === v - this.s) {
4190 this.s = v
4191 this.count++
4192 } else {
4193 flushIntDiffOptRleEncoder(this)
4194 this.count = 1
4195 this.diff = v - this.s
4196 this.s = v
4197 }
4198 }
4199
4200 toUint8Array () {
4201 flushIntDiffOptRleEncoder(this)
4202 return toUint8Array(this.encoder)
4203 }
4204 }
4205
4206 /**
4207 * Optimized String Encoder.
4208 *
4209 * 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.
4210 * 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?).
4211 *
4212 * This string encoder solves the above problem. All strings are concatenated and written as a single string using a single encoding call.
4213 *
4214 * The lengths are encoded using a UintOptRleEncoder.
4215 */
4216 class StringEncoder {
4217 constructor () {
4218 /**
4219 * @type {Array<string>}
4220 */
4221 this.sarr = []
4222 this.s = ''
4223 this.lensE = new UintOptRleEncoder()
4224 }
4225
4226 /**
4227 * @param {string} string
4228 */
4229 write (string) {
4230 this.s += string
4231 if (this.s.length > 19) {
4232 this.sarr.push(this.s)
4233 this.s = ''
4234 }
4235 this.lensE.write(string.length)
4236 }
4237
4238 toUint8Array () {
4239 const encoder = new Encoder()
4240 this.sarr.push(this.s)
4241 this.s = ''
4242 writeVarString(encoder, this.sarr.join(''))
4243 writeUint8Array(encoder, this.lensE.toUint8Array())
4244 return toUint8Array(encoder)
4245 }
4246 }
4247
4248 ;// CONCATENATED MODULE: ./node_modules/lib0/error.js
4249 /**
4250 * Error helpers.
4251 *
4252 * @module error
4253 */
4254
4255 /**
4256 * @param {string} s
4257 * @return {Error}
4258 */
4259 /* c8 ignore next */
4260 const error_create = s => new Error(s)
4261
4262 /**
4263 * @throws {Error}
4264 * @return {never}
4265 */
4266 /* c8 ignore next 3 */
4267 const methodUnimplemented = () => {
4268 throw error_create('Method unimplemented')
4269 }
4270
4271 /**
4272 * @throws {Error}
4273 * @return {never}
4274 */
4275 /* c8 ignore next 3 */
4276 const unexpectedCase = () => {
4277 throw error_create('Unexpected case')
4278 }
4279
4280 ;// CONCATENATED MODULE: ./node_modules/lib0/decoding.js
4281 /**
4282 * Efficient schema-less binary decoding with support for variable length encoding.
4283 *
4284 * Use [lib0/decoding] with [lib0/encoding]. Every encoding function has a corresponding decoding function.
4285 *
4286 * Encodes numbers in little-endian order (least to most significant byte order)
4287 * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
4288 * which is also used in Protocol Buffers.
4289 *
4290 * ```js
4291 * // encoding step
4292 * const encoder = encoding.createEncoder()
4293 * encoding.writeVarUint(encoder, 256)
4294 * encoding.writeVarString(encoder, 'Hello world!')
4295 * const buf = encoding.toUint8Array(encoder)
4296 * ```
4297 *
4298 * ```js
4299 * // decoding step
4300 * const decoder = decoding.createDecoder(buf)
4301 * decoding.readVarUint(decoder) // => 256
4302 * decoding.readVarString(decoder) // => 'Hello world!'
4303 * decoding.hasContent(decoder) // => false - all data is read
4304 * ```
4305 *
4306 * @module decoding
4307 */
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317 const errorUnexpectedEndOfArray = error_create('Unexpected end of array')
4318 const errorIntegerOutOfRange = error_create('Integer out of Range')
4319
4320 /**
4321 * A Decoder handles the decoding of an Uint8Array.
4322 */
4323 class Decoder {
4324 /**
4325 * @param {Uint8Array} uint8Array Binary data to decode
4326 */
4327 constructor (uint8Array) {
4328 /**
4329 * Decoding target.
4330 *
4331 * @type {Uint8Array}
4332 */
4333 this.arr = uint8Array
4334 /**
4335 * Current decoding position.
4336 *
4337 * @type {number}
4338 */
4339 this.pos = 0
4340 }
4341 }
4342
4343 /**
4344 * @function
4345 * @param {Uint8Array} uint8Array
4346 * @return {Decoder}
4347 */
4348 const createDecoder = uint8Array => new Decoder(uint8Array)
4349
4350 /**
4351 * @function
4352 * @param {Decoder} decoder
4353 * @return {boolean}
4354 */
4355 const decoding_hasContent = decoder => decoder.pos !== decoder.arr.length
4356
4357 /**
4358 * Clone a decoder instance.
4359 * Optionally set a new position parameter.
4360 *
4361 * @function
4362 * @param {Decoder} decoder The decoder instance
4363 * @param {number} [newPos] Defaults to current position
4364 * @return {Decoder} A clone of `decoder`
4365 */
4366 const clone = (decoder, newPos = decoder.pos) => {
4367 const _decoder = createDecoder(decoder.arr)
4368 _decoder.pos = newPos
4369 return _decoder
4370 }
4371
4372 /**
4373 * Create an Uint8Array view of the next `len` bytes and advance the position by `len`.
4374 *
4375 * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
4376 * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
4377 *
4378 * @function
4379 * @param {Decoder} decoder The decoder instance
4380 * @param {number} len The length of bytes to read
4381 * @return {Uint8Array}
4382 */
4383 const readUint8Array = (decoder, len) => {
4384 const view = createUint8ArrayViewFromArrayBuffer(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len)
4385 decoder.pos += len
4386 return view
4387 }
4388
4389 /**
4390 * Read variable length Uint8Array.
4391 *
4392 * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
4393 * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
4394 *
4395 * @function
4396 * @param {Decoder} decoder
4397 * @return {Uint8Array}
4398 */
4399 const readVarUint8Array = decoder => readUint8Array(decoder, readVarUint(decoder))
4400
4401 /**
4402 * Read the rest of the content as an ArrayBuffer
4403 * @function
4404 * @param {Decoder} decoder
4405 * @return {Uint8Array}
4406 */
4407 const readTailAsUint8Array = decoder => readUint8Array(decoder, decoder.arr.length - decoder.pos)
4408
4409 /**
4410 * Skip one byte, jump to the next position.
4411 * @function
4412 * @param {Decoder} decoder The decoder instance
4413 * @return {number} The next position
4414 */
4415 const skip8 = decoder => decoder.pos++
4416
4417 /**
4418 * Read one byte as unsigned integer.
4419 * @function
4420 * @param {Decoder} decoder The decoder instance
4421 * @return {number} Unsigned 8-bit integer
4422 */
4423 const readUint8 = decoder => decoder.arr[decoder.pos++]
4424
4425 /**
4426 * Read 2 bytes as unsigned integer.
4427 *
4428 * @function
4429 * @param {Decoder} decoder
4430 * @return {number} An unsigned integer.
4431 */
4432 const readUint16 = decoder => {
4433 const uint =
4434 decoder.arr[decoder.pos] +
4435 (decoder.arr[decoder.pos + 1] << 8)
4436 decoder.pos += 2
4437 return uint
4438 }
4439
4440 /**
4441 * Read 4 bytes as unsigned integer.
4442 *
4443 * @function
4444 * @param {Decoder} decoder
4445 * @return {number} An unsigned integer.
4446 */
4447 const readUint32 = decoder => {
4448 const uint =
4449 (decoder.arr[decoder.pos] +
4450 (decoder.arr[decoder.pos + 1] << 8) +
4451 (decoder.arr[decoder.pos + 2] << 16) +
4452 (decoder.arr[decoder.pos + 3] << 24)) >>> 0
4453 decoder.pos += 4
4454 return uint
4455 }
4456
4457 /**
4458 * Read 4 bytes as unsigned integer in big endian order.
4459 * (most significant byte first)
4460 *
4461 * @function
4462 * @param {Decoder} decoder
4463 * @return {number} An unsigned integer.
4464 */
4465 const readUint32BigEndian = decoder => {
4466 const uint =
4467 (decoder.arr[decoder.pos + 3] +
4468 (decoder.arr[decoder.pos + 2] << 8) +
4469 (decoder.arr[decoder.pos + 1] << 16) +
4470 (decoder.arr[decoder.pos] << 24)) >>> 0
4471 decoder.pos += 4
4472 return uint
4473 }
4474
4475 /**
4476 * Look ahead without incrementing the position
4477 * to the next byte and read it as unsigned integer.
4478 *
4479 * @function
4480 * @param {Decoder} decoder
4481 * @return {number} An unsigned integer.
4482 */
4483 const peekUint8 = decoder => decoder.arr[decoder.pos]
4484
4485 /**
4486 * Look ahead without incrementing the position
4487 * to the next byte and read it as unsigned integer.
4488 *
4489 * @function
4490 * @param {Decoder} decoder
4491 * @return {number} An unsigned integer.
4492 */
4493 const peekUint16 = decoder =>
4494 decoder.arr[decoder.pos] +
4495 (decoder.arr[decoder.pos + 1] << 8)
4496
4497 /**
4498 * Look ahead without incrementing the position
4499 * to the next byte and read it as unsigned integer.
4500 *
4501 * @function
4502 * @param {Decoder} decoder
4503 * @return {number} An unsigned integer.
4504 */
4505 const peekUint32 = decoder => (
4506 decoder.arr[decoder.pos] +
4507 (decoder.arr[decoder.pos + 1] << 8) +
4508 (decoder.arr[decoder.pos + 2] << 16) +
4509 (decoder.arr[decoder.pos + 3] << 24)
4510 ) >>> 0
4511
4512 /**
4513 * Read unsigned integer (32bit) with variable length.
4514 * 1/8th of the storage is used as encoding overhead.
4515 * * numbers < 2^7 is stored in one bytlength
4516 * * numbers < 2^14 is stored in two bylength
4517 *
4518 * @function
4519 * @param {Decoder} decoder
4520 * @return {number} An unsigned integer.length
4521 */
4522 const readVarUint = decoder => {
4523 let num = 0
4524 let mult = 1
4525 const len = decoder.arr.length
4526 while (decoder.pos < len) {
4527 const r = decoder.arr[decoder.pos++]
4528 // num = num | ((r & binary.BITS7) << len)
4529 num = num + (r & BITS7) * mult // shift $r << (7*#iterations) and add it to num
4530 mult *= 128 // next iteration, shift 7 "more" to the left
4531 if (r < BIT8) {
4532 return num
4533 }
4534 /* c8 ignore start */
4535 if (num > MAX_SAFE_INTEGER) {
4536 throw errorIntegerOutOfRange
4537 }
4538 /* c8 ignore stop */
4539 }
4540 throw errorUnexpectedEndOfArray
4541 }
4542
4543 /**
4544 * Read signed integer (32bit) with variable length.
4545 * 1/8th of the storage is used as encoding overhead.
4546 * * numbers < 2^7 is stored in one bytlength
4547 * * numbers < 2^14 is stored in two bylength
4548 * @todo This should probably create the inverse ~num if number is negative - but this would be a breaking change.
4549 *
4550 * @function
4551 * @param {Decoder} decoder
4552 * @return {number} An unsigned integer.length
4553 */
4554 const readVarInt = decoder => {
4555 let r = decoder.arr[decoder.pos++]
4556 let num = r & BITS6
4557 let mult = 64
4558 const sign = (r & BIT7) > 0 ? -1 : 1
4559 if ((r & BIT8) === 0) {
4560 // don't continue reading
4561 return sign * num
4562 }
4563 const len = decoder.arr.length
4564 while (decoder.pos < len) {
4565 r = decoder.arr[decoder.pos++]
4566 // num = num | ((r & binary.BITS7) << len)
4567 num = num + (r & BITS7) * mult
4568 mult *= 128
4569 if (r < BIT8) {
4570 return sign * num
4571 }
4572 /* c8 ignore start */
4573 if (num > MAX_SAFE_INTEGER) {
4574 throw errorIntegerOutOfRange
4575 }
4576 /* c8 ignore stop */
4577 }
4578 throw errorUnexpectedEndOfArray
4579 }
4580
4581 /**
4582 * Look ahead and read varUint without incrementing position
4583 *
4584 * @function
4585 * @param {Decoder} decoder
4586 * @return {number}
4587 */
4588 const peekVarUint = decoder => {
4589 const pos = decoder.pos
4590 const s = readVarUint(decoder)
4591 decoder.pos = pos
4592 return s
4593 }
4594
4595 /**
4596 * Look ahead and read varUint without incrementing position
4597 *
4598 * @function
4599 * @param {Decoder} decoder
4600 * @return {number}
4601 */
4602 const peekVarInt = decoder => {
4603 const pos = decoder.pos
4604 const s = readVarInt(decoder)
4605 decoder.pos = pos
4606 return s
4607 }
4608
4609 /**
4610 * We don't test this function anymore as we use native decoding/encoding by default now.
4611 * Better not modify this anymore..
4612 *
4613 * Transforming utf8 to a string is pretty expensive. The code performs 10x better
4614 * when String.fromCodePoint is fed with all characters as arguments.
4615 * But most environments have a maximum number of arguments per functions.
4616 * For effiency reasons we apply a maximum of 10000 characters at once.
4617 *
4618 * @function
4619 * @param {Decoder} decoder
4620 * @return {String} The read String.
4621 */
4622 /* c8 ignore start */
4623 const _readVarStringPolyfill = decoder => {
4624 let remainingLen = readVarUint(decoder)
4625 if (remainingLen === 0) {
4626 return ''
4627 } else {
4628 let encodedString = String.fromCodePoint(readUint8(decoder)) // remember to decrease remainingLen
4629 if (--remainingLen < 100) { // do not create a Uint8Array for small strings
4630 while (remainingLen--) {
4631 encodedString += String.fromCodePoint(readUint8(decoder))
4632 }
4633 } else {
4634 while (remainingLen > 0) {
4635 const nextLen = remainingLen < 10000 ? remainingLen : 10000
4636 // this is dangerous, we create a fresh array view from the existing buffer
4637 const bytes = decoder.arr.subarray(decoder.pos, decoder.pos + nextLen)
4638 decoder.pos += nextLen
4639 // Starting with ES5.1 we can supply a generic array-like object as arguments
4640 encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes))
4641 remainingLen -= nextLen
4642 }
4643 }
4644 return decodeURIComponent(escape(encodedString))
4645 }
4646 }
4647 /* c8 ignore stop */
4648
4649 /**
4650 * @function
4651 * @param {Decoder} decoder
4652 * @return {String} The read String
4653 */
4654 const _readVarStringNative = decoder =>
4655 /** @type any */ (utf8TextDecoder).decode(readVarUint8Array(decoder))
4656
4657 /**
4658 * Read string of variable length
4659 * * varUint is used to store the length of the string
4660 *
4661 * @function
4662 * @param {Decoder} decoder
4663 * @return {String} The read String
4664 *
4665 */
4666 /* c8 ignore next */
4667 const readVarString = utf8TextDecoder ? _readVarStringNative : _readVarStringPolyfill
4668
4669 /**
4670 * @param {Decoder} decoder
4671 * @return {Uint8Array}
4672 */
4673 const readTerminatedUint8Array = decoder => {
4674 const encoder = encoding.createEncoder()
4675 let b
4676 while (true) {
4677 b = readUint8(decoder)
4678 if (b === 0) {
4679 return encoding.toUint8Array(encoder)
4680 }
4681 if (b === 1) {
4682 b = readUint8(decoder)
4683 }
4684 encoding.write(encoder, b)
4685 }
4686 }
4687
4688 /**
4689 * @param {Decoder} decoder
4690 * @return {string}
4691 */
4692 const readTerminatedString = decoder => string.decodeUtf8(readTerminatedUint8Array(decoder))
4693
4694 /**
4695 * Look ahead and read varString without incrementing position
4696 *
4697 * @function
4698 * @param {Decoder} decoder
4699 * @return {string}
4700 */
4701 const peekVarString = decoder => {
4702 const pos = decoder.pos
4703 const s = readVarString(decoder)
4704 decoder.pos = pos
4705 return s
4706 }
4707
4708 /**
4709 * @param {Decoder} decoder
4710 * @param {number} len
4711 * @return {DataView}
4712 */
4713 const readFromDataView = (decoder, len) => {
4714 const dv = new DataView(decoder.arr.buffer, decoder.arr.byteOffset + decoder.pos, len)
4715 decoder.pos += len
4716 return dv
4717 }
4718
4719 /**
4720 * @param {Decoder} decoder
4721 */
4722 const readFloat32 = decoder => readFromDataView(decoder, 4).getFloat32(0, false)
4723
4724 /**
4725 * @param {Decoder} decoder
4726 */
4727 const readFloat64 = decoder => readFromDataView(decoder, 8).getFloat64(0, false)
4728
4729 /**
4730 * @param {Decoder} decoder
4731 */
4732 const readBigInt64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigInt64(0, false)
4733
4734 /**
4735 * @param {Decoder} decoder
4736 */
4737 const readBigUint64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigUint64(0, false)
4738
4739 /**
4740 * @type {Array<function(Decoder):any>}
4741 */
4742 const readAnyLookupTable = [
4743 decoder => undefined, // CASE 127: undefined
4744 decoder => null, // CASE 126: null
4745 readVarInt, // CASE 125: integer
4746 readFloat32, // CASE 124: float32
4747 readFloat64, // CASE 123: float64
4748 readBigInt64, // CASE 122: bigint
4749 decoder => false, // CASE 121: boolean (false)
4750 decoder => true, // CASE 120: boolean (true)
4751 readVarString, // CASE 119: string
4752 decoder => { // CASE 118: object<string,any>
4753 const len = readVarUint(decoder)
4754 /**
4755 * @type {Object<string,any>}
4756 */
4757 const obj = {}
4758 for (let i = 0; i < len; i++) {
4759 const key = readVarString(decoder)
4760 obj[key] = readAny(decoder)
4761 }
4762 return obj
4763 },
4764 decoder => { // CASE 117: array<any>
4765 const len = readVarUint(decoder)
4766 const arr = []
4767 for (let i = 0; i < len; i++) {
4768 arr.push(readAny(decoder))
4769 }
4770 return arr
4771 },
4772 readVarUint8Array // CASE 116: Uint8Array
4773 ]
4774
4775 /**
4776 * @param {Decoder} decoder
4777 */
4778 const readAny = decoder => readAnyLookupTable[127 - readUint8(decoder)](decoder)
4779
4780 /**
4781 * T must not be null.
4782 *
4783 * @template T
4784 */
4785 class RleDecoder extends Decoder {
4786 /**
4787 * @param {Uint8Array} uint8Array
4788 * @param {function(Decoder):T} reader
4789 */
4790 constructor (uint8Array, reader) {
4791 super(uint8Array)
4792 /**
4793 * The reader
4794 */
4795 this.reader = reader
4796 /**
4797 * Current state
4798 * @type {T|null}
4799 */
4800 this.s = null
4801 this.count = 0
4802 }
4803
4804 read () {
4805 if (this.count === 0) {
4806 this.s = this.reader(this)
4807 if (decoding_hasContent(this)) {
4808 this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented
4809 } else {
4810 this.count = -1 // read the current value forever
4811 }
4812 }
4813 this.count--
4814 return /** @type {T} */ (this.s)
4815 }
4816 }
4817
4818 class IntDiffDecoder extends (/* unused pure expression or super */ null && (Decoder)) {
4819 /**
4820 * @param {Uint8Array} uint8Array
4821 * @param {number} start
4822 */
4823 constructor (uint8Array, start) {
4824 super(uint8Array)
4825 /**
4826 * Current state
4827 * @type {number}
4828 */
4829 this.s = start
4830 }
4831
4832 /**
4833 * @return {number}
4834 */
4835 read () {
4836 this.s += readVarInt(this)
4837 return this.s
4838 }
4839 }
4840
4841 class RleIntDiffDecoder extends (/* unused pure expression or super */ null && (Decoder)) {
4842 /**
4843 * @param {Uint8Array} uint8Array
4844 * @param {number} start
4845 */
4846 constructor (uint8Array, start) {
4847 super(uint8Array)
4848 /**
4849 * Current state
4850 * @type {number}
4851 */
4852 this.s = start
4853 this.count = 0
4854 }
4855
4856 /**
4857 * @return {number}
4858 */
4859 read () {
4860 if (this.count === 0) {
4861 this.s += readVarInt(this)
4862 if (decoding_hasContent(this)) {
4863 this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented
4864 } else {
4865 this.count = -1 // read the current value forever
4866 }
4867 }
4868 this.count--
4869 return /** @type {number} */ (this.s)
4870 }
4871 }
4872
4873 class UintOptRleDecoder extends Decoder {
4874 /**
4875 * @param {Uint8Array} uint8Array
4876 */
4877 constructor (uint8Array) {
4878 super(uint8Array)
4879 /**
4880 * @type {number}
4881 */
4882 this.s = 0
4883 this.count = 0
4884 }
4885
4886 read () {
4887 if (this.count === 0) {
4888 this.s = readVarInt(this)
4889 // if the sign is negative, we read the count too, otherwise count is 1
4890 const isNegative = isNegativeZero(this.s)
4891 this.count = 1
4892 if (isNegative) {
4893 this.s = -this.s
4894 this.count = readVarUint(this) + 2
4895 }
4896 }
4897 this.count--
4898 return /** @type {number} */ (this.s)
4899 }
4900 }
4901
4902 class IncUintOptRleDecoder extends (/* unused pure expression or super */ null && (Decoder)) {
4903 /**
4904 * @param {Uint8Array} uint8Array
4905 */
4906 constructor (uint8Array) {
4907 super(uint8Array)
4908 /**
4909 * @type {number}
4910 */
4911 this.s = 0
4912 this.count = 0
4913 }
4914
4915 read () {
4916 if (this.count === 0) {
4917 this.s = readVarInt(this)
4918 // if the sign is negative, we read the count too, otherwise count is 1
4919 const isNegative = math.isNegativeZero(this.s)
4920 this.count = 1
4921 if (isNegative) {
4922 this.s = -this.s
4923 this.count = readVarUint(this) + 2
4924 }
4925 }
4926 this.count--
4927 return /** @type {number} */ (this.s++)
4928 }
4929 }
4930
4931 class IntDiffOptRleDecoder extends Decoder {
4932 /**
4933 * @param {Uint8Array} uint8Array
4934 */
4935 constructor (uint8Array) {
4936 super(uint8Array)
4937 /**
4938 * @type {number}
4939 */
4940 this.s = 0
4941 this.count = 0
4942 this.diff = 0
4943 }
4944
4945 /**
4946 * @return {number}
4947 */
4948 read () {
4949 if (this.count === 0) {
4950 const diff = readVarInt(this)
4951 // if the first bit is set, we read more data
4952 const hasCount = diff & 1
4953 this.diff = floor(diff / 2) // shift >> 1
4954 this.count = 1
4955 if (hasCount) {
4956 this.count = readVarUint(this) + 2
4957 }
4958 }
4959 this.s += this.diff
4960 this.count--
4961 return this.s
4962 }
4963 }
4964
4965 class StringDecoder {
4966 /**
4967 * @param {Uint8Array} uint8Array
4968 */
4969 constructor (uint8Array) {
4970 this.decoder = new UintOptRleDecoder(uint8Array)
4971 this.str = readVarString(this.decoder)
4972 /**
4973 * @type {number}
4974 */
4975 this.spos = 0
4976 }
4977
4978 /**
4979 * @return {string}
4980 */
4981 read () {
4982 const end = this.spos + this.decoder.read()
4983 const res = this.str.slice(this.spos, end)
4984 this.spos = end
4985 return res
4986 }
4987 }
4988
4989 ;// CONCATENATED MODULE: ./node_modules/lib0/webcrypto.js
4990 /* eslint-env browser */
4991
4992 const subtle = crypto.subtle
4993 const webcrypto_getRandomValues = crypto.getRandomValues.bind(crypto)
4994
4995 ;// CONCATENATED MODULE: ./node_modules/lib0/random.js
4996 /**
4997 * Isomorphic module for true random numbers / buffers / uuids.
4998 *
4999 * Attention: falls back to Math.random if the browser does not support crypto.
5000 *
5001 * @module random
5002 */
5003
5004
5005
5006
5007
5008 const rand = Math.random
5009
5010 const uint32 = () => webcrypto_getRandomValues(new Uint32Array(1))[0]
5011
5012 const uint53 = () => {
5013 const arr = getRandomValues(new Uint32Array(8))
5014 return (arr[0] & binary.BITS21) * (binary.BITS32 + 1) + (arr[1] >>> 0)
5015 }
5016
5017 /**
5018 * @template T
5019 * @param {Array<T>} arr
5020 * @return {T}
5021 */
5022 const oneOf = arr => arr[math.floor(rand() * arr.length)]
5023
5024 // @ts-ignore
5025 const uuidv4Template = [1e7] + -1e3 + -4e3 + -8e3 + -1e11
5026
5027 /**
5028 * @return {string}
5029 */
5030 const uuidv4 = () => uuidv4Template.replace(/[018]/g, /** @param {number} c */ c =>
5031 (c ^ uint32() & 15 >> c / 4).toString(16)
5032 )
5033
5034 ;// CONCATENATED MODULE: ./node_modules/lib0/promise.js
5035 /**
5036 * Utility helpers to work with promises.
5037 *
5038 * @module promise
5039 */
5040
5041
5042
5043 /**
5044 * @template T
5045 * @callback PromiseResolve
5046 * @param {T|PromiseLike<T>} [result]
5047 */
5048
5049 /**
5050 * @template T
5051 * @param {function(PromiseResolve<T>,function(Error):void):any} f
5052 * @return {Promise<T>}
5053 */
5054 const promise_create = f => /** @type {Promise<T>} */ (new Promise(f))
5055
5056 /**
5057 * @param {function(function():void,function(Error):void):void} f
5058 * @return {Promise<void>}
5059 */
5060 const createEmpty = f => new Promise(f)
5061
5062 /**
5063 * `Promise.all` wait for all promises in the array to resolve and return the result
5064 * @template {unknown[] | []} PS
5065 *
5066 * @param {PS} ps
5067 * @return {Promise<{ -readonly [P in keyof PS]: Awaited<PS[P]> }>}
5068 */
5069 const promise_all = Promise.all.bind(Promise)
5070
5071 /**
5072 * @param {Error} [reason]
5073 * @return {Promise<never>}
5074 */
5075 const reject = reason => Promise.reject(reason)
5076
5077 /**
5078 * @template T
5079 * @param {T|void} res
5080 * @return {Promise<T|void>}
5081 */
5082 const resolve = res => Promise.resolve(res)
5083
5084 /**
5085 * @template T
5086 * @param {T} res
5087 * @return {Promise<T>}
5088 */
5089 const resolveWith = res => Promise.resolve(res)
5090
5091 /**
5092 * @todo Next version, reorder parameters: check, [timeout, [intervalResolution]]
5093 *
5094 * @param {number} timeout
5095 * @param {function():boolean} check
5096 * @param {number} [intervalResolution]
5097 * @return {Promise<void>}
5098 */
5099 const until = (timeout, check, intervalResolution = 10) => promise_create((resolve, reject) => {
5100 const startTime = time.getUnixTime()
5101 const hasTimeout = timeout > 0
5102 const untilInterval = () => {
5103 if (check()) {
5104 clearInterval(intervalHandle)
5105 resolve()
5106 } else if (hasTimeout) {
5107 /* c8 ignore else */
5108 if (time.getUnixTime() - startTime > timeout) {
5109 clearInterval(intervalHandle)
5110 reject(new Error('Timeout'))
5111 }
5112 }
5113 }
5114 const intervalHandle = setInterval(untilInterval, intervalResolution)
5115 })
5116
5117 /**
5118 * @param {number} timeout
5119 * @return {Promise<undefined>}
5120 */
5121 const wait = timeout => promise_create((resolve, reject) => setTimeout(resolve, timeout))
5122
5123 /**
5124 * Checks if an object is a promise using ducktyping.
5125 *
5126 * Promises are often polyfilled, so it makes sense to add some additional guarantees if the user of this
5127 * library has some insane environment where global Promise objects are overwritten.
5128 *
5129 * @param {any} p
5130 * @return {boolean}
5131 */
5132 const isPromise = p => p instanceof Promise || (p && p.then && p.catch && p.finally)
5133
5134 ;// CONCATENATED MODULE: ./node_modules/lib0/pair.js
5135 /**
5136 * Working with value pairs.
5137 *
5138 * @module pair
5139 */
5140
5141 /**
5142 * @template L,R
5143 */
5144 class Pair {
5145 /**
5146 * @param {L} left
5147 * @param {R} right
5148 */
5149 constructor (left, right) {
5150 this.left = left
5151 this.right = right
5152 }
5153 }
5154
5155 /**
5156 * @template L,R
5157 * @param {L} left
5158 * @param {R} right
5159 * @return {Pair<L,R>}
5160 */
5161 const pair_create = (left, right) => new Pair(left, right)
5162
5163 /**
5164 * @template L,R
5165 * @param {R} right
5166 * @param {L} left
5167 * @return {Pair<L,R>}
5168 */
5169 const createReversed = (right, left) => new Pair(left, right)
5170
5171 /**
5172 * @template L,R
5173 * @param {Array<Pair<L,R>>} arr
5174 * @param {function(L, R):any} f
5175 */
5176 const pair_forEach = (arr, f) => arr.forEach(p => f(p.left, p.right))
5177
5178 /**
5179 * @template L,R,X
5180 * @param {Array<Pair<L,R>>} arr
5181 * @param {function(L, R):X} f
5182 * @return {Array<X>}
5183 */
5184 const pair_map = (arr, f) => arr.map(p => f(p.left, p.right))
5185
5186 ;// CONCATENATED MODULE: ./node_modules/lib0/dom.js
5187 /* eslint-env browser */
5188
5189 /**
5190 * Utility module to work with the DOM.
5191 *
5192 * @module dom
5193 */
5194
5195
5196
5197
5198 /* c8 ignore start */
5199 /**
5200 * @type {Document}
5201 */
5202 const doc = /** @type {Document} */ (typeof document !== 'undefined' ? document : {})
5203
5204 /**
5205 * @param {string} name
5206 * @return {HTMLElement}
5207 */
5208 const createElement = name => doc.createElement(name)
5209
5210 /**
5211 * @return {DocumentFragment}
5212 */
5213 const createDocumentFragment = () => doc.createDocumentFragment()
5214
5215 /**
5216 * @param {string} text
5217 * @return {Text}
5218 */
5219 const createTextNode = text => doc.createTextNode(text)
5220
5221 const domParser = /** @type {DOMParser} */ (typeof DOMParser !== 'undefined' ? new DOMParser() : null)
5222
5223 /**
5224 * @param {HTMLElement} el
5225 * @param {string} name
5226 * @param {Object} opts
5227 */
5228 const emitCustomEvent = (el, name, opts) => el.dispatchEvent(new CustomEvent(name, opts))
5229
5230 /**
5231 * @param {Element} el
5232 * @param {Array<pair.Pair<string,string|boolean>>} attrs Array of key-value pairs
5233 * @return {Element}
5234 */
5235 const setAttributes = (el, attrs) => {
5236 pair.forEach(attrs, (key, value) => {
5237 if (value === false) {
5238 el.removeAttribute(key)
5239 } else if (value === true) {
5240 el.setAttribute(key, '')
5241 } else {
5242 // @ts-ignore
5243 el.setAttribute(key, value)
5244 }
5245 })
5246 return el
5247 }
5248
5249 /**
5250 * @param {Element} el
5251 * @param {Map<string, string>} attrs Array of key-value pairs
5252 * @return {Element}
5253 */
5254 const setAttributesMap = (el, attrs) => {
5255 attrs.forEach((value, key) => { el.setAttribute(key, value) })
5256 return el
5257 }
5258
5259 /**
5260 * @param {Array<Node>|HTMLCollection} children
5261 * @return {DocumentFragment}
5262 */
5263 const fragment = children => {
5264 const fragment = createDocumentFragment()
5265 for (let i = 0; i < children.length; i++) {
5266 appendChild(fragment, children[i])
5267 }
5268 return fragment
5269 }
5270
5271 /**
5272 * @param {Element} parent
5273 * @param {Array<Node>} nodes
5274 * @return {Element}
5275 */
5276 const append = (parent, nodes) => {
5277 appendChild(parent, fragment(nodes))
5278 return parent
5279 }
5280
5281 /**
5282 * @param {HTMLElement} el
5283 */
5284 const remove = el => el.remove()
5285
5286 /**
5287 * @param {EventTarget} el
5288 * @param {string} name
5289 * @param {EventListener} f
5290 */
5291 const dom_addEventListener = (el, name, f) => el.addEventListener(name, f)
5292
5293 /**
5294 * @param {EventTarget} el
5295 * @param {string} name
5296 * @param {EventListener} f
5297 */
5298 const dom_removeEventListener = (el, name, f) => el.removeEventListener(name, f)
5299
5300 /**
5301 * @param {Node} node
5302 * @param {Array<pair.Pair<string,EventListener>>} listeners
5303 * @return {Node}
5304 */
5305 const addEventListeners = (node, listeners) => {
5306 pair.forEach(listeners, (name, f) => dom_addEventListener(node, name, f))
5307 return node
5308 }
5309
5310 /**
5311 * @param {Node} node
5312 * @param {Array<pair.Pair<string,EventListener>>} listeners
5313 * @return {Node}
5314 */
5315 const removeEventListeners = (node, listeners) => {
5316 pair.forEach(listeners, (name, f) => dom_removeEventListener(node, name, f))
5317 return node
5318 }
5319
5320 /**
5321 * @param {string} name
5322 * @param {Array<pair.Pair<string,string>|pair.Pair<string,boolean>>} attrs Array of key-value pairs
5323 * @param {Array<Node>} children
5324 * @return {Element}
5325 */
5326 const dom_element = (name, attrs = [], children = []) =>
5327 append(setAttributes(createElement(name), attrs), children)
5328
5329 /**
5330 * @param {number} width
5331 * @param {number} height
5332 */
5333 const canvas = (width, height) => {
5334 const c = /** @type {HTMLCanvasElement} */ (createElement('canvas'))
5335 c.height = height
5336 c.width = width
5337 return c
5338 }
5339
5340 /**
5341 * @param {string} t
5342 * @return {Text}
5343 */
5344 const dom_text = (/* unused pure expression or super */ null && (createTextNode))
5345
5346 /**
5347 * @param {pair.Pair<string,string>} pair
5348 */
5349 const pairToStyleString = pair => `${pair.left}:${pair.right};`
5350
5351 /**
5352 * @param {Array<pair.Pair<string,string>>} pairs
5353 * @return {string}
5354 */
5355 const pairsToStyleString = pairs => pairs.map(pairToStyleString).join('')
5356
5357 /**
5358 * @param {Map<string,string>} m
5359 * @return {string}
5360 */
5361 const mapToStyleString = m => map_map(m, (value, key) => `${key}:${value};`).join('')
5362
5363 /**
5364 * @todo should always query on a dom element
5365 *
5366 * @param {HTMLElement|ShadowRoot} el
5367 * @param {string} query
5368 * @return {HTMLElement | null}
5369 */
5370 const querySelector = (el, query) => el.querySelector(query)
5371
5372 /**
5373 * @param {HTMLElement|ShadowRoot} el
5374 * @param {string} query
5375 * @return {NodeListOf<HTMLElement>}
5376 */
5377 const querySelectorAll = (el, query) => el.querySelectorAll(query)
5378
5379 /**
5380 * @param {string} id
5381 * @return {HTMLElement}
5382 */
5383 const getElementById = id => /** @type {HTMLElement} */ (doc.getElementById(id))
5384
5385 /**
5386 * @param {string} html
5387 * @return {HTMLElement}
5388 */
5389 const _parse = html => domParser.parseFromString(`<html><body>${html}</body></html>`, 'text/html').body
5390
5391 /**
5392 * @param {string} html
5393 * @return {DocumentFragment}
5394 */
5395 const parseFragment = html => fragment(/** @type {any} */ (_parse(html).childNodes))
5396
5397 /**
5398 * @param {string} html
5399 * @return {HTMLElement}
5400 */
5401 const parseElement = html => /** @type HTMLElement */ (_parse(html).firstElementChild)
5402
5403 /**
5404 * @param {HTMLElement} oldEl
5405 * @param {HTMLElement|DocumentFragment} newEl
5406 */
5407 const replaceWith = (oldEl, newEl) => oldEl.replaceWith(newEl)
5408
5409 /**
5410 * @param {HTMLElement} parent
5411 * @param {HTMLElement} el
5412 * @param {Node|null} ref
5413 * @return {HTMLElement}
5414 */
5415 const insertBefore = (parent, el, ref) => parent.insertBefore(el, ref)
5416
5417 /**
5418 * @param {Node} parent
5419 * @param {Node} child
5420 * @return {Node}
5421 */
5422 const appendChild = (parent, child) => parent.appendChild(child)
5423
5424 const ELEMENT_NODE = doc.ELEMENT_NODE
5425 const TEXT_NODE = doc.TEXT_NODE
5426 const CDATA_SECTION_NODE = doc.CDATA_SECTION_NODE
5427 const COMMENT_NODE = doc.COMMENT_NODE
5428 const DOCUMENT_NODE = doc.DOCUMENT_NODE
5429 const DOCUMENT_TYPE_NODE = doc.DOCUMENT_TYPE_NODE
5430 const DOCUMENT_FRAGMENT_NODE = doc.DOCUMENT_FRAGMENT_NODE
5431
5432 /**
5433 * @param {any} node
5434 * @param {number} type
5435 */
5436 const checkNodeType = (node, type) => node.nodeType === type
5437
5438 /**
5439 * @param {Node} parent
5440 * @param {HTMLElement} child
5441 */
5442 const isParentOf = (parent, child) => {
5443 let p = child.parentNode
5444 while (p && p !== parent) {
5445 p = p.parentNode
5446 }
5447 return p === parent
5448 }
5449 /* c8 ignore stop */
5450
5451 ;// CONCATENATED MODULE: ./node_modules/lib0/symbol.js
5452 /**
5453 * Utility module to work with EcmaScript Symbols.
5454 *
5455 * @module symbol
5456 */
5457
5458 /**
5459 * Return fresh symbol.
5460 *
5461 * @return {Symbol}
5462 */
5463 const symbol_create = Symbol
5464
5465 /**
5466 * @param {any} s
5467 * @return {boolean}
5468 */
5469 const isSymbol = s => typeof s === 'symbol'
5470
5471 ;// CONCATENATED MODULE: ./node_modules/lib0/time.js
5472 /**
5473 * Utility module to work with time.
5474 *
5475 * @module time
5476 */
5477
5478
5479
5480
5481 /**
5482 * Return current time.
5483 *
5484 * @return {Date}
5485 */
5486 const getDate = () => new Date()
5487
5488 /**
5489 * Return current unix time.
5490 *
5491 * @return {number}
5492 */
5493 const getUnixTime = Date.now
5494
5495 /**
5496 * Transform time (in ms) to a human readable format. E.g. 1100 => 1.1s. 60s => 1min. .001 => 10μs.
5497 *
5498 * @param {number} d duration in milliseconds
5499 * @return {string} humanized approximation of time
5500 */
5501 const humanizeDuration = d => {
5502 if (d < 60000) {
5503 const p = metric.prefix(d, -1)
5504 return math.round(p.n * 100) / 100 + p.prefix + 's'
5505 }
5506 d = math.floor(d / 1000)
5507 const seconds = d % 60
5508 const minutes = math.floor(d / 60) % 60
5509 const hours = math.floor(d / 3600) % 24
5510 const days = math.floor(d / 86400)
5511 if (days > 0) {
5512 return days + 'd' + ((hours > 0 || minutes > 30) ? ' ' + (minutes > 30 ? hours + 1 : hours) + 'h' : '')
5513 }
5514 if (hours > 0) {
5515 /* c8 ignore next */
5516 return hours + 'h' + ((minutes > 0 || seconds > 30) ? ' ' + (seconds > 30 ? minutes + 1 : minutes) + 'min' : '')
5517 }
5518 return minutes + 'min' + (seconds > 0 ? ' ' + seconds + 's' : '')
5519 }
5520
5521 ;// CONCATENATED MODULE: ./node_modules/lib0/logging.common.js
5522
5523
5524
5525
5526
5527 const BOLD = symbol_create()
5528 const UNBOLD = symbol_create()
5529 const BLUE = symbol_create()
5530 const GREY = symbol_create()
5531 const GREEN = symbol_create()
5532 const RED = symbol_create()
5533 const PURPLE = symbol_create()
5534 const ORANGE = symbol_create()
5535 const UNCOLOR = symbol_create()
5536
5537 /* c8 ignore start */
5538 /**
5539 * @param {Array<string|Symbol|Object|number>} args
5540 * @return {Array<string|object|number>}
5541 */
5542 const computeNoColorLoggingArgs = args => {
5543 const strBuilder = []
5544 const logArgs = []
5545 // try with formatting until we find something unsupported
5546 let i = 0
5547 for (; i < args.length; i++) {
5548 const arg = args[i]
5549 if (arg.constructor === String || arg.constructor === Number) {
5550 strBuilder.push(arg)
5551 } else if (arg.constructor === Object) {
5552 logArgs.push(JSON.stringify(arg))
5553 }
5554 }
5555 return logArgs
5556 }
5557 /* c8 ignore stop */
5558
5559 const loggingColors = [GREEN, PURPLE, ORANGE, BLUE]
5560 let nextColor = 0
5561 let lastLoggingTime = getUnixTime()
5562
5563 /* c8 ignore start */
5564 /**
5565 * @param {function(...any):void} _print
5566 * @param {string} moduleName
5567 * @return {function(...any):void}
5568 */
5569 const createModuleLogger = (_print, moduleName) => {
5570 const color = loggingColors[nextColor]
5571 const debugRegexVar = getVariable('log')
5572 const doLogging = debugRegexVar !== null &&
5573 (debugRegexVar === '*' || debugRegexVar === 'true' ||
5574 new RegExp(debugRegexVar, 'gi').test(moduleName))
5575 nextColor = (nextColor + 1) % loggingColors.length
5576 moduleName += ': '
5577 return !doLogging
5578 ? nop
5579 : (...args) => {
5580 const timeNow = getUnixTime()
5581 const timeDiff = timeNow - lastLoggingTime
5582 lastLoggingTime = timeNow
5583 _print(
5584 color,
5585 moduleName,
5586 UNCOLOR,
5587 ...args.map((arg) =>
5588 (typeof arg === 'string' || typeof arg === 'symbol')
5589 ? arg
5590 : JSON.stringify(arg)
5591 ),
5592 color,
5593 ' +' + timeDiff + 'ms'
5594 )
5595 }
5596 }
5597 /* c8 ignore stop */
5598
5599 ;// CONCATENATED MODULE: ./node_modules/lib0/logging.js
5600 /**
5601 * Isomorphic logging module with support for colors!
5602 *
5603 * @module logging
5604 */
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618 /**
5619 * @type {Object<Symbol,pair.Pair<string,string>>}
5620 */
5621 const _browserStyleMap = {
5622 [BOLD]: pair_create('font-weight', 'bold'),
5623 [UNBOLD]: pair_create('font-weight', 'normal'),
5624 [BLUE]: pair_create('color', 'blue'),
5625 [GREEN]: pair_create('color', 'green'),
5626 [GREY]: pair_create('color', 'grey'),
5627 [RED]: pair_create('color', 'red'),
5628 [PURPLE]: pair_create('color', 'purple'),
5629 [ORANGE]: pair_create('color', 'orange'), // not well supported in chrome when debugging node with inspector - TODO: deprecate
5630 [UNCOLOR]: pair_create('color', 'black')
5631 }
5632
5633 /**
5634 * @param {Array<string|Symbol|Object|number>} args
5635 * @return {Array<string|object|number>}
5636 */
5637 /* c8 ignore start */
5638 const computeBrowserLoggingArgs = (args) => {
5639 const strBuilder = []
5640 const styles = []
5641 const currentStyle = create()
5642 /**
5643 * @type {Array<string|Object|number>}
5644 */
5645 let logArgs = []
5646 // try with formatting until we find something unsupported
5647 let i = 0
5648 for (; i < args.length; i++) {
5649 const arg = args[i]
5650 // @ts-ignore
5651 const style = _browserStyleMap[arg]
5652 if (style !== undefined) {
5653 currentStyle.set(style.left, style.right)
5654 } else {
5655 if (arg.constructor === String || arg.constructor === Number) {
5656 const style = mapToStyleString(currentStyle)
5657 if (i > 0 || style.length > 0) {
5658 strBuilder.push('%c' + arg)
5659 styles.push(style)
5660 } else {
5661 strBuilder.push(arg)
5662 }
5663 } else {
5664 break
5665 }
5666 }
5667 }
5668 if (i > 0) {
5669 // create logArgs with what we have so far
5670 logArgs = styles
5671 logArgs.unshift(strBuilder.join(''))
5672 }
5673 // append the rest
5674 for (; i < args.length; i++) {
5675 const arg = args[i]
5676 if (!(arg instanceof Symbol)) {
5677 logArgs.push(arg)
5678 }
5679 }
5680 return logArgs
5681 }
5682 /* c8 ignore stop */
5683
5684 /* c8 ignore start */
5685 const computeLoggingArgs = supportsColor
5686 ? computeBrowserLoggingArgs
5687 : computeNoColorLoggingArgs
5688 /* c8 ignore stop */
5689
5690 /**
5691 * @param {Array<string|Symbol|Object|number>} args
5692 */
5693 const print = (...args) => {
5694 console.log(...computeLoggingArgs(args))
5695 /* c8 ignore next */
5696 vconsoles.forEach((vc) => vc.print(args))
5697 }
5698
5699 /* c8 ignore start */
5700 /**
5701 * @param {Array<string|Symbol|Object|number>} args
5702 */
5703 const warn = (...args) => {
5704 console.warn(...computeLoggingArgs(args))
5705 args.unshift(common.ORANGE)
5706 vconsoles.forEach((vc) => vc.print(args))
5707 }
5708 /* c8 ignore stop */
5709
5710 /**
5711 * @param {Error} err
5712 */
5713 /* c8 ignore start */
5714 const printError = (err) => {
5715 console.error(err)
5716 vconsoles.forEach((vc) => vc.printError(err))
5717 }
5718 /* c8 ignore stop */
5719
5720 /**
5721 * @param {string} url image location
5722 * @param {number} height height of the image in pixel
5723 */
5724 /* c8 ignore start */
5725 const printImg = (url, height) => {
5726 if (env.isBrowser) {
5727 console.log(
5728 '%c ',
5729 `font-size: ${height}px; background-size: contain; background-repeat: no-repeat; background-image: url(${url})`
5730 )
5731 // console.log('%c ', `font-size: ${height}x; background: url(${url}) no-repeat;`)
5732 }
5733 vconsoles.forEach((vc) => vc.printImg(url, height))
5734 }
5735 /* c8 ignore stop */
5736
5737 /**
5738 * @param {string} base64
5739 * @param {number} height
5740 */
5741 /* c8 ignore next 2 */
5742 const printImgBase64 = (base64, height) =>
5743 printImg(`data:image/gif;base64,${base64}`, height)
5744
5745 /**
5746 * @param {Array<string|Symbol|Object|number>} args
5747 */
5748 const group = (...args) => {
5749 console.group(...computeLoggingArgs(args))
5750 /* c8 ignore next */
5751 vconsoles.forEach((vc) => vc.group(args))
5752 }
5753
5754 /**
5755 * @param {Array<string|Symbol|Object|number>} args
5756 */
5757 const groupCollapsed = (...args) => {
5758 console.groupCollapsed(...computeLoggingArgs(args))
5759 /* c8 ignore next */
5760 vconsoles.forEach((vc) => vc.groupCollapsed(args))
5761 }
5762
5763 const groupEnd = () => {
5764 console.groupEnd()
5765 /* c8 ignore next */
5766 vconsoles.forEach((vc) => vc.groupEnd())
5767 }
5768
5769 /**
5770 * @param {function():Node} createNode
5771 */
5772 /* c8 ignore next 2 */
5773 const printDom = (createNode) =>
5774 vconsoles.forEach((vc) => vc.printDom(createNode()))
5775
5776 /**
5777 * @param {HTMLCanvasElement} canvas
5778 * @param {number} height
5779 */
5780 /* c8 ignore next 2 */
5781 const printCanvas = (canvas, height) =>
5782 printImg(canvas.toDataURL(), height)
5783
5784 const vconsoles = set_create()
5785
5786 /**
5787 * @param {Array<string|Symbol|Object|number>} args
5788 * @return {Array<Element>}
5789 */
5790 /* c8 ignore start */
5791 const _computeLineSpans = (args) => {
5792 const spans = []
5793 const currentStyle = new Map()
5794 // try with formatting until we find something unsupported
5795 let i = 0
5796 for (; i < args.length; i++) {
5797 const arg = args[i]
5798 // @ts-ignore
5799 const style = _browserStyleMap[arg]
5800 if (style !== undefined) {
5801 currentStyle.set(style.left, style.right)
5802 } else {
5803 if (arg.constructor === String || arg.constructor === Number) {
5804 // @ts-ignore
5805 const span = dom.element('span', [
5806 pair.create('style', dom.mapToStyleString(currentStyle))
5807 ], [dom.text(arg.toString())])
5808 if (span.innerHTML === '') {
5809 span.innerHTML = '&nbsp;'
5810 }
5811 spans.push(span)
5812 } else {
5813 break
5814 }
5815 }
5816 }
5817 // append the rest
5818 for (; i < args.length; i++) {
5819 let content = args[i]
5820 if (!(content instanceof Symbol)) {
5821 if (content.constructor !== String && content.constructor !== Number) {
5822 content = ' ' + json.stringify(content) + ' '
5823 }
5824 spans.push(
5825 dom.element('span', [], [dom.text(/** @type {string} */ (content))])
5826 )
5827 }
5828 }
5829 return spans
5830 }
5831 /* c8 ignore stop */
5832
5833 const lineStyle =
5834 'font-family:monospace;border-bottom:1px solid #e2e2e2;padding:2px;'
5835
5836 /* c8 ignore start */
5837 class VConsole {
5838 /**
5839 * @param {Element} dom
5840 */
5841 constructor (dom) {
5842 this.dom = dom
5843 /**
5844 * @type {Element}
5845 */
5846 this.ccontainer = this.dom
5847 this.depth = 0
5848 vconsoles.add(this)
5849 }
5850
5851 /**
5852 * @param {Array<string|Symbol|Object|number>} args
5853 * @param {boolean} collapsed
5854 */
5855 group (args, collapsed = false) {
5856 eventloop.enqueue(() => {
5857 const triangleDown = dom.element('span', [
5858 pair.create('hidden', collapsed),
5859 pair.create('style', 'color:grey;font-size:120%;')
5860 ], [dom.text('▼')])
5861 const triangleRight = dom.element('span', [
5862 pair.create('hidden', !collapsed),
5863 pair.create('style', 'color:grey;font-size:125%;')
5864 ], [dom.text('▶')])
5865 const content = dom.element(
5866 'div',
5867 [pair.create(
5868 'style',
5869 `${lineStyle};padding-left:${this.depth * 10}px`
5870 )],
5871 [triangleDown, triangleRight, dom.text(' ')].concat(
5872 _computeLineSpans(args)
5873 )
5874 )
5875 const nextContainer = dom.element('div', [
5876 pair.create('hidden', collapsed)
5877 ])
5878 const nextLine = dom.element('div', [], [content, nextContainer])
5879 dom.append(this.ccontainer, [nextLine])
5880 this.ccontainer = nextContainer
5881 this.depth++
5882 // when header is clicked, collapse/uncollapse container
5883 dom.addEventListener(content, 'click', (_event) => {
5884 nextContainer.toggleAttribute('hidden')
5885 triangleDown.toggleAttribute('hidden')
5886 triangleRight.toggleAttribute('hidden')
5887 })
5888 })
5889 }
5890
5891 /**
5892 * @param {Array<string|Symbol|Object|number>} args
5893 */
5894 groupCollapsed (args) {
5895 this.group(args, true)
5896 }
5897
5898 groupEnd () {
5899 eventloop.enqueue(() => {
5900 if (this.depth > 0) {
5901 this.depth--
5902 // @ts-ignore
5903 this.ccontainer = this.ccontainer.parentElement.parentElement
5904 }
5905 })
5906 }
5907
5908 /**
5909 * @param {Array<string|Symbol|Object|number>} args
5910 */
5911 print (args) {
5912 eventloop.enqueue(() => {
5913 dom.append(this.ccontainer, [
5914 dom.element('div', [
5915 pair.create(
5916 'style',
5917 `${lineStyle};padding-left:${this.depth * 10}px`
5918 )
5919 ], _computeLineSpans(args))
5920 ])
5921 })
5922 }
5923
5924 /**
5925 * @param {Error} err
5926 */
5927 printError (err) {
5928 this.print([common.RED, common.BOLD, err.toString()])
5929 }
5930
5931 /**
5932 * @param {string} url
5933 * @param {number} height
5934 */
5935 printImg (url, height) {
5936 eventloop.enqueue(() => {
5937 dom.append(this.ccontainer, [
5938 dom.element('img', [
5939 pair.create('src', url),
5940 pair.create('height', `${math.round(height * 1.5)}px`)
5941 ])
5942 ])
5943 })
5944 }
5945
5946 /**
5947 * @param {Node} node
5948 */
5949 printDom (node) {
5950 eventloop.enqueue(() => {
5951 dom.append(this.ccontainer, [node])
5952 })
5953 }
5954
5955 destroy () {
5956 eventloop.enqueue(() => {
5957 vconsoles.delete(this)
5958 })
5959 }
5960 }
5961 /* c8 ignore stop */
5962
5963 /**
5964 * @param {Element} dom
5965 */
5966 /* c8 ignore next */
5967 const createVConsole = (dom) => new VConsole(dom)
5968
5969 /**
5970 * @param {string} moduleName
5971 * @return {function(...any):void}
5972 */
5973 const logging_createModuleLogger = (moduleName) => createModuleLogger(print, moduleName)
5974
5975 ;// CONCATENATED MODULE: ./node_modules/lib0/iterator.js
5976 /**
5977 * Utility module to create and manipulate Iterators.
5978 *
5979 * @module iterator
5980 */
5981
5982 /**
5983 * @template T,R
5984 * @param {Iterator<T>} iterator
5985 * @param {function(T):R} f
5986 * @return {IterableIterator<R>}
5987 */
5988 const mapIterator = (iterator, f) => ({
5989 [Symbol.iterator] () {
5990 return this
5991 },
5992 // @ts-ignore
5993 next () {
5994 const r = iterator.next()
5995 return { value: r.done ? undefined : f(r.value), done: r.done }
5996 }
5997 })
5998
5999 /**
6000 * @template T
6001 * @param {function():IteratorResult<T>} next
6002 * @return {IterableIterator<T>}
6003 */
6004 const createIterator = next => ({
6005 /**
6006 * @return {IterableIterator<T>}
6007 */
6008 [Symbol.iterator] () {
6009 return this
6010 },
6011 // @ts-ignore
6012 next
6013 })
6014
6015 /**
6016 * @template T
6017 * @param {Iterator<T>} iterator
6018 * @param {function(T):boolean} filter
6019 */
6020 const iteratorFilter = (iterator, filter) => createIterator(() => {
6021 let res
6022 do {
6023 res = iterator.next()
6024 } while (!res.done && !filter(res.value))
6025 return res
6026 })
6027
6028 /**
6029 * @template T,M
6030 * @param {Iterator<T>} iterator
6031 * @param {function(T):M} fmap
6032 */
6033 const iteratorMap = (iterator, fmap) => createIterator(() => {
6034 const { done, value } = iterator.next()
6035 return { done, value: done ? undefined : fmap(value) }
6036 })
6037
6038 ;// CONCATENATED MODULE: ./node_modules/yjs/dist/yjs.mjs
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059 /**
6060 * This is an abstract interface that all Connectors should implement to keep them interchangeable.
6061 *
6062 * @note This interface is experimental and it is not advised to actually inherit this class.
6063 * It just serves as typing information.
6064 *
6065 * @extends {Observable<any>}
6066 */
6067 class AbstractConnector extends (/* unused pure expression or super */ null && (Observable)) {
6068 /**
6069 * @param {Doc} ydoc
6070 * @param {any} awareness
6071 */
6072 constructor (ydoc, awareness) {
6073 super();
6074 this.doc = ydoc;
6075 this.awareness = awareness;
6076 }
6077 }
6078
6079 class DeleteItem {
6080 /**
6081 * @param {number} clock
6082 * @param {number} len
6083 */
6084 constructor (clock, len) {
6085 /**
6086 * @type {number}
6087 */
6088 this.clock = clock;
6089 /**
6090 * @type {number}
6091 */
6092 this.len = len;
6093 }
6094 }
6095
6096 /**
6097 * We no longer maintain a DeleteStore. DeleteSet is a temporary object that is created when needed.
6098 * - When created in a transaction, it must only be accessed after sorting, and merging
6099 * - This DeleteSet is send to other clients
6100 * - We do not create a DeleteSet when we send a sync message. The DeleteSet message is created directly from StructStore
6101 * - We read a DeleteSet as part of a sync/update message. In this case the DeleteSet is already sorted and merged.
6102 */
6103 class DeleteSet {
6104 constructor () {
6105 /**
6106 * @type {Map<number,Array<DeleteItem>>}
6107 */
6108 this.clients = new Map();
6109 }
6110 }
6111
6112 /**
6113 * Iterate over all structs that the DeleteSet gc's.
6114 *
6115 * @param {Transaction} transaction
6116 * @param {DeleteSet} ds
6117 * @param {function(GC|Item):void} f
6118 *
6119 * @function
6120 */
6121 const iterateDeletedStructs = (transaction, ds, f) =>
6122 ds.clients.forEach((deletes, clientid) => {
6123 const structs = /** @type {Array<GC|Item>} */ (transaction.doc.store.clients.get(clientid));
6124 for (let i = 0; i < deletes.length; i++) {
6125 const del = deletes[i];
6126 iterateStructs(transaction, structs, del.clock, del.len, f);
6127 }
6128 });
6129
6130 /**
6131 * @param {Array<DeleteItem>} dis
6132 * @param {number} clock
6133 * @return {number|null}
6134 *
6135 * @private
6136 * @function
6137 */
6138 const findIndexDS = (dis, clock) => {
6139 let left = 0;
6140 let right = dis.length - 1;
6141 while (left <= right) {
6142 const midindex = floor((left + right) / 2);
6143 const mid = dis[midindex];
6144 const midclock = mid.clock;
6145 if (midclock <= clock) {
6146 if (clock < midclock + mid.len) {
6147 return midindex
6148 }
6149 left = midindex + 1;
6150 } else {
6151 right = midindex - 1;
6152 }
6153 }
6154 return null
6155 };
6156
6157 /**
6158 * @param {DeleteSet} ds
6159 * @param {ID} id
6160 * @return {boolean}
6161 *
6162 * @private
6163 * @function
6164 */
6165 const isDeleted = (ds, id) => {
6166 const dis = ds.clients.get(id.client);
6167 return dis !== undefined && findIndexDS(dis, id.clock) !== null
6168 };
6169
6170 /**
6171 * @param {DeleteSet} ds
6172 *
6173 * @private
6174 * @function
6175 */
6176 const sortAndMergeDeleteSet = ds => {
6177 ds.clients.forEach(dels => {
6178 dels.sort((a, b) => a.clock - b.clock);
6179 // merge items without filtering or splicing the array
6180 // i is the current pointer
6181 // j refers to the current insert position for the pointed item
6182 // try to merge dels[i] into dels[j-1] or set dels[j]=dels[i]
6183 let i, j;
6184 for (i = 1, j = 1; i < dels.length; i++) {
6185 const left = dels[j - 1];
6186 const right = dels[i];
6187 if (left.clock + left.len >= right.clock) {
6188 left.len = max(left.len, right.clock + right.len - left.clock);
6189 } else {
6190 if (j < i) {
6191 dels[j] = right;
6192 }
6193 j++;
6194 }
6195 }
6196 dels.length = j;
6197 });
6198 };
6199
6200 /**
6201 * @param {Array<DeleteSet>} dss
6202 * @return {DeleteSet} A fresh DeleteSet
6203 */
6204 const mergeDeleteSets = dss => {
6205 const merged = new DeleteSet();
6206 for (let dssI = 0; dssI < dss.length; dssI++) {
6207 dss[dssI].clients.forEach((delsLeft, client) => {
6208 if (!merged.clients.has(client)) {
6209 // Write all missing keys from current ds and all following.
6210 // If merged already contains `client` current ds has already been added.
6211 /**
6212 * @type {Array<DeleteItem>}
6213 */
6214 const dels = delsLeft.slice();
6215 for (let i = dssI + 1; i < dss.length; i++) {
6216 appendTo(dels, dss[i].clients.get(client) || []);
6217 }
6218 merged.clients.set(client, dels);
6219 }
6220 });
6221 }
6222 sortAndMergeDeleteSet(merged);
6223 return merged
6224 };
6225
6226 /**
6227 * @param {DeleteSet} ds
6228 * @param {number} client
6229 * @param {number} clock
6230 * @param {number} length
6231 *
6232 * @private
6233 * @function
6234 */
6235 const addToDeleteSet = (ds, client, clock, length) => {
6236 setIfUndefined(ds.clients, client, () => /** @type {Array<DeleteItem>} */ ([])).push(new DeleteItem(clock, length));
6237 };
6238
6239 const createDeleteSet = () => new DeleteSet();
6240
6241 /**
6242 * @param {StructStore} ss
6243 * @return {DeleteSet} Merged and sorted DeleteSet
6244 *
6245 * @private
6246 * @function
6247 */
6248 const createDeleteSetFromStructStore = ss => {
6249 const ds = createDeleteSet();
6250 ss.clients.forEach((structs, client) => {
6251 /**
6252 * @type {Array<DeleteItem>}
6253 */
6254 const dsitems = [];
6255 for (let i = 0; i < structs.length; i++) {
6256 const struct = structs[i];
6257 if (struct.deleted) {
6258 const clock = struct.id.clock;
6259 let len = struct.length;
6260 if (i + 1 < structs.length) {
6261 for (let next = structs[i + 1]; i + 1 < structs.length && next.deleted; next = structs[++i + 1]) {
6262 len += next.length;
6263 }
6264 }
6265 dsitems.push(new DeleteItem(clock, len));
6266 }
6267 }
6268 if (dsitems.length > 0) {
6269 ds.clients.set(client, dsitems);
6270 }
6271 });
6272 return ds
6273 };
6274
6275 /**
6276 * @param {DSEncoderV1 | DSEncoderV2} encoder
6277 * @param {DeleteSet} ds
6278 *
6279 * @private
6280 * @function
6281 */
6282 const writeDeleteSet = (encoder, ds) => {
6283 writeVarUint(encoder.restEncoder, ds.clients.size);
6284
6285 // Ensure that the delete set is written in a deterministic order
6286 array_from(ds.clients.entries())
6287 .sort((a, b) => b[0] - a[0])
6288 .forEach(([client, dsitems]) => {
6289 encoder.resetDsCurVal();
6290 writeVarUint(encoder.restEncoder, client);
6291 const len = dsitems.length;
6292 writeVarUint(encoder.restEncoder, len);
6293 for (let i = 0; i < len; i++) {
6294 const item = dsitems[i];
6295 encoder.writeDsClock(item.clock);
6296 encoder.writeDsLen(item.len);
6297 }
6298 });
6299 };
6300
6301 /**
6302 * @param {DSDecoderV1 | DSDecoderV2} decoder
6303 * @return {DeleteSet}
6304 *
6305 * @private
6306 * @function
6307 */
6308 const readDeleteSet = decoder => {
6309 const ds = new DeleteSet();
6310 const numClients = readVarUint(decoder.restDecoder);
6311 for (let i = 0; i < numClients; i++) {
6312 decoder.resetDsCurVal();
6313 const client = readVarUint(decoder.restDecoder);
6314 const numberOfDeletes = readVarUint(decoder.restDecoder);
6315 if (numberOfDeletes > 0) {
6316 const dsField = setIfUndefined(ds.clients, client, () => /** @type {Array<DeleteItem>} */ ([]));
6317 for (let i = 0; i < numberOfDeletes; i++) {
6318 dsField.push(new DeleteItem(decoder.readDsClock(), decoder.readDsLen()));
6319 }
6320 }
6321 }
6322 return ds
6323 };
6324
6325 /**
6326 * @todo YDecoder also contains references to String and other Decoders. Would make sense to exchange YDecoder.toUint8Array for YDecoder.DsToUint8Array()..
6327 */
6328
6329 /**
6330 * @param {DSDecoderV1 | DSDecoderV2} decoder
6331 * @param {Transaction} transaction
6332 * @param {StructStore} store
6333 * @return {Uint8Array|null} Returns a v2 update containing all deletes that couldn't be applied yet; or null if all deletes were applied successfully.
6334 *
6335 * @private
6336 * @function
6337 */
6338 const readAndApplyDeleteSet = (decoder, transaction, store) => {
6339 const unappliedDS = new DeleteSet();
6340 const numClients = readVarUint(decoder.restDecoder);
6341 for (let i = 0; i < numClients; i++) {
6342 decoder.resetDsCurVal();
6343 const client = readVarUint(decoder.restDecoder);
6344 const numberOfDeletes = readVarUint(decoder.restDecoder);
6345 const structs = store.clients.get(client) || [];
6346 const state = getState(store, client);
6347 for (let i = 0; i < numberOfDeletes; i++) {
6348 const clock = decoder.readDsClock();
6349 const clockEnd = clock + decoder.readDsLen();
6350 if (clock < state) {
6351 if (state < clockEnd) {
6352 addToDeleteSet(unappliedDS, client, state, clockEnd - state);
6353 }
6354 let index = findIndexSS(structs, clock);
6355 /**
6356 * We can ignore the case of GC and Delete structs, because we are going to skip them
6357 * @type {Item}
6358 */
6359 // @ts-ignore
6360 let struct = structs[index];
6361 // split the first item if necessary
6362 if (!struct.deleted && struct.id.clock < clock) {
6363 structs.splice(index + 1, 0, splitItem(transaction, struct, clock - struct.id.clock));
6364 index++; // increase we now want to use the next struct
6365 }
6366 while (index < structs.length) {
6367 // @ts-ignore
6368 struct = structs[index++];
6369 if (struct.id.clock < clockEnd) {
6370 if (!struct.deleted) {
6371 if (clockEnd < struct.id.clock + struct.length) {
6372 structs.splice(index, 0, splitItem(transaction, struct, clockEnd - struct.id.clock));
6373 }
6374 struct.delete(transaction);
6375 }
6376 } else {
6377 break
6378 }
6379 }
6380 } else {
6381 addToDeleteSet(unappliedDS, client, clock, clockEnd - clock);
6382 }
6383 }
6384 }
6385 if (unappliedDS.clients.size > 0) {
6386 const ds = new UpdateEncoderV2();
6387 writeVarUint(ds.restEncoder, 0); // encode 0 structs
6388 writeDeleteSet(ds, unappliedDS);
6389 return ds.toUint8Array()
6390 }
6391 return null
6392 };
6393
6394 /**
6395 * @param {DeleteSet} ds1
6396 * @param {DeleteSet} ds2
6397 */
6398 const equalDeleteSets = (ds1, ds2) => {
6399 if (ds1.clients.size !== ds2.clients.size) return false
6400 for (const [client, deleteItems1] of ds1.clients.entries()) {
6401 const deleteItems2 = /** @type {Array<import('../internals.js').DeleteItem>} */ (ds2.clients.get(client));
6402 if (deleteItems2 === undefined || deleteItems1.length !== deleteItems2.length) return false
6403 for (let i = 0; i < deleteItems1.length; i++) {
6404 const di1 = deleteItems1[i];
6405 const di2 = deleteItems2[i];
6406 if (di1.clock !== di2.clock || di1.len !== di2.len) {
6407 return false
6408 }
6409 }
6410 }
6411 return true
6412 };
6413
6414 /**
6415 * @module Y
6416 */
6417
6418 const generateNewClientId = uint32;
6419
6420 /**
6421 * @typedef {Object} DocOpts
6422 * @property {boolean} [DocOpts.gc=true] Disable garbage collection (default: gc=true)
6423 * @property {function(Item):boolean} [DocOpts.gcFilter] Will be called before an Item is garbage collected. Return false to keep the Item.
6424 * @property {string} [DocOpts.guid] Define a globally unique identifier for this document
6425 * @property {string | null} [DocOpts.collectionid] Associate this document with a collection. This only plays a role if your provider has a concept of collection.
6426 * @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.
6427 * @property {boolean} [DocOpts.autoLoad] If a subdocument, automatically load document. If this is a subdocument, remote peers will load the document as well automatically.
6428 * @property {boolean} [DocOpts.shouldLoad] Whether the document should be synced by the provider now. This is toggled to true when you call ydoc.load()
6429 */
6430
6431 /**
6432 * A Yjs instance handles the state of shared data.
6433 * @extends Observable<string>
6434 */
6435 class Doc extends observable_Observable {
6436 /**
6437 * @param {DocOpts} opts configuration
6438 */
6439 constructor ({ guid = uuidv4(), collectionid = null, gc = true, gcFilter = () => true, meta = null, autoLoad = false, shouldLoad = true } = {}) {
6440 super();
6441 this.gc = gc;
6442 this.gcFilter = gcFilter;
6443 this.clientID = generateNewClientId();
6444 this.guid = guid;
6445 this.collectionid = collectionid;
6446 /**
6447 * @type {Map<string, AbstractType<YEvent<any>>>}
6448 */
6449 this.share = new Map();
6450 this.store = new StructStore();
6451 /**
6452 * @type {Transaction | null}
6453 */
6454 this._transaction = null;
6455 /**
6456 * @type {Array<Transaction>}
6457 */
6458 this._transactionCleanups = [];
6459 /**
6460 * @type {Set<Doc>}
6461 */
6462 this.subdocs = new Set();
6463 /**
6464 * If this document is a subdocument - a document integrated into another document - then _item is defined.
6465 * @type {Item?}
6466 */
6467 this._item = null;
6468 this.shouldLoad = shouldLoad;
6469 this.autoLoad = autoLoad;
6470 this.meta = meta;
6471 /**
6472 * This is set to true when the persistence provider loaded the document from the database or when the `sync` event fires.
6473 * 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.
6474 *
6475 * @type {boolean}
6476 */
6477 this.isLoaded = false;
6478 /**
6479 * This is set to true when the connection provider has successfully synced with a backend.
6480 * Note that when using peer-to-peer providers this event may not provide very useful.
6481 * Also note that not all providers implement this feature. Provider authors are encouraged to fire
6482 * the `sync` event when the doc has been synced (with `true` as a parameter) or if connection is
6483 * lost (with false as a parameter).
6484 */
6485 this.isSynced = false;
6486 /**
6487 * Promise that resolves once the document has been loaded from a presistence provider.
6488 */
6489 this.whenLoaded = promise_create(resolve => {
6490 this.on('load', () => {
6491 this.isLoaded = true;
6492 resolve(this);
6493 });
6494 });
6495 const provideSyncedPromise = () => promise_create(resolve => {
6496 /**
6497 * @param {boolean} isSynced
6498 */
6499 const eventHandler = (isSynced) => {
6500 if (isSynced === undefined || isSynced === true) {
6501 this.off('sync', eventHandler);
6502 resolve();
6503 }
6504 };
6505 this.on('sync', eventHandler);
6506 });
6507 this.on('sync', isSynced => {
6508 if (isSynced === false && this.isSynced) {
6509 this.whenSynced = provideSyncedPromise();
6510 }
6511 this.isSynced = isSynced === undefined || isSynced === true;
6512 if (!this.isLoaded) {
6513 this.emit('load', []);
6514 }
6515 });
6516 /**
6517 * Promise that resolves once the document has been synced with a backend.
6518 * This promise is recreated when the connection is lost.
6519 * Note the documentation about the `isSynced` property.
6520 */
6521 this.whenSynced = provideSyncedPromise();
6522 }
6523
6524 /**
6525 * Notify the parent document that you request to load data into this subdocument (if it is a subdocument).
6526 *
6527 * `load()` might be used in the future to request any provider to load the most current data.
6528 *
6529 * It is safe to call `load()` multiple times.
6530 */
6531 load () {
6532 const item = this._item;
6533 if (item !== null && !this.shouldLoad) {
6534 transact(/** @type {any} */ (item.parent).doc, transaction => {
6535 transaction.subdocsLoaded.add(this);
6536 }, null, true);
6537 }
6538 this.shouldLoad = true;
6539 }
6540
6541 getSubdocs () {
6542 return this.subdocs
6543 }
6544
6545 getSubdocGuids () {
6546 return new Set(array_from(this.subdocs).map(doc => doc.guid))
6547 }
6548
6549 /**
6550 * Changes that happen inside of a transaction are bundled. This means that
6551 * the observer fires _after_ the transaction is finished and that all changes
6552 * that happened inside of the transaction are sent as one message to the
6553 * other peers.
6554 *
6555 * @template T
6556 * @param {function(Transaction):T} f The function that should be executed as a transaction
6557 * @param {any} [origin] Origin of who started the transaction. Will be stored on transaction.origin
6558 * @return T
6559 *
6560 * @public
6561 */
6562 transact (f, origin = null) {
6563 return transact(this, f, origin)
6564 }
6565
6566 /**
6567 * Define a shared data type.
6568 *
6569 * Multiple calls of `y.get(name, TypeConstructor)` yield the same result
6570 * and do not overwrite each other. I.e.
6571 * `y.define(name, Y.Array) === y.define(name, Y.Array)`
6572 *
6573 * After this method is called, the type is also available on `y.share.get(name)`.
6574 *
6575 * *Best Practices:*
6576 * Define all types right after the Yjs instance is created and store them in a separate object.
6577 * Also use the typed methods `getText(name)`, `getArray(name)`, ..
6578 *
6579 * @example
6580 * const y = new Y(..)
6581 * const appState = {
6582 * document: y.getText('document')
6583 * comments: y.getArray('comments')
6584 * }
6585 *
6586 * @param {string} name
6587 * @param {Function} TypeConstructor The constructor of the type definition. E.g. Y.Text, Y.Array, Y.Map, ...
6588 * @return {AbstractType<any>} The created type. Constructed with TypeConstructor
6589 *
6590 * @public
6591 */
6592 get (name, TypeConstructor = AbstractType) {
6593 const type = setIfUndefined(this.share, name, () => {
6594 // @ts-ignore
6595 const t = new TypeConstructor();
6596 t._integrate(this, null);
6597 return t
6598 });
6599 const Constr = type.constructor;
6600 if (TypeConstructor !== AbstractType && Constr !== TypeConstructor) {
6601 if (Constr === AbstractType) {
6602 // @ts-ignore
6603 const t = new TypeConstructor();
6604 t._map = type._map;
6605 type._map.forEach(/** @param {Item?} n */ n => {
6606 for (; n !== null; n = n.left) {
6607 // @ts-ignore
6608 n.parent = t;
6609 }
6610 });
6611 t._start = type._start;
6612 for (let n = t._start; n !== null; n = n.right) {
6613 n.parent = t;
6614 }
6615 t._length = type._length;
6616 this.share.set(name, t);
6617 t._integrate(this, null);
6618 return t
6619 } else {
6620 throw new Error(`Type with the name ${name} has already been defined with a different constructor`)
6621 }
6622 }
6623 return type
6624 }
6625
6626 /**
6627 * @template T
6628 * @param {string} [name]
6629 * @return {YArray<T>}
6630 *
6631 * @public
6632 */
6633 getArray (name = '') {
6634 // @ts-ignore
6635 return this.get(name, YArray)
6636 }
6637
6638 /**
6639 * @param {string} [name]
6640 * @return {YText}
6641 *
6642 * @public
6643 */
6644 getText (name = '') {
6645 // @ts-ignore
6646 return this.get(name, YText)
6647 }
6648
6649 /**
6650 * @template T
6651 * @param {string} [name]
6652 * @return {YMap<T>}
6653 *
6654 * @public
6655 */
6656 getMap (name = '') {
6657 // @ts-ignore
6658 return this.get(name, YMap)
6659 }
6660
6661 /**
6662 * @param {string} [name]
6663 * @return {YXmlFragment}
6664 *
6665 * @public
6666 */
6667 getXmlFragment (name = '') {
6668 // @ts-ignore
6669 return this.get(name, YXmlFragment)
6670 }
6671
6672 /**
6673 * Converts the entire document into a js object, recursively traversing each yjs type
6674 * Doesn't log types that have not been defined (using ydoc.getType(..)).
6675 *
6676 * @deprecated Do not use this method and rather call toJSON directly on the shared types.
6677 *
6678 * @return {Object<string, any>}
6679 */
6680 toJSON () {
6681 /**
6682 * @type {Object<string, any>}
6683 */
6684 const doc = {};
6685
6686 this.share.forEach((value, key) => {
6687 doc[key] = value.toJSON();
6688 });
6689
6690 return doc
6691 }
6692
6693 /**
6694 * Emit `destroy` event and unregister all event handlers.
6695 */
6696 destroy () {
6697 array_from(this.subdocs).forEach(subdoc => subdoc.destroy());
6698 const item = this._item;
6699 if (item !== null) {
6700 this._item = null;
6701 const content = /** @type {ContentDoc} */ (item.content);
6702 content.doc = new Doc({ guid: this.guid, ...content.opts, shouldLoad: false });
6703 content.doc._item = item;
6704 transact(/** @type {any} */ (item).parent.doc, transaction => {
6705 const doc = content.doc;
6706 if (!item.deleted) {
6707 transaction.subdocsAdded.add(doc);
6708 }
6709 transaction.subdocsRemoved.add(this);
6710 }, null, true);
6711 }
6712 this.emit('destroyed', [true]);
6713 this.emit('destroy', [this]);
6714 super.destroy();
6715 }
6716
6717 /**
6718 * @param {string} eventName
6719 * @param {function(...any):any} f
6720 */
6721 on (eventName, f) {
6722 super.on(eventName, f);
6723 }
6724
6725 /**
6726 * @param {string} eventName
6727 * @param {function} f
6728 */
6729 off (eventName, f) {
6730 super.off(eventName, f);
6731 }
6732 }
6733
6734 class DSDecoderV1 {
6735 /**
6736 * @param {decoding.Decoder} decoder
6737 */
6738 constructor (decoder) {
6739 this.restDecoder = decoder;
6740 }
6741
6742 resetDsCurVal () {
6743 // nop
6744 }
6745
6746 /**
6747 * @return {number}
6748 */
6749 readDsClock () {
6750 return readVarUint(this.restDecoder)
6751 }
6752
6753 /**
6754 * @return {number}
6755 */
6756 readDsLen () {
6757 return readVarUint(this.restDecoder)
6758 }
6759 }
6760
6761 class UpdateDecoderV1 extends DSDecoderV1 {
6762 /**
6763 * @return {ID}
6764 */
6765 readLeftID () {
6766 return createID(readVarUint(this.restDecoder), readVarUint(this.restDecoder))
6767 }
6768
6769 /**
6770 * @return {ID}
6771 */
6772 readRightID () {
6773 return createID(readVarUint(this.restDecoder), readVarUint(this.restDecoder))
6774 }
6775
6776 /**
6777 * Read the next client id.
6778 * Use this in favor of readID whenever possible to reduce the number of objects created.
6779 */
6780 readClient () {
6781 return readVarUint(this.restDecoder)
6782 }
6783
6784 /**
6785 * @return {number} info An unsigned 8-bit integer
6786 */
6787 readInfo () {
6788 return readUint8(this.restDecoder)
6789 }
6790
6791 /**
6792 * @return {string}
6793 */
6794 readString () {
6795 return readVarString(this.restDecoder)
6796 }
6797
6798 /**
6799 * @return {boolean} isKey
6800 */
6801 readParentInfo () {
6802 return readVarUint(this.restDecoder) === 1
6803 }
6804
6805 /**
6806 * @return {number} info An unsigned 8-bit integer
6807 */
6808 readTypeRef () {
6809 return readVarUint(this.restDecoder)
6810 }
6811
6812 /**
6813 * Write len of a struct - well suited for Opt RLE encoder.
6814 *
6815 * @return {number} len
6816 */
6817 readLen () {
6818 return readVarUint(this.restDecoder)
6819 }
6820
6821 /**
6822 * @return {any}
6823 */
6824 readAny () {
6825 return readAny(this.restDecoder)
6826 }
6827
6828 /**
6829 * @return {Uint8Array}
6830 */
6831 readBuf () {
6832 return copyUint8Array(readVarUint8Array(this.restDecoder))
6833 }
6834
6835 /**
6836 * Legacy implementation uses JSON parse. We use any-decoding in v2.
6837 *
6838 * @return {any}
6839 */
6840 readJSON () {
6841 return JSON.parse(readVarString(this.restDecoder))
6842 }
6843
6844 /**
6845 * @return {string}
6846 */
6847 readKey () {
6848 return readVarString(this.restDecoder)
6849 }
6850 }
6851
6852 class DSDecoderV2 {
6853 /**
6854 * @param {decoding.Decoder} decoder
6855 */
6856 constructor (decoder) {
6857 /**
6858 * @private
6859 */
6860 this.dsCurrVal = 0;
6861 this.restDecoder = decoder;
6862 }
6863
6864 resetDsCurVal () {
6865 this.dsCurrVal = 0;
6866 }
6867
6868 /**
6869 * @return {number}
6870 */
6871 readDsClock () {
6872 this.dsCurrVal += readVarUint(this.restDecoder);
6873 return this.dsCurrVal
6874 }
6875
6876 /**
6877 * @return {number}
6878 */
6879 readDsLen () {
6880 const diff = readVarUint(this.restDecoder) + 1;
6881 this.dsCurrVal += diff;
6882 return diff
6883 }
6884 }
6885
6886 class UpdateDecoderV2 extends DSDecoderV2 {
6887 /**
6888 * @param {decoding.Decoder} decoder
6889 */
6890 constructor (decoder) {
6891 super(decoder);
6892 /**
6893 * List of cached keys. If the keys[id] does not exist, we read a new key
6894 * from stringEncoder and push it to keys.
6895 *
6896 * @type {Array<string>}
6897 */
6898 this.keys = [];
6899 readVarUint(decoder); // read feature flag - currently unused
6900 this.keyClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder));
6901 this.clientDecoder = new UintOptRleDecoder(readVarUint8Array(decoder));
6902 this.leftClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder));
6903 this.rightClockDecoder = new IntDiffOptRleDecoder(readVarUint8Array(decoder));
6904 this.infoDecoder = new RleDecoder(readVarUint8Array(decoder), readUint8);
6905 this.stringDecoder = new StringDecoder(readVarUint8Array(decoder));
6906 this.parentInfoDecoder = new RleDecoder(readVarUint8Array(decoder), readUint8);
6907 this.typeRefDecoder = new UintOptRleDecoder(readVarUint8Array(decoder));
6908 this.lenDecoder = new UintOptRleDecoder(readVarUint8Array(decoder));
6909 }
6910
6911 /**
6912 * @return {ID}
6913 */
6914 readLeftID () {
6915 return new ID(this.clientDecoder.read(), this.leftClockDecoder.read())
6916 }
6917
6918 /**
6919 * @return {ID}
6920 */
6921 readRightID () {
6922 return new ID(this.clientDecoder.read(), this.rightClockDecoder.read())
6923 }
6924
6925 /**
6926 * Read the next client id.
6927 * Use this in favor of readID whenever possible to reduce the number of objects created.
6928 */
6929 readClient () {
6930 return this.clientDecoder.read()
6931 }
6932
6933 /**
6934 * @return {number} info An unsigned 8-bit integer
6935 */
6936 readInfo () {
6937 return /** @type {number} */ (this.infoDecoder.read())
6938 }
6939
6940 /**
6941 * @return {string}
6942 */
6943 readString () {
6944 return this.stringDecoder.read()
6945 }
6946
6947 /**
6948 * @return {boolean}
6949 */
6950 readParentInfo () {
6951 return this.parentInfoDecoder.read() === 1
6952 }
6953
6954 /**
6955 * @return {number} An unsigned 8-bit integer
6956 */
6957 readTypeRef () {
6958 return this.typeRefDecoder.read()
6959 }
6960
6961 /**
6962 * Write len of a struct - well suited for Opt RLE encoder.
6963 *
6964 * @return {number}
6965 */
6966 readLen () {
6967 return this.lenDecoder.read()
6968 }
6969
6970 /**
6971 * @return {any}
6972 */
6973 readAny () {
6974 return readAny(this.restDecoder)
6975 }
6976
6977 /**
6978 * @return {Uint8Array}
6979 */
6980 readBuf () {
6981 return readVarUint8Array(this.restDecoder)
6982 }
6983
6984 /**
6985 * This is mainly here for legacy purposes.
6986 *
6987 * 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.
6988 *
6989 * @return {any}
6990 */
6991 readJSON () {
6992 return readAny(this.restDecoder)
6993 }
6994
6995 /**
6996 * @return {string}
6997 */
6998 readKey () {
6999 const keyClock = this.keyClockDecoder.read();
7000 if (keyClock < this.keys.length) {
7001 return this.keys[keyClock]
7002 } else {
7003 const key = this.stringDecoder.read();
7004 this.keys.push(key);
7005 return key
7006 }
7007 }
7008 }
7009
7010 class DSEncoderV1 {
7011 constructor () {
7012 this.restEncoder = createEncoder();
7013 }
7014
7015 toUint8Array () {
7016 return toUint8Array(this.restEncoder)
7017 }
7018
7019 resetDsCurVal () {
7020 // nop
7021 }
7022
7023 /**
7024 * @param {number} clock
7025 */
7026 writeDsClock (clock) {
7027 writeVarUint(this.restEncoder, clock);
7028 }
7029
7030 /**
7031 * @param {number} len
7032 */
7033 writeDsLen (len) {
7034 writeVarUint(this.restEncoder, len);
7035 }
7036 }
7037
7038 class UpdateEncoderV1 extends DSEncoderV1 {
7039 /**
7040 * @param {ID} id
7041 */
7042 writeLeftID (id) {
7043 writeVarUint(this.restEncoder, id.client);
7044 writeVarUint(this.restEncoder, id.clock);
7045 }
7046
7047 /**
7048 * @param {ID} id
7049 */
7050 writeRightID (id) {
7051 writeVarUint(this.restEncoder, id.client);
7052 writeVarUint(this.restEncoder, id.clock);
7053 }
7054
7055 /**
7056 * Use writeClient and writeClock instead of writeID if possible.
7057 * @param {number} client
7058 */
7059 writeClient (client) {
7060 writeVarUint(this.restEncoder, client);
7061 }
7062
7063 /**
7064 * @param {number} info An unsigned 8-bit integer
7065 */
7066 writeInfo (info) {
7067 writeUint8(this.restEncoder, info);
7068 }
7069
7070 /**
7071 * @param {string} s
7072 */
7073 writeString (s) {
7074 writeVarString(this.restEncoder, s);
7075 }
7076
7077 /**
7078 * @param {boolean} isYKey
7079 */
7080 writeParentInfo (isYKey) {
7081 writeVarUint(this.restEncoder, isYKey ? 1 : 0);
7082 }
7083
7084 /**
7085 * @param {number} info An unsigned 8-bit integer
7086 */
7087 writeTypeRef (info) {
7088 writeVarUint(this.restEncoder, info);
7089 }
7090
7091 /**
7092 * Write len of a struct - well suited for Opt RLE encoder.
7093 *
7094 * @param {number} len
7095 */
7096 writeLen (len) {
7097 writeVarUint(this.restEncoder, len);
7098 }
7099
7100 /**
7101 * @param {any} any
7102 */
7103 writeAny (any) {
7104 writeAny(this.restEncoder, any);
7105 }
7106
7107 /**
7108 * @param {Uint8Array} buf
7109 */
7110 writeBuf (buf) {
7111 writeVarUint8Array(this.restEncoder, buf);
7112 }
7113
7114 /**
7115 * @param {any} embed
7116 */
7117 writeJSON (embed) {
7118 writeVarString(this.restEncoder, JSON.stringify(embed));
7119 }
7120
7121 /**
7122 * @param {string} key
7123 */
7124 writeKey (key) {
7125 writeVarString(this.restEncoder, key);
7126 }
7127 }
7128
7129 class DSEncoderV2 {
7130 constructor () {
7131 this.restEncoder = createEncoder(); // encodes all the rest / non-optimized
7132 this.dsCurrVal = 0;
7133 }
7134
7135 toUint8Array () {
7136 return toUint8Array(this.restEncoder)
7137 }
7138
7139 resetDsCurVal () {
7140 this.dsCurrVal = 0;
7141 }
7142
7143 /**
7144 * @param {number} clock
7145 */
7146 writeDsClock (clock) {
7147 const diff = clock - this.dsCurrVal;
7148 this.dsCurrVal = clock;
7149 writeVarUint(this.restEncoder, diff);
7150 }
7151
7152 /**
7153 * @param {number} len
7154 */
7155 writeDsLen (len) {
7156 if (len === 0) {
7157 unexpectedCase();
7158 }
7159 writeVarUint(this.restEncoder, len - 1);
7160 this.dsCurrVal += len;
7161 }
7162 }
7163
7164 class UpdateEncoderV2 extends DSEncoderV2 {
7165 constructor () {
7166 super();
7167 /**
7168 * @type {Map<string,number>}
7169 */
7170 this.keyMap = new Map();
7171 /**
7172 * Refers to the next uniqe key-identifier to me used.
7173 * See writeKey method for more information.
7174 *
7175 * @type {number}
7176 */
7177 this.keyClock = 0;
7178 this.keyClockEncoder = new IntDiffOptRleEncoder();
7179 this.clientEncoder = new UintOptRleEncoder();
7180 this.leftClockEncoder = new IntDiffOptRleEncoder();
7181 this.rightClockEncoder = new IntDiffOptRleEncoder();
7182 this.infoEncoder = new RleEncoder(writeUint8);
7183 this.stringEncoder = new StringEncoder();
7184 this.parentInfoEncoder = new RleEncoder(writeUint8);
7185 this.typeRefEncoder = new UintOptRleEncoder();
7186 this.lenEncoder = new UintOptRleEncoder();
7187 }
7188
7189 toUint8Array () {
7190 const encoder = createEncoder();
7191 writeVarUint(encoder, 0); // this is a feature flag that we might use in the future
7192 writeVarUint8Array(encoder, this.keyClockEncoder.toUint8Array());
7193 writeVarUint8Array(encoder, this.clientEncoder.toUint8Array());
7194 writeVarUint8Array(encoder, this.leftClockEncoder.toUint8Array());
7195 writeVarUint8Array(encoder, this.rightClockEncoder.toUint8Array());
7196 writeVarUint8Array(encoder, toUint8Array(this.infoEncoder));
7197 writeVarUint8Array(encoder, this.stringEncoder.toUint8Array());
7198 writeVarUint8Array(encoder, toUint8Array(this.parentInfoEncoder));
7199 writeVarUint8Array(encoder, this.typeRefEncoder.toUint8Array());
7200 writeVarUint8Array(encoder, this.lenEncoder.toUint8Array());
7201 // @note The rest encoder is appended! (note the missing var)
7202 writeUint8Array(encoder, toUint8Array(this.restEncoder));
7203 return toUint8Array(encoder)
7204 }
7205
7206 /**
7207 * @param {ID} id
7208 */
7209 writeLeftID (id) {
7210 this.clientEncoder.write(id.client);
7211 this.leftClockEncoder.write(id.clock);
7212 }
7213
7214 /**
7215 * @param {ID} id
7216 */
7217 writeRightID (id) {
7218 this.clientEncoder.write(id.client);
7219 this.rightClockEncoder.write(id.clock);
7220 }
7221
7222 /**
7223 * @param {number} client
7224 */
7225 writeClient (client) {
7226 this.clientEncoder.write(client);
7227 }
7228
7229 /**
7230 * @param {number} info An unsigned 8-bit integer
7231 */
7232 writeInfo (info) {
7233 this.infoEncoder.write(info);
7234 }
7235
7236 /**
7237 * @param {string} s
7238 */
7239 writeString (s) {
7240 this.stringEncoder.write(s);
7241 }
7242
7243 /**
7244 * @param {boolean} isYKey
7245 */
7246 writeParentInfo (isYKey) {
7247 this.parentInfoEncoder.write(isYKey ? 1 : 0);
7248 }
7249
7250 /**
7251 * @param {number} info An unsigned 8-bit integer
7252 */
7253 writeTypeRef (info) {
7254 this.typeRefEncoder.write(info);
7255 }
7256
7257 /**
7258 * Write len of a struct - well suited for Opt RLE encoder.
7259 *
7260 * @param {number} len
7261 */
7262 writeLen (len) {
7263 this.lenEncoder.write(len);
7264 }
7265
7266 /**
7267 * @param {any} any
7268 */
7269 writeAny (any) {
7270 writeAny(this.restEncoder, any);
7271 }
7272
7273 /**
7274 * @param {Uint8Array} buf
7275 */
7276 writeBuf (buf) {
7277 writeVarUint8Array(this.restEncoder, buf);
7278 }
7279
7280 /**
7281 * This is mainly here for legacy purposes.
7282 *
7283 * 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.
7284 *
7285 * @param {any} embed
7286 */
7287 writeJSON (embed) {
7288 writeAny(this.restEncoder, embed);
7289 }
7290
7291 /**
7292 * Property keys are often reused. For example, in y-prosemirror the key `bold` might
7293 * occur very often. For a 3d application, the key `position` might occur very often.
7294 *
7295 * We cache these keys in a Map and refer to them via a unique number.
7296 *
7297 * @param {string} key
7298 */
7299 writeKey (key) {
7300 const clock = this.keyMap.get(key);
7301 if (clock === undefined) {
7302 /**
7303 * @todo uncomment to introduce this feature finally
7304 *
7305 * Background. The ContentFormat object was always encoded using writeKey, but the decoder used to use readString.
7306 * Furthermore, I forgot to set the keyclock. So everything was working fine.
7307 *
7308 * However, this feature here is basically useless as it is not being used (it actually only consumes extra memory).
7309 *
7310 * I don't know yet how to reintroduce this feature..
7311 *
7312 * Older clients won't be able to read updates when we reintroduce this feature. So this should probably be done using a flag.
7313 *
7314 */
7315 // this.keyMap.set(key, this.keyClock)
7316 this.keyClockEncoder.write(this.keyClock++);
7317 this.stringEncoder.write(key);
7318 } else {
7319 this.keyClockEncoder.write(clock);
7320 }
7321 }
7322 }
7323
7324 /**
7325 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7326 * @param {Array<GC|Item>} structs All structs by `client`
7327 * @param {number} client
7328 * @param {number} clock write structs starting with `ID(client,clock)`
7329 *
7330 * @function
7331 */
7332 const writeStructs = (encoder, structs, client, clock) => {
7333 // write first id
7334 clock = max(clock, structs[0].id.clock); // make sure the first id exists
7335 const startNewStructs = findIndexSS(structs, clock);
7336 // write # encoded structs
7337 writeVarUint(encoder.restEncoder, structs.length - startNewStructs);
7338 encoder.writeClient(client);
7339 writeVarUint(encoder.restEncoder, clock);
7340 const firstStruct = structs[startNewStructs];
7341 // write first struct with an offset
7342 firstStruct.write(encoder, clock - firstStruct.id.clock);
7343 for (let i = startNewStructs + 1; i < structs.length; i++) {
7344 structs[i].write(encoder, 0);
7345 }
7346 };
7347
7348 /**
7349 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7350 * @param {StructStore} store
7351 * @param {Map<number,number>} _sm
7352 *
7353 * @private
7354 * @function
7355 */
7356 const writeClientsStructs = (encoder, store, _sm) => {
7357 // we filter all valid _sm entries into sm
7358 const sm = new Map();
7359 _sm.forEach((clock, client) => {
7360 // only write if new structs are available
7361 if (getState(store, client) > clock) {
7362 sm.set(client, clock);
7363 }
7364 });
7365 getStateVector(store).forEach((_clock, client) => {
7366 if (!_sm.has(client)) {
7367 sm.set(client, 0);
7368 }
7369 });
7370 // write # states that were updated
7371 writeVarUint(encoder.restEncoder, sm.size);
7372 // Write items with higher client ids first
7373 // This heavily improves the conflict algorithm.
7374 array_from(sm.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
7375 writeStructs(encoder, /** @type {Array<GC|Item>} */ (store.clients.get(client)), client, clock);
7376 });
7377 };
7378
7379 /**
7380 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder The decoder object to read data from.
7381 * @param {Doc} doc
7382 * @return {Map<number, { i: number, refs: Array<Item | GC> }>}
7383 *
7384 * @private
7385 * @function
7386 */
7387 const readClientsStructRefs = (decoder, doc) => {
7388 /**
7389 * @type {Map<number, { i: number, refs: Array<Item | GC> }>}
7390 */
7391 const clientRefs = create();
7392 const numOfStateUpdates = readVarUint(decoder.restDecoder);
7393 for (let i = 0; i < numOfStateUpdates; i++) {
7394 const numberOfStructs = readVarUint(decoder.restDecoder);
7395 /**
7396 * @type {Array<GC|Item>}
7397 */
7398 const refs = new Array(numberOfStructs);
7399 const client = decoder.readClient();
7400 let clock = readVarUint(decoder.restDecoder);
7401 // const start = performance.now()
7402 clientRefs.set(client, { i: 0, refs });
7403 for (let i = 0; i < numberOfStructs; i++) {
7404 const info = decoder.readInfo();
7405 switch (BITS5 & info) {
7406 case 0: { // GC
7407 const len = decoder.readLen();
7408 refs[i] = new GC(createID(client, clock), len);
7409 clock += len;
7410 break
7411 }
7412 case 10: { // Skip Struct (nothing to apply)
7413 // @todo we could reduce the amount of checks by adding Skip struct to clientRefs so we know that something is missing.
7414 const len = readVarUint(decoder.restDecoder);
7415 refs[i] = new Skip(createID(client, clock), len);
7416 clock += len;
7417 break
7418 }
7419 default: { // Item with content
7420 /**
7421 * The optimized implementation doesn't use any variables because inlining variables is faster.
7422 * Below a non-optimized version is shown that implements the basic algorithm with
7423 * a few comments
7424 */
7425 const cantCopyParentInfo = (info & (BIT7 | BIT8)) === 0;
7426 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
7427 // and we read the next string as parentYKey.
7428 // It indicates how we store/retrieve parent from `y.share`
7429 // @type {string|null}
7430 const struct = new Item(
7431 createID(client, clock),
7432 null, // leftd
7433 (info & BIT8) === BIT8 ? decoder.readLeftID() : null, // origin
7434 null, // right
7435 (info & BIT7) === BIT7 ? decoder.readRightID() : null, // right origin
7436 cantCopyParentInfo ? (decoder.readParentInfo() ? doc.get(decoder.readString()) : decoder.readLeftID()) : null, // parent
7437 cantCopyParentInfo && (info & BIT6) === BIT6 ? decoder.readString() : null, // parentSub
7438 readItemContent(decoder, info) // item content
7439 );
7440 /* A non-optimized implementation of the above algorithm:
7441
7442 // The item that was originally to the left of this item.
7443 const origin = (info & binary.BIT8) === binary.BIT8 ? decoder.readLeftID() : null
7444 // The item that was originally to the right of this item.
7445 const rightOrigin = (info & binary.BIT7) === binary.BIT7 ? decoder.readRightID() : null
7446 const cantCopyParentInfo = (info & (binary.BIT7 | binary.BIT8)) === 0
7447 const hasParentYKey = cantCopyParentInfo ? decoder.readParentInfo() : false
7448 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
7449 // and we read the next string as parentYKey.
7450 // It indicates how we store/retrieve parent from `y.share`
7451 // @type {string|null}
7452 const parentYKey = cantCopyParentInfo && hasParentYKey ? decoder.readString() : null
7453
7454 const struct = new Item(
7455 createID(client, clock),
7456 null, // leftd
7457 origin, // origin
7458 null, // right
7459 rightOrigin, // right origin
7460 cantCopyParentInfo && !hasParentYKey ? decoder.readLeftID() : (parentYKey !== null ? doc.get(parentYKey) : null), // parent
7461 cantCopyParentInfo && (info & binary.BIT6) === binary.BIT6 ? decoder.readString() : null, // parentSub
7462 readItemContent(decoder, info) // item content
7463 )
7464 */
7465 refs[i] = struct;
7466 clock += struct.length;
7467 }
7468 }
7469 }
7470 // console.log('time to read: ', performance.now() - start) // @todo remove
7471 }
7472 return clientRefs
7473 };
7474
7475 /**
7476 * Resume computing structs generated by struct readers.
7477 *
7478 * While there is something to do, we integrate structs in this order
7479 * 1. top element on stack, if stack is not empty
7480 * 2. next element from current struct reader (if empty, use next struct reader)
7481 *
7482 * If struct causally depends on another struct (ref.missing), we put next reader of
7483 * `ref.id.client` on top of stack.
7484 *
7485 * At some point we find a struct that has no causal dependencies,
7486 * then we start emptying the stack.
7487 *
7488 * It is not possible to have circles: i.e. struct1 (from client1) depends on struct2 (from client2)
7489 * depends on struct3 (from client1). Therefore the max stack size is eqaul to `structReaders.length`.
7490 *
7491 * This method is implemented in a way so that we can resume computation if this update
7492 * causally depends on another update.
7493 *
7494 * @param {Transaction} transaction
7495 * @param {StructStore} store
7496 * @param {Map<number, { i: number, refs: (GC | Item)[] }>} clientsStructRefs
7497 * @return { null | { update: Uint8Array, missing: Map<number,number> } }
7498 *
7499 * @private
7500 * @function
7501 */
7502 const integrateStructs = (transaction, store, clientsStructRefs) => {
7503 /**
7504 * @type {Array<Item | GC>}
7505 */
7506 const stack = [];
7507 // 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.
7508 let clientsStructRefsIds = array_from(clientsStructRefs.keys()).sort((a, b) => a - b);
7509 if (clientsStructRefsIds.length === 0) {
7510 return null
7511 }
7512 const getNextStructTarget = () => {
7513 if (clientsStructRefsIds.length === 0) {
7514 return null
7515 }
7516 let nextStructsTarget = /** @type {{i:number,refs:Array<GC|Item>}} */ (clientsStructRefs.get(clientsStructRefsIds[clientsStructRefsIds.length - 1]));
7517 while (nextStructsTarget.refs.length === nextStructsTarget.i) {
7518 clientsStructRefsIds.pop();
7519 if (clientsStructRefsIds.length > 0) {
7520 nextStructsTarget = /** @type {{i:number,refs:Array<GC|Item>}} */ (clientsStructRefs.get(clientsStructRefsIds[clientsStructRefsIds.length - 1]));
7521 } else {
7522 return null
7523 }
7524 }
7525 return nextStructsTarget
7526 };
7527 let curStructsTarget = getNextStructTarget();
7528 if (curStructsTarget === null && stack.length === 0) {
7529 return null
7530 }
7531
7532 /**
7533 * @type {StructStore}
7534 */
7535 const restStructs = new StructStore();
7536 const missingSV = new Map();
7537 /**
7538 * @param {number} client
7539 * @param {number} clock
7540 */
7541 const updateMissingSv = (client, clock) => {
7542 const mclock = missingSV.get(client);
7543 if (mclock == null || mclock > clock) {
7544 missingSV.set(client, clock);
7545 }
7546 };
7547 /**
7548 * @type {GC|Item}
7549 */
7550 let stackHead = /** @type {any} */ (curStructsTarget).refs[/** @type {any} */ (curStructsTarget).i++];
7551 // caching the state because it is used very often
7552 const state = new Map();
7553
7554 const addStackToRestSS = () => {
7555 for (const item of stack) {
7556 const client = item.id.client;
7557 const unapplicableItems = clientsStructRefs.get(client);
7558 if (unapplicableItems) {
7559 // decrement because we weren't able to apply previous operation
7560 unapplicableItems.i--;
7561 restStructs.clients.set(client, unapplicableItems.refs.slice(unapplicableItems.i));
7562 clientsStructRefs.delete(client);
7563 unapplicableItems.i = 0;
7564 unapplicableItems.refs = [];
7565 } else {
7566 // item was the last item on clientsStructRefs and the field was already cleared. Add item to restStructs and continue
7567 restStructs.clients.set(client, [item]);
7568 }
7569 // remove client from clientsStructRefsIds to prevent users from applying the same update again
7570 clientsStructRefsIds = clientsStructRefsIds.filter(c => c !== client);
7571 }
7572 stack.length = 0;
7573 };
7574
7575 // iterate over all struct readers until we are done
7576 while (true) {
7577 if (stackHead.constructor !== Skip) {
7578 const localClock = setIfUndefined(state, stackHead.id.client, () => getState(store, stackHead.id.client));
7579 const offset = localClock - stackHead.id.clock;
7580 if (offset < 0) {
7581 // update from the same client is missing
7582 stack.push(stackHead);
7583 updateMissingSv(stackHead.id.client, stackHead.id.clock - 1);
7584 // hid a dead wall, add all items from stack to restSS
7585 addStackToRestSS();
7586 } else {
7587 const missing = stackHead.getMissing(transaction, store);
7588 if (missing !== null) {
7589 stack.push(stackHead);
7590 // get the struct reader that has the missing struct
7591 /**
7592 * @type {{ refs: Array<GC|Item>, i: number }}
7593 */
7594 const structRefs = clientsStructRefs.get(/** @type {number} */ (missing)) || { refs: [], i: 0 };
7595 if (structRefs.refs.length === structRefs.i) {
7596 // This update message causally depends on another update message that doesn't exist yet
7597 updateMissingSv(/** @type {number} */ (missing), getState(store, missing));
7598 addStackToRestSS();
7599 } else {
7600 stackHead = structRefs.refs[structRefs.i++];
7601 continue
7602 }
7603 } else if (offset === 0 || offset < stackHead.length) {
7604 // all fine, apply the stackhead
7605 stackHead.integrate(transaction, offset);
7606 state.set(stackHead.id.client, stackHead.id.clock + stackHead.length);
7607 }
7608 }
7609 }
7610 // iterate to next stackHead
7611 if (stack.length > 0) {
7612 stackHead = /** @type {GC|Item} */ (stack.pop());
7613 } else if (curStructsTarget !== null && curStructsTarget.i < curStructsTarget.refs.length) {
7614 stackHead = /** @type {GC|Item} */ (curStructsTarget.refs[curStructsTarget.i++]);
7615 } else {
7616 curStructsTarget = getNextStructTarget();
7617 if (curStructsTarget === null) {
7618 // we are done!
7619 break
7620 } else {
7621 stackHead = /** @type {GC|Item} */ (curStructsTarget.refs[curStructsTarget.i++]);
7622 }
7623 }
7624 }
7625 if (restStructs.clients.size > 0) {
7626 const encoder = new UpdateEncoderV2();
7627 writeClientsStructs(encoder, restStructs, new Map());
7628 // write empty deleteset
7629 // writeDeleteSet(encoder, new DeleteSet())
7630 writeVarUint(encoder.restEncoder, 0); // => no need for an extra function call, just write 0 deletes
7631 return { missing: missingSV, update: encoder.toUint8Array() }
7632 }
7633 return null
7634 };
7635
7636 /**
7637 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7638 * @param {Transaction} transaction
7639 *
7640 * @private
7641 * @function
7642 */
7643 const writeStructsFromTransaction = (encoder, transaction) => writeClientsStructs(encoder, transaction.doc.store, transaction.beforeState);
7644
7645 /**
7646 * Read and apply a document update.
7647 *
7648 * This function has the same effect as `applyUpdate` but accepts an decoder.
7649 *
7650 * @param {decoding.Decoder} decoder
7651 * @param {Doc} ydoc
7652 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7653 * @param {UpdateDecoderV1 | UpdateDecoderV2} [structDecoder]
7654 *
7655 * @function
7656 */
7657 const readUpdateV2 = (decoder, ydoc, transactionOrigin, structDecoder = new UpdateDecoderV2(decoder)) =>
7658 transact(ydoc, transaction => {
7659 // force that transaction.local is set to non-local
7660 transaction.local = false;
7661 let retry = false;
7662 const doc = transaction.doc;
7663 const store = doc.store;
7664 // let start = performance.now()
7665 const ss = readClientsStructRefs(structDecoder, doc);
7666 // console.log('time to read structs: ', performance.now() - start) // @todo remove
7667 // start = performance.now()
7668 // console.log('time to merge: ', performance.now() - start) // @todo remove
7669 // start = performance.now()
7670 const restStructs = integrateStructs(transaction, store, ss);
7671 const pending = store.pendingStructs;
7672 if (pending) {
7673 // check if we can apply something
7674 for (const [client, clock] of pending.missing) {
7675 if (clock < getState(store, client)) {
7676 retry = true;
7677 break
7678 }
7679 }
7680 if (restStructs) {
7681 // merge restStructs into store.pending
7682 for (const [client, clock] of restStructs.missing) {
7683 const mclock = pending.missing.get(client);
7684 if (mclock == null || mclock > clock) {
7685 pending.missing.set(client, clock);
7686 }
7687 }
7688 pending.update = mergeUpdatesV2([pending.update, restStructs.update]);
7689 }
7690 } else {
7691 store.pendingStructs = restStructs;
7692 }
7693 // console.log('time to integrate: ', performance.now() - start) // @todo remove
7694 // start = performance.now()
7695 const dsRest = readAndApplyDeleteSet(structDecoder, transaction, store);
7696 if (store.pendingDs) {
7697 // @todo we could make a lower-bound state-vector check as we do above
7698 const pendingDSUpdate = new UpdateDecoderV2(createDecoder(store.pendingDs));
7699 readVarUint(pendingDSUpdate.restDecoder); // read 0 structs, because we only encode deletes in pendingdsupdate
7700 const dsRest2 = readAndApplyDeleteSet(pendingDSUpdate, transaction, store);
7701 if (dsRest && dsRest2) {
7702 // case 1: ds1 != null && ds2 != null
7703 store.pendingDs = mergeUpdatesV2([dsRest, dsRest2]);
7704 } else {
7705 // case 2: ds1 != null
7706 // case 3: ds2 != null
7707 // case 4: ds1 == null && ds2 == null
7708 store.pendingDs = dsRest || dsRest2;
7709 }
7710 } else {
7711 // Either dsRest == null && pendingDs == null OR dsRest != null
7712 store.pendingDs = dsRest;
7713 }
7714 // console.log('time to cleanup: ', performance.now() - start) // @todo remove
7715 // start = performance.now()
7716
7717 // console.log('time to resume delete readers: ', performance.now() - start) // @todo remove
7718 // start = performance.now()
7719 if (retry) {
7720 const update = /** @type {{update: Uint8Array}} */ (store.pendingStructs).update;
7721 store.pendingStructs = null;
7722 applyUpdateV2(transaction.doc, update);
7723 }
7724 }, transactionOrigin, false);
7725
7726 /**
7727 * Read and apply a document update.
7728 *
7729 * This function has the same effect as `applyUpdate` but accepts an decoder.
7730 *
7731 * @param {decoding.Decoder} decoder
7732 * @param {Doc} ydoc
7733 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7734 *
7735 * @function
7736 */
7737 const readUpdate = (decoder, ydoc, transactionOrigin) => readUpdateV2(decoder, ydoc, transactionOrigin, new UpdateDecoderV1(decoder));
7738
7739 /**
7740 * Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`.
7741 *
7742 * This function has the same effect as `readUpdate` but accepts an Uint8Array instead of a Decoder.
7743 *
7744 * @param {Doc} ydoc
7745 * @param {Uint8Array} update
7746 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7747 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
7748 *
7749 * @function
7750 */
7751 const applyUpdateV2 = (ydoc, update, transactionOrigin, YDecoder = UpdateDecoderV2) => {
7752 const decoder = createDecoder(update);
7753 readUpdateV2(decoder, ydoc, transactionOrigin, new YDecoder(decoder));
7754 };
7755
7756 /**
7757 * Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`.
7758 *
7759 * This function has the same effect as `readUpdate` but accepts an Uint8Array instead of a Decoder.
7760 *
7761 * @param {Doc} ydoc
7762 * @param {Uint8Array} update
7763 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
7764 *
7765 * @function
7766 */
7767 const applyUpdate = (ydoc, update, transactionOrigin) => applyUpdateV2(ydoc, update, transactionOrigin, UpdateDecoderV1);
7768
7769 /**
7770 * Write all the document as a single update message. If you specify the state of the remote client (`targetStateVector`) it will
7771 * only write the operations that are missing.
7772 *
7773 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
7774 * @param {Doc} doc
7775 * @param {Map<number,number>} [targetStateVector] The state of the target that receives the update. Leave empty to write all known structs
7776 *
7777 * @function
7778 */
7779 const writeStateAsUpdate = (encoder, doc, targetStateVector = new Map()) => {
7780 writeClientsStructs(encoder, doc.store, targetStateVector);
7781 writeDeleteSet(encoder, createDeleteSetFromStructStore(doc.store));
7782 };
7783
7784 /**
7785 * 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
7786 * only write the operations that are missing.
7787 *
7788 * Use `writeStateAsUpdate` instead if you are working with lib0/encoding.js#Encoder
7789 *
7790 * @param {Doc} doc
7791 * @param {Uint8Array} [encodedTargetStateVector] The state of the target that receives the update. Leave empty to write all known structs
7792 * @param {UpdateEncoderV1 | UpdateEncoderV2} [encoder]
7793 * @return {Uint8Array}
7794 *
7795 * @function
7796 */
7797 const encodeStateAsUpdateV2 = (doc, encodedTargetStateVector = new Uint8Array([0]), encoder = new UpdateEncoderV2()) => {
7798 const targetStateVector = decodeStateVector(encodedTargetStateVector);
7799 writeStateAsUpdate(encoder, doc, targetStateVector);
7800 const updates = [encoder.toUint8Array()];
7801 // also add the pending updates (if there are any)
7802 if (doc.store.pendingDs) {
7803 updates.push(doc.store.pendingDs);
7804 }
7805 if (doc.store.pendingStructs) {
7806 updates.push(diffUpdateV2(doc.store.pendingStructs.update, encodedTargetStateVector));
7807 }
7808 if (updates.length > 1) {
7809 if (encoder.constructor === UpdateEncoderV1) {
7810 return mergeUpdates(updates.map((update, i) => i === 0 ? update : convertUpdateFormatV2ToV1(update)))
7811 } else if (encoder.constructor === UpdateEncoderV2) {
7812 return mergeUpdatesV2(updates)
7813 }
7814 }
7815 return updates[0]
7816 };
7817
7818 /**
7819 * 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
7820 * only write the operations that are missing.
7821 *
7822 * Use `writeStateAsUpdate` instead if you are working with lib0/encoding.js#Encoder
7823 *
7824 * @param {Doc} doc
7825 * @param {Uint8Array} [encodedTargetStateVector] The state of the target that receives the update. Leave empty to write all known structs
7826 * @return {Uint8Array}
7827 *
7828 * @function
7829 */
7830 const encodeStateAsUpdate = (doc, encodedTargetStateVector) => encodeStateAsUpdateV2(doc, encodedTargetStateVector, new UpdateEncoderV1());
7831
7832 /**
7833 * Read state vector from Decoder and return as Map
7834 *
7835 * @param {DSDecoderV1 | DSDecoderV2} decoder
7836 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client.
7837 *
7838 * @function
7839 */
7840 const readStateVector = decoder => {
7841 const ss = new Map();
7842 const ssLength = readVarUint(decoder.restDecoder);
7843 for (let i = 0; i < ssLength; i++) {
7844 const client = readVarUint(decoder.restDecoder);
7845 const clock = readVarUint(decoder.restDecoder);
7846 ss.set(client, clock);
7847 }
7848 return ss
7849 };
7850
7851 /**
7852 * Read decodedState and return State as Map.
7853 *
7854 * @param {Uint8Array} decodedState
7855 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client.
7856 *
7857 * @function
7858 */
7859 // export const decodeStateVectorV2 = decodedState => readStateVector(new DSDecoderV2(decoding.createDecoder(decodedState)))
7860
7861 /**
7862 * Read decodedState and return State as Map.
7863 *
7864 * @param {Uint8Array} decodedState
7865 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client.
7866 *
7867 * @function
7868 */
7869 const decodeStateVector = decodedState => readStateVector(new DSDecoderV1(createDecoder(decodedState)));
7870
7871 /**
7872 * @param {DSEncoderV1 | DSEncoderV2} encoder
7873 * @param {Map<number,number>} sv
7874 * @function
7875 */
7876 const writeStateVector = (encoder, sv) => {
7877 writeVarUint(encoder.restEncoder, sv.size);
7878 array_from(sv.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
7879 writeVarUint(encoder.restEncoder, client); // @todo use a special client decoder that is based on mapping
7880 writeVarUint(encoder.restEncoder, clock);
7881 });
7882 return encoder
7883 };
7884
7885 /**
7886 * @param {DSEncoderV1 | DSEncoderV2} encoder
7887 * @param {Doc} doc
7888 *
7889 * @function
7890 */
7891 const writeDocumentStateVector = (encoder, doc) => writeStateVector(encoder, getStateVector(doc.store));
7892
7893 /**
7894 * Encode State as Uint8Array.
7895 *
7896 * @param {Doc|Map<number,number>} doc
7897 * @param {DSEncoderV1 | DSEncoderV2} [encoder]
7898 * @return {Uint8Array}
7899 *
7900 * @function
7901 */
7902 const encodeStateVectorV2 = (doc, encoder = new DSEncoderV2()) => {
7903 if (doc instanceof Map) {
7904 writeStateVector(encoder, doc);
7905 } else {
7906 writeDocumentStateVector(encoder, doc);
7907 }
7908 return encoder.toUint8Array()
7909 };
7910
7911 /**
7912 * Encode State as Uint8Array.
7913 *
7914 * @param {Doc|Map<number,number>} doc
7915 * @return {Uint8Array}
7916 *
7917 * @function
7918 */
7919 const encodeStateVector = doc => encodeStateVectorV2(doc, new DSEncoderV1());
7920
7921 /**
7922 * General event handler implementation.
7923 *
7924 * @template ARG0, ARG1
7925 *
7926 * @private
7927 */
7928 class EventHandler {
7929 constructor () {
7930 /**
7931 * @type {Array<function(ARG0, ARG1):void>}
7932 */
7933 this.l = [];
7934 }
7935 }
7936
7937 /**
7938 * @template ARG0,ARG1
7939 * @returns {EventHandler<ARG0,ARG1>}
7940 *
7941 * @private
7942 * @function
7943 */
7944 const createEventHandler = () => new EventHandler();
7945
7946 /**
7947 * Adds an event listener that is called when
7948 * {@link EventHandler#callEventListeners} is called.
7949 *
7950 * @template ARG0,ARG1
7951 * @param {EventHandler<ARG0,ARG1>} eventHandler
7952 * @param {function(ARG0,ARG1):void} f The event handler.
7953 *
7954 * @private
7955 * @function
7956 */
7957 const addEventHandlerListener = (eventHandler, f) =>
7958 eventHandler.l.push(f);
7959
7960 /**
7961 * Removes an event listener.
7962 *
7963 * @template ARG0,ARG1
7964 * @param {EventHandler<ARG0,ARG1>} eventHandler
7965 * @param {function(ARG0,ARG1):void} f The event handler that was added with
7966 * {@link EventHandler#addEventListener}
7967 *
7968 * @private
7969 * @function
7970 */
7971 const removeEventHandlerListener = (eventHandler, f) => {
7972 const l = eventHandler.l;
7973 const len = l.length;
7974 eventHandler.l = l.filter(g => f !== g);
7975 if (len === eventHandler.l.length) {
7976 console.error('[yjs] Tried to remove event handler that doesn\'t exist.');
7977 }
7978 };
7979
7980 /**
7981 * Call all event listeners that were added via
7982 * {@link EventHandler#addEventListener}.
7983 *
7984 * @template ARG0,ARG1
7985 * @param {EventHandler<ARG0,ARG1>} eventHandler
7986 * @param {ARG0} arg0
7987 * @param {ARG1} arg1
7988 *
7989 * @private
7990 * @function
7991 */
7992 const callEventHandlerListeners = (eventHandler, arg0, arg1) =>
7993 callAll(eventHandler.l, [arg0, arg1]);
7994
7995 class ID {
7996 /**
7997 * @param {number} client client id
7998 * @param {number} clock unique per client id, continuous number
7999 */
8000 constructor (client, clock) {
8001 /**
8002 * Client id
8003 * @type {number}
8004 */
8005 this.client = client;
8006 /**
8007 * unique per client id, continuous number
8008 * @type {number}
8009 */
8010 this.clock = clock;
8011 }
8012 }
8013
8014 /**
8015 * @param {ID | null} a
8016 * @param {ID | null} b
8017 * @return {boolean}
8018 *
8019 * @function
8020 */
8021 const compareIDs = (a, b) => a === b || (a !== null && b !== null && a.client === b.client && a.clock === b.clock);
8022
8023 /**
8024 * @param {number} client
8025 * @param {number} clock
8026 *
8027 * @private
8028 * @function
8029 */
8030 const createID = (client, clock) => new ID(client, clock);
8031
8032 /**
8033 * @param {encoding.Encoder} encoder
8034 * @param {ID} id
8035 *
8036 * @private
8037 * @function
8038 */
8039 const writeID = (encoder, id) => {
8040 encoding.writeVarUint(encoder, id.client);
8041 encoding.writeVarUint(encoder, id.clock);
8042 };
8043
8044 /**
8045 * Read ID.
8046 * * If first varUint read is 0xFFFFFF a RootID is returned.
8047 * * Otherwise an ID is returned
8048 *
8049 * @param {decoding.Decoder} decoder
8050 * @return {ID}
8051 *
8052 * @private
8053 * @function
8054 */
8055 const readID = decoder =>
8056 createID(decoding.readVarUint(decoder), decoding.readVarUint(decoder));
8057
8058 /**
8059 * The top types are mapped from y.share.get(keyname) => type.
8060 * `type` does not store any information about the `keyname`.
8061 * This function finds the correct `keyname` for `type` and throws otherwise.
8062 *
8063 * @param {AbstractType<any>} type
8064 * @return {string}
8065 *
8066 * @private
8067 * @function
8068 */
8069 const findRootTypeKey = type => {
8070 // @ts-ignore _y must be defined, otherwise unexpected case
8071 for (const [key, value] of type.doc.share.entries()) {
8072 if (value === type) {
8073 return key
8074 }
8075 }
8076 throw unexpectedCase()
8077 };
8078
8079 /**
8080 * Check if `parent` is a parent of `child`.
8081 *
8082 * @param {AbstractType<any>} parent
8083 * @param {Item|null} child
8084 * @return {Boolean} Whether `parent` is a parent of `child`.
8085 *
8086 * @private
8087 * @function
8088 */
8089 const yjs_isParentOf = (parent, child) => {
8090 while (child !== null) {
8091 if (child.parent === parent) {
8092 return true
8093 }
8094 child = /** @type {AbstractType<any>} */ (child.parent)._item;
8095 }
8096 return false
8097 };
8098
8099 /**
8100 * Convenient helper to log type information.
8101 *
8102 * Do not use in productive systems as the output can be immense!
8103 *
8104 * @param {AbstractType<any>} type
8105 */
8106 const logType = type => {
8107 const res = [];
8108 let n = type._start;
8109 while (n) {
8110 res.push(n);
8111 n = n.right;
8112 }
8113 console.log('Children: ', res);
8114 console.log('Children content: ', res.filter(m => !m.deleted).map(m => m.content));
8115 };
8116
8117 class PermanentUserData {
8118 /**
8119 * @param {Doc} doc
8120 * @param {YMap<any>} [storeType]
8121 */
8122 constructor (doc, storeType = doc.getMap('users')) {
8123 /**
8124 * @type {Map<string,DeleteSet>}
8125 */
8126 const dss = new Map();
8127 this.yusers = storeType;
8128 this.doc = doc;
8129 /**
8130 * Maps from clientid to userDescription
8131 *
8132 * @type {Map<number,string>}
8133 */
8134 this.clients = new Map();
8135 this.dss = dss;
8136 /**
8137 * @param {YMap<any>} user
8138 * @param {string} userDescription
8139 */
8140 const initUser = (user, userDescription) => {
8141 /**
8142 * @type {YArray<Uint8Array>}
8143 */
8144 const ds = user.get('ds');
8145 const ids = user.get('ids');
8146 const addClientId = /** @param {number} clientid */ clientid => this.clients.set(clientid, userDescription);
8147 ds.observe(/** @param {YArrayEvent<any>} event */ event => {
8148 event.changes.added.forEach(item => {
8149 item.content.getContent().forEach(encodedDs => {
8150 if (encodedDs instanceof Uint8Array) {
8151 this.dss.set(userDescription, mergeDeleteSets([this.dss.get(userDescription) || createDeleteSet(), readDeleteSet(new DSDecoderV1(decoding.createDecoder(encodedDs)))]));
8152 }
8153 });
8154 });
8155 });
8156 this.dss.set(userDescription, mergeDeleteSets(ds.map(encodedDs => readDeleteSet(new DSDecoderV1(decoding.createDecoder(encodedDs))))));
8157 ids.observe(/** @param {YArrayEvent<any>} event */ event =>
8158 event.changes.added.forEach(item => item.content.getContent().forEach(addClientId))
8159 );
8160 ids.forEach(addClientId);
8161 };
8162 // observe users
8163 storeType.observe(event => {
8164 event.keysChanged.forEach(userDescription =>
8165 initUser(storeType.get(userDescription), userDescription)
8166 );
8167 });
8168 // add intial data
8169 storeType.forEach(initUser);
8170 }
8171
8172 /**
8173 * @param {Doc} doc
8174 * @param {number} clientid
8175 * @param {string} userDescription
8176 * @param {Object} conf
8177 * @param {function(Transaction, DeleteSet):boolean} [conf.filter]
8178 */
8179 setUserMapping (doc, clientid, userDescription, { filter = () => true } = {}) {
8180 const users = this.yusers;
8181 let user = users.get(userDescription);
8182 if (!user) {
8183 user = new YMap();
8184 user.set('ids', new YArray());
8185 user.set('ds', new YArray());
8186 users.set(userDescription, user);
8187 }
8188 user.get('ids').push([clientid]);
8189 users.observe(_event => {
8190 setTimeout(() => {
8191 const userOverwrite = users.get(userDescription);
8192 if (userOverwrite !== user) {
8193 // user was overwritten, port all data over to the next user object
8194 // @todo Experiment with Y.Sets here
8195 user = userOverwrite;
8196 // @todo iterate over old type
8197 this.clients.forEach((_userDescription, clientid) => {
8198 if (userDescription === _userDescription) {
8199 user.get('ids').push([clientid]);
8200 }
8201 });
8202 const encoder = new DSEncoderV1();
8203 const ds = this.dss.get(userDescription);
8204 if (ds) {
8205 writeDeleteSet(encoder, ds);
8206 user.get('ds').push([encoder.toUint8Array()]);
8207 }
8208 }
8209 }, 0);
8210 });
8211 doc.on('afterTransaction', /** @param {Transaction} transaction */ transaction => {
8212 setTimeout(() => {
8213 const yds = user.get('ds');
8214 const ds = transaction.deleteSet;
8215 if (transaction.local && ds.clients.size > 0 && filter(transaction, ds)) {
8216 const encoder = new DSEncoderV1();
8217 writeDeleteSet(encoder, ds);
8218 yds.push([encoder.toUint8Array()]);
8219 }
8220 });
8221 });
8222 }
8223
8224 /**
8225 * @param {number} clientid
8226 * @return {any}
8227 */
8228 getUserByClientId (clientid) {
8229 return this.clients.get(clientid) || null
8230 }
8231
8232 /**
8233 * @param {ID} id
8234 * @return {string | null}
8235 */
8236 getUserByDeletedId (id) {
8237 for (const [userDescription, ds] of this.dss.entries()) {
8238 if (isDeleted(ds, id)) {
8239 return userDescription
8240 }
8241 }
8242 return null
8243 }
8244 }
8245
8246 /**
8247 * A relative position is based on the Yjs model and is not affected by document changes.
8248 * E.g. If you place a relative position before a certain character, it will always point to this character.
8249 * If you place a relative position at the end of a type, it will always point to the end of the type.
8250 *
8251 * A numeric position is often unsuited for user selections, because it does not change when content is inserted
8252 * before or after.
8253 *
8254 * ```Insert(0, 'x')('a|bc') = 'xa|bc'``` Where | is the relative position.
8255 *
8256 * One of the properties must be defined.
8257 *
8258 * @example
8259 * // Current cursor position is at position 10
8260 * const relativePosition = createRelativePositionFromIndex(yText, 10)
8261 * // modify yText
8262 * yText.insert(0, 'abc')
8263 * yText.delete(3, 10)
8264 * // Compute the cursor position
8265 * const absolutePosition = createAbsolutePositionFromRelativePosition(y, relativePosition)
8266 * absolutePosition.type === yText // => true
8267 * console.log('cursor location is ' + absolutePosition.index) // => cursor location is 3
8268 *
8269 */
8270 class RelativePosition {
8271 /**
8272 * @param {ID|null} type
8273 * @param {string|null} tname
8274 * @param {ID|null} item
8275 * @param {number} assoc
8276 */
8277 constructor (type, tname, item, assoc = 0) {
8278 /**
8279 * @type {ID|null}
8280 */
8281 this.type = type;
8282 /**
8283 * @type {string|null}
8284 */
8285 this.tname = tname;
8286 /**
8287 * @type {ID | null}
8288 */
8289 this.item = item;
8290 /**
8291 * A relative position is associated to a specific character. By default
8292 * assoc >= 0, the relative position is associated to the character
8293 * after the meant position.
8294 * I.e. position 1 in 'ab' is associated to character 'b'.
8295 *
8296 * If assoc < 0, then the relative position is associated to the caharacter
8297 * before the meant position.
8298 *
8299 * @type {number}
8300 */
8301 this.assoc = assoc;
8302 }
8303 }
8304
8305 /**
8306 * @param {RelativePosition} rpos
8307 * @return {any}
8308 */
8309 const relativePositionToJSON = rpos => {
8310 const json = {};
8311 if (rpos.type) {
8312 json.type = rpos.type;
8313 }
8314 if (rpos.tname) {
8315 json.tname = rpos.tname;
8316 }
8317 if (rpos.item) {
8318 json.item = rpos.item;
8319 }
8320 if (rpos.assoc != null) {
8321 json.assoc = rpos.assoc;
8322 }
8323 return json
8324 };
8325
8326 /**
8327 * @param {any} json
8328 * @return {RelativePosition}
8329 *
8330 * @function
8331 */
8332 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);
8333
8334 class AbsolutePosition {
8335 /**
8336 * @param {AbstractType<any>} type
8337 * @param {number} index
8338 * @param {number} [assoc]
8339 */
8340 constructor (type, index, assoc = 0) {
8341 /**
8342 * @type {AbstractType<any>}
8343 */
8344 this.type = type;
8345 /**
8346 * @type {number}
8347 */
8348 this.index = index;
8349 this.assoc = assoc;
8350 }
8351 }
8352
8353 /**
8354 * @param {AbstractType<any>} type
8355 * @param {number} index
8356 * @param {number} [assoc]
8357 *
8358 * @function
8359 */
8360 const createAbsolutePosition = (type, index, assoc = 0) => new AbsolutePosition(type, index, assoc);
8361
8362 /**
8363 * @param {AbstractType<any>} type
8364 * @param {ID|null} item
8365 * @param {number} [assoc]
8366 *
8367 * @function
8368 */
8369 const createRelativePosition = (type, item, assoc) => {
8370 let typeid = null;
8371 let tname = null;
8372 if (type._item === null) {
8373 tname = findRootTypeKey(type);
8374 } else {
8375 typeid = createID(type._item.id.client, type._item.id.clock);
8376 }
8377 return new RelativePosition(typeid, tname, item, assoc)
8378 };
8379
8380 /**
8381 * Create a relativePosition based on a absolute position.
8382 *
8383 * @param {AbstractType<any>} type The base type (e.g. YText or YArray).
8384 * @param {number} index The absolute position.
8385 * @param {number} [assoc]
8386 * @return {RelativePosition}
8387 *
8388 * @function
8389 */
8390 const createRelativePositionFromTypeIndex = (type, index, assoc = 0) => {
8391 let t = type._start;
8392 if (assoc < 0) {
8393 // associated to the left character or the beginning of a type, increment index if possible.
8394 if (index === 0) {
8395 return createRelativePosition(type, null, assoc)
8396 }
8397 index--;
8398 }
8399 while (t !== null) {
8400 if (!t.deleted && t.countable) {
8401 if (t.length > index) {
8402 // case 1: found position somewhere in the linked list
8403 return createRelativePosition(type, createID(t.id.client, t.id.clock + index), assoc)
8404 }
8405 index -= t.length;
8406 }
8407 if (t.right === null && assoc < 0) {
8408 // left-associated position, return last available id
8409 return createRelativePosition(type, t.lastId, assoc)
8410 }
8411 t = t.right;
8412 }
8413 return createRelativePosition(type, null, assoc)
8414 };
8415
8416 /**
8417 * @param {encoding.Encoder} encoder
8418 * @param {RelativePosition} rpos
8419 *
8420 * @function
8421 */
8422 const writeRelativePosition = (encoder, rpos) => {
8423 const { type, tname, item, assoc } = rpos;
8424 if (item !== null) {
8425 encoding.writeVarUint(encoder, 0);
8426 writeID(encoder, item);
8427 } else if (tname !== null) {
8428 // case 2: found position at the end of the list and type is stored in y.share
8429 encoding.writeUint8(encoder, 1);
8430 encoding.writeVarString(encoder, tname);
8431 } else if (type !== null) {
8432 // case 3: found position at the end of the list and type is attached to an item
8433 encoding.writeUint8(encoder, 2);
8434 writeID(encoder, type);
8435 } else {
8436 throw error.unexpectedCase()
8437 }
8438 encoding.writeVarInt(encoder, assoc);
8439 return encoder
8440 };
8441
8442 /**
8443 * @param {RelativePosition} rpos
8444 * @return {Uint8Array}
8445 */
8446 const encodeRelativePosition = rpos => {
8447 const encoder = encoding.createEncoder();
8448 writeRelativePosition(encoder, rpos);
8449 return encoding.toUint8Array(encoder)
8450 };
8451
8452 /**
8453 * @param {decoding.Decoder} decoder
8454 * @return {RelativePosition}
8455 *
8456 * @function
8457 */
8458 const readRelativePosition = decoder => {
8459 let type = null;
8460 let tname = null;
8461 let itemID = null;
8462 switch (decoding.readVarUint(decoder)) {
8463 case 0:
8464 // case 1: found position somewhere in the linked list
8465 itemID = readID(decoder);
8466 break
8467 case 1:
8468 // case 2: found position at the end of the list and type is stored in y.share
8469 tname = decoding.readVarString(decoder);
8470 break
8471 case 2: {
8472 // case 3: found position at the end of the list and type is attached to an item
8473 type = readID(decoder);
8474 }
8475 }
8476 const assoc = decoding.hasContent(decoder) ? decoding.readVarInt(decoder) : 0;
8477 return new RelativePosition(type, tname, itemID, assoc)
8478 };
8479
8480 /**
8481 * @param {Uint8Array} uint8Array
8482 * @return {RelativePosition}
8483 */
8484 const decodeRelativePosition = uint8Array => readRelativePosition(decoding.createDecoder(uint8Array));
8485
8486 /**
8487 * @param {RelativePosition} rpos
8488 * @param {Doc} doc
8489 * @return {AbsolutePosition|null}
8490 *
8491 * @function
8492 */
8493 const createAbsolutePositionFromRelativePosition = (rpos, doc) => {
8494 const store = doc.store;
8495 const rightID = rpos.item;
8496 const typeID = rpos.type;
8497 const tname = rpos.tname;
8498 const assoc = rpos.assoc;
8499 let type = null;
8500 let index = 0;
8501 if (rightID !== null) {
8502 if (getState(store, rightID.client) <= rightID.clock) {
8503 return null
8504 }
8505 const res = followRedone(store, rightID);
8506 const right = res.item;
8507 if (!(right instanceof Item)) {
8508 return null
8509 }
8510 type = /** @type {AbstractType<any>} */ (right.parent);
8511 if (type._item === null || !type._item.deleted) {
8512 index = (right.deleted || !right.countable) ? 0 : (res.diff + (assoc >= 0 ? 0 : 1)); // adjust position based on left association if necessary
8513 let n = right.left;
8514 while (n !== null) {
8515 if (!n.deleted && n.countable) {
8516 index += n.length;
8517 }
8518 n = n.left;
8519 }
8520 }
8521 } else {
8522 if (tname !== null) {
8523 type = doc.get(tname);
8524 } else if (typeID !== null) {
8525 if (getState(store, typeID.client) <= typeID.clock) {
8526 // type does not exist yet
8527 return null
8528 }
8529 const { item } = followRedone(store, typeID);
8530 if (item instanceof Item && item.content instanceof ContentType) {
8531 type = item.content.type;
8532 } else {
8533 // struct is garbage collected
8534 return null
8535 }
8536 } else {
8537 throw error.unexpectedCase()
8538 }
8539 if (assoc >= 0) {
8540 index = type._length;
8541 } else {
8542 index = 0;
8543 }
8544 }
8545 return createAbsolutePosition(type, index, rpos.assoc)
8546 };
8547
8548 /**
8549 * @param {RelativePosition|null} a
8550 * @param {RelativePosition|null} b
8551 * @return {boolean}
8552 *
8553 * @function
8554 */
8555 const compareRelativePositions = (a, b) => a === b || (
8556 a !== null && b !== null && a.tname === b.tname && compareIDs(a.item, b.item) && compareIDs(a.type, b.type) && a.assoc === b.assoc
8557 );
8558
8559 class Snapshot {
8560 /**
8561 * @param {DeleteSet} ds
8562 * @param {Map<number,number>} sv state map
8563 */
8564 constructor (ds, sv) {
8565 /**
8566 * @type {DeleteSet}
8567 */
8568 this.ds = ds;
8569 /**
8570 * State Map
8571 * @type {Map<number,number>}
8572 */
8573 this.sv = sv;
8574 }
8575 }
8576
8577 /**
8578 * @param {Snapshot} snap1
8579 * @param {Snapshot} snap2
8580 * @return {boolean}
8581 */
8582 const equalSnapshots = (snap1, snap2) => {
8583 const ds1 = snap1.ds.clients;
8584 const ds2 = snap2.ds.clients;
8585 const sv1 = snap1.sv;
8586 const sv2 = snap2.sv;
8587 if (sv1.size !== sv2.size || ds1.size !== ds2.size) {
8588 return false
8589 }
8590 for (const [key, value] of sv1.entries()) {
8591 if (sv2.get(key) !== value) {
8592 return false
8593 }
8594 }
8595 for (const [client, dsitems1] of ds1.entries()) {
8596 const dsitems2 = ds2.get(client) || [];
8597 if (dsitems1.length !== dsitems2.length) {
8598 return false
8599 }
8600 for (let i = 0; i < dsitems1.length; i++) {
8601 const dsitem1 = dsitems1[i];
8602 const dsitem2 = dsitems2[i];
8603 if (dsitem1.clock !== dsitem2.clock || dsitem1.len !== dsitem2.len) {
8604 return false
8605 }
8606 }
8607 }
8608 return true
8609 };
8610
8611 /**
8612 * @param {Snapshot} snapshot
8613 * @param {DSEncoderV1 | DSEncoderV2} [encoder]
8614 * @return {Uint8Array}
8615 */
8616 const encodeSnapshotV2 = (snapshot, encoder = new DSEncoderV2()) => {
8617 writeDeleteSet(encoder, snapshot.ds);
8618 writeStateVector(encoder, snapshot.sv);
8619 return encoder.toUint8Array()
8620 };
8621
8622 /**
8623 * @param {Snapshot} snapshot
8624 * @return {Uint8Array}
8625 */
8626 const encodeSnapshot = snapshot => encodeSnapshotV2(snapshot, new DSEncoderV1());
8627
8628 /**
8629 * @param {Uint8Array} buf
8630 * @param {DSDecoderV1 | DSDecoderV2} [decoder]
8631 * @return {Snapshot}
8632 */
8633 const decodeSnapshotV2 = (buf, decoder = new DSDecoderV2(decoding.createDecoder(buf))) => {
8634 return new Snapshot(readDeleteSet(decoder), readStateVector(decoder))
8635 };
8636
8637 /**
8638 * @param {Uint8Array} buf
8639 * @return {Snapshot}
8640 */
8641 const decodeSnapshot = buf => decodeSnapshotV2(buf, new DSDecoderV1(decoding.createDecoder(buf)));
8642
8643 /**
8644 * @param {DeleteSet} ds
8645 * @param {Map<number,number>} sm
8646 * @return {Snapshot}
8647 */
8648 const createSnapshot = (ds, sm) => new Snapshot(ds, sm);
8649
8650 const emptySnapshot = createSnapshot(createDeleteSet(), new Map());
8651
8652 /**
8653 * @param {Doc} doc
8654 * @return {Snapshot}
8655 */
8656 const snapshot = doc => createSnapshot(createDeleteSetFromStructStore(doc.store), getStateVector(doc.store));
8657
8658 /**
8659 * @param {Item} item
8660 * @param {Snapshot|undefined} snapshot
8661 *
8662 * @protected
8663 * @function
8664 */
8665 const isVisible = (item, snapshot) => snapshot === undefined
8666 ? !item.deleted
8667 : snapshot.sv.has(item.id.client) && (snapshot.sv.get(item.id.client) || 0) > item.id.clock && !isDeleted(snapshot.ds, item.id);
8668
8669 /**
8670 * @param {Transaction} transaction
8671 * @param {Snapshot} snapshot
8672 */
8673 const splitSnapshotAffectedStructs = (transaction, snapshot) => {
8674 const meta = setIfUndefined(transaction.meta, splitSnapshotAffectedStructs, set_create);
8675 const store = transaction.doc.store;
8676 // check if we already split for this snapshot
8677 if (!meta.has(snapshot)) {
8678 snapshot.sv.forEach((clock, client) => {
8679 if (clock < getState(store, client)) {
8680 getItemCleanStart(transaction, createID(client, clock));
8681 }
8682 });
8683 iterateDeletedStructs(transaction, snapshot.ds, _item => {});
8684 meta.add(snapshot);
8685 }
8686 };
8687
8688 /**
8689 * @example
8690 * const ydoc = new Y.Doc({ gc: false })
8691 * ydoc.getText().insert(0, 'world!')
8692 * const snapshot = Y.snapshot(ydoc)
8693 * ydoc.getText().insert(0, 'hello ')
8694 * const restored = Y.createDocFromSnapshot(ydoc, snapshot)
8695 * assert(restored.getText().toString() === 'world!')
8696 *
8697 * @param {Doc} originDoc
8698 * @param {Snapshot} snapshot
8699 * @param {Doc} [newDoc] Optionally, you may define the Yjs document that receives the data from originDoc
8700 * @return {Doc}
8701 */
8702 const createDocFromSnapshot = (originDoc, snapshot, newDoc = new Doc()) => {
8703 if (originDoc.gc) {
8704 // we should not try to restore a GC-ed document, because some of the restored items might have their content deleted
8705 throw new Error('Garbage-collection must be disabled in `originDoc`!')
8706 }
8707 const { sv, ds } = snapshot;
8708
8709 const encoder = new UpdateEncoderV2();
8710 originDoc.transact(transaction => {
8711 let size = 0;
8712 sv.forEach(clock => {
8713 if (clock > 0) {
8714 size++;
8715 }
8716 });
8717 encoding.writeVarUint(encoder.restEncoder, size);
8718 // splitting the structs before writing them to the encoder
8719 for (const [client, clock] of sv) {
8720 if (clock === 0) {
8721 continue
8722 }
8723 if (clock < getState(originDoc.store, client)) {
8724 getItemCleanStart(transaction, createID(client, clock));
8725 }
8726 const structs = originDoc.store.clients.get(client) || [];
8727 const lastStructIndex = findIndexSS(structs, clock - 1);
8728 // write # encoded structs
8729 encoding.writeVarUint(encoder.restEncoder, lastStructIndex + 1);
8730 encoder.writeClient(client);
8731 // first clock written is 0
8732 encoding.writeVarUint(encoder.restEncoder, 0);
8733 for (let i = 0; i <= lastStructIndex; i++) {
8734 structs[i].write(encoder, 0);
8735 }
8736 }
8737 writeDeleteSet(encoder, ds);
8738 });
8739
8740 applyUpdateV2(newDoc, encoder.toUint8Array(), 'snapshot');
8741 return newDoc
8742 };
8743
8744 /**
8745 * @param {Snapshot} snapshot
8746 * @param {Uint8Array} update
8747 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
8748 */
8749 const snapshotContainsUpdateV2 = (snapshot, update, YDecoder = UpdateDecoderV2) => {
8750 const updateDecoder = new YDecoder(decoding.createDecoder(update));
8751 const lazyDecoder = new LazyStructReader(updateDecoder, false);
8752 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
8753 if ((snapshot.sv.get(curr.id.client) || 0) < curr.id.clock + curr.length) {
8754 return false
8755 }
8756 }
8757 const mergedDS = mergeDeleteSets([snapshot.ds, readDeleteSet(updateDecoder)]);
8758 return equalDeleteSets(snapshot.ds, mergedDS)
8759 };
8760
8761 /**
8762 * @param {Snapshot} snapshot
8763 * @param {Uint8Array} update
8764 */
8765 const snapshotContainsUpdate = (snapshot, update) => snapshotContainsUpdateV2(snapshot, update, UpdateDecoderV1);
8766
8767 class StructStore {
8768 constructor () {
8769 /**
8770 * @type {Map<number,Array<GC|Item>>}
8771 */
8772 this.clients = new Map();
8773 /**
8774 * @type {null | { missing: Map<number, number>, update: Uint8Array }}
8775 */
8776 this.pendingStructs = null;
8777 /**
8778 * @type {null | Uint8Array}
8779 */
8780 this.pendingDs = null;
8781 }
8782 }
8783
8784 /**
8785 * Return the states as a Map<client,clock>.
8786 * Note that clock refers to the next expected clock id.
8787 *
8788 * @param {StructStore} store
8789 * @return {Map<number,number>}
8790 *
8791 * @public
8792 * @function
8793 */
8794 const getStateVector = store => {
8795 const sm = new Map();
8796 store.clients.forEach((structs, client) => {
8797 const struct = structs[structs.length - 1];
8798 sm.set(client, struct.id.clock + struct.length);
8799 });
8800 return sm
8801 };
8802
8803 /**
8804 * @param {StructStore} store
8805 * @param {number} client
8806 * @return {number}
8807 *
8808 * @public
8809 * @function
8810 */
8811 const getState = (store, client) => {
8812 const structs = store.clients.get(client);
8813 if (structs === undefined) {
8814 return 0
8815 }
8816 const lastStruct = structs[structs.length - 1];
8817 return lastStruct.id.clock + lastStruct.length
8818 };
8819
8820 /**
8821 * @param {StructStore} store
8822 * @param {GC|Item} struct
8823 *
8824 * @private
8825 * @function
8826 */
8827 const addStruct = (store, struct) => {
8828 let structs = store.clients.get(struct.id.client);
8829 if (structs === undefined) {
8830 structs = [];
8831 store.clients.set(struct.id.client, structs);
8832 } else {
8833 const lastStruct = structs[structs.length - 1];
8834 if (lastStruct.id.clock + lastStruct.length !== struct.id.clock) {
8835 throw unexpectedCase()
8836 }
8837 }
8838 structs.push(struct);
8839 };
8840
8841 /**
8842 * Perform a binary search on a sorted array
8843 * @param {Array<Item|GC>} structs
8844 * @param {number} clock
8845 * @return {number}
8846 *
8847 * @private
8848 * @function
8849 */
8850 const findIndexSS = (structs, clock) => {
8851 let left = 0;
8852 let right = structs.length - 1;
8853 let mid = structs[right];
8854 let midclock = mid.id.clock;
8855 if (midclock === clock) {
8856 return right
8857 }
8858 // @todo does it even make sense to pivot the search?
8859 // If a good split misses, it might actually increase the time to find the correct item.
8860 // Currently, the only advantage is that search with pivoting might find the item on the first try.
8861 let midindex = floor((clock / (midclock + mid.length - 1)) * right); // pivoting the search
8862 while (left <= right) {
8863 mid = structs[midindex];
8864 midclock = mid.id.clock;
8865 if (midclock <= clock) {
8866 if (clock < midclock + mid.length) {
8867 return midindex
8868 }
8869 left = midindex + 1;
8870 } else {
8871 right = midindex - 1;
8872 }
8873 midindex = floor((left + right) / 2);
8874 }
8875 // Always check state before looking for a struct in StructStore
8876 // Therefore the case of not finding a struct is unexpected
8877 throw unexpectedCase()
8878 };
8879
8880 /**
8881 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8882 *
8883 * @param {StructStore} store
8884 * @param {ID} id
8885 * @return {GC|Item}
8886 *
8887 * @private
8888 * @function
8889 */
8890 const find = (store, id) => {
8891 /**
8892 * @type {Array<GC|Item>}
8893 */
8894 // @ts-ignore
8895 const structs = store.clients.get(id.client);
8896 return structs[findIndexSS(structs, id.clock)]
8897 };
8898
8899 /**
8900 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8901 * @private
8902 * @function
8903 */
8904 const getItem = /** @type {function(StructStore,ID):Item} */ (find);
8905
8906 /**
8907 * @param {Transaction} transaction
8908 * @param {Array<Item|GC>} structs
8909 * @param {number} clock
8910 */
8911 const findIndexCleanStart = (transaction, structs, clock) => {
8912 const index = findIndexSS(structs, clock);
8913 const struct = structs[index];
8914 if (struct.id.clock < clock && struct instanceof Item) {
8915 structs.splice(index + 1, 0, splitItem(transaction, struct, clock - struct.id.clock));
8916 return index + 1
8917 }
8918 return index
8919 };
8920
8921 /**
8922 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8923 *
8924 * @param {Transaction} transaction
8925 * @param {ID} id
8926 * @return {Item}
8927 *
8928 * @private
8929 * @function
8930 */
8931 const getItemCleanStart = (transaction, id) => {
8932 const structs = /** @type {Array<Item>} */ (transaction.doc.store.clients.get(id.client));
8933 return structs[findIndexCleanStart(transaction, structs, id.clock)]
8934 };
8935
8936 /**
8937 * Expects that id is actually in store. This function throws or is an infinite loop otherwise.
8938 *
8939 * @param {Transaction} transaction
8940 * @param {StructStore} store
8941 * @param {ID} id
8942 * @return {Item}
8943 *
8944 * @private
8945 * @function
8946 */
8947 const getItemCleanEnd = (transaction, store, id) => {
8948 /**
8949 * @type {Array<Item>}
8950 */
8951 // @ts-ignore
8952 const structs = store.clients.get(id.client);
8953 const index = findIndexSS(structs, id.clock);
8954 const struct = structs[index];
8955 if (id.clock !== struct.id.clock + struct.length - 1 && struct.constructor !== GC) {
8956 structs.splice(index + 1, 0, splitItem(transaction, struct, id.clock - struct.id.clock + 1));
8957 }
8958 return struct
8959 };
8960
8961 /**
8962 * Replace `item` with `newitem` in store
8963 * @param {StructStore} store
8964 * @param {GC|Item} struct
8965 * @param {GC|Item} newStruct
8966 *
8967 * @private
8968 * @function
8969 */
8970 const replaceStruct = (store, struct, newStruct) => {
8971 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(struct.id.client));
8972 structs[findIndexSS(structs, struct.id.clock)] = newStruct;
8973 };
8974
8975 /**
8976 * Iterate over a range of structs
8977 *
8978 * @param {Transaction} transaction
8979 * @param {Array<Item|GC>} structs
8980 * @param {number} clockStart Inclusive start
8981 * @param {number} len
8982 * @param {function(GC|Item):void} f
8983 *
8984 * @function
8985 */
8986 const iterateStructs = (transaction, structs, clockStart, len, f) => {
8987 if (len === 0) {
8988 return
8989 }
8990 const clockEnd = clockStart + len;
8991 let index = findIndexCleanStart(transaction, structs, clockStart);
8992 let struct;
8993 do {
8994 struct = structs[index++];
8995 if (clockEnd < struct.id.clock + struct.length) {
8996 findIndexCleanStart(transaction, structs, clockEnd);
8997 }
8998 f(struct);
8999 } while (index < structs.length && structs[index].id.clock < clockEnd)
9000 };
9001
9002 /**
9003 * A transaction is created for every change on the Yjs model. It is possible
9004 * to bundle changes on the Yjs model in a single transaction to
9005 * minimize the number on messages sent and the number of observer calls.
9006 * If possible the user of this library should bundle as many changes as
9007 * possible. Here is an example to illustrate the advantages of bundling:
9008 *
9009 * @example
9010 * const map = y.define('map', YMap)
9011 * // Log content when change is triggered
9012 * map.observe(() => {
9013 * console.log('change triggered')
9014 * })
9015 * // Each change on the map type triggers a log message:
9016 * map.set('a', 0) // => "change triggered"
9017 * map.set('b', 0) // => "change triggered"
9018 * // When put in a transaction, it will trigger the log after the transaction:
9019 * y.transact(() => {
9020 * map.set('a', 1)
9021 * map.set('b', 1)
9022 * }) // => "change triggered"
9023 *
9024 * @public
9025 */
9026 class Transaction {
9027 /**
9028 * @param {Doc} doc
9029 * @param {any} origin
9030 * @param {boolean} local
9031 */
9032 constructor (doc, origin, local) {
9033 /**
9034 * The Yjs instance.
9035 * @type {Doc}
9036 */
9037 this.doc = doc;
9038 /**
9039 * Describes the set of deleted items by ids
9040 * @type {DeleteSet}
9041 */
9042 this.deleteSet = new DeleteSet();
9043 /**
9044 * Holds the state before the transaction started.
9045 * @type {Map<Number,Number>}
9046 */
9047 this.beforeState = getStateVector(doc.store);
9048 /**
9049 * Holds the state after the transaction.
9050 * @type {Map<Number,Number>}
9051 */
9052 this.afterState = new Map();
9053 /**
9054 * All types that were directly modified (property added or child
9055 * inserted/deleted). New types are not included in this Set.
9056 * Maps from type to parentSubs (`item.parentSub = null` for YArray)
9057 * @type {Map<AbstractType<YEvent<any>>,Set<String|null>>}
9058 */
9059 this.changed = new Map();
9060 /**
9061 * Stores the events for the types that observe also child elements.
9062 * It is mainly used by `observeDeep`.
9063 * @type {Map<AbstractType<YEvent<any>>,Array<YEvent<any>>>}
9064 */
9065 this.changedParentTypes = new Map();
9066 /**
9067 * @type {Array<AbstractStruct>}
9068 */
9069 this._mergeStructs = [];
9070 /**
9071 * @type {any}
9072 */
9073 this.origin = origin;
9074 /**
9075 * Stores meta information on the transaction
9076 * @type {Map<any,any>}
9077 */
9078 this.meta = new Map();
9079 /**
9080 * Whether this change originates from this doc.
9081 * @type {boolean}
9082 */
9083 this.local = local;
9084 /**
9085 * @type {Set<Doc>}
9086 */
9087 this.subdocsAdded = new Set();
9088 /**
9089 * @type {Set<Doc>}
9090 */
9091 this.subdocsRemoved = new Set();
9092 /**
9093 * @type {Set<Doc>}
9094 */
9095 this.subdocsLoaded = new Set();
9096 /**
9097 * @type {boolean}
9098 */
9099 this._needFormattingCleanup = false;
9100 }
9101 }
9102
9103 /**
9104 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
9105 * @param {Transaction} transaction
9106 * @return {boolean} Whether data was written.
9107 */
9108 const writeUpdateMessageFromTransaction = (encoder, transaction) => {
9109 if (transaction.deleteSet.clients.size === 0 && !any(transaction.afterState, (clock, client) => transaction.beforeState.get(client) !== clock)) {
9110 return false
9111 }
9112 sortAndMergeDeleteSet(transaction.deleteSet);
9113 writeStructsFromTransaction(encoder, transaction);
9114 writeDeleteSet(encoder, transaction.deleteSet);
9115 return true
9116 };
9117
9118 /**
9119 * If `type.parent` was added in current transaction, `type` technically
9120 * did not change, it was just added and we should not fire events for `type`.
9121 *
9122 * @param {Transaction} transaction
9123 * @param {AbstractType<YEvent<any>>} type
9124 * @param {string|null} parentSub
9125 */
9126 const addChangedTypeToTransaction = (transaction, type, parentSub) => {
9127 const item = type._item;
9128 if (item === null || (item.id.clock < (transaction.beforeState.get(item.id.client) || 0) && !item.deleted)) {
9129 setIfUndefined(transaction.changed, type, set_create).add(parentSub);
9130 }
9131 };
9132
9133 /**
9134 * @param {Array<AbstractStruct>} structs
9135 * @param {number} pos
9136 * @return {number} # of merged structs
9137 */
9138 const tryToMergeWithLefts = (structs, pos) => {
9139 let right = structs[pos];
9140 let left = structs[pos - 1];
9141 let i = pos;
9142 for (; i > 0; right = left, left = structs[--i - 1]) {
9143 if (left.deleted === right.deleted && left.constructor === right.constructor) {
9144 if (left.mergeWith(right)) {
9145 if (right instanceof Item && right.parentSub !== null && /** @type {AbstractType<any>} */ (right.parent)._map.get(right.parentSub) === right) {
9146 /** @type {AbstractType<any>} */ (right.parent)._map.set(right.parentSub, /** @type {Item} */ (left));
9147 }
9148 continue
9149 }
9150 }
9151 break
9152 }
9153 const merged = pos - i;
9154 if (merged) {
9155 // remove all merged structs from the array
9156 structs.splice(pos + 1 - merged, merged);
9157 }
9158 return merged
9159 };
9160
9161 /**
9162 * @param {DeleteSet} ds
9163 * @param {StructStore} store
9164 * @param {function(Item):boolean} gcFilter
9165 */
9166 const tryGcDeleteSet = (ds, store, gcFilter) => {
9167 for (const [client, deleteItems] of ds.clients.entries()) {
9168 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9169 for (let di = deleteItems.length - 1; di >= 0; di--) {
9170 const deleteItem = deleteItems[di];
9171 const endDeleteItemClock = deleteItem.clock + deleteItem.len;
9172 for (
9173 let si = findIndexSS(structs, deleteItem.clock), struct = structs[si];
9174 si < structs.length && struct.id.clock < endDeleteItemClock;
9175 struct = structs[++si]
9176 ) {
9177 const struct = structs[si];
9178 if (deleteItem.clock + deleteItem.len <= struct.id.clock) {
9179 break
9180 }
9181 if (struct instanceof Item && struct.deleted && !struct.keep && gcFilter(struct)) {
9182 struct.gc(store, false);
9183 }
9184 }
9185 }
9186 }
9187 };
9188
9189 /**
9190 * @param {DeleteSet} ds
9191 * @param {StructStore} store
9192 */
9193 const tryMergeDeleteSet = (ds, store) => {
9194 // try to merge deleted / gc'd items
9195 // merge from right to left for better efficiecy and so we don't miss any merge targets
9196 ds.clients.forEach((deleteItems, client) => {
9197 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9198 for (let di = deleteItems.length - 1; di >= 0; di--) {
9199 const deleteItem = deleteItems[di];
9200 // start with merging the item next to the last deleted item
9201 const mostRightIndexToCheck = min(structs.length - 1, 1 + findIndexSS(structs, deleteItem.clock + deleteItem.len - 1));
9202 for (
9203 let si = mostRightIndexToCheck, struct = structs[si];
9204 si > 0 && struct.id.clock >= deleteItem.clock;
9205 struct = structs[si]
9206 ) {
9207 si -= 1 + tryToMergeWithLefts(structs, si);
9208 }
9209 }
9210 });
9211 };
9212
9213 /**
9214 * @param {DeleteSet} ds
9215 * @param {StructStore} store
9216 * @param {function(Item):boolean} gcFilter
9217 */
9218 const tryGc = (ds, store, gcFilter) => {
9219 tryGcDeleteSet(ds, store, gcFilter);
9220 tryMergeDeleteSet(ds, store);
9221 };
9222
9223 /**
9224 * @param {Array<Transaction>} transactionCleanups
9225 * @param {number} i
9226 */
9227 const cleanupTransactions = (transactionCleanups, i) => {
9228 if (i < transactionCleanups.length) {
9229 const transaction = transactionCleanups[i];
9230 const doc = transaction.doc;
9231 const store = doc.store;
9232 const ds = transaction.deleteSet;
9233 const mergeStructs = transaction._mergeStructs;
9234 try {
9235 sortAndMergeDeleteSet(ds);
9236 transaction.afterState = getStateVector(transaction.doc.store);
9237 doc.emit('beforeObserverCalls', [transaction, doc]);
9238 /**
9239 * An array of event callbacks.
9240 *
9241 * Each callback is called even if the other ones throw errors.
9242 *
9243 * @type {Array<function():void>}
9244 */
9245 const fs = [];
9246 // observe events on changed types
9247 transaction.changed.forEach((subs, itemtype) =>
9248 fs.push(() => {
9249 if (itemtype._item === null || !itemtype._item.deleted) {
9250 itemtype._callObserver(transaction, subs);
9251 }
9252 })
9253 );
9254 fs.push(() => {
9255 // deep observe events
9256 transaction.changedParentTypes.forEach((events, type) => {
9257 // We need to think about the possibility that the user transforms the
9258 // Y.Doc in the event.
9259 if (type._dEH.l.length > 0 && (type._item === null || !type._item.deleted)) {
9260 events = events
9261 .filter(event =>
9262 event.target._item === null || !event.target._item.deleted
9263 );
9264 events
9265 .forEach(event => {
9266 event.currentTarget = type;
9267 // path is relative to the current target
9268 event._path = null;
9269 });
9270 // sort events by path length so that top-level events are fired first.
9271 events
9272 .sort((event1, event2) => event1.path.length - event2.path.length);
9273 // We don't need to check for events.length
9274 // because we know it has at least one element
9275 callEventHandlerListeners(type._dEH, events, transaction);
9276 }
9277 });
9278 });
9279 fs.push(() => doc.emit('afterTransaction', [transaction, doc]));
9280 callAll(fs, []);
9281 if (transaction._needFormattingCleanup) {
9282 cleanupYTextAfterTransaction(transaction);
9283 }
9284 } finally {
9285 // Replace deleted items with ItemDeleted / GC.
9286 // This is where content is actually remove from the Yjs Doc.
9287 if (doc.gc) {
9288 tryGcDeleteSet(ds, store, doc.gcFilter);
9289 }
9290 tryMergeDeleteSet(ds, store);
9291
9292 // on all affected store.clients props, try to merge
9293 transaction.afterState.forEach((clock, client) => {
9294 const beforeClock = transaction.beforeState.get(client) || 0;
9295 if (beforeClock !== clock) {
9296 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9297 // we iterate from right to left so we can safely remove entries
9298 const firstChangePos = max(findIndexSS(structs, beforeClock), 1);
9299 for (let i = structs.length - 1; i >= firstChangePos;) {
9300 i -= 1 + tryToMergeWithLefts(structs, i);
9301 }
9302 }
9303 });
9304 // try to merge mergeStructs
9305 // @todo: it makes more sense to transform mergeStructs to a DS, sort it, and merge from right to left
9306 // but at the moment DS does not handle duplicates
9307 for (let i = mergeStructs.length - 1; i >= 0; i--) {
9308 const { client, clock } = mergeStructs[i].id;
9309 const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client));
9310 const replacedStructPos = findIndexSS(structs, clock);
9311 if (replacedStructPos + 1 < structs.length) {
9312 if (tryToMergeWithLefts(structs, replacedStructPos + 1) > 1) {
9313 continue // no need to perform next check, both are already merged
9314 }
9315 }
9316 if (replacedStructPos > 0) {
9317 tryToMergeWithLefts(structs, replacedStructPos);
9318 }
9319 }
9320 if (!transaction.local && transaction.afterState.get(doc.clientID) !== transaction.beforeState.get(doc.clientID)) {
9321 print(ORANGE, BOLD, '[yjs] ', UNBOLD, RED, 'Changed the client-id because another client seems to be using it.');
9322 doc.clientID = generateNewClientId();
9323 }
9324 // @todo Merge all the transactions into one and provide send the data as a single update message
9325 doc.emit('afterTransactionCleanup', [transaction, doc]);
9326 if (doc._observers.has('update')) {
9327 const encoder = new UpdateEncoderV1();
9328 const hasContent = writeUpdateMessageFromTransaction(encoder, transaction);
9329 if (hasContent) {
9330 doc.emit('update', [encoder.toUint8Array(), transaction.origin, doc, transaction]);
9331 }
9332 }
9333 if (doc._observers.has('updateV2')) {
9334 const encoder = new UpdateEncoderV2();
9335 const hasContent = writeUpdateMessageFromTransaction(encoder, transaction);
9336 if (hasContent) {
9337 doc.emit('updateV2', [encoder.toUint8Array(), transaction.origin, doc, transaction]);
9338 }
9339 }
9340 const { subdocsAdded, subdocsLoaded, subdocsRemoved } = transaction;
9341 if (subdocsAdded.size > 0 || subdocsRemoved.size > 0 || subdocsLoaded.size > 0) {
9342 subdocsAdded.forEach(subdoc => {
9343 subdoc.clientID = doc.clientID;
9344 if (subdoc.collectionid == null) {
9345 subdoc.collectionid = doc.collectionid;
9346 }
9347 doc.subdocs.add(subdoc);
9348 });
9349 subdocsRemoved.forEach(subdoc => doc.subdocs.delete(subdoc));
9350 doc.emit('subdocs', [{ loaded: subdocsLoaded, added: subdocsAdded, removed: subdocsRemoved }, doc, transaction]);
9351 subdocsRemoved.forEach(subdoc => subdoc.destroy());
9352 }
9353
9354 if (transactionCleanups.length <= i + 1) {
9355 doc._transactionCleanups = [];
9356 doc.emit('afterAllTransactions', [doc, transactionCleanups]);
9357 } else {
9358 cleanupTransactions(transactionCleanups, i + 1);
9359 }
9360 }
9361 }
9362 };
9363
9364 /**
9365 * Implements the functionality of `y.transact(()=>{..})`
9366 *
9367 * @template T
9368 * @param {Doc} doc
9369 * @param {function(Transaction):T} f
9370 * @param {any} [origin=true]
9371 * @return {T}
9372 *
9373 * @function
9374 */
9375 const transact = (doc, f, origin = null, local = true) => {
9376 const transactionCleanups = doc._transactionCleanups;
9377 let initialCall = false;
9378 /**
9379 * @type {any}
9380 */
9381 let result = null;
9382 if (doc._transaction === null) {
9383 initialCall = true;
9384 doc._transaction = new Transaction(doc, origin, local);
9385 transactionCleanups.push(doc._transaction);
9386 if (transactionCleanups.length === 1) {
9387 doc.emit('beforeAllTransactions', [doc]);
9388 }
9389 doc.emit('beforeTransaction', [doc._transaction, doc]);
9390 }
9391 try {
9392 result = f(doc._transaction);
9393 } finally {
9394 if (initialCall) {
9395 const finishCleanup = doc._transaction === transactionCleanups[0];
9396 doc._transaction = null;
9397 if (finishCleanup) {
9398 // The first transaction ended, now process observer calls.
9399 // Observer call may create new transactions for which we need to call the observers and do cleanup.
9400 // We don't want to nest these calls, so we execute these calls one after
9401 // another.
9402 // Also we need to ensure that all cleanups are called, even if the
9403 // observes throw errors.
9404 // This file is full of hacky try {} finally {} blocks to ensure that an
9405 // event can throw errors and also that the cleanup is called.
9406 cleanupTransactions(transactionCleanups, 0);
9407 }
9408 }
9409 }
9410 return result
9411 };
9412
9413 class StackItem {
9414 /**
9415 * @param {DeleteSet} deletions
9416 * @param {DeleteSet} insertions
9417 */
9418 constructor (deletions, insertions) {
9419 this.insertions = insertions;
9420 this.deletions = deletions;
9421 /**
9422 * Use this to save and restore metadata like selection range
9423 */
9424 this.meta = new Map();
9425 }
9426 }
9427 /**
9428 * @param {Transaction} tr
9429 * @param {UndoManager} um
9430 * @param {StackItem} stackItem
9431 */
9432 const clearUndoManagerStackItem = (tr, um, stackItem) => {
9433 iterateDeletedStructs(tr, stackItem.deletions, item => {
9434 if (item instanceof Item && um.scope.some(type => yjs_isParentOf(type, item))) {
9435 keepItem(item, false);
9436 }
9437 });
9438 };
9439
9440 /**
9441 * @param {UndoManager} undoManager
9442 * @param {Array<StackItem>} stack
9443 * @param {string} eventType
9444 * @return {StackItem?}
9445 */
9446 const popStackItem = (undoManager, stack, eventType) => {
9447 /**
9448 * Whether a change happened
9449 * @type {StackItem?}
9450 */
9451 let result = null;
9452 /**
9453 * Keep a reference to the transaction so we can fire the event with the changedParentTypes
9454 * @type {any}
9455 */
9456 let _tr = null;
9457 const doc = undoManager.doc;
9458 const scope = undoManager.scope;
9459 transact(doc, transaction => {
9460 while (stack.length > 0 && result === null) {
9461 const store = doc.store;
9462 const stackItem = /** @type {StackItem} */ (stack.pop());
9463 /**
9464 * @type {Set<Item>}
9465 */
9466 const itemsToRedo = new Set();
9467 /**
9468 * @type {Array<Item>}
9469 */
9470 const itemsToDelete = [];
9471 let performedChange = false;
9472 iterateDeletedStructs(transaction, stackItem.insertions, struct => {
9473 if (struct instanceof Item) {
9474 if (struct.redone !== null) {
9475 let { item, diff } = followRedone(store, struct.id);
9476 if (diff > 0) {
9477 item = getItemCleanStart(transaction, createID(item.id.client, item.id.clock + diff));
9478 }
9479 struct = item;
9480 }
9481 if (!struct.deleted && scope.some(type => yjs_isParentOf(type, /** @type {Item} */ (struct)))) {
9482 itemsToDelete.push(struct);
9483 }
9484 }
9485 });
9486 iterateDeletedStructs(transaction, stackItem.deletions, struct => {
9487 if (
9488 struct instanceof Item &&
9489 scope.some(type => yjs_isParentOf(type, struct)) &&
9490 // Never redo structs in stackItem.insertions because they were created and deleted in the same capture interval.
9491 !isDeleted(stackItem.insertions, struct.id)
9492 ) {
9493 itemsToRedo.add(struct);
9494 }
9495 });
9496 itemsToRedo.forEach(struct => {
9497 performedChange = redoItem(transaction, struct, itemsToRedo, stackItem.insertions, undoManager.ignoreRemoteMapChanges, undoManager) !== null || performedChange;
9498 });
9499 // We want to delete in reverse order so that children are deleted before
9500 // parents, so we have more information available when items are filtered.
9501 for (let i = itemsToDelete.length - 1; i >= 0; i--) {
9502 const item = itemsToDelete[i];
9503 if (undoManager.deleteFilter(item)) {
9504 item.delete(transaction);
9505 performedChange = true;
9506 }
9507 }
9508 result = performedChange ? stackItem : null;
9509 }
9510 transaction.changed.forEach((subProps, type) => {
9511 // destroy search marker if necessary
9512 if (subProps.has(null) && type._searchMarker) {
9513 type._searchMarker.length = 0;
9514 }
9515 });
9516 _tr = transaction;
9517 }, undoManager);
9518 if (result != null) {
9519 const changedParentTypes = _tr.changedParentTypes;
9520 undoManager.emit('stack-item-popped', [{ stackItem: result, type: eventType, changedParentTypes }, undoManager]);
9521 }
9522 return result
9523 };
9524
9525 /**
9526 * @typedef {Object} UndoManagerOptions
9527 * @property {number} [UndoManagerOptions.captureTimeout=500]
9528 * @property {function(Transaction):boolean} [UndoManagerOptions.captureTransaction] Do not capture changes of a Transaction if result false.
9529 * @property {function(Item):boolean} [UndoManagerOptions.deleteFilter=()=>true] Sometimes
9530 * it is necessary to filter what an Undo/Redo operation can delete. If this
9531 * filter returns false, the type/item won't be deleted even it is in the
9532 * undo/redo scope.
9533 * @property {Set<any>} [UndoManagerOptions.trackedOrigins=new Set([null])]
9534 * @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..).
9535 * @property {Doc} [doc] The document that this UndoManager operates on. Only needed if typeScope is empty.
9536 */
9537
9538 /**
9539 * Fires 'stack-item-added' event when a stack item was added to either the undo- or
9540 * the redo-stack. You may store additional stack information via the
9541 * metadata property on `event.stackItem.meta` (it is a `Map` of metadata properties).
9542 * Fires 'stack-item-popped' event when a stack item was popped from either the
9543 * undo- or the redo-stack. You may restore the saved stack information from `event.stackItem.meta`.
9544 *
9545 * @extends {Observable<'stack-item-added'|'stack-item-popped'|'stack-cleared'|'stack-item-updated'>}
9546 */
9547 class UndoManager extends (/* unused pure expression or super */ null && (Observable)) {
9548 /**
9549 * @param {AbstractType<any>|Array<AbstractType<any>>} typeScope Accepts either a single type, or an array of types
9550 * @param {UndoManagerOptions} options
9551 */
9552 constructor (typeScope, {
9553 captureTimeout = 500,
9554 captureTransaction = _tr => true,
9555 deleteFilter = () => true,
9556 trackedOrigins = new Set([null]),
9557 ignoreRemoteMapChanges = false,
9558 doc = /** @type {Doc} */ (array.isArray(typeScope) ? typeScope[0].doc : typeScope.doc)
9559 } = {}) {
9560 super();
9561 /**
9562 * @type {Array<AbstractType<any>>}
9563 */
9564 this.scope = [];
9565 this.addToScope(typeScope);
9566 this.deleteFilter = deleteFilter;
9567 trackedOrigins.add(this);
9568 this.trackedOrigins = trackedOrigins;
9569 this.captureTransaction = captureTransaction;
9570 /**
9571 * @type {Array<StackItem>}
9572 */
9573 this.undoStack = [];
9574 /**
9575 * @type {Array<StackItem>}
9576 */
9577 this.redoStack = [];
9578 /**
9579 * Whether the client is currently undoing (calling UndoManager.undo)
9580 *
9581 * @type {boolean}
9582 */
9583 this.undoing = false;
9584 this.redoing = false;
9585 this.doc = doc;
9586 this.lastChange = 0;
9587 this.ignoreRemoteMapChanges = ignoreRemoteMapChanges;
9588 this.captureTimeout = captureTimeout;
9589 /**
9590 * @param {Transaction} transaction
9591 */
9592 this.afterTransactionHandler = transaction => {
9593 // Only track certain transactions
9594 if (
9595 !this.captureTransaction(transaction) ||
9596 !this.scope.some(type => transaction.changedParentTypes.has(type)) ||
9597 (!this.trackedOrigins.has(transaction.origin) && (!transaction.origin || !this.trackedOrigins.has(transaction.origin.constructor)))
9598 ) {
9599 return
9600 }
9601 const undoing = this.undoing;
9602 const redoing = this.redoing;
9603 const stack = undoing ? this.redoStack : this.undoStack;
9604 if (undoing) {
9605 this.stopCapturing(); // next undo should not be appended to last stack item
9606 } else if (!redoing) {
9607 // neither undoing nor redoing: delete redoStack
9608 this.clear(false, true);
9609 }
9610 const insertions = new DeleteSet();
9611 transaction.afterState.forEach((endClock, client) => {
9612 const startClock = transaction.beforeState.get(client) || 0;
9613 const len = endClock - startClock;
9614 if (len > 0) {
9615 addToDeleteSet(insertions, client, startClock, len);
9616 }
9617 });
9618 const now = time.getUnixTime();
9619 let didAdd = false;
9620 if (this.lastChange > 0 && now - this.lastChange < this.captureTimeout && stack.length > 0 && !undoing && !redoing) {
9621 // append change to last stack op
9622 const lastOp = stack[stack.length - 1];
9623 lastOp.deletions = mergeDeleteSets([lastOp.deletions, transaction.deleteSet]);
9624 lastOp.insertions = mergeDeleteSets([lastOp.insertions, insertions]);
9625 } else {
9626 // create a new stack op
9627 stack.push(new StackItem(transaction.deleteSet, insertions));
9628 didAdd = true;
9629 }
9630 if (!undoing && !redoing) {
9631 this.lastChange = now;
9632 }
9633 // make sure that deleted structs are not gc'd
9634 iterateDeletedStructs(transaction, transaction.deleteSet, /** @param {Item|GC} item */ item => {
9635 if (item instanceof Item && this.scope.some(type => yjs_isParentOf(type, item))) {
9636 keepItem(item, true);
9637 }
9638 });
9639 const changeEvent = [{ stackItem: stack[stack.length - 1], origin: transaction.origin, type: undoing ? 'redo' : 'undo', changedParentTypes: transaction.changedParentTypes }, this];
9640 if (didAdd) {
9641 this.emit('stack-item-added', changeEvent);
9642 } else {
9643 this.emit('stack-item-updated', changeEvent);
9644 }
9645 };
9646 this.doc.on('afterTransaction', this.afterTransactionHandler);
9647 this.doc.on('destroy', () => {
9648 this.destroy();
9649 });
9650 }
9651
9652 /**
9653 * @param {Array<AbstractType<any>> | AbstractType<any>} ytypes
9654 */
9655 addToScope (ytypes) {
9656 ytypes = array.isArray(ytypes) ? ytypes : [ytypes];
9657 ytypes.forEach(ytype => {
9658 if (this.scope.every(yt => yt !== ytype)) {
9659 this.scope.push(ytype);
9660 }
9661 });
9662 }
9663
9664 /**
9665 * @param {any} origin
9666 */
9667 addTrackedOrigin (origin) {
9668 this.trackedOrigins.add(origin);
9669 }
9670
9671 /**
9672 * @param {any} origin
9673 */
9674 removeTrackedOrigin (origin) {
9675 this.trackedOrigins.delete(origin);
9676 }
9677
9678 clear (clearUndoStack = true, clearRedoStack = true) {
9679 if ((clearUndoStack && this.canUndo()) || (clearRedoStack && this.canRedo())) {
9680 this.doc.transact(tr => {
9681 if (clearUndoStack) {
9682 this.undoStack.forEach(item => clearUndoManagerStackItem(tr, this, item));
9683 this.undoStack = [];
9684 }
9685 if (clearRedoStack) {
9686 this.redoStack.forEach(item => clearUndoManagerStackItem(tr, this, item));
9687 this.redoStack = [];
9688 }
9689 this.emit('stack-cleared', [{ undoStackCleared: clearUndoStack, redoStackCleared: clearRedoStack }]);
9690 });
9691 }
9692 }
9693
9694 /**
9695 * UndoManager merges Undo-StackItem if they are created within time-gap
9696 * smaller than `options.captureTimeout`. Call `um.stopCapturing()` so that the next
9697 * StackItem won't be merged.
9698 *
9699 *
9700 * @example
9701 * // without stopCapturing
9702 * ytext.insert(0, 'a')
9703 * ytext.insert(1, 'b')
9704 * um.undo()
9705 * ytext.toString() // => '' (note that 'ab' was removed)
9706 * // with stopCapturing
9707 * ytext.insert(0, 'a')
9708 * um.stopCapturing()
9709 * ytext.insert(0, 'b')
9710 * um.undo()
9711 * ytext.toString() // => 'a' (note that only 'b' was removed)
9712 *
9713 */
9714 stopCapturing () {
9715 this.lastChange = 0;
9716 }
9717
9718 /**
9719 * Undo last changes on type.
9720 *
9721 * @return {StackItem?} Returns StackItem if a change was applied
9722 */
9723 undo () {
9724 this.undoing = true;
9725 let res;
9726 try {
9727 res = popStackItem(this, this.undoStack, 'undo');
9728 } finally {
9729 this.undoing = false;
9730 }
9731 return res
9732 }
9733
9734 /**
9735 * Redo last undo operation.
9736 *
9737 * @return {StackItem?} Returns StackItem if a change was applied
9738 */
9739 redo () {
9740 this.redoing = true;
9741 let res;
9742 try {
9743 res = popStackItem(this, this.redoStack, 'redo');
9744 } finally {
9745 this.redoing = false;
9746 }
9747 return res
9748 }
9749
9750 /**
9751 * Are undo steps available?
9752 *
9753 * @return {boolean} `true` if undo is possible
9754 */
9755 canUndo () {
9756 return this.undoStack.length > 0
9757 }
9758
9759 /**
9760 * Are redo steps available?
9761 *
9762 * @return {boolean} `true` if redo is possible
9763 */
9764 canRedo () {
9765 return this.redoStack.length > 0
9766 }
9767
9768 destroy () {
9769 this.trackedOrigins.delete(this);
9770 this.doc.off('afterTransaction', this.afterTransactionHandler);
9771 super.destroy();
9772 }
9773 }
9774
9775 /**
9776 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
9777 */
9778 function * lazyStructReaderGenerator (decoder) {
9779 const numOfStateUpdates = readVarUint(decoder.restDecoder);
9780 for (let i = 0; i < numOfStateUpdates; i++) {
9781 const numberOfStructs = readVarUint(decoder.restDecoder);
9782 const client = decoder.readClient();
9783 let clock = readVarUint(decoder.restDecoder);
9784 for (let i = 0; i < numberOfStructs; i++) {
9785 const info = decoder.readInfo();
9786 // @todo use switch instead of ifs
9787 if (info === 10) {
9788 const len = readVarUint(decoder.restDecoder);
9789 yield new Skip(createID(client, clock), len);
9790 clock += len;
9791 } else if ((BITS5 & info) !== 0) {
9792 const cantCopyParentInfo = (info & (BIT7 | BIT8)) === 0;
9793 // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
9794 // and we read the next string as parentYKey.
9795 // It indicates how we store/retrieve parent from `y.share`
9796 // @type {string|null}
9797 const struct = new Item(
9798 createID(client, clock),
9799 null, // left
9800 (info & BIT8) === BIT8 ? decoder.readLeftID() : null, // origin
9801 null, // right
9802 (info & BIT7) === BIT7 ? decoder.readRightID() : null, // right origin
9803 // @ts-ignore Force writing a string here.
9804 cantCopyParentInfo ? (decoder.readParentInfo() ? decoder.readString() : decoder.readLeftID()) : null, // parent
9805 cantCopyParentInfo && (info & BIT6) === BIT6 ? decoder.readString() : null, // parentSub
9806 readItemContent(decoder, info) // item content
9807 );
9808 yield struct;
9809 clock += struct.length;
9810 } else {
9811 const len = decoder.readLen();
9812 yield new GC(createID(client, clock), len);
9813 clock += len;
9814 }
9815 }
9816 }
9817 }
9818
9819 class LazyStructReader {
9820 /**
9821 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
9822 * @param {boolean} filterSkips
9823 */
9824 constructor (decoder, filterSkips) {
9825 this.gen = lazyStructReaderGenerator(decoder);
9826 /**
9827 * @type {null | Item | Skip | GC}
9828 */
9829 this.curr = null;
9830 this.done = false;
9831 this.filterSkips = filterSkips;
9832 this.next();
9833 }
9834
9835 /**
9836 * @return {Item | GC | Skip |null}
9837 */
9838 next () {
9839 // ignore "Skip" structs
9840 do {
9841 this.curr = this.gen.next().value || null;
9842 } while (this.filterSkips && this.curr !== null && this.curr.constructor === Skip)
9843 return this.curr
9844 }
9845 }
9846
9847 /**
9848 * @param {Uint8Array} update
9849 *
9850 */
9851 const logUpdate = update => logUpdateV2(update, UpdateDecoderV1);
9852
9853 /**
9854 * @param {Uint8Array} update
9855 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
9856 *
9857 */
9858 const logUpdateV2 = (update, YDecoder = UpdateDecoderV2) => {
9859 const structs = [];
9860 const updateDecoder = new YDecoder(decoding.createDecoder(update));
9861 const lazyDecoder = new LazyStructReader(updateDecoder, false);
9862 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
9863 structs.push(curr);
9864 }
9865 logging.print('Structs: ', structs);
9866 const ds = readDeleteSet(updateDecoder);
9867 logging.print('DeleteSet: ', ds);
9868 };
9869
9870 /**
9871 * @param {Uint8Array} update
9872 *
9873 */
9874 const decodeUpdate = (update) => decodeUpdateV2(update, UpdateDecoderV1);
9875
9876 /**
9877 * @param {Uint8Array} update
9878 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
9879 *
9880 */
9881 const decodeUpdateV2 = (update, YDecoder = UpdateDecoderV2) => {
9882 const structs = [];
9883 const updateDecoder = new YDecoder(decoding.createDecoder(update));
9884 const lazyDecoder = new LazyStructReader(updateDecoder, false);
9885 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
9886 structs.push(curr);
9887 }
9888 return {
9889 structs,
9890 ds: readDeleteSet(updateDecoder)
9891 }
9892 };
9893
9894 class LazyStructWriter {
9895 /**
9896 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
9897 */
9898 constructor (encoder) {
9899 this.currClient = 0;
9900 this.startClock = 0;
9901 this.written = 0;
9902 this.encoder = encoder;
9903 /**
9904 * We want to write operations lazily, but also we need to know beforehand how many operations we want to write for each client.
9905 *
9906 * This kind of meta-information (#clients, #structs-per-client-written) is written to the restEncoder.
9907 *
9908 * We fragment the restEncoder and store a slice of it per-client until we know how many clients there are.
9909 * When we flush (toUint8Array) we write the restEncoder using the fragments and the meta-information.
9910 *
9911 * @type {Array<{ written: number, restEncoder: Uint8Array }>}
9912 */
9913 this.clientStructs = [];
9914 }
9915 }
9916
9917 /**
9918 * @param {Array<Uint8Array>} updates
9919 * @return {Uint8Array}
9920 */
9921 const mergeUpdates = updates => mergeUpdatesV2(updates, UpdateDecoderV1, UpdateEncoderV1);
9922
9923 /**
9924 * @param {Uint8Array} update
9925 * @param {typeof DSEncoderV1 | typeof DSEncoderV2} YEncoder
9926 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} YDecoder
9927 * @return {Uint8Array}
9928 */
9929 const encodeStateVectorFromUpdateV2 = (update, YEncoder = DSEncoderV2, YDecoder = UpdateDecoderV2) => {
9930 const encoder = new YEncoder();
9931 const updateDecoder = new LazyStructReader(new YDecoder(decoding.createDecoder(update)), false);
9932 let curr = updateDecoder.curr;
9933 if (curr !== null) {
9934 let size = 0;
9935 let currClient = curr.id.client;
9936 let stopCounting = curr.id.clock !== 0; // must start at 0
9937 let currClock = stopCounting ? 0 : curr.id.clock + curr.length;
9938 for (; curr !== null; curr = updateDecoder.next()) {
9939 if (currClient !== curr.id.client) {
9940 if (currClock !== 0) {
9941 size++;
9942 // We found a new client
9943 // write what we have to the encoder
9944 encoding.writeVarUint(encoder.restEncoder, currClient);
9945 encoding.writeVarUint(encoder.restEncoder, currClock);
9946 }
9947 currClient = curr.id.client;
9948 currClock = 0;
9949 stopCounting = curr.id.clock !== 0;
9950 }
9951 // we ignore skips
9952 if (curr.constructor === Skip) {
9953 stopCounting = true;
9954 }
9955 if (!stopCounting) {
9956 currClock = curr.id.clock + curr.length;
9957 }
9958 }
9959 // write what we have
9960 if (currClock !== 0) {
9961 size++;
9962 encoding.writeVarUint(encoder.restEncoder, currClient);
9963 encoding.writeVarUint(encoder.restEncoder, currClock);
9964 }
9965 // prepend the size of the state vector
9966 const enc = encoding.createEncoder();
9967 encoding.writeVarUint(enc, size);
9968 encoding.writeBinaryEncoder(enc, encoder.restEncoder);
9969 encoder.restEncoder = enc;
9970 return encoder.toUint8Array()
9971 } else {
9972 encoding.writeVarUint(encoder.restEncoder, 0);
9973 return encoder.toUint8Array()
9974 }
9975 };
9976
9977 /**
9978 * @param {Uint8Array} update
9979 * @return {Uint8Array}
9980 */
9981 const encodeStateVectorFromUpdate = update => encodeStateVectorFromUpdateV2(update, DSEncoderV1, UpdateDecoderV1);
9982
9983 /**
9984 * @param {Uint8Array} update
9985 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} YDecoder
9986 * @return {{ from: Map<number,number>, to: Map<number,number> }}
9987 */
9988 const parseUpdateMetaV2 = (update, YDecoder = UpdateDecoderV2) => {
9989 /**
9990 * @type {Map<number, number>}
9991 */
9992 const from = new Map();
9993 /**
9994 * @type {Map<number, number>}
9995 */
9996 const to = new Map();
9997 const updateDecoder = new LazyStructReader(new YDecoder(decoding.createDecoder(update)), false);
9998 let curr = updateDecoder.curr;
9999 if (curr !== null) {
10000 let currClient = curr.id.client;
10001 let currClock = curr.id.clock;
10002 // write the beginning to `from`
10003 from.set(currClient, currClock);
10004 for (; curr !== null; curr = updateDecoder.next()) {
10005 if (currClient !== curr.id.client) {
10006 // We found a new client
10007 // write the end to `to`
10008 to.set(currClient, currClock);
10009 // write the beginning to `from`
10010 from.set(curr.id.client, curr.id.clock);
10011 // update currClient
10012 currClient = curr.id.client;
10013 }
10014 currClock = curr.id.clock + curr.length;
10015 }
10016 // write the end to `to`
10017 to.set(currClient, currClock);
10018 }
10019 return { from, to }
10020 };
10021
10022 /**
10023 * @param {Uint8Array} update
10024 * @return {{ from: Map<number,number>, to: Map<number,number> }}
10025 */
10026 const parseUpdateMeta = update => parseUpdateMetaV2(update, UpdateDecoderV1);
10027
10028 /**
10029 * This method is intended to slice any kind of struct and retrieve the right part.
10030 * It does not handle side-effects, so it should only be used by the lazy-encoder.
10031 *
10032 * @param {Item | GC | Skip} left
10033 * @param {number} diff
10034 * @return {Item | GC}
10035 */
10036 const sliceStruct = (left, diff) => {
10037 if (left.constructor === GC) {
10038 const { client, clock } = left.id;
10039 return new GC(createID(client, clock + diff), left.length - diff)
10040 } else if (left.constructor === Skip) {
10041 const { client, clock } = left.id;
10042 return new Skip(createID(client, clock + diff), left.length - diff)
10043 } else {
10044 const leftItem = /** @type {Item} */ (left);
10045 const { client, clock } = leftItem.id;
10046 return new Item(
10047 createID(client, clock + diff),
10048 null,
10049 createID(client, clock + diff - 1),
10050 null,
10051 leftItem.rightOrigin,
10052 leftItem.parent,
10053 leftItem.parentSub,
10054 leftItem.content.splice(diff)
10055 )
10056 }
10057 };
10058
10059 /**
10060 *
10061 * This function works similarly to `readUpdateV2`.
10062 *
10063 * @param {Array<Uint8Array>} updates
10064 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
10065 * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder]
10066 * @return {Uint8Array}
10067 */
10068 const mergeUpdatesV2 = (updates, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => {
10069 if (updates.length === 1) {
10070 return updates[0]
10071 }
10072 const updateDecoders = updates.map(update => new YDecoder(createDecoder(update)));
10073 let lazyStructDecoders = updateDecoders.map(decoder => new LazyStructReader(decoder, true));
10074
10075 /**
10076 * @todo we don't need offset because we always slice before
10077 * @type {null | { struct: Item | GC | Skip, offset: number }}
10078 */
10079 let currWrite = null;
10080
10081 const updateEncoder = new YEncoder();
10082 // write structs lazily
10083 const lazyStructEncoder = new LazyStructWriter(updateEncoder);
10084
10085 // Note: We need to ensure that all lazyStructDecoders are fully consumed
10086 // Note: Should merge document updates whenever possible - even from different updates
10087 // Note: Should handle that some operations cannot be applied yet ()
10088
10089 while (true) {
10090 // Write higher clients first ⇒ sort by clientID & clock and remove decoders without content
10091 lazyStructDecoders = lazyStructDecoders.filter(dec => dec.curr !== null);
10092 lazyStructDecoders.sort(
10093 /** @type {function(any,any):number} */ (dec1, dec2) => {
10094 if (dec1.curr.id.client === dec2.curr.id.client) {
10095 const clockDiff = dec1.curr.id.clock - dec2.curr.id.clock;
10096 if (clockDiff === 0) {
10097 // @todo remove references to skip since the structDecoders must filter Skips.
10098 return dec1.curr.constructor === dec2.curr.constructor
10099 ? 0
10100 : dec1.curr.constructor === Skip ? 1 : -1 // we are filtering skips anyway.
10101 } else {
10102 return clockDiff
10103 }
10104 } else {
10105 return dec2.curr.id.client - dec1.curr.id.client
10106 }
10107 }
10108 );
10109 if (lazyStructDecoders.length === 0) {
10110 break
10111 }
10112 const currDecoder = lazyStructDecoders[0];
10113 // write from currDecoder until the next operation is from another client or if filler-struct
10114 // then we need to reorder the decoders and find the next operation to write
10115 const firstClient = /** @type {Item | GC} */ (currDecoder.curr).id.client;
10116
10117 if (currWrite !== null) {
10118 let curr = /** @type {Item | GC | null} */ (currDecoder.curr);
10119 let iterated = false;
10120
10121 // iterate until we find something that we haven't written already
10122 // remember: first the high client-ids are written
10123 while (curr !== null && curr.id.clock + curr.length <= currWrite.struct.id.clock + currWrite.struct.length && curr.id.client >= currWrite.struct.id.client) {
10124 curr = currDecoder.next();
10125 iterated = true;
10126 }
10127 if (
10128 curr === null || // current decoder is empty
10129 curr.id.client !== firstClient || // check whether there is another decoder that has has updates from `firstClient`
10130 (iterated && curr.id.clock > currWrite.struct.id.clock + currWrite.struct.length) // the above while loop was used and we are potentially missing updates
10131 ) {
10132 continue
10133 }
10134
10135 if (firstClient !== currWrite.struct.id.client) {
10136 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10137 currWrite = { struct: curr, offset: 0 };
10138 currDecoder.next();
10139 } else {
10140 if (currWrite.struct.id.clock + currWrite.struct.length < curr.id.clock) {
10141 // @todo write currStruct & set currStruct = Skip(clock = currStruct.id.clock + currStruct.length, length = curr.id.clock - self.clock)
10142 if (currWrite.struct.constructor === Skip) {
10143 // extend existing skip
10144 currWrite.struct.length = curr.id.clock + curr.length - currWrite.struct.id.clock;
10145 } else {
10146 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10147 const diff = curr.id.clock - currWrite.struct.id.clock - currWrite.struct.length;
10148 /**
10149 * @type {Skip}
10150 */
10151 const struct = new Skip(createID(firstClient, currWrite.struct.id.clock + currWrite.struct.length), diff);
10152 currWrite = { struct, offset: 0 };
10153 }
10154 } else { // if (currWrite.struct.id.clock + currWrite.struct.length >= curr.id.clock) {
10155 const diff = currWrite.struct.id.clock + currWrite.struct.length - curr.id.clock;
10156 if (diff > 0) {
10157 if (currWrite.struct.constructor === Skip) {
10158 // prefer to slice Skip because the other struct might contain more information
10159 currWrite.struct.length -= diff;
10160 } else {
10161 curr = sliceStruct(curr, diff);
10162 }
10163 }
10164 if (!currWrite.struct.mergeWith(/** @type {any} */ (curr))) {
10165 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10166 currWrite = { struct: curr, offset: 0 };
10167 currDecoder.next();
10168 }
10169 }
10170 }
10171 } else {
10172 currWrite = { struct: /** @type {Item | GC} */ (currDecoder.curr), offset: 0 };
10173 currDecoder.next();
10174 }
10175 for (
10176 let next = currDecoder.curr;
10177 next !== null && next.id.client === firstClient && next.id.clock === currWrite.struct.id.clock + currWrite.struct.length && next.constructor !== Skip;
10178 next = currDecoder.next()
10179 ) {
10180 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10181 currWrite = { struct: next, offset: 0 };
10182 }
10183 }
10184 if (currWrite !== null) {
10185 writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset);
10186 currWrite = null;
10187 }
10188 finishLazyStructWriting(lazyStructEncoder);
10189
10190 const dss = updateDecoders.map(decoder => readDeleteSet(decoder));
10191 const ds = mergeDeleteSets(dss);
10192 writeDeleteSet(updateEncoder, ds);
10193 return updateEncoder.toUint8Array()
10194 };
10195
10196 /**
10197 * @param {Uint8Array} update
10198 * @param {Uint8Array} sv
10199 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
10200 * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder]
10201 */
10202 const diffUpdateV2 = (update, sv, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => {
10203 const state = decodeStateVector(sv);
10204 const encoder = new YEncoder();
10205 const lazyStructWriter = new LazyStructWriter(encoder);
10206 const decoder = new YDecoder(createDecoder(update));
10207 const reader = new LazyStructReader(decoder, false);
10208 while (reader.curr) {
10209 const curr = reader.curr;
10210 const currClient = curr.id.client;
10211 const svClock = state.get(currClient) || 0;
10212 if (reader.curr.constructor === Skip) {
10213 // the first written struct shouldn't be a skip
10214 reader.next();
10215 continue
10216 }
10217 if (curr.id.clock + curr.length > svClock) {
10218 writeStructToLazyStructWriter(lazyStructWriter, curr, max(svClock - curr.id.clock, 0));
10219 reader.next();
10220 while (reader.curr && reader.curr.id.client === currClient) {
10221 writeStructToLazyStructWriter(lazyStructWriter, reader.curr, 0);
10222 reader.next();
10223 }
10224 } else {
10225 // read until something new comes up
10226 while (reader.curr && reader.curr.id.client === currClient && reader.curr.id.clock + reader.curr.length <= svClock) {
10227 reader.next();
10228 }
10229 }
10230 }
10231 finishLazyStructWriting(lazyStructWriter);
10232 // write ds
10233 const ds = readDeleteSet(decoder);
10234 writeDeleteSet(encoder, ds);
10235 return encoder.toUint8Array()
10236 };
10237
10238 /**
10239 * @param {Uint8Array} update
10240 * @param {Uint8Array} sv
10241 */
10242 const diffUpdate = (update, sv) => diffUpdateV2(update, sv, UpdateDecoderV1, UpdateEncoderV1);
10243
10244 /**
10245 * @param {LazyStructWriter} lazyWriter
10246 */
10247 const flushLazyStructWriter = lazyWriter => {
10248 if (lazyWriter.written > 0) {
10249 lazyWriter.clientStructs.push({ written: lazyWriter.written, restEncoder: toUint8Array(lazyWriter.encoder.restEncoder) });
10250 lazyWriter.encoder.restEncoder = createEncoder();
10251 lazyWriter.written = 0;
10252 }
10253 };
10254
10255 /**
10256 * @param {LazyStructWriter} lazyWriter
10257 * @param {Item | GC} struct
10258 * @param {number} offset
10259 */
10260 const writeStructToLazyStructWriter = (lazyWriter, struct, offset) => {
10261 // flush curr if we start another client
10262 if (lazyWriter.written > 0 && lazyWriter.currClient !== struct.id.client) {
10263 flushLazyStructWriter(lazyWriter);
10264 }
10265 if (lazyWriter.written === 0) {
10266 lazyWriter.currClient = struct.id.client;
10267 // write next client
10268 lazyWriter.encoder.writeClient(struct.id.client);
10269 // write startClock
10270 writeVarUint(lazyWriter.encoder.restEncoder, struct.id.clock + offset);
10271 }
10272 struct.write(lazyWriter.encoder, offset);
10273 lazyWriter.written++;
10274 };
10275 /**
10276 * Call this function when we collected all parts and want to
10277 * put all the parts together. After calling this method,
10278 * you can continue using the UpdateEncoder.
10279 *
10280 * @param {LazyStructWriter} lazyWriter
10281 */
10282 const finishLazyStructWriting = (lazyWriter) => {
10283 flushLazyStructWriter(lazyWriter);
10284
10285 // this is a fresh encoder because we called flushCurr
10286 const restEncoder = lazyWriter.encoder.restEncoder;
10287
10288 /**
10289 * Now we put all the fragments together.
10290 * This works similarly to `writeClientsStructs`
10291 */
10292
10293 // write # states that were updated - i.e. the clients
10294 writeVarUint(restEncoder, lazyWriter.clientStructs.length);
10295
10296 for (let i = 0; i < lazyWriter.clientStructs.length; i++) {
10297 const partStructs = lazyWriter.clientStructs[i];
10298 /**
10299 * Works similarly to `writeStructs`
10300 */
10301 // write # encoded structs
10302 writeVarUint(restEncoder, partStructs.written);
10303 // write the rest of the fragment
10304 writeUint8Array(restEncoder, partStructs.restEncoder);
10305 }
10306 };
10307
10308 /**
10309 * @param {Uint8Array} update
10310 * @param {function(Item|GC|Skip):Item|GC|Skip} blockTransformer
10311 * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} YDecoder
10312 * @param {typeof UpdateEncoderV2 | typeof UpdateEncoderV1 } YEncoder
10313 */
10314 const convertUpdateFormat = (update, blockTransformer, YDecoder, YEncoder) => {
10315 const updateDecoder = new YDecoder(createDecoder(update));
10316 const lazyDecoder = new LazyStructReader(updateDecoder, false);
10317 const updateEncoder = new YEncoder();
10318 const lazyWriter = new LazyStructWriter(updateEncoder);
10319 for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
10320 writeStructToLazyStructWriter(lazyWriter, blockTransformer(curr), 0);
10321 }
10322 finishLazyStructWriting(lazyWriter);
10323 const ds = readDeleteSet(updateDecoder);
10324 writeDeleteSet(updateEncoder, ds);
10325 return updateEncoder.toUint8Array()
10326 };
10327
10328 /**
10329 * @typedef {Object} ObfuscatorOptions
10330 * @property {boolean} [ObfuscatorOptions.formatting=true]
10331 * @property {boolean} [ObfuscatorOptions.subdocs=true]
10332 * @property {boolean} [ObfuscatorOptions.yxml=true] Whether to obfuscate nodeName / hookName
10333 */
10334
10335 /**
10336 * @param {ObfuscatorOptions} obfuscator
10337 */
10338 const createObfuscator = ({ formatting = true, subdocs = true, yxml = true } = {}) => {
10339 let i = 0;
10340 const mapKeyCache = map.create();
10341 const nodeNameCache = map.create();
10342 const formattingKeyCache = map.create();
10343 const formattingValueCache = map.create();
10344 formattingValueCache.set(null, null); // end of a formatting range should always be the end of a formatting range
10345 /**
10346 * @param {Item|GC|Skip} block
10347 * @return {Item|GC|Skip}
10348 */
10349 return block => {
10350 switch (block.constructor) {
10351 case GC:
10352 case Skip:
10353 return block
10354 case Item: {
10355 const item = /** @type {Item} */ (block);
10356 const content = item.content;
10357 switch (content.constructor) {
10358 case ContentDeleted:
10359 break
10360 case ContentType: {
10361 if (yxml) {
10362 const type = /** @type {ContentType} */ (content).type;
10363 if (type instanceof YXmlElement) {
10364 type.nodeName = map.setIfUndefined(nodeNameCache, type.nodeName, () => 'node-' + i);
10365 }
10366 if (type instanceof YXmlHook) {
10367 type.hookName = map.setIfUndefined(nodeNameCache, type.hookName, () => 'hook-' + i);
10368 }
10369 }
10370 break
10371 }
10372 case ContentAny: {
10373 const c = /** @type {ContentAny} */ (content);
10374 c.arr = c.arr.map(() => i);
10375 break
10376 }
10377 case ContentBinary: {
10378 const c = /** @type {ContentBinary} */ (content);
10379 c.content = new Uint8Array([i]);
10380 break
10381 }
10382 case ContentDoc: {
10383 const c = /** @type {ContentDoc} */ (content);
10384 if (subdocs) {
10385 c.opts = {};
10386 c.doc.guid = i + '';
10387 }
10388 break
10389 }
10390 case ContentEmbed: {
10391 const c = /** @type {ContentEmbed} */ (content);
10392 c.embed = {};
10393 break
10394 }
10395 case ContentFormat: {
10396 const c = /** @type {ContentFormat} */ (content);
10397 if (formatting) {
10398 c.key = map.setIfUndefined(formattingKeyCache, c.key, () => i + '');
10399 c.value = map.setIfUndefined(formattingValueCache, c.value, () => ({ i }));
10400 }
10401 break
10402 }
10403 case ContentJSON: {
10404 const c = /** @type {ContentJSON} */ (content);
10405 c.arr = c.arr.map(() => i);
10406 break
10407 }
10408 case ContentString: {
10409 const c = /** @type {ContentString} */ (content);
10410 c.str = string.repeat((i % 10) + '', c.str.length);
10411 break
10412 }
10413 default:
10414 // unknown content type
10415 error.unexpectedCase();
10416 }
10417 if (item.parentSub) {
10418 item.parentSub = map.setIfUndefined(mapKeyCache, item.parentSub, () => i + '');
10419 }
10420 i++;
10421 return block
10422 }
10423 default:
10424 // unknown block-type
10425 error.unexpectedCase();
10426 }
10427 }
10428 };
10429
10430 /**
10431 * This function obfuscates the content of a Yjs update. This is useful to share
10432 * buggy Yjs documents while significantly limiting the possibility that a
10433 * developer can on the user. Note that it might still be possible to deduce
10434 * some information by analyzing the "structure" of the document or by analyzing
10435 * the typing behavior using the CRDT-related metadata that is still kept fully
10436 * intact.
10437 *
10438 * @param {Uint8Array} update
10439 * @param {ObfuscatorOptions} [opts]
10440 */
10441 const obfuscateUpdate = (update, opts) => convertUpdateFormat(update, createObfuscator(opts), UpdateDecoderV1, UpdateEncoderV1);
10442
10443 /**
10444 * @param {Uint8Array} update
10445 * @param {ObfuscatorOptions} [opts]
10446 */
10447 const obfuscateUpdateV2 = (update, opts) => convertUpdateFormat(update, createObfuscator(opts), UpdateDecoderV2, UpdateEncoderV2);
10448
10449 /**
10450 * @param {Uint8Array} update
10451 */
10452 const convertUpdateFormatV1ToV2 = update => convertUpdateFormat(update, f.id, UpdateDecoderV1, UpdateEncoderV2);
10453
10454 /**
10455 * @param {Uint8Array} update
10456 */
10457 const convertUpdateFormatV2ToV1 = update => convertUpdateFormat(update, id, UpdateDecoderV2, UpdateEncoderV1);
10458
10459 const errorComputeChanges = 'You must not compute changes after the event-handler fired.';
10460
10461 /**
10462 * @template {AbstractType<any>} T
10463 * YEvent describes the changes on a YType.
10464 */
10465 class YEvent {
10466 /**
10467 * @param {T} target The changed type.
10468 * @param {Transaction} transaction
10469 */
10470 constructor (target, transaction) {
10471 /**
10472 * The type on which this event was created on.
10473 * @type {T}
10474 */
10475 this.target = target;
10476 /**
10477 * The current target on which the observe callback is called.
10478 * @type {AbstractType<any>}
10479 */
10480 this.currentTarget = target;
10481 /**
10482 * The transaction that triggered this event.
10483 * @type {Transaction}
10484 */
10485 this.transaction = transaction;
10486 /**
10487 * @type {Object|null}
10488 */
10489 this._changes = null;
10490 /**
10491 * @type {null | Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>}
10492 */
10493 this._keys = null;
10494 /**
10495 * @type {null | Array<{ insert?: string | Array<any> | object | AbstractType<any>, retain?: number, delete?: number, attributes?: Object<string, any> }>}
10496 */
10497 this._delta = null;
10498 /**
10499 * @type {Array<string|number>|null}
10500 */
10501 this._path = null;
10502 }
10503
10504 /**
10505 * Computes the path from `y` to the changed type.
10506 *
10507 * @todo v14 should standardize on path: Array<{parent, index}> because that is easier to work with.
10508 *
10509 * The following property holds:
10510 * @example
10511 * let type = y
10512 * event.path.forEach(dir => {
10513 * type = type.get(dir)
10514 * })
10515 * type === event.target // => true
10516 */
10517 get path () {
10518 return this._path || (this._path = getPathTo(this.currentTarget, this.target))
10519 }
10520
10521 /**
10522 * Check if a struct is deleted by this event.
10523 *
10524 * In contrast to change.deleted, this method also returns true if the struct was added and then deleted.
10525 *
10526 * @param {AbstractStruct} struct
10527 * @return {boolean}
10528 */
10529 deletes (struct) {
10530 return isDeleted(this.transaction.deleteSet, struct.id)
10531 }
10532
10533 /**
10534 * @type {Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>}
10535 */
10536 get keys () {
10537 if (this._keys === null) {
10538 if (this.transaction.doc._transactionCleanups.length === 0) {
10539 throw error_create(errorComputeChanges)
10540 }
10541 const keys = new Map();
10542 const target = this.target;
10543 const changed = /** @type Set<string|null> */ (this.transaction.changed.get(target));
10544 changed.forEach(key => {
10545 if (key !== null) {
10546 const item = /** @type {Item} */ (target._map.get(key));
10547 /**
10548 * @type {'delete' | 'add' | 'update'}
10549 */
10550 let action;
10551 let oldValue;
10552 if (this.adds(item)) {
10553 let prev = item.left;
10554 while (prev !== null && this.adds(prev)) {
10555 prev = prev.left;
10556 }
10557 if (this.deletes(item)) {
10558 if (prev !== null && this.deletes(prev)) {
10559 action = 'delete';
10560 oldValue = last(prev.content.getContent());
10561 } else {
10562 return
10563 }
10564 } else {
10565 if (prev !== null && this.deletes(prev)) {
10566 action = 'update';
10567 oldValue = last(prev.content.getContent());
10568 } else {
10569 action = 'add';
10570 oldValue = undefined;
10571 }
10572 }
10573 } else {
10574 if (this.deletes(item)) {
10575 action = 'delete';
10576 oldValue = last(/** @type {Item} */ item.content.getContent());
10577 } else {
10578 return // nop
10579 }
10580 }
10581 keys.set(key, { action, oldValue });
10582 }
10583 });
10584 this._keys = keys;
10585 }
10586 return this._keys
10587 }
10588
10589 /**
10590 * This is a computed property. Note that this can only be safely computed during the
10591 * event call. Computing this property after other changes happened might result in
10592 * unexpected behavior (incorrect computation of deltas). A safe way to collect changes
10593 * is to store the `changes` or the `delta` object. Avoid storing the `transaction` object.
10594 *
10595 * @type {Array<{insert?: string | Array<any> | object | AbstractType<any>, retain?: number, delete?: number, attributes?: Object<string, any>}>}
10596 */
10597 get delta () {
10598 return this.changes.delta
10599 }
10600
10601 /**
10602 * Check if a struct is added by this event.
10603 *
10604 * In contrast to change.deleted, this method also returns true if the struct was added and then deleted.
10605 *
10606 * @param {AbstractStruct} struct
10607 * @return {boolean}
10608 */
10609 adds (struct) {
10610 return struct.id.clock >= (this.transaction.beforeState.get(struct.id.client) || 0)
10611 }
10612
10613 /**
10614 * This is a computed property. Note that this can only be safely computed during the
10615 * event call. Computing this property after other changes happened might result in
10616 * unexpected behavior (incorrect computation of deltas). A safe way to collect changes
10617 * is to store the `changes` or the `delta` object. Avoid storing the `transaction` object.
10618 *
10619 * @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}>}}
10620 */
10621 get changes () {
10622 let changes = this._changes;
10623 if (changes === null) {
10624 if (this.transaction.doc._transactionCleanups.length === 0) {
10625 throw error_create(errorComputeChanges)
10626 }
10627 const target = this.target;
10628 const added = set_create();
10629 const deleted = set_create();
10630 /**
10631 * @type {Array<{insert:Array<any>}|{delete:number}|{retain:number}>}
10632 */
10633 const delta = [];
10634 changes = {
10635 added,
10636 deleted,
10637 delta,
10638 keys: this.keys
10639 };
10640 const changed = /** @type Set<string|null> */ (this.transaction.changed.get(target));
10641 if (changed.has(null)) {
10642 /**
10643 * @type {any}
10644 */
10645 let lastOp = null;
10646 const packOp = () => {
10647 if (lastOp) {
10648 delta.push(lastOp);
10649 }
10650 };
10651 for (let item = target._start; item !== null; item = item.right) {
10652 if (item.deleted) {
10653 if (this.deletes(item) && !this.adds(item)) {
10654 if (lastOp === null || lastOp.delete === undefined) {
10655 packOp();
10656 lastOp = { delete: 0 };
10657 }
10658 lastOp.delete += item.length;
10659 deleted.add(item);
10660 } // else nop
10661 } else {
10662 if (this.adds(item)) {
10663 if (lastOp === null || lastOp.insert === undefined) {
10664 packOp();
10665 lastOp = { insert: [] };
10666 }
10667 lastOp.insert = lastOp.insert.concat(item.content.getContent());
10668 added.add(item);
10669 } else {
10670 if (lastOp === null || lastOp.retain === undefined) {
10671 packOp();
10672 lastOp = { retain: 0 };
10673 }
10674 lastOp.retain += item.length;
10675 }
10676 }
10677 }
10678 if (lastOp !== null && lastOp.retain === undefined) {
10679 packOp();
10680 }
10681 }
10682 this._changes = changes;
10683 }
10684 return /** @type {any} */ (changes)
10685 }
10686 }
10687
10688 /**
10689 * Compute the path from this type to the specified target.
10690 *
10691 * @example
10692 * // `child` should be accessible via `type.get(path[0]).get(path[1])..`
10693 * const path = type.getPathTo(child)
10694 * // assuming `type instanceof YArray`
10695 * console.log(path) // might look like => [2, 'key1']
10696 * child === type.get(path[0]).get(path[1])
10697 *
10698 * @param {AbstractType<any>} parent
10699 * @param {AbstractType<any>} child target
10700 * @return {Array<string|number>} Path to the target
10701 *
10702 * @private
10703 * @function
10704 */
10705 const getPathTo = (parent, child) => {
10706 const path = [];
10707 while (child._item !== null && child !== parent) {
10708 if (child._item.parentSub !== null) {
10709 // parent is map-ish
10710 path.unshift(child._item.parentSub);
10711 } else {
10712 // parent is array-ish
10713 let i = 0;
10714 let c = /** @type {AbstractType<any>} */ (child._item.parent)._start;
10715 while (c !== child._item && c !== null) {
10716 if (!c.deleted) {
10717 i++;
10718 }
10719 c = c.right;
10720 }
10721 path.unshift(i);
10722 }
10723 child = /** @type {AbstractType<any>} */ (child._item.parent);
10724 }
10725 return path
10726 };
10727
10728 const maxSearchMarker = 80;
10729
10730 /**
10731 * A unique timestamp that identifies each marker.
10732 *
10733 * Time is relative,.. this is more like an ever-increasing clock.
10734 *
10735 * @type {number}
10736 */
10737 let globalSearchMarkerTimestamp = 0;
10738
10739 class ArraySearchMarker {
10740 /**
10741 * @param {Item} p
10742 * @param {number} index
10743 */
10744 constructor (p, index) {
10745 p.marker = true;
10746 this.p = p;
10747 this.index = index;
10748 this.timestamp = globalSearchMarkerTimestamp++;
10749 }
10750 }
10751
10752 /**
10753 * @param {ArraySearchMarker} marker
10754 */
10755 const refreshMarkerTimestamp = marker => { marker.timestamp = globalSearchMarkerTimestamp++; };
10756
10757 /**
10758 * This is rather complex so this function is the only thing that should overwrite a marker
10759 *
10760 * @param {ArraySearchMarker} marker
10761 * @param {Item} p
10762 * @param {number} index
10763 */
10764 const overwriteMarker = (marker, p, index) => {
10765 marker.p.marker = false;
10766 marker.p = p;
10767 p.marker = true;
10768 marker.index = index;
10769 marker.timestamp = globalSearchMarkerTimestamp++;
10770 };
10771
10772 /**
10773 * @param {Array<ArraySearchMarker>} searchMarker
10774 * @param {Item} p
10775 * @param {number} index
10776 */
10777 const markPosition = (searchMarker, p, index) => {
10778 if (searchMarker.length >= maxSearchMarker) {
10779 // override oldest marker (we don't want to create more objects)
10780 const marker = searchMarker.reduce((a, b) => a.timestamp < b.timestamp ? a : b);
10781 overwriteMarker(marker, p, index);
10782 return marker
10783 } else {
10784 // create new marker
10785 const pm = new ArraySearchMarker(p, index);
10786 searchMarker.push(pm);
10787 return pm
10788 }
10789 };
10790
10791 /**
10792 * Search marker help us to find positions in the associative array faster.
10793 *
10794 * They speed up the process of finding a position without much bookkeeping.
10795 *
10796 * A maximum of `maxSearchMarker` objects are created.
10797 *
10798 * This function always returns a refreshed marker (updated timestamp)
10799 *
10800 * @param {AbstractType<any>} yarray
10801 * @param {number} index
10802 */
10803 const findMarker = (yarray, index) => {
10804 if (yarray._start === null || index === 0 || yarray._searchMarker === null) {
10805 return null
10806 }
10807 const marker = yarray._searchMarker.length === 0 ? null : yarray._searchMarker.reduce((a, b) => abs(index - a.index) < abs(index - b.index) ? a : b);
10808 let p = yarray._start;
10809 let pindex = 0;
10810 if (marker !== null) {
10811 p = marker.p;
10812 pindex = marker.index;
10813 refreshMarkerTimestamp(marker); // we used it, we might need to use it again
10814 }
10815 // iterate to right if possible
10816 while (p.right !== null && pindex < index) {
10817 if (!p.deleted && p.countable) {
10818 if (index < pindex + p.length) {
10819 break
10820 }
10821 pindex += p.length;
10822 }
10823 p = p.right;
10824 }
10825 // iterate to left if necessary (might be that pindex > index)
10826 while (p.left !== null && pindex > index) {
10827 p = p.left;
10828 if (!p.deleted && p.countable) {
10829 pindex -= p.length;
10830 }
10831 }
10832 // we want to make sure that p can't be merged with left, because that would screw up everything
10833 // in that cas just return what we have (it is most likely the best marker anyway)
10834 // iterate to left until p can't be merged with left
10835 while (p.left !== null && p.left.id.client === p.id.client && p.left.id.clock + p.left.length === p.id.clock) {
10836 p = p.left;
10837 if (!p.deleted && p.countable) {
10838 pindex -= p.length;
10839 }
10840 }
10841
10842 // @todo remove!
10843 // assure position
10844 // {
10845 // let start = yarray._start
10846 // let pos = 0
10847 // while (start !== p) {
10848 // if (!start.deleted && start.countable) {
10849 // pos += start.length
10850 // }
10851 // start = /** @type {Item} */ (start.right)
10852 // }
10853 // if (pos !== pindex) {
10854 // debugger
10855 // throw new Error('Gotcha position fail!')
10856 // }
10857 // }
10858 // if (marker) {
10859 // if (window.lengthes == null) {
10860 // window.lengthes = []
10861 // window.getLengthes = () => window.lengthes.sort((a, b) => a - b)
10862 // }
10863 // window.lengthes.push(marker.index - pindex)
10864 // console.log('distance', marker.index - pindex, 'len', p && p.parent.length)
10865 // }
10866 if (marker !== null && abs(marker.index - pindex) < /** @type {YText|YArray<any>} */ (p.parent).length / maxSearchMarker) {
10867 // adjust existing marker
10868 overwriteMarker(marker, p, pindex);
10869 return marker
10870 } else {
10871 // create new marker
10872 return markPosition(yarray._searchMarker, p, pindex)
10873 }
10874 };
10875
10876 /**
10877 * Update markers when a change happened.
10878 *
10879 * This should be called before doing a deletion!
10880 *
10881 * @param {Array<ArraySearchMarker>} searchMarker
10882 * @param {number} index
10883 * @param {number} len If insertion, len is positive. If deletion, len is negative.
10884 */
10885 const updateMarkerChanges = (searchMarker, index, len) => {
10886 for (let i = searchMarker.length - 1; i >= 0; i--) {
10887 const m = searchMarker[i];
10888 if (len > 0) {
10889 /**
10890 * @type {Item|null}
10891 */
10892 let p = m.p;
10893 p.marker = false;
10894 // Ideally we just want to do a simple position comparison, but this will only work if
10895 // search markers don't point to deleted items for formats.
10896 // Iterate marker to prev undeleted countable position so we know what to do when updating a position
10897 while (p && (p.deleted || !p.countable)) {
10898 p = p.left;
10899 if (p && !p.deleted && p.countable) {
10900 // adjust position. the loop should break now
10901 m.index -= p.length;
10902 }
10903 }
10904 if (p === null || p.marker === true) {
10905 // remove search marker if updated position is null or if position is already marked
10906 searchMarker.splice(i, 1);
10907 continue
10908 }
10909 m.p = p;
10910 p.marker = true;
10911 }
10912 if (index < m.index || (len > 0 && index === m.index)) { // a simple index <= m.index check would actually suffice
10913 m.index = max(index, m.index + len);
10914 }
10915 }
10916 };
10917
10918 /**
10919 * Accumulate all (list) children of a type and return them as an Array.
10920 *
10921 * @param {AbstractType<any>} t
10922 * @return {Array<Item>}
10923 */
10924 const getTypeChildren = t => {
10925 let s = t._start;
10926 const arr = [];
10927 while (s) {
10928 arr.push(s);
10929 s = s.right;
10930 }
10931 return arr
10932 };
10933
10934 /**
10935 * Call event listeners with an event. This will also add an event to all
10936 * parents (for `.observeDeep` handlers).
10937 *
10938 * @template EventType
10939 * @param {AbstractType<EventType>} type
10940 * @param {Transaction} transaction
10941 * @param {EventType} event
10942 */
10943 const callTypeObservers = (type, transaction, event) => {
10944 const changedType = type;
10945 const changedParentTypes = transaction.changedParentTypes;
10946 while (true) {
10947 // @ts-ignore
10948 setIfUndefined(changedParentTypes, type, () => []).push(event);
10949 if (type._item === null) {
10950 break
10951 }
10952 type = /** @type {AbstractType<any>} */ (type._item.parent);
10953 }
10954 callEventHandlerListeners(changedType._eH, event, transaction);
10955 };
10956
10957 /**
10958 * @template EventType
10959 * Abstract Yjs Type class
10960 */
10961 class AbstractType {
10962 constructor () {
10963 /**
10964 * @type {Item|null}
10965 */
10966 this._item = null;
10967 /**
10968 * @type {Map<string,Item>}
10969 */
10970 this._map = new Map();
10971 /**
10972 * @type {Item|null}
10973 */
10974 this._start = null;
10975 /**
10976 * @type {Doc|null}
10977 */
10978 this.doc = null;
10979 this._length = 0;
10980 /**
10981 * Event handlers
10982 * @type {EventHandler<EventType,Transaction>}
10983 */
10984 this._eH = createEventHandler();
10985 /**
10986 * Deep event handlers
10987 * @type {EventHandler<Array<YEvent<any>>,Transaction>}
10988 */
10989 this._dEH = createEventHandler();
10990 /**
10991 * @type {null | Array<ArraySearchMarker>}
10992 */
10993 this._searchMarker = null;
10994 }
10995
10996 /**
10997 * @return {AbstractType<any>|null}
10998 */
10999 get parent () {
11000 return this._item ? /** @type {AbstractType<any>} */ (this._item.parent) : null
11001 }
11002
11003 /**
11004 * Integrate this type into the Yjs instance.
11005 *
11006 * * Save this struct in the os
11007 * * This type is sent to other client
11008 * * Observer functions are fired
11009 *
11010 * @param {Doc} y The Yjs instance
11011 * @param {Item|null} item
11012 */
11013 _integrate (y, item) {
11014 this.doc = y;
11015 this._item = item;
11016 }
11017
11018 /**
11019 * @return {AbstractType<EventType>}
11020 */
11021 _copy () {
11022 throw methodUnimplemented()
11023 }
11024
11025 /**
11026 * @return {AbstractType<EventType>}
11027 */
11028 clone () {
11029 throw methodUnimplemented()
11030 }
11031
11032 /**
11033 * @param {UpdateEncoderV1 | UpdateEncoderV2} _encoder
11034 */
11035 _write (_encoder) { }
11036
11037 /**
11038 * The first non-deleted item
11039 */
11040 get _first () {
11041 let n = this._start;
11042 while (n !== null && n.deleted) {
11043 n = n.right;
11044 }
11045 return n
11046 }
11047
11048 /**
11049 * Creates YEvent and calls all type observers.
11050 * Must be implemented by each type.
11051 *
11052 * @param {Transaction} transaction
11053 * @param {Set<null|string>} _parentSubs Keys changed on this type. `null` if list was modified.
11054 */
11055 _callObserver (transaction, _parentSubs) {
11056 if (!transaction.local && this._searchMarker) {
11057 this._searchMarker.length = 0;
11058 }
11059 }
11060
11061 /**
11062 * Observe all events that are created on this type.
11063 *
11064 * @param {function(EventType, Transaction):void} f Observer function
11065 */
11066 observe (f) {
11067 addEventHandlerListener(this._eH, f);
11068 }
11069
11070 /**
11071 * Observe all events that are created by this type and its children.
11072 *
11073 * @param {function(Array<YEvent<any>>,Transaction):void} f Observer function
11074 */
11075 observeDeep (f) {
11076 addEventHandlerListener(this._dEH, f);
11077 }
11078
11079 /**
11080 * Unregister an observer function.
11081 *
11082 * @param {function(EventType,Transaction):void} f Observer function
11083 */
11084 unobserve (f) {
11085 removeEventHandlerListener(this._eH, f);
11086 }
11087
11088 /**
11089 * Unregister an observer function.
11090 *
11091 * @param {function(Array<YEvent<any>>,Transaction):void} f Observer function
11092 */
11093 unobserveDeep (f) {
11094 removeEventHandlerListener(this._dEH, f);
11095 }
11096
11097 /**
11098 * @abstract
11099 * @return {any}
11100 */
11101 toJSON () {}
11102 }
11103
11104 /**
11105 * @param {AbstractType<any>} type
11106 * @param {number} start
11107 * @param {number} end
11108 * @return {Array<any>}
11109 *
11110 * @private
11111 * @function
11112 */
11113 const typeListSlice = (type, start, end) => {
11114 if (start < 0) {
11115 start = type._length + start;
11116 }
11117 if (end < 0) {
11118 end = type._length + end;
11119 }
11120 let len = end - start;
11121 const cs = [];
11122 let n = type._start;
11123 while (n !== null && len > 0) {
11124 if (n.countable && !n.deleted) {
11125 const c = n.content.getContent();
11126 if (c.length <= start) {
11127 start -= c.length;
11128 } else {
11129 for (let i = start; i < c.length && len > 0; i++) {
11130 cs.push(c[i]);
11131 len--;
11132 }
11133 start = 0;
11134 }
11135 }
11136 n = n.right;
11137 }
11138 return cs
11139 };
11140
11141 /**
11142 * @param {AbstractType<any>} type
11143 * @return {Array<any>}
11144 *
11145 * @private
11146 * @function
11147 */
11148 const typeListToArray = type => {
11149 const cs = [];
11150 let n = type._start;
11151 while (n !== null) {
11152 if (n.countable && !n.deleted) {
11153 const c = n.content.getContent();
11154 for (let i = 0; i < c.length; i++) {
11155 cs.push(c[i]);
11156 }
11157 }
11158 n = n.right;
11159 }
11160 return cs
11161 };
11162
11163 /**
11164 * @param {AbstractType<any>} type
11165 * @param {Snapshot} snapshot
11166 * @return {Array<any>}
11167 *
11168 * @private
11169 * @function
11170 */
11171 const typeListToArraySnapshot = (type, snapshot) => {
11172 const cs = [];
11173 let n = type._start;
11174 while (n !== null) {
11175 if (n.countable && isVisible(n, snapshot)) {
11176 const c = n.content.getContent();
11177 for (let i = 0; i < c.length; i++) {
11178 cs.push(c[i]);
11179 }
11180 }
11181 n = n.right;
11182 }
11183 return cs
11184 };
11185
11186 /**
11187 * Executes a provided function on once on overy element of this YArray.
11188 *
11189 * @param {AbstractType<any>} type
11190 * @param {function(any,number,any):void} f A function to execute on every element of this YArray.
11191 *
11192 * @private
11193 * @function
11194 */
11195 const typeListForEach = (type, f) => {
11196 let index = 0;
11197 let n = type._start;
11198 while (n !== null) {
11199 if (n.countable && !n.deleted) {
11200 const c = n.content.getContent();
11201 for (let i = 0; i < c.length; i++) {
11202 f(c[i], index++, type);
11203 }
11204 }
11205 n = n.right;
11206 }
11207 };
11208
11209 /**
11210 * @template C,R
11211 * @param {AbstractType<any>} type
11212 * @param {function(C,number,AbstractType<any>):R} f
11213 * @return {Array<R>}
11214 *
11215 * @private
11216 * @function
11217 */
11218 const typeListMap = (type, f) => {
11219 /**
11220 * @type {Array<any>}
11221 */
11222 const result = [];
11223 typeListForEach(type, (c, i) => {
11224 result.push(f(c, i, type));
11225 });
11226 return result
11227 };
11228
11229 /**
11230 * @param {AbstractType<any>} type
11231 * @return {IterableIterator<any>}
11232 *
11233 * @private
11234 * @function
11235 */
11236 const typeListCreateIterator = type => {
11237 let n = type._start;
11238 /**
11239 * @type {Array<any>|null}
11240 */
11241 let currentContent = null;
11242 let currentContentIndex = 0;
11243 return {
11244 [Symbol.iterator] () {
11245 return this
11246 },
11247 next: () => {
11248 // find some content
11249 if (currentContent === null) {
11250 while (n !== null && n.deleted) {
11251 n = n.right;
11252 }
11253 // check if we reached the end, no need to check currentContent, because it does not exist
11254 if (n === null) {
11255 return {
11256 done: true,
11257 value: undefined
11258 }
11259 }
11260 // we found n, so we can set currentContent
11261 currentContent = n.content.getContent();
11262 currentContentIndex = 0;
11263 n = n.right; // we used the content of n, now iterate to next
11264 }
11265 const value = currentContent[currentContentIndex++];
11266 // check if we need to empty currentContent
11267 if (currentContent.length <= currentContentIndex) {
11268 currentContent = null;
11269 }
11270 return {
11271 done: false,
11272 value
11273 }
11274 }
11275 }
11276 };
11277
11278 /**
11279 * @param {AbstractType<any>} type
11280 * @param {number} index
11281 * @return {any}
11282 *
11283 * @private
11284 * @function
11285 */
11286 const typeListGet = (type, index) => {
11287 const marker = findMarker(type, index);
11288 let n = type._start;
11289 if (marker !== null) {
11290 n = marker.p;
11291 index -= marker.index;
11292 }
11293 for (; n !== null; n = n.right) {
11294 if (!n.deleted && n.countable) {
11295 if (index < n.length) {
11296 return n.content.getContent()[index]
11297 }
11298 index -= n.length;
11299 }
11300 }
11301 };
11302
11303 /**
11304 * @param {Transaction} transaction
11305 * @param {AbstractType<any>} parent
11306 * @param {Item?} referenceItem
11307 * @param {Array<Object<string,any>|Array<any>|boolean|number|null|string|Uint8Array>} content
11308 *
11309 * @private
11310 * @function
11311 */
11312 const typeListInsertGenericsAfter = (transaction, parent, referenceItem, content) => {
11313 let left = referenceItem;
11314 const doc = transaction.doc;
11315 const ownClientId = doc.clientID;
11316 const store = doc.store;
11317 const right = referenceItem === null ? parent._start : referenceItem.right;
11318 /**
11319 * @type {Array<Object|Array<any>|number|null>}
11320 */
11321 let jsonContent = [];
11322 const packJsonContent = () => {
11323 if (jsonContent.length > 0) {
11324 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentAny(jsonContent));
11325 left.integrate(transaction, 0);
11326 jsonContent = [];
11327 }
11328 };
11329 content.forEach(c => {
11330 if (c === null) {
11331 jsonContent.push(c);
11332 } else {
11333 switch (c.constructor) {
11334 case Number:
11335 case Object:
11336 case Boolean:
11337 case Array:
11338 case String:
11339 jsonContent.push(c);
11340 break
11341 default:
11342 packJsonContent();
11343 switch (c.constructor) {
11344 case Uint8Array:
11345 case ArrayBuffer:
11346 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))));
11347 left.integrate(transaction, 0);
11348 break
11349 case Doc:
11350 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentDoc(/** @type {Doc} */ (c)));
11351 left.integrate(transaction, 0);
11352 break
11353 default:
11354 if (c instanceof AbstractType) {
11355 left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentType(c));
11356 left.integrate(transaction, 0);
11357 } else {
11358 throw new Error('Unexpected content type in insert operation')
11359 }
11360 }
11361 }
11362 }
11363 });
11364 packJsonContent();
11365 };
11366
11367 const lengthExceeded = error_create('Length exceeded!');
11368
11369 /**
11370 * @param {Transaction} transaction
11371 * @param {AbstractType<any>} parent
11372 * @param {number} index
11373 * @param {Array<Object<string,any>|Array<any>|number|null|string|Uint8Array>} content
11374 *
11375 * @private
11376 * @function
11377 */
11378 const typeListInsertGenerics = (transaction, parent, index, content) => {
11379 if (index > parent._length) {
11380 throw lengthExceeded
11381 }
11382 if (index === 0) {
11383 if (parent._searchMarker) {
11384 updateMarkerChanges(parent._searchMarker, index, content.length);
11385 }
11386 return typeListInsertGenericsAfter(transaction, parent, null, content)
11387 }
11388 const startIndex = index;
11389 const marker = findMarker(parent, index);
11390 let n = parent._start;
11391 if (marker !== null) {
11392 n = marker.p;
11393 index -= marker.index;
11394 // we need to iterate one to the left so that the algorithm works
11395 if (index === 0) {
11396 // @todo refactor this as it actually doesn't consider formats
11397 n = n.prev; // important! get the left undeleted item so that we can actually decrease index
11398 index += (n && n.countable && !n.deleted) ? n.length : 0;
11399 }
11400 }
11401 for (; n !== null; n = n.right) {
11402 if (!n.deleted && n.countable) {
11403 if (index <= n.length) {
11404 if (index < n.length) {
11405 // insert in-between
11406 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + index));
11407 }
11408 break
11409 }
11410 index -= n.length;
11411 }
11412 }
11413 if (parent._searchMarker) {
11414 updateMarkerChanges(parent._searchMarker, startIndex, content.length);
11415 }
11416 return typeListInsertGenericsAfter(transaction, parent, n, content)
11417 };
11418
11419 /**
11420 * Pushing content is special as we generally want to push after the last item. So we don't have to update
11421 * the serach marker.
11422 *
11423 * @param {Transaction} transaction
11424 * @param {AbstractType<any>} parent
11425 * @param {Array<Object<string,any>|Array<any>|number|null|string|Uint8Array>} content
11426 *
11427 * @private
11428 * @function
11429 */
11430 const typeListPushGenerics = (transaction, parent, content) => {
11431 // Use the marker with the highest index and iterate to the right.
11432 const marker = (parent._searchMarker || []).reduce((maxMarker, currMarker) => currMarker.index > maxMarker.index ? currMarker : maxMarker, { index: 0, p: parent._start });
11433 let n = marker.p;
11434 if (n) {
11435 while (n.right) {
11436 n = n.right;
11437 }
11438 }
11439 return typeListInsertGenericsAfter(transaction, parent, n, content)
11440 };
11441
11442 /**
11443 * @param {Transaction} transaction
11444 * @param {AbstractType<any>} parent
11445 * @param {number} index
11446 * @param {number} length
11447 *
11448 * @private
11449 * @function
11450 */
11451 const typeListDelete = (transaction, parent, index, length) => {
11452 if (length === 0) { return }
11453 const startIndex = index;
11454 const startLength = length;
11455 const marker = findMarker(parent, index);
11456 let n = parent._start;
11457 if (marker !== null) {
11458 n = marker.p;
11459 index -= marker.index;
11460 }
11461 // compute the first item to be deleted
11462 for (; n !== null && index > 0; n = n.right) {
11463 if (!n.deleted && n.countable) {
11464 if (index < n.length) {
11465 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + index));
11466 }
11467 index -= n.length;
11468 }
11469 }
11470 // delete all items until done
11471 while (length > 0 && n !== null) {
11472 if (!n.deleted) {
11473 if (length < n.length) {
11474 getItemCleanStart(transaction, createID(n.id.client, n.id.clock + length));
11475 }
11476 n.delete(transaction);
11477 length -= n.length;
11478 }
11479 n = n.right;
11480 }
11481 if (length > 0) {
11482 throw lengthExceeded
11483 }
11484 if (parent._searchMarker) {
11485 updateMarkerChanges(parent._searchMarker, startIndex, -startLength + length /* in case we remove the above exception */);
11486 }
11487 };
11488
11489 /**
11490 * @param {Transaction} transaction
11491 * @param {AbstractType<any>} parent
11492 * @param {string} key
11493 *
11494 * @private
11495 * @function
11496 */
11497 const typeMapDelete = (transaction, parent, key) => {
11498 const c = parent._map.get(key);
11499 if (c !== undefined) {
11500 c.delete(transaction);
11501 }
11502 };
11503
11504 /**
11505 * @param {Transaction} transaction
11506 * @param {AbstractType<any>} parent
11507 * @param {string} key
11508 * @param {Object|number|null|Array<any>|string|Uint8Array|AbstractType<any>} value
11509 *
11510 * @private
11511 * @function
11512 */
11513 const typeMapSet = (transaction, parent, key, value) => {
11514 const left = parent._map.get(key) || null;
11515 const doc = transaction.doc;
11516 const ownClientId = doc.clientID;
11517 let content;
11518 if (value == null) {
11519 content = new ContentAny([value]);
11520 } else {
11521 switch (value.constructor) {
11522 case Number:
11523 case Object:
11524 case Boolean:
11525 case Array:
11526 case String:
11527 content = new ContentAny([value]);
11528 break
11529 case Uint8Array:
11530 content = new ContentBinary(/** @type {Uint8Array} */ (value));
11531 break
11532 case Doc:
11533 content = new ContentDoc(/** @type {Doc} */ (value));
11534 break
11535 default:
11536 if (value instanceof AbstractType) {
11537 content = new ContentType(value);
11538 } else {
11539 throw new Error('Unexpected content type')
11540 }
11541 }
11542 }
11543 new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, null, null, parent, key, content).integrate(transaction, 0);
11544 };
11545
11546 /**
11547 * @param {AbstractType<any>} parent
11548 * @param {string} key
11549 * @return {Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined}
11550 *
11551 * @private
11552 * @function
11553 */
11554 const typeMapGet = (parent, key) => {
11555 const val = parent._map.get(key);
11556 return val !== undefined && !val.deleted ? val.content.getContent()[val.length - 1] : undefined
11557 };
11558
11559 /**
11560 * @param {AbstractType<any>} parent
11561 * @return {Object<string,Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined>}
11562 *
11563 * @private
11564 * @function
11565 */
11566 const typeMapGetAll = (parent) => {
11567 /**
11568 * @type {Object<string,any>}
11569 */
11570 const res = {};
11571 parent._map.forEach((value, key) => {
11572 if (!value.deleted) {
11573 res[key] = value.content.getContent()[value.length - 1];
11574 }
11575 });
11576 return res
11577 };
11578
11579 /**
11580 * @param {AbstractType<any>} parent
11581 * @param {string} key
11582 * @return {boolean}
11583 *
11584 * @private
11585 * @function
11586 */
11587 const typeMapHas = (parent, key) => {
11588 const val = parent._map.get(key);
11589 return val !== undefined && !val.deleted
11590 };
11591
11592 /**
11593 * @param {AbstractType<any>} parent
11594 * @param {string} key
11595 * @param {Snapshot} snapshot
11596 * @return {Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined}
11597 *
11598 * @private
11599 * @function
11600 */
11601 const typeMapGetSnapshot = (parent, key, snapshot) => {
11602 let v = parent._map.get(key) || null;
11603 while (v !== null && (!snapshot.sv.has(v.id.client) || v.id.clock >= (snapshot.sv.get(v.id.client) || 0))) {
11604 v = v.left;
11605 }
11606 return v !== null && isVisible(v, snapshot) ? v.content.getContent()[v.length - 1] : undefined
11607 };
11608
11609 /**
11610 * @param {Map<string,Item>} map
11611 * @return {IterableIterator<Array<any>>}
11612 *
11613 * @private
11614 * @function
11615 */
11616 const createMapIterator = map => iteratorFilter(map.entries(), /** @param {any} entry */ entry => !entry[1].deleted);
11617
11618 /**
11619 * @module YArray
11620 */
11621
11622 /**
11623 * Event that describes the changes on a YArray
11624 * @template T
11625 * @extends YEvent<YArray<T>>
11626 */
11627 class YArrayEvent extends YEvent {
11628 /**
11629 * @param {YArray<T>} yarray The changed type
11630 * @param {Transaction} transaction The transaction object
11631 */
11632 constructor (yarray, transaction) {
11633 super(yarray, transaction);
11634 this._transaction = transaction;
11635 }
11636 }
11637
11638 /**
11639 * A shared Array implementation.
11640 * @template T
11641 * @extends AbstractType<YArrayEvent<T>>
11642 * @implements {Iterable<T>}
11643 */
11644 class YArray extends AbstractType {
11645 constructor () {
11646 super();
11647 /**
11648 * @type {Array<any>?}
11649 * @private
11650 */
11651 this._prelimContent = [];
11652 /**
11653 * @type {Array<ArraySearchMarker>}
11654 */
11655 this._searchMarker = [];
11656 }
11657
11658 /**
11659 * Construct a new YArray containing the specified items.
11660 * @template {Object<string,any>|Array<any>|number|null|string|Uint8Array} T
11661 * @param {Array<T>} items
11662 * @return {YArray<T>}
11663 */
11664 static from (items) {
11665 /**
11666 * @type {YArray<T>}
11667 */
11668 const a = new YArray();
11669 a.push(items);
11670 return a
11671 }
11672
11673 /**
11674 * Integrate this type into the Yjs instance.
11675 *
11676 * * Save this struct in the os
11677 * * This type is sent to other client
11678 * * Observer functions are fired
11679 *
11680 * @param {Doc} y The Yjs instance
11681 * @param {Item} item
11682 */
11683 _integrate (y, item) {
11684 super._integrate(y, item);
11685 this.insert(0, /** @type {Array<any>} */ (this._prelimContent));
11686 this._prelimContent = null;
11687 }
11688
11689 /**
11690 * @return {YArray<T>}
11691 */
11692 _copy () {
11693 return new YArray()
11694 }
11695
11696 /**
11697 * @return {YArray<T>}
11698 */
11699 clone () {
11700 /**
11701 * @type {YArray<T>}
11702 */
11703 const arr = new YArray();
11704 arr.insert(0, this.toArray().map(el =>
11705 el instanceof AbstractType ? /** @type {typeof el} */ (el.clone()) : el
11706 ));
11707 return arr
11708 }
11709
11710 get length () {
11711 return this._prelimContent === null ? this._length : this._prelimContent.length
11712 }
11713
11714 /**
11715 * Creates YArrayEvent and calls observers.
11716 *
11717 * @param {Transaction} transaction
11718 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
11719 */
11720 _callObserver (transaction, parentSubs) {
11721 super._callObserver(transaction, parentSubs);
11722 callTypeObservers(this, transaction, new YArrayEvent(this, transaction));
11723 }
11724
11725 /**
11726 * Inserts new content at an index.
11727 *
11728 * Important: This function expects an array of content. Not just a content
11729 * object. The reason for this "weirdness" is that inserting several elements
11730 * is very efficient when it is done as a single operation.
11731 *
11732 * @example
11733 * // Insert character 'a' at position 0
11734 * yarray.insert(0, ['a'])
11735 * // Insert numbers 1, 2 at position 1
11736 * yarray.insert(1, [1, 2])
11737 *
11738 * @param {number} index The index to insert content at.
11739 * @param {Array<T>} content The array of content
11740 */
11741 insert (index, content) {
11742 if (this.doc !== null) {
11743 transact(this.doc, transaction => {
11744 typeListInsertGenerics(transaction, this, index, /** @type {any} */ (content));
11745 });
11746 } else {
11747 /** @type {Array<any>} */ (this._prelimContent).splice(index, 0, ...content);
11748 }
11749 }
11750
11751 /**
11752 * Appends content to this YArray.
11753 *
11754 * @param {Array<T>} content Array of content to append.
11755 *
11756 * @todo Use the following implementation in all types.
11757 */
11758 push (content) {
11759 if (this.doc !== null) {
11760 transact(this.doc, transaction => {
11761 typeListPushGenerics(transaction, this, /** @type {any} */ (content));
11762 });
11763 } else {
11764 /** @type {Array<any>} */ (this._prelimContent).push(...content);
11765 }
11766 }
11767
11768 /**
11769 * Preppends content to this YArray.
11770 *
11771 * @param {Array<T>} content Array of content to preppend.
11772 */
11773 unshift (content) {
11774 this.insert(0, content);
11775 }
11776
11777 /**
11778 * Deletes elements starting from an index.
11779 *
11780 * @param {number} index Index at which to start deleting elements
11781 * @param {number} length The number of elements to remove. Defaults to 1.
11782 */
11783 delete (index, length = 1) {
11784 if (this.doc !== null) {
11785 transact(this.doc, transaction => {
11786 typeListDelete(transaction, this, index, length);
11787 });
11788 } else {
11789 /** @type {Array<any>} */ (this._prelimContent).splice(index, length);
11790 }
11791 }
11792
11793 /**
11794 * Returns the i-th element from a YArray.
11795 *
11796 * @param {number} index The index of the element to return from the YArray
11797 * @return {T}
11798 */
11799 get (index) {
11800 return typeListGet(this, index)
11801 }
11802
11803 /**
11804 * Transforms this YArray to a JavaScript Array.
11805 *
11806 * @return {Array<T>}
11807 */
11808 toArray () {
11809 return typeListToArray(this)
11810 }
11811
11812 /**
11813 * Transforms this YArray to a JavaScript Array.
11814 *
11815 * @param {number} [start]
11816 * @param {number} [end]
11817 * @return {Array<T>}
11818 */
11819 slice (start = 0, end = this.length) {
11820 return typeListSlice(this, start, end)
11821 }
11822
11823 /**
11824 * Transforms this Shared Type to a JSON object.
11825 *
11826 * @return {Array<any>}
11827 */
11828 toJSON () {
11829 return this.map(c => c instanceof AbstractType ? c.toJSON() : c)
11830 }
11831
11832 /**
11833 * Returns an Array with the result of calling a provided function on every
11834 * element of this YArray.
11835 *
11836 * @template M
11837 * @param {function(T,number,YArray<T>):M} f Function that produces an element of the new Array
11838 * @return {Array<M>} A new array with each element being the result of the
11839 * callback function
11840 */
11841 map (f) {
11842 return typeListMap(this, /** @type {any} */ (f))
11843 }
11844
11845 /**
11846 * Executes a provided function once on overy element of this YArray.
11847 *
11848 * @param {function(T,number,YArray<T>):void} f A function to execute on every element of this YArray.
11849 */
11850 forEach (f) {
11851 typeListForEach(this, f);
11852 }
11853
11854 /**
11855 * @return {IterableIterator<T>}
11856 */
11857 [Symbol.iterator] () {
11858 return typeListCreateIterator(this)
11859 }
11860
11861 /**
11862 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
11863 */
11864 _write (encoder) {
11865 encoder.writeTypeRef(YArrayRefID);
11866 }
11867 }
11868
11869 /**
11870 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
11871 *
11872 * @private
11873 * @function
11874 */
11875 const readYArray = _decoder => new YArray();
11876
11877 /**
11878 * @template T
11879 * @extends YEvent<YMap<T>>
11880 * Event that describes the changes on a YMap.
11881 */
11882 class YMapEvent extends YEvent {
11883 /**
11884 * @param {YMap<T>} ymap The YArray that changed.
11885 * @param {Transaction} transaction
11886 * @param {Set<any>} subs The keys that changed.
11887 */
11888 constructor (ymap, transaction, subs) {
11889 super(ymap, transaction);
11890 this.keysChanged = subs;
11891 }
11892 }
11893
11894 /**
11895 * @template MapType
11896 * A shared Map implementation.
11897 *
11898 * @extends AbstractType<YMapEvent<MapType>>
11899 * @implements {Iterable<MapType>}
11900 */
11901 class YMap extends AbstractType {
11902 /**
11903 *
11904 * @param {Iterable<readonly [string, any]>=} entries - an optional iterable to initialize the YMap
11905 */
11906 constructor (entries) {
11907 super();
11908 /**
11909 * @type {Map<string,any>?}
11910 * @private
11911 */
11912 this._prelimContent = null;
11913
11914 if (entries === undefined) {
11915 this._prelimContent = new Map();
11916 } else {
11917 this._prelimContent = new Map(entries);
11918 }
11919 }
11920
11921 /**
11922 * Integrate this type into the Yjs instance.
11923 *
11924 * * Save this struct in the os
11925 * * This type is sent to other client
11926 * * Observer functions are fired
11927 *
11928 * @param {Doc} y The Yjs instance
11929 * @param {Item} item
11930 */
11931 _integrate (y, item) {
11932 super._integrate(y, item)
11933 ;/** @type {Map<string, any>} */ (this._prelimContent).forEach((value, key) => {
11934 this.set(key, value);
11935 });
11936 this._prelimContent = null;
11937 }
11938
11939 /**
11940 * @return {YMap<MapType>}
11941 */
11942 _copy () {
11943 return new YMap()
11944 }
11945
11946 /**
11947 * @return {YMap<MapType>}
11948 */
11949 clone () {
11950 /**
11951 * @type {YMap<MapType>}
11952 */
11953 const map = new YMap();
11954 this.forEach((value, key) => {
11955 map.set(key, value instanceof AbstractType ? /** @type {typeof value} */ (value.clone()) : value);
11956 });
11957 return map
11958 }
11959
11960 /**
11961 * Creates YMapEvent and calls observers.
11962 *
11963 * @param {Transaction} transaction
11964 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
11965 */
11966 _callObserver (transaction, parentSubs) {
11967 callTypeObservers(this, transaction, new YMapEvent(this, transaction, parentSubs));
11968 }
11969
11970 /**
11971 * Transforms this Shared Type to a JSON object.
11972 *
11973 * @return {Object<string,any>}
11974 */
11975 toJSON () {
11976 /**
11977 * @type {Object<string,MapType>}
11978 */
11979 const map = {};
11980 this._map.forEach((item, key) => {
11981 if (!item.deleted) {
11982 const v = item.content.getContent()[item.length - 1];
11983 map[key] = v instanceof AbstractType ? v.toJSON() : v;
11984 }
11985 });
11986 return map
11987 }
11988
11989 /**
11990 * Returns the size of the YMap (count of key/value pairs)
11991 *
11992 * @return {number}
11993 */
11994 get size () {
11995 return [...createMapIterator(this._map)].length
11996 }
11997
11998 /**
11999 * Returns the keys for each element in the YMap Type.
12000 *
12001 * @return {IterableIterator<string>}
12002 */
12003 keys () {
12004 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => v[0])
12005 }
12006
12007 /**
12008 * Returns the values for each element in the YMap Type.
12009 *
12010 * @return {IterableIterator<any>}
12011 */
12012 values () {
12013 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => v[1].content.getContent()[v[1].length - 1])
12014 }
12015
12016 /**
12017 * Returns an Iterator of [key, value] pairs
12018 *
12019 * @return {IterableIterator<any>}
12020 */
12021 entries () {
12022 return iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => [v[0], v[1].content.getContent()[v[1].length - 1]])
12023 }
12024
12025 /**
12026 * Executes a provided function on once on every key-value pair.
12027 *
12028 * @param {function(MapType,string,YMap<MapType>):void} f A function to execute on every element of this YArray.
12029 */
12030 forEach (f) {
12031 this._map.forEach((item, key) => {
12032 if (!item.deleted) {
12033 f(item.content.getContent()[item.length - 1], key, this);
12034 }
12035 });
12036 }
12037
12038 /**
12039 * Returns an Iterator of [key, value] pairs
12040 *
12041 * @return {IterableIterator<any>}
12042 */
12043 [Symbol.iterator] () {
12044 return this.entries()
12045 }
12046
12047 /**
12048 * Remove a specified element from this YMap.
12049 *
12050 * @param {string} key The key of the element to remove.
12051 */
12052 delete (key) {
12053 if (this.doc !== null) {
12054 transact(this.doc, transaction => {
12055 typeMapDelete(transaction, this, key);
12056 });
12057 } else {
12058 /** @type {Map<string, any>} */ (this._prelimContent).delete(key);
12059 }
12060 }
12061
12062 /**
12063 * Adds or updates an element with a specified key and value.
12064 * @template {MapType} VAL
12065 *
12066 * @param {string} key The key of the element to add to this YMap
12067 * @param {VAL} value The value of the element to add
12068 * @return {VAL}
12069 */
12070 set (key, value) {
12071 if (this.doc !== null) {
12072 transact(this.doc, transaction => {
12073 typeMapSet(transaction, this, key, /** @type {any} */ (value));
12074 });
12075 } else {
12076 /** @type {Map<string, any>} */ (this._prelimContent).set(key, value);
12077 }
12078 return value
12079 }
12080
12081 /**
12082 * Returns a specified element from this YMap.
12083 *
12084 * @param {string} key
12085 * @return {MapType|undefined}
12086 */
12087 get (key) {
12088 return /** @type {any} */ (typeMapGet(this, key))
12089 }
12090
12091 /**
12092 * Returns a boolean indicating whether the specified key exists or not.
12093 *
12094 * @param {string} key The key to test.
12095 * @return {boolean}
12096 */
12097 has (key) {
12098 return typeMapHas(this, key)
12099 }
12100
12101 /**
12102 * Removes all elements from this YMap.
12103 */
12104 clear () {
12105 if (this.doc !== null) {
12106 transact(this.doc, transaction => {
12107 this.forEach(function (_value, key, map) {
12108 typeMapDelete(transaction, map, key);
12109 });
12110 });
12111 } else {
12112 /** @type {Map<string, any>} */ (this._prelimContent).clear();
12113 }
12114 }
12115
12116 /**
12117 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
12118 */
12119 _write (encoder) {
12120 encoder.writeTypeRef(YMapRefID);
12121 }
12122 }
12123
12124 /**
12125 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
12126 *
12127 * @private
12128 * @function
12129 */
12130 const readYMap = _decoder => new YMap();
12131
12132 /**
12133 * @param {any} a
12134 * @param {any} b
12135 * @return {boolean}
12136 */
12137 const equalAttrs = (a, b) => a === b || (typeof a === 'object' && typeof b === 'object' && a && b && object_equalFlat(a, b));
12138
12139 class ItemTextListPosition {
12140 /**
12141 * @param {Item|null} left
12142 * @param {Item|null} right
12143 * @param {number} index
12144 * @param {Map<string,any>} currentAttributes
12145 */
12146 constructor (left, right, index, currentAttributes) {
12147 this.left = left;
12148 this.right = right;
12149 this.index = index;
12150 this.currentAttributes = currentAttributes;
12151 }
12152
12153 /**
12154 * Only call this if you know that this.right is defined
12155 */
12156 forward () {
12157 if (this.right === null) {
12158 unexpectedCase();
12159 }
12160 switch (this.right.content.constructor) {
12161 case ContentFormat:
12162 if (!this.right.deleted) {
12163 updateCurrentAttributes(this.currentAttributes, /** @type {ContentFormat} */ (this.right.content));
12164 }
12165 break
12166 default:
12167 if (!this.right.deleted) {
12168 this.index += this.right.length;
12169 }
12170 break
12171 }
12172 this.left = this.right;
12173 this.right = this.right.right;
12174 }
12175 }
12176
12177 /**
12178 * @param {Transaction} transaction
12179 * @param {ItemTextListPosition} pos
12180 * @param {number} count steps to move forward
12181 * @return {ItemTextListPosition}
12182 *
12183 * @private
12184 * @function
12185 */
12186 const findNextPosition = (transaction, pos, count) => {
12187 while (pos.right !== null && count > 0) {
12188 switch (pos.right.content.constructor) {
12189 case ContentFormat:
12190 if (!pos.right.deleted) {
12191 updateCurrentAttributes(pos.currentAttributes, /** @type {ContentFormat} */ (pos.right.content));
12192 }
12193 break
12194 default:
12195 if (!pos.right.deleted) {
12196 if (count < pos.right.length) {
12197 // split right
12198 getItemCleanStart(transaction, createID(pos.right.id.client, pos.right.id.clock + count));
12199 }
12200 pos.index += pos.right.length;
12201 count -= pos.right.length;
12202 }
12203 break
12204 }
12205 pos.left = pos.right;
12206 pos.right = pos.right.right;
12207 // pos.forward() - we don't forward because that would halve the performance because we already do the checks above
12208 }
12209 return pos
12210 };
12211
12212 /**
12213 * @param {Transaction} transaction
12214 * @param {AbstractType<any>} parent
12215 * @param {number} index
12216 * @return {ItemTextListPosition}
12217 *
12218 * @private
12219 * @function
12220 */
12221 const findPosition = (transaction, parent, index) => {
12222 const currentAttributes = new Map();
12223 const marker = findMarker(parent, index);
12224 if (marker) {
12225 const pos = new ItemTextListPosition(marker.p.left, marker.p, marker.index, currentAttributes);
12226 return findNextPosition(transaction, pos, index - marker.index)
12227 } else {
12228 const pos = new ItemTextListPosition(null, parent._start, 0, currentAttributes);
12229 return findNextPosition(transaction, pos, index)
12230 }
12231 };
12232
12233 /**
12234 * Negate applied formats
12235 *
12236 * @param {Transaction} transaction
12237 * @param {AbstractType<any>} parent
12238 * @param {ItemTextListPosition} currPos
12239 * @param {Map<string,any>} negatedAttributes
12240 *
12241 * @private
12242 * @function
12243 */
12244 const insertNegatedAttributes = (transaction, parent, currPos, negatedAttributes) => {
12245 // check if we really need to remove attributes
12246 while (
12247 currPos.right !== null && (
12248 currPos.right.deleted === true || (
12249 currPos.right.content.constructor === ContentFormat &&
12250 equalAttrs(negatedAttributes.get(/** @type {ContentFormat} */ (currPos.right.content).key), /** @type {ContentFormat} */ (currPos.right.content).value)
12251 )
12252 )
12253 ) {
12254 if (!currPos.right.deleted) {
12255 negatedAttributes.delete(/** @type {ContentFormat} */ (currPos.right.content).key);
12256 }
12257 currPos.forward();
12258 }
12259 const doc = transaction.doc;
12260 const ownClientId = doc.clientID;
12261 negatedAttributes.forEach((val, key) => {
12262 const left = currPos.left;
12263 const right = currPos.right;
12264 const nextFormat = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentFormat(key, val));
12265 nextFormat.integrate(transaction, 0);
12266 currPos.right = nextFormat;
12267 currPos.forward();
12268 });
12269 };
12270
12271 /**
12272 * @param {Map<string,any>} currentAttributes
12273 * @param {ContentFormat} format
12274 *
12275 * @private
12276 * @function
12277 */
12278 const updateCurrentAttributes = (currentAttributes, format) => {
12279 const { key, value } = format;
12280 if (value === null) {
12281 currentAttributes.delete(key);
12282 } else {
12283 currentAttributes.set(key, value);
12284 }
12285 };
12286
12287 /**
12288 * @param {ItemTextListPosition} currPos
12289 * @param {Object<string,any>} attributes
12290 *
12291 * @private
12292 * @function
12293 */
12294 const minimizeAttributeChanges = (currPos, attributes) => {
12295 // go right while attributes[right.key] === right.value (or right is deleted)
12296 while (true) {
12297 if (currPos.right === null) {
12298 break
12299 } 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 {
12300 break
12301 }
12302 currPos.forward();
12303 }
12304 };
12305
12306 /**
12307 * @param {Transaction} transaction
12308 * @param {AbstractType<any>} parent
12309 * @param {ItemTextListPosition} currPos
12310 * @param {Object<string,any>} attributes
12311 * @return {Map<string,any>}
12312 *
12313 * @private
12314 * @function
12315 **/
12316 const insertAttributes = (transaction, parent, currPos, attributes) => {
12317 const doc = transaction.doc;
12318 const ownClientId = doc.clientID;
12319 const negatedAttributes = new Map();
12320 // insert format-start items
12321 for (const key in attributes) {
12322 const val = attributes[key];
12323 const currentVal = currPos.currentAttributes.get(key) || null;
12324 if (!equalAttrs(currentVal, val)) {
12325 // save negated attribute (set null if currentVal undefined)
12326 negatedAttributes.set(key, currentVal);
12327 const { left, right } = currPos;
12328 currPos.right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentFormat(key, val));
12329 currPos.right.integrate(transaction, 0);
12330 currPos.forward();
12331 }
12332 }
12333 return negatedAttributes
12334 };
12335
12336 /**
12337 * @param {Transaction} transaction
12338 * @param {AbstractType<any>} parent
12339 * @param {ItemTextListPosition} currPos
12340 * @param {string|object|AbstractType<any>} text
12341 * @param {Object<string,any>} attributes
12342 *
12343 * @private
12344 * @function
12345 **/
12346 const insertText = (transaction, parent, currPos, text, attributes) => {
12347 currPos.currentAttributes.forEach((_val, key) => {
12348 if (attributes[key] === undefined) {
12349 attributes[key] = null;
12350 }
12351 });
12352 const doc = transaction.doc;
12353 const ownClientId = doc.clientID;
12354 minimizeAttributeChanges(currPos, attributes);
12355 const negatedAttributes = insertAttributes(transaction, parent, currPos, attributes);
12356 // insert content
12357 const content = text.constructor === String ? new ContentString(/** @type {string} */ (text)) : (text instanceof AbstractType ? new ContentType(text) : new ContentEmbed(text));
12358 let { left, right, index } = currPos;
12359 if (parent._searchMarker) {
12360 updateMarkerChanges(parent._searchMarker, currPos.index, content.getLength());
12361 }
12362 right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, content);
12363 right.integrate(transaction, 0);
12364 currPos.right = right;
12365 currPos.index = index;
12366 currPos.forward();
12367 insertNegatedAttributes(transaction, parent, currPos, negatedAttributes);
12368 };
12369
12370 /**
12371 * @param {Transaction} transaction
12372 * @param {AbstractType<any>} parent
12373 * @param {ItemTextListPosition} currPos
12374 * @param {number} length
12375 * @param {Object<string,any>} attributes
12376 *
12377 * @private
12378 * @function
12379 */
12380 const formatText = (transaction, parent, currPos, length, attributes) => {
12381 const doc = transaction.doc;
12382 const ownClientId = doc.clientID;
12383 minimizeAttributeChanges(currPos, attributes);
12384 const negatedAttributes = insertAttributes(transaction, parent, currPos, attributes);
12385 // iterate until first non-format or null is found
12386 // delete all formats with attributes[format.key] != null
12387 // also check the attributes after the first non-format as we do not want to insert redundant negated attributes there
12388 // eslint-disable-next-line no-labels
12389 iterationLoop: while (
12390 currPos.right !== null &&
12391 (length > 0 ||
12392 (
12393 negatedAttributes.size > 0 &&
12394 (currPos.right.deleted || currPos.right.content.constructor === ContentFormat)
12395 )
12396 )
12397 ) {
12398 if (!currPos.right.deleted) {
12399 switch (currPos.right.content.constructor) {
12400 case ContentFormat: {
12401 const { key, value } = /** @type {ContentFormat} */ (currPos.right.content);
12402 const attr = attributes[key];
12403 if (attr !== undefined) {
12404 if (equalAttrs(attr, value)) {
12405 negatedAttributes.delete(key);
12406 } else {
12407 if (length === 0) {
12408 // no need to further extend negatedAttributes
12409 // eslint-disable-next-line no-labels
12410 break iterationLoop
12411 }
12412 negatedAttributes.set(key, value);
12413 }
12414 currPos.right.delete(transaction);
12415 } else {
12416 currPos.currentAttributes.set(key, value);
12417 }
12418 break
12419 }
12420 default:
12421 if (length < currPos.right.length) {
12422 getItemCleanStart(transaction, createID(currPos.right.id.client, currPos.right.id.clock + length));
12423 }
12424 length -= currPos.right.length;
12425 break
12426 }
12427 }
12428 currPos.forward();
12429 }
12430 // Quill just assumes that the editor starts with a newline and that it always
12431 // ends with a newline. We only insert that newline when a new newline is
12432 // inserted - i.e when length is bigger than type.length
12433 if (length > 0) {
12434 let newlines = '';
12435 for (; length > 0; length--) {
12436 newlines += '\n';
12437 }
12438 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));
12439 currPos.right.integrate(transaction, 0);
12440 currPos.forward();
12441 }
12442 insertNegatedAttributes(transaction, parent, currPos, negatedAttributes);
12443 };
12444
12445 /**
12446 * Call this function after string content has been deleted in order to
12447 * clean up formatting Items.
12448 *
12449 * @param {Transaction} transaction
12450 * @param {Item} start
12451 * @param {Item|null} curr exclusive end, automatically iterates to the next Content Item
12452 * @param {Map<string,any>} startAttributes
12453 * @param {Map<string,any>} currAttributes
12454 * @return {number} The amount of formatting Items deleted.
12455 *
12456 * @function
12457 */
12458 const cleanupFormattingGap = (transaction, start, curr, startAttributes, currAttributes) => {
12459 /**
12460 * @type {Item|null}
12461 */
12462 let end = start;
12463 /**
12464 * @type {Map<string,ContentFormat>}
12465 */
12466 const endFormats = create();
12467 while (end && (!end.countable || end.deleted)) {
12468 if (!end.deleted && end.content.constructor === ContentFormat) {
12469 const cf = /** @type {ContentFormat} */ (end.content);
12470 endFormats.set(cf.key, cf);
12471 }
12472 end = end.right;
12473 }
12474 let cleanups = 0;
12475 let reachedCurr = false;
12476 while (start !== end) {
12477 if (curr === start) {
12478 reachedCurr = true;
12479 }
12480 if (!start.deleted) {
12481 const content = start.content;
12482 switch (content.constructor) {
12483 case ContentFormat: {
12484 const { key, value } = /** @type {ContentFormat} */ (content);
12485 const startAttrValue = startAttributes.get(key) || null;
12486 if (endFormats.get(key) !== content || startAttrValue === value) {
12487 // Either this format is overwritten or it is not necessary because the attribute already existed.
12488 start.delete(transaction);
12489 cleanups++;
12490 if (!reachedCurr && (currAttributes.get(key) || null) === value && startAttrValue !== value) {
12491 if (startAttrValue === null) {
12492 currAttributes.delete(key);
12493 } else {
12494 currAttributes.set(key, startAttrValue);
12495 }
12496 }
12497 }
12498 if (!reachedCurr && !start.deleted) {
12499 updateCurrentAttributes(currAttributes, /** @type {ContentFormat} */ (content));
12500 }
12501 break
12502 }
12503 }
12504 }
12505 start = /** @type {Item} */ (start.right);
12506 }
12507 return cleanups
12508 };
12509
12510 /**
12511 * @param {Transaction} transaction
12512 * @param {Item | null} item
12513 */
12514 const cleanupContextlessFormattingGap = (transaction, item) => {
12515 // iterate until item.right is null or content
12516 while (item && item.right && (item.right.deleted || !item.right.countable)) {
12517 item = item.right;
12518 }
12519 const attrs = new Set();
12520 // iterate back until a content item is found
12521 while (item && (item.deleted || !item.countable)) {
12522 if (!item.deleted && item.content.constructor === ContentFormat) {
12523 const key = /** @type {ContentFormat} */ (item.content).key;
12524 if (attrs.has(key)) {
12525 item.delete(transaction);
12526 } else {
12527 attrs.add(key);
12528 }
12529 }
12530 item = item.left;
12531 }
12532 };
12533
12534 /**
12535 * This function is experimental and subject to change / be removed.
12536 *
12537 * Ideally, we don't need this function at all. Formatting attributes should be cleaned up
12538 * automatically after each change. This function iterates twice over the complete YText type
12539 * and removes unnecessary formatting attributes. This is also helpful for testing.
12540 *
12541 * This function won't be exported anymore as soon as there is confidence that the YText type works as intended.
12542 *
12543 * @param {YText} type
12544 * @return {number} How many formatting attributes have been cleaned up.
12545 */
12546 const cleanupYTextFormatting = type => {
12547 let res = 0;
12548 transact(/** @type {Doc} */ (type.doc), transaction => {
12549 let start = /** @type {Item} */ (type._start);
12550 let end = type._start;
12551 let startAttributes = create();
12552 const currentAttributes = copy(startAttributes);
12553 while (end) {
12554 if (end.deleted === false) {
12555 switch (end.content.constructor) {
12556 case ContentFormat:
12557 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (end.content));
12558 break
12559 default:
12560 res += cleanupFormattingGap(transaction, start, end, startAttributes, currentAttributes);
12561 startAttributes = copy(currentAttributes);
12562 start = end;
12563 break
12564 }
12565 }
12566 end = end.right;
12567 }
12568 });
12569 return res
12570 };
12571
12572 /**
12573 * This will be called by the transction once the event handlers are called to potentially cleanup
12574 * formatting attributes.
12575 *
12576 * @param {Transaction} transaction
12577 */
12578 const cleanupYTextAfterTransaction = transaction => {
12579 /**
12580 * @type {Set<YText>}
12581 */
12582 const needFullCleanup = new Set();
12583 // check if another formatting item was inserted
12584 const doc = transaction.doc;
12585 for (const [client, afterClock] of transaction.afterState.entries()) {
12586 const clock = transaction.beforeState.get(client) || 0;
12587 if (afterClock === clock) {
12588 continue
12589 }
12590 iterateStructs(transaction, /** @type {Array<Item|GC>} */ (doc.store.clients.get(client)), clock, afterClock, item => {
12591 if (
12592 !item.deleted && /** @type {Item} */ (item).content.constructor === ContentFormat && item.constructor !== GC
12593 ) {
12594 needFullCleanup.add(/** @type {any} */ (item).parent);
12595 }
12596 });
12597 }
12598 // cleanup in a new transaction
12599 transact(doc, (t) => {
12600 iterateDeletedStructs(transaction, transaction.deleteSet, item => {
12601 if (item instanceof GC || !(/** @type {YText} */ (item.parent)._hasFormatting) || needFullCleanup.has(/** @type {YText} */ (item.parent))) {
12602 return
12603 }
12604 const parent = /** @type {YText} */ (item.parent);
12605 if (item.content.constructor === ContentFormat) {
12606 needFullCleanup.add(parent);
12607 } else {
12608 // If no formatting attribute was inserted or deleted, we can make due with contextless
12609 // formatting cleanups.
12610 // Contextless: it is not necessary to compute currentAttributes for the affected position.
12611 cleanupContextlessFormattingGap(t, item);
12612 }
12613 });
12614 // If a formatting item was inserted, we simply clean the whole type.
12615 // We need to compute currentAttributes for the current position anyway.
12616 for (const yText of needFullCleanup) {
12617 cleanupYTextFormatting(yText);
12618 }
12619 });
12620 };
12621
12622 /**
12623 * @param {Transaction} transaction
12624 * @param {ItemTextListPosition} currPos
12625 * @param {number} length
12626 * @return {ItemTextListPosition}
12627 *
12628 * @private
12629 * @function
12630 */
12631 const deleteText = (transaction, currPos, length) => {
12632 const startLength = length;
12633 const startAttrs = copy(currPos.currentAttributes);
12634 const start = currPos.right;
12635 while (length > 0 && currPos.right !== null) {
12636 if (currPos.right.deleted === false) {
12637 switch (currPos.right.content.constructor) {
12638 case ContentType:
12639 case ContentEmbed:
12640 case ContentString:
12641 if (length < currPos.right.length) {
12642 getItemCleanStart(transaction, createID(currPos.right.id.client, currPos.right.id.clock + length));
12643 }
12644 length -= currPos.right.length;
12645 currPos.right.delete(transaction);
12646 break
12647 }
12648 }
12649 currPos.forward();
12650 }
12651 if (start) {
12652 cleanupFormattingGap(transaction, start, currPos.right, startAttrs, currPos.currentAttributes);
12653 }
12654 const parent = /** @type {AbstractType<any>} */ (/** @type {Item} */ (currPos.left || currPos.right).parent);
12655 if (parent._searchMarker) {
12656 updateMarkerChanges(parent._searchMarker, currPos.index, -startLength + length);
12657 }
12658 return currPos
12659 };
12660
12661 /**
12662 * The Quill Delta format represents changes on a text document with
12663 * formatting information. For mor information visit {@link https://quilljs.com/docs/delta/|Quill Delta}
12664 *
12665 * @example
12666 * {
12667 * ops: [
12668 * { insert: 'Gandalf', attributes: { bold: true } },
12669 * { insert: ' the ' },
12670 * { insert: 'Grey', attributes: { color: '#cccccc' } }
12671 * ]
12672 * }
12673 *
12674 */
12675
12676 /**
12677 * Attributes that can be assigned to a selection of text.
12678 *
12679 * @example
12680 * {
12681 * bold: true,
12682 * font-size: '40px'
12683 * }
12684 *
12685 * @typedef {Object} TextAttributes
12686 */
12687
12688 /**
12689 * @extends YEvent<YText>
12690 * Event that describes the changes on a YText type.
12691 */
12692 class YTextEvent extends YEvent {
12693 /**
12694 * @param {YText} ytext
12695 * @param {Transaction} transaction
12696 * @param {Set<any>} subs The keys that changed
12697 */
12698 constructor (ytext, transaction, subs) {
12699 super(ytext, transaction);
12700 /**
12701 * Whether the children changed.
12702 * @type {Boolean}
12703 * @private
12704 */
12705 this.childListChanged = false;
12706 /**
12707 * Set of all changed attributes.
12708 * @type {Set<string>}
12709 */
12710 this.keysChanged = new Set();
12711 subs.forEach((sub) => {
12712 if (sub === null) {
12713 this.childListChanged = true;
12714 } else {
12715 this.keysChanged.add(sub);
12716 }
12717 });
12718 }
12719
12720 /**
12721 * @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}>}}
12722 */
12723 get changes () {
12724 if (this._changes === null) {
12725 /**
12726 * @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}>}}
12727 */
12728 const changes = {
12729 keys: this.keys,
12730 delta: this.delta,
12731 added: new Set(),
12732 deleted: new Set()
12733 };
12734 this._changes = changes;
12735 }
12736 return /** @type {any} */ (this._changes)
12737 }
12738
12739 /**
12740 * Compute the changes in the delta format.
12741 * A {@link https://quilljs.com/docs/delta/|Quill Delta}) that represents the changes on the document.
12742 *
12743 * @type {Array<{insert?:string|object|AbstractType<any>, delete?:number, retain?:number, attributes?: Object<string,any>}>}
12744 *
12745 * @public
12746 */
12747 get delta () {
12748 if (this._delta === null) {
12749 const y = /** @type {Doc} */ (this.target.doc);
12750 /**
12751 * @type {Array<{insert?:string|object|AbstractType<any>, delete?:number, retain?:number, attributes?: Object<string,any>}>}
12752 */
12753 const delta = [];
12754 transact(y, transaction => {
12755 const currentAttributes = new Map(); // saves all current attributes for insert
12756 const oldAttributes = new Map();
12757 let item = this.target._start;
12758 /**
12759 * @type {string?}
12760 */
12761 let action = null;
12762 /**
12763 * @type {Object<string,any>}
12764 */
12765 const attributes = {}; // counts added or removed new attributes for retain
12766 /**
12767 * @type {string|object}
12768 */
12769 let insert = '';
12770 let retain = 0;
12771 let deleteLen = 0;
12772 const addOp = () => {
12773 if (action !== null) {
12774 /**
12775 * @type {any}
12776 */
12777 let op = null;
12778 switch (action) {
12779 case 'delete':
12780 if (deleteLen > 0) {
12781 op = { delete: deleteLen };
12782 }
12783 deleteLen = 0;
12784 break
12785 case 'insert':
12786 if (typeof insert === 'object' || insert.length > 0) {
12787 op = { insert };
12788 if (currentAttributes.size > 0) {
12789 op.attributes = {};
12790 currentAttributes.forEach((value, key) => {
12791 if (value !== null) {
12792 op.attributes[key] = value;
12793 }
12794 });
12795 }
12796 }
12797 insert = '';
12798 break
12799 case 'retain':
12800 if (retain > 0) {
12801 op = { retain };
12802 if (!isEmpty(attributes)) {
12803 op.attributes = object_assign({}, attributes);
12804 }
12805 }
12806 retain = 0;
12807 break
12808 }
12809 if (op) delta.push(op);
12810 action = null;
12811 }
12812 };
12813 while (item !== null) {
12814 switch (item.content.constructor) {
12815 case ContentType:
12816 case ContentEmbed:
12817 if (this.adds(item)) {
12818 if (!this.deletes(item)) {
12819 addOp();
12820 action = 'insert';
12821 insert = item.content.getContent()[0];
12822 addOp();
12823 }
12824 } else if (this.deletes(item)) {
12825 if (action !== 'delete') {
12826 addOp();
12827 action = 'delete';
12828 }
12829 deleteLen += 1;
12830 } else if (!item.deleted) {
12831 if (action !== 'retain') {
12832 addOp();
12833 action = 'retain';
12834 }
12835 retain += 1;
12836 }
12837 break
12838 case ContentString:
12839 if (this.adds(item)) {
12840 if (!this.deletes(item)) {
12841 if (action !== 'insert') {
12842 addOp();
12843 action = 'insert';
12844 }
12845 insert += /** @type {ContentString} */ (item.content).str;
12846 }
12847 } else if (this.deletes(item)) {
12848 if (action !== 'delete') {
12849 addOp();
12850 action = 'delete';
12851 }
12852 deleteLen += item.length;
12853 } else if (!item.deleted) {
12854 if (action !== 'retain') {
12855 addOp();
12856 action = 'retain';
12857 }
12858 retain += item.length;
12859 }
12860 break
12861 case ContentFormat: {
12862 const { key, value } = /** @type {ContentFormat} */ (item.content);
12863 if (this.adds(item)) {
12864 if (!this.deletes(item)) {
12865 const curVal = currentAttributes.get(key) || null;
12866 if (!equalAttrs(curVal, value)) {
12867 if (action === 'retain') {
12868 addOp();
12869 }
12870 if (equalAttrs(value, (oldAttributes.get(key) || null))) {
12871 delete attributes[key];
12872 } else {
12873 attributes[key] = value;
12874 }
12875 } else if (value !== null) {
12876 item.delete(transaction);
12877 }
12878 }
12879 } else if (this.deletes(item)) {
12880 oldAttributes.set(key, value);
12881 const curVal = currentAttributes.get(key) || null;
12882 if (!equalAttrs(curVal, value)) {
12883 if (action === 'retain') {
12884 addOp();
12885 }
12886 attributes[key] = curVal;
12887 }
12888 } else if (!item.deleted) {
12889 oldAttributes.set(key, value);
12890 const attr = attributes[key];
12891 if (attr !== undefined) {
12892 if (!equalAttrs(attr, value)) {
12893 if (action === 'retain') {
12894 addOp();
12895 }
12896 if (value === null) {
12897 delete attributes[key];
12898 } else {
12899 attributes[key] = value;
12900 }
12901 } else if (attr !== null) { // this will be cleaned up automatically by the contextless cleanup function
12902 item.delete(transaction);
12903 }
12904 }
12905 }
12906 if (!item.deleted) {
12907 if (action === 'insert') {
12908 addOp();
12909 }
12910 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (item.content));
12911 }
12912 break
12913 }
12914 }
12915 item = item.right;
12916 }
12917 addOp();
12918 while (delta.length > 0) {
12919 const lastOp = delta[delta.length - 1];
12920 if (lastOp.retain !== undefined && lastOp.attributes === undefined) {
12921 // retain delta's if they don't assign attributes
12922 delta.pop();
12923 } else {
12924 break
12925 }
12926 }
12927 });
12928 this._delta = delta;
12929 }
12930 return /** @type {any} */ (this._delta)
12931 }
12932 }
12933
12934 /**
12935 * Type that represents text with formatting information.
12936 *
12937 * This type replaces y-richtext as this implementation is able to handle
12938 * block formats (format information on a paragraph), embeds (complex elements
12939 * like pictures and videos), and text formats (**bold**, *italic*).
12940 *
12941 * @extends AbstractType<YTextEvent>
12942 */
12943 class YText extends AbstractType {
12944 /**
12945 * @param {String} [string] The initial value of the YText.
12946 */
12947 constructor (string) {
12948 super();
12949 /**
12950 * Array of pending operations on this type
12951 * @type {Array<function():void>?}
12952 */
12953 this._pending = string !== undefined ? [() => this.insert(0, string)] : [];
12954 /**
12955 * @type {Array<ArraySearchMarker>|null}
12956 */
12957 this._searchMarker = [];
12958 /**
12959 * Whether this YText contains formatting attributes.
12960 * This flag is updated when a formatting item is integrated (see ContentFormat.integrate)
12961 */
12962 this._hasFormatting = false;
12963 }
12964
12965 /**
12966 * Number of characters of this text type.
12967 *
12968 * @type {number}
12969 */
12970 get length () {
12971 return this._length
12972 }
12973
12974 /**
12975 * @param {Doc} y
12976 * @param {Item} item
12977 */
12978 _integrate (y, item) {
12979 super._integrate(y, item);
12980 try {
12981 /** @type {Array<function>} */ (this._pending).forEach(f => f());
12982 } catch (e) {
12983 console.error(e);
12984 }
12985 this._pending = null;
12986 }
12987
12988 _copy () {
12989 return new YText()
12990 }
12991
12992 /**
12993 * @return {YText}
12994 */
12995 clone () {
12996 const text = new YText();
12997 text.applyDelta(this.toDelta());
12998 return text
12999 }
13000
13001 /**
13002 * Creates YTextEvent and calls observers.
13003 *
13004 * @param {Transaction} transaction
13005 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
13006 */
13007 _callObserver (transaction, parentSubs) {
13008 super._callObserver(transaction, parentSubs);
13009 const event = new YTextEvent(this, transaction, parentSubs);
13010 callTypeObservers(this, transaction, event);
13011 // If a remote change happened, we try to cleanup potential formatting duplicates.
13012 if (!transaction.local && this._hasFormatting) {
13013 transaction._needFormattingCleanup = true;
13014 }
13015 }
13016
13017 /**
13018 * Returns the unformatted string representation of this YText type.
13019 *
13020 * @public
13021 */
13022 toString () {
13023 let str = '';
13024 /**
13025 * @type {Item|null}
13026 */
13027 let n = this._start;
13028 while (n !== null) {
13029 if (!n.deleted && n.countable && n.content.constructor === ContentString) {
13030 str += /** @type {ContentString} */ (n.content).str;
13031 }
13032 n = n.right;
13033 }
13034 return str
13035 }
13036
13037 /**
13038 * Returns the unformatted string representation of this YText type.
13039 *
13040 * @return {string}
13041 * @public
13042 */
13043 toJSON () {
13044 return this.toString()
13045 }
13046
13047 /**
13048 * Apply a {@link Delta} on this shared YText type.
13049 *
13050 * @param {any} delta The changes to apply on this element.
13051 * @param {object} opts
13052 * @param {boolean} [opts.sanitize] Sanitize input delta. Removes ending newlines if set to true.
13053 *
13054 *
13055 * @public
13056 */
13057 applyDelta (delta, { sanitize = true } = {}) {
13058 if (this.doc !== null) {
13059 transact(this.doc, transaction => {
13060 const currPos = new ItemTextListPosition(null, this._start, 0, new Map());
13061 for (let i = 0; i < delta.length; i++) {
13062 const op = delta[i];
13063 if (op.insert !== undefined) {
13064 // Quill assumes that the content starts with an empty paragraph.
13065 // Yjs/Y.Text assumes that it starts empty. We always hide that
13066 // there is a newline at the end of the content.
13067 // If we omit this step, clients will see a different number of
13068 // paragraphs, but nothing bad will happen.
13069 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;
13070 if (typeof ins !== 'string' || ins.length > 0) {
13071 insertText(transaction, this, currPos, ins, op.attributes || {});
13072 }
13073 } else if (op.retain !== undefined) {
13074 formatText(transaction, this, currPos, op.retain, op.attributes || {});
13075 } else if (op.delete !== undefined) {
13076 deleteText(transaction, currPos, op.delete);
13077 }
13078 }
13079 });
13080 } else {
13081 /** @type {Array<function>} */ (this._pending).push(() => this.applyDelta(delta));
13082 }
13083 }
13084
13085 /**
13086 * Returns the Delta representation of this YText type.
13087 *
13088 * @param {Snapshot} [snapshot]
13089 * @param {Snapshot} [prevSnapshot]
13090 * @param {function('removed' | 'added', ID):any} [computeYChange]
13091 * @return {any} The Delta representation of this type.
13092 *
13093 * @public
13094 */
13095 toDelta (snapshot, prevSnapshot, computeYChange) {
13096 /**
13097 * @type{Array<any>}
13098 */
13099 const ops = [];
13100 const currentAttributes = new Map();
13101 const doc = /** @type {Doc} */ (this.doc);
13102 let str = '';
13103 let n = this._start;
13104 function packStr () {
13105 if (str.length > 0) {
13106 // pack str with attributes to ops
13107 /**
13108 * @type {Object<string,any>}
13109 */
13110 const attributes = {};
13111 let addAttributes = false;
13112 currentAttributes.forEach((value, key) => {
13113 addAttributes = true;
13114 attributes[key] = value;
13115 });
13116 /**
13117 * @type {Object<string,any>}
13118 */
13119 const op = { insert: str };
13120 if (addAttributes) {
13121 op.attributes = attributes;
13122 }
13123 ops.push(op);
13124 str = '';
13125 }
13126 }
13127 const computeDelta = () => {
13128 while (n !== null) {
13129 if (isVisible(n, snapshot) || (prevSnapshot !== undefined && isVisible(n, prevSnapshot))) {
13130 switch (n.content.constructor) {
13131 case ContentString: {
13132 const cur = currentAttributes.get('ychange');
13133 if (snapshot !== undefined && !isVisible(n, snapshot)) {
13134 if (cur === undefined || cur.user !== n.id.client || cur.type !== 'removed') {
13135 packStr();
13136 currentAttributes.set('ychange', computeYChange ? computeYChange('removed', n.id) : { type: 'removed' });
13137 }
13138 } else if (prevSnapshot !== undefined && !isVisible(n, prevSnapshot)) {
13139 if (cur === undefined || cur.user !== n.id.client || cur.type !== 'added') {
13140 packStr();
13141 currentAttributes.set('ychange', computeYChange ? computeYChange('added', n.id) : { type: 'added' });
13142 }
13143 } else if (cur !== undefined) {
13144 packStr();
13145 currentAttributes.delete('ychange');
13146 }
13147 str += /** @type {ContentString} */ (n.content).str;
13148 break
13149 }
13150 case ContentType:
13151 case ContentEmbed: {
13152 packStr();
13153 /**
13154 * @type {Object<string,any>}
13155 */
13156 const op = {
13157 insert: n.content.getContent()[0]
13158 };
13159 if (currentAttributes.size > 0) {
13160 const attrs = /** @type {Object<string,any>} */ ({});
13161 op.attributes = attrs;
13162 currentAttributes.forEach((value, key) => {
13163 attrs[key] = value;
13164 });
13165 }
13166 ops.push(op);
13167 break
13168 }
13169 case ContentFormat:
13170 if (isVisible(n, snapshot)) {
13171 packStr();
13172 updateCurrentAttributes(currentAttributes, /** @type {ContentFormat} */ (n.content));
13173 }
13174 break
13175 }
13176 }
13177 n = n.right;
13178 }
13179 packStr();
13180 };
13181 if (snapshot || prevSnapshot) {
13182 // snapshots are merged again after the transaction, so we need to keep the
13183 // transaction alive until we are done
13184 transact(doc, transaction => {
13185 if (snapshot) {
13186 splitSnapshotAffectedStructs(transaction, snapshot);
13187 }
13188 if (prevSnapshot) {
13189 splitSnapshotAffectedStructs(transaction, prevSnapshot);
13190 }
13191 computeDelta();
13192 }, 'cleanup');
13193 } else {
13194 computeDelta();
13195 }
13196 return ops
13197 }
13198
13199 /**
13200 * Insert text at a given index.
13201 *
13202 * @param {number} index The index at which to start inserting.
13203 * @param {String} text The text to insert at the specified position.
13204 * @param {TextAttributes} [attributes] Optionally define some formatting
13205 * information to apply on the inserted
13206 * Text.
13207 * @public
13208 */
13209 insert (index, text, attributes) {
13210 if (text.length <= 0) {
13211 return
13212 }
13213 const y = this.doc;
13214 if (y !== null) {
13215 transact(y, transaction => {
13216 const pos = findPosition(transaction, this, index);
13217 if (!attributes) {
13218 attributes = {};
13219 // @ts-ignore
13220 pos.currentAttributes.forEach((v, k) => { attributes[k] = v; });
13221 }
13222 insertText(transaction, this, pos, text, attributes);
13223 });
13224 } else {
13225 /** @type {Array<function>} */ (this._pending).push(() => this.insert(index, text, attributes));
13226 }
13227 }
13228
13229 /**
13230 * Inserts an embed at a index.
13231 *
13232 * @param {number} index The index to insert the embed at.
13233 * @param {Object | AbstractType<any>} embed The Object that represents the embed.
13234 * @param {TextAttributes} attributes Attribute information to apply on the
13235 * embed
13236 *
13237 * @public
13238 */
13239 insertEmbed (index, embed, attributes = {}) {
13240 const y = this.doc;
13241 if (y !== null) {
13242 transact(y, transaction => {
13243 const pos = findPosition(transaction, this, index);
13244 insertText(transaction, this, pos, embed, attributes);
13245 });
13246 } else {
13247 /** @type {Array<function>} */ (this._pending).push(() => this.insertEmbed(index, embed, attributes));
13248 }
13249 }
13250
13251 /**
13252 * Deletes text starting from an index.
13253 *
13254 * @param {number} index Index at which to start deleting.
13255 * @param {number} length The number of characters to remove. Defaults to 1.
13256 *
13257 * @public
13258 */
13259 delete (index, length) {
13260 if (length === 0) {
13261 return
13262 }
13263 const y = this.doc;
13264 if (y !== null) {
13265 transact(y, transaction => {
13266 deleteText(transaction, findPosition(transaction, this, index), length);
13267 });
13268 } else {
13269 /** @type {Array<function>} */ (this._pending).push(() => this.delete(index, length));
13270 }
13271 }
13272
13273 /**
13274 * Assigns properties to a range of text.
13275 *
13276 * @param {number} index The position where to start formatting.
13277 * @param {number} length The amount of characters to assign properties to.
13278 * @param {TextAttributes} attributes Attribute information to apply on the
13279 * text.
13280 *
13281 * @public
13282 */
13283 format (index, length, attributes) {
13284 if (length === 0) {
13285 return
13286 }
13287 const y = this.doc;
13288 if (y !== null) {
13289 transact(y, transaction => {
13290 const pos = findPosition(transaction, this, index);
13291 if (pos.right === null) {
13292 return
13293 }
13294 formatText(transaction, this, pos, length, attributes);
13295 });
13296 } else {
13297 /** @type {Array<function>} */ (this._pending).push(() => this.format(index, length, attributes));
13298 }
13299 }
13300
13301 /**
13302 * Removes an attribute.
13303 *
13304 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13305 *
13306 * @param {String} attributeName The attribute name that is to be removed.
13307 *
13308 * @public
13309 */
13310 removeAttribute (attributeName) {
13311 if (this.doc !== null) {
13312 transact(this.doc, transaction => {
13313 typeMapDelete(transaction, this, attributeName);
13314 });
13315 } else {
13316 /** @type {Array<function>} */ (this._pending).push(() => this.removeAttribute(attributeName));
13317 }
13318 }
13319
13320 /**
13321 * Sets or updates an attribute.
13322 *
13323 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13324 *
13325 * @param {String} attributeName The attribute name that is to be set.
13326 * @param {any} attributeValue The attribute value that is to be set.
13327 *
13328 * @public
13329 */
13330 setAttribute (attributeName, attributeValue) {
13331 if (this.doc !== null) {
13332 transact(this.doc, transaction => {
13333 typeMapSet(transaction, this, attributeName, attributeValue);
13334 });
13335 } else {
13336 /** @type {Array<function>} */ (this._pending).push(() => this.setAttribute(attributeName, attributeValue));
13337 }
13338 }
13339
13340 /**
13341 * Returns an attribute value that belongs to the attribute name.
13342 *
13343 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13344 *
13345 * @param {String} attributeName The attribute name that identifies the
13346 * queried value.
13347 * @return {any} The queried attribute value.
13348 *
13349 * @public
13350 */
13351 getAttribute (attributeName) {
13352 return /** @type {any} */ (typeMapGet(this, attributeName))
13353 }
13354
13355 /**
13356 * Returns all attribute name/value pairs in a JSON Object.
13357 *
13358 * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
13359 *
13360 * @return {Object<string, any>} A JSON Object that describes the attributes.
13361 *
13362 * @public
13363 */
13364 getAttributes () {
13365 return typeMapGetAll(this)
13366 }
13367
13368 /**
13369 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
13370 */
13371 _write (encoder) {
13372 encoder.writeTypeRef(YTextRefID);
13373 }
13374 }
13375
13376 /**
13377 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
13378 * @return {YText}
13379 *
13380 * @private
13381 * @function
13382 */
13383 const readYText = _decoder => new YText();
13384
13385 /**
13386 * @module YXml
13387 */
13388
13389 /**
13390 * Define the elements to which a set of CSS queries apply.
13391 * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors}
13392 *
13393 * @example
13394 * query = '.classSelector'
13395 * query = 'nodeSelector'
13396 * query = '#idSelector'
13397 *
13398 * @typedef {string} CSS_Selector
13399 */
13400
13401 /**
13402 * Dom filter function.
13403 *
13404 * @callback domFilter
13405 * @param {string} nodeName The nodeName of the element
13406 * @param {Map} attributes The map of attributes.
13407 * @return {boolean} Whether to include the Dom node in the YXmlElement.
13408 */
13409
13410 /**
13411 * Represents a subset of the nodes of a YXmlElement / YXmlFragment and a
13412 * position within them.
13413 *
13414 * Can be created with {@link YXmlFragment#createTreeWalker}
13415 *
13416 * @public
13417 * @implements {Iterable<YXmlElement|YXmlText|YXmlElement|YXmlHook>}
13418 */
13419 class YXmlTreeWalker {
13420 /**
13421 * @param {YXmlFragment | YXmlElement} root
13422 * @param {function(AbstractType<any>):boolean} [f]
13423 */
13424 constructor (root, f = () => true) {
13425 this._filter = f;
13426 this._root = root;
13427 /**
13428 * @type {Item}
13429 */
13430 this._currentNode = /** @type {Item} */ (root._start);
13431 this._firstCall = true;
13432 }
13433
13434 [Symbol.iterator] () {
13435 return this
13436 }
13437
13438 /**
13439 * Get the next node.
13440 *
13441 * @return {IteratorResult<YXmlElement|YXmlText|YXmlHook>} The next node.
13442 *
13443 * @public
13444 */
13445 next () {
13446 /**
13447 * @type {Item|null}
13448 */
13449 let n = this._currentNode;
13450 let type = n && n.content && /** @type {any} */ (n.content).type;
13451 if (n !== null && (!this._firstCall || n.deleted || !this._filter(type))) { // if first call, we check if we can use the first item
13452 do {
13453 type = /** @type {any} */ (n.content).type;
13454 if (!n.deleted && (type.constructor === YXmlElement || type.constructor === YXmlFragment) && type._start !== null) {
13455 // walk down in the tree
13456 n = type._start;
13457 } else {
13458 // walk right or up in the tree
13459 while (n !== null) {
13460 if (n.right !== null) {
13461 n = n.right;
13462 break
13463 } else if (n.parent === this._root) {
13464 n = null;
13465 } else {
13466 n = /** @type {AbstractType<any>} */ (n.parent)._item;
13467 }
13468 }
13469 }
13470 } while (n !== null && (n.deleted || !this._filter(/** @type {ContentType} */ (n.content).type)))
13471 }
13472 this._firstCall = false;
13473 if (n === null) {
13474 // @ts-ignore
13475 return { value: undefined, done: true }
13476 }
13477 this._currentNode = n;
13478 return { value: /** @type {any} */ (n.content).type, done: false }
13479 }
13480 }
13481
13482 /**
13483 * Represents a list of {@link YXmlElement}.and {@link YXmlText} types.
13484 * A YxmlFragment is similar to a {@link YXmlElement}, but it does not have a
13485 * nodeName and it does not have attributes. Though it can be bound to a DOM
13486 * element - in this case the attributes and the nodeName are not shared.
13487 *
13488 * @public
13489 * @extends AbstractType<YXmlEvent>
13490 */
13491 class YXmlFragment extends AbstractType {
13492 constructor () {
13493 super();
13494 /**
13495 * @type {Array<any>|null}
13496 */
13497 this._prelimContent = [];
13498 }
13499
13500 /**
13501 * @type {YXmlElement|YXmlText|null}
13502 */
13503 get firstChild () {
13504 const first = this._first;
13505 return first ? first.content.getContent()[0] : null
13506 }
13507
13508 /**
13509 * Integrate this type into the Yjs instance.
13510 *
13511 * * Save this struct in the os
13512 * * This type is sent to other client
13513 * * Observer functions are fired
13514 *
13515 * @param {Doc} y The Yjs instance
13516 * @param {Item} item
13517 */
13518 _integrate (y, item) {
13519 super._integrate(y, item);
13520 this.insert(0, /** @type {Array<any>} */ (this._prelimContent));
13521 this._prelimContent = null;
13522 }
13523
13524 _copy () {
13525 return new YXmlFragment()
13526 }
13527
13528 /**
13529 * @return {YXmlFragment}
13530 */
13531 clone () {
13532 const el = new YXmlFragment();
13533 // @ts-ignore
13534 el.insert(0, this.toArray().map(item => item instanceof AbstractType ? item.clone() : item));
13535 return el
13536 }
13537
13538 get length () {
13539 return this._prelimContent === null ? this._length : this._prelimContent.length
13540 }
13541
13542 /**
13543 * Create a subtree of childNodes.
13544 *
13545 * @example
13546 * const walker = elem.createTreeWalker(dom => dom.nodeName === 'div')
13547 * for (let node in walker) {
13548 * // `node` is a div node
13549 * nop(node)
13550 * }
13551 *
13552 * @param {function(AbstractType<any>):boolean} filter Function that is called on each child element and
13553 * returns a Boolean indicating whether the child
13554 * is to be included in the subtree.
13555 * @return {YXmlTreeWalker} A subtree and a position within it.
13556 *
13557 * @public
13558 */
13559 createTreeWalker (filter) {
13560 return new YXmlTreeWalker(this, filter)
13561 }
13562
13563 /**
13564 * Returns the first YXmlElement that matches the query.
13565 * Similar to DOM's {@link querySelector}.
13566 *
13567 * Query support:
13568 * - tagname
13569 * TODO:
13570 * - id
13571 * - attribute
13572 *
13573 * @param {CSS_Selector} query The query on the children.
13574 * @return {YXmlElement|YXmlText|YXmlHook|null} The first element that matches the query or null.
13575 *
13576 * @public
13577 */
13578 querySelector (query) {
13579 query = query.toUpperCase();
13580 // @ts-ignore
13581 const iterator = new YXmlTreeWalker(this, element => element.nodeName && element.nodeName.toUpperCase() === query);
13582 const next = iterator.next();
13583 if (next.done) {
13584 return null
13585 } else {
13586 return next.value
13587 }
13588 }
13589
13590 /**
13591 * Returns all YXmlElements that match the query.
13592 * Similar to Dom's {@link querySelectorAll}.
13593 *
13594 * @todo Does not yet support all queries. Currently only query by tagName.
13595 *
13596 * @param {CSS_Selector} query The query on the children
13597 * @return {Array<YXmlElement|YXmlText|YXmlHook|null>} The elements that match this query.
13598 *
13599 * @public
13600 */
13601 querySelectorAll (query) {
13602 query = query.toUpperCase();
13603 // @ts-ignore
13604 return array_from(new YXmlTreeWalker(this, element => element.nodeName && element.nodeName.toUpperCase() === query))
13605 }
13606
13607 /**
13608 * Creates YXmlEvent and calls observers.
13609 *
13610 * @param {Transaction} transaction
13611 * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
13612 */
13613 _callObserver (transaction, parentSubs) {
13614 callTypeObservers(this, transaction, new YXmlEvent(this, parentSubs, transaction));
13615 }
13616
13617 /**
13618 * Get the string representation of all the children of this YXmlFragment.
13619 *
13620 * @return {string} The string representation of all children.
13621 */
13622 toString () {
13623 return typeListMap(this, xml => xml.toString()).join('')
13624 }
13625
13626 /**
13627 * @return {string}
13628 */
13629 toJSON () {
13630 return this.toString()
13631 }
13632
13633 /**
13634 * Creates a Dom Element that mirrors this YXmlElement.
13635 *
13636 * @param {Document} [_document=document] The document object (you must define
13637 * this when calling this method in
13638 * nodejs)
13639 * @param {Object<string, any>} [hooks={}] Optional property to customize how hooks
13640 * are presented in the DOM
13641 * @param {any} [binding] You should not set this property. This is
13642 * used if DomBinding wants to create a
13643 * association to the created DOM type.
13644 * @return {Node} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
13645 *
13646 * @public
13647 */
13648 toDOM (_document = document, hooks = {}, binding) {
13649 const fragment = _document.createDocumentFragment();
13650 if (binding !== undefined) {
13651 binding._createAssociation(fragment, this);
13652 }
13653 typeListForEach(this, xmlType => {
13654 fragment.insertBefore(xmlType.toDOM(_document, hooks, binding), null);
13655 });
13656 return fragment
13657 }
13658
13659 /**
13660 * Inserts new content at an index.
13661 *
13662 * @example
13663 * // Insert character 'a' at position 0
13664 * xml.insert(0, [new Y.XmlText('text')])
13665 *
13666 * @param {number} index The index to insert content at
13667 * @param {Array<YXmlElement|YXmlText>} content The array of content
13668 */
13669 insert (index, content) {
13670 if (this.doc !== null) {
13671 transact(this.doc, transaction => {
13672 typeListInsertGenerics(transaction, this, index, content);
13673 });
13674 } else {
13675 // @ts-ignore _prelimContent is defined because this is not yet integrated
13676 this._prelimContent.splice(index, 0, ...content);
13677 }
13678 }
13679
13680 /**
13681 * Inserts new content at an index.
13682 *
13683 * @example
13684 * // Insert character 'a' at position 0
13685 * xml.insert(0, [new Y.XmlText('text')])
13686 *
13687 * @param {null|Item|YXmlElement|YXmlText} ref The index to insert content at
13688 * @param {Array<YXmlElement|YXmlText>} content The array of content
13689 */
13690 insertAfter (ref, content) {
13691 if (this.doc !== null) {
13692 transact(this.doc, transaction => {
13693 const refItem = (ref && ref instanceof AbstractType) ? ref._item : ref;
13694 typeListInsertGenericsAfter(transaction, this, refItem, content);
13695 });
13696 } else {
13697 const pc = /** @type {Array<any>} */ (this._prelimContent);
13698 const index = ref === null ? 0 : pc.findIndex(el => el === ref) + 1;
13699 if (index === 0 && ref !== null) {
13700 throw error_create('Reference item not found')
13701 }
13702 pc.splice(index, 0, ...content);
13703 }
13704 }
13705
13706 /**
13707 * Deletes elements starting from an index.
13708 *
13709 * @param {number} index Index at which to start deleting elements
13710 * @param {number} [length=1] The number of elements to remove. Defaults to 1.
13711 */
13712 delete (index, length = 1) {
13713 if (this.doc !== null) {
13714 transact(this.doc, transaction => {
13715 typeListDelete(transaction, this, index, length);
13716 });
13717 } else {
13718 // @ts-ignore _prelimContent is defined because this is not yet integrated
13719 this._prelimContent.splice(index, length);
13720 }
13721 }
13722
13723 /**
13724 * Transforms this YArray to a JavaScript Array.
13725 *
13726 * @return {Array<YXmlElement|YXmlText|YXmlHook>}
13727 */
13728 toArray () {
13729 return typeListToArray(this)
13730 }
13731
13732 /**
13733 * Appends content to this YArray.
13734 *
13735 * @param {Array<YXmlElement|YXmlText>} content Array of content to append.
13736 */
13737 push (content) {
13738 this.insert(this.length, content);
13739 }
13740
13741 /**
13742 * Preppends content to this YArray.
13743 *
13744 * @param {Array<YXmlElement|YXmlText>} content Array of content to preppend.
13745 */
13746 unshift (content) {
13747 this.insert(0, content);
13748 }
13749
13750 /**
13751 * Returns the i-th element from a YArray.
13752 *
13753 * @param {number} index The index of the element to return from the YArray
13754 * @return {YXmlElement|YXmlText}
13755 */
13756 get (index) {
13757 return typeListGet(this, index)
13758 }
13759
13760 /**
13761 * Transforms this YArray to a JavaScript Array.
13762 *
13763 * @param {number} [start]
13764 * @param {number} [end]
13765 * @return {Array<YXmlElement|YXmlText>}
13766 */
13767 slice (start = 0, end = this.length) {
13768 return typeListSlice(this, start, end)
13769 }
13770
13771 /**
13772 * Executes a provided function on once on overy child element.
13773 *
13774 * @param {function(YXmlElement|YXmlText,number, typeof self):void} f A function to execute on every element of this YArray.
13775 */
13776 forEach (f) {
13777 typeListForEach(this, f);
13778 }
13779
13780 /**
13781 * Transform the properties of this type to binary and write it to an
13782 * BinaryEncoder.
13783 *
13784 * This is called when this Item is sent to a remote peer.
13785 *
13786 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
13787 */
13788 _write (encoder) {
13789 encoder.writeTypeRef(YXmlFragmentRefID);
13790 }
13791 }
13792
13793 /**
13794 * @param {UpdateDecoderV1 | UpdateDecoderV2} _decoder
13795 * @return {YXmlFragment}
13796 *
13797 * @private
13798 * @function
13799 */
13800 const readYXmlFragment = _decoder => new YXmlFragment();
13801
13802 /**
13803 * @typedef {Object|number|null|Array<any>|string|Uint8Array|AbstractType<any>} ValueTypes
13804 */
13805
13806 /**
13807 * An YXmlElement imitates the behavior of a
13808 * {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}.
13809 *
13810 * * An YXmlElement has attributes (key value pairs)
13811 * * An YXmlElement has childElements that must inherit from YXmlElement
13812 *
13813 * @template {{ [key: string]: ValueTypes }} [KV={ [key: string]: string }]
13814 */
13815 class YXmlElement extends YXmlFragment {
13816 constructor (nodeName = 'UNDEFINED') {
13817 super();
13818 this.nodeName = nodeName;
13819 /**
13820 * @type {Map<string, any>|null}
13821 */
13822 this._prelimAttrs = new Map();
13823 }
13824
13825 /**
13826 * @type {YXmlElement|YXmlText|null}
13827 */
13828 get nextSibling () {
13829 const n = this._item ? this._item.next : null;
13830 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
13831 }
13832
13833 /**
13834 * @type {YXmlElement|YXmlText|null}
13835 */
13836 get prevSibling () {
13837 const n = this._item ? this._item.prev : null;
13838 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
13839 }
13840
13841 /**
13842 * Integrate this type into the Yjs instance.
13843 *
13844 * * Save this struct in the os
13845 * * This type is sent to other client
13846 * * Observer functions are fired
13847 *
13848 * @param {Doc} y The Yjs instance
13849 * @param {Item} item
13850 */
13851 _integrate (y, item) {
13852 super._integrate(y, item)
13853 ;(/** @type {Map<string, any>} */ (this._prelimAttrs)).forEach((value, key) => {
13854 this.setAttribute(key, value);
13855 });
13856 this._prelimAttrs = null;
13857 }
13858
13859 /**
13860 * Creates an Item with the same effect as this Item (without position effect)
13861 *
13862 * @return {YXmlElement}
13863 */
13864 _copy () {
13865 return new YXmlElement(this.nodeName)
13866 }
13867
13868 /**
13869 * @return {YXmlElement<KV>}
13870 */
13871 clone () {
13872 /**
13873 * @type {YXmlElement<KV>}
13874 */
13875 const el = new YXmlElement(this.nodeName);
13876 const attrs = this.getAttributes();
13877 forEach(attrs, (value, key) => {
13878 if (typeof value === 'string') {
13879 el.setAttribute(key, value);
13880 }
13881 });
13882 // @ts-ignore
13883 el.insert(0, this.toArray().map(item => item instanceof AbstractType ? item.clone() : item));
13884 return el
13885 }
13886
13887 /**
13888 * Returns the XML serialization of this YXmlElement.
13889 * The attributes are ordered by attribute-name, so you can easily use this
13890 * method to compare YXmlElements
13891 *
13892 * @return {string} The string representation of this type.
13893 *
13894 * @public
13895 */
13896 toString () {
13897 const attrs = this.getAttributes();
13898 const stringBuilder = [];
13899 const keys = [];
13900 for (const key in attrs) {
13901 keys.push(key);
13902 }
13903 keys.sort();
13904 const keysLen = keys.length;
13905 for (let i = 0; i < keysLen; i++) {
13906 const key = keys[i];
13907 stringBuilder.push(key + '="' + attrs[key] + '"');
13908 }
13909 const nodeName = this.nodeName.toLocaleLowerCase();
13910 const attrsString = stringBuilder.length > 0 ? ' ' + stringBuilder.join(' ') : '';
13911 return `<${nodeName}${attrsString}>${super.toString()}</${nodeName}>`
13912 }
13913
13914 /**
13915 * Removes an attribute from this YXmlElement.
13916 *
13917 * @param {string} attributeName The attribute name that is to be removed.
13918 *
13919 * @public
13920 */
13921 removeAttribute (attributeName) {
13922 if (this.doc !== null) {
13923 transact(this.doc, transaction => {
13924 typeMapDelete(transaction, this, attributeName);
13925 });
13926 } else {
13927 /** @type {Map<string,any>} */ (this._prelimAttrs).delete(attributeName);
13928 }
13929 }
13930
13931 /**
13932 * Sets or updates an attribute.
13933 *
13934 * @template {keyof KV & string} KEY
13935 *
13936 * @param {KEY} attributeName The attribute name that is to be set.
13937 * @param {KV[KEY]} attributeValue The attribute value that is to be set.
13938 *
13939 * @public
13940 */
13941 setAttribute (attributeName, attributeValue) {
13942 if (this.doc !== null) {
13943 transact(this.doc, transaction => {
13944 typeMapSet(transaction, this, attributeName, attributeValue);
13945 });
13946 } else {
13947 /** @type {Map<string, any>} */ (this._prelimAttrs).set(attributeName, attributeValue);
13948 }
13949 }
13950
13951 /**
13952 * Returns an attribute value that belongs to the attribute name.
13953 *
13954 * @template {keyof KV & string} KEY
13955 *
13956 * @param {KEY} attributeName The attribute name that identifies the
13957 * queried value.
13958 * @return {KV[KEY]|undefined} The queried attribute value.
13959 *
13960 * @public
13961 */
13962 getAttribute (attributeName) {
13963 return /** @type {any} */ (typeMapGet(this, attributeName))
13964 }
13965
13966 /**
13967 * Returns whether an attribute exists
13968 *
13969 * @param {string} attributeName The attribute name to check for existence.
13970 * @return {boolean} whether the attribute exists.
13971 *
13972 * @public
13973 */
13974 hasAttribute (attributeName) {
13975 return /** @type {any} */ (typeMapHas(this, attributeName))
13976 }
13977
13978 /**
13979 * Returns all attribute name/value pairs in a JSON Object.
13980 *
13981 * @return {{ [Key in Extract<keyof KV,string>]?: KV[Key]}} A JSON Object that describes the attributes.
13982 *
13983 * @public
13984 */
13985 getAttributes () {
13986 return /** @type {any} */ (typeMapGetAll(this))
13987 }
13988
13989 /**
13990 * Creates a Dom Element that mirrors this YXmlElement.
13991 *
13992 * @param {Document} [_document=document] The document object (you must define
13993 * this when calling this method in
13994 * nodejs)
13995 * @param {Object<string, any>} [hooks={}] Optional property to customize how hooks
13996 * are presented in the DOM
13997 * @param {any} [binding] You should not set this property. This is
13998 * used if DomBinding wants to create a
13999 * association to the created DOM type.
14000 * @return {Node} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
14001 *
14002 * @public
14003 */
14004 toDOM (_document = document, hooks = {}, binding) {
14005 const dom = _document.createElement(this.nodeName);
14006 const attrs = this.getAttributes();
14007 for (const key in attrs) {
14008 const value = attrs[key];
14009 if (typeof value === 'string') {
14010 dom.setAttribute(key, value);
14011 }
14012 }
14013 typeListForEach(this, yxml => {
14014 dom.appendChild(yxml.toDOM(_document, hooks, binding));
14015 });
14016 if (binding !== undefined) {
14017 binding._createAssociation(dom, this);
14018 }
14019 return dom
14020 }
14021
14022 /**
14023 * Transform the properties of this type to binary and write it to an
14024 * BinaryEncoder.
14025 *
14026 * This is called when this Item is sent to a remote peer.
14027 *
14028 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
14029 */
14030 _write (encoder) {
14031 encoder.writeTypeRef(YXmlElementRefID);
14032 encoder.writeKey(this.nodeName);
14033 }
14034 }
14035
14036 /**
14037 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14038 * @return {YXmlElement}
14039 *
14040 * @function
14041 */
14042 const readYXmlElement = decoder => new YXmlElement(decoder.readKey());
14043
14044 /**
14045 * @extends YEvent<YXmlElement|YXmlText|YXmlFragment>
14046 * An Event that describes changes on a YXml Element or Yxml Fragment
14047 */
14048 class YXmlEvent extends YEvent {
14049 /**
14050 * @param {YXmlElement|YXmlText|YXmlFragment} target The target on which the event is created.
14051 * @param {Set<string|null>} subs The set of changed attributes. `null` is included if the
14052 * child list changed.
14053 * @param {Transaction} transaction The transaction instance with wich the
14054 * change was created.
14055 */
14056 constructor (target, subs, transaction) {
14057 super(target, transaction);
14058 /**
14059 * Whether the children changed.
14060 * @type {Boolean}
14061 * @private
14062 */
14063 this.childListChanged = false;
14064 /**
14065 * Set of all changed attributes.
14066 * @type {Set<string>}
14067 */
14068 this.attributesChanged = new Set();
14069 subs.forEach((sub) => {
14070 if (sub === null) {
14071 this.childListChanged = true;
14072 } else {
14073 this.attributesChanged.add(sub);
14074 }
14075 });
14076 }
14077 }
14078
14079 /**
14080 * You can manage binding to a custom type with YXmlHook.
14081 *
14082 * @extends {YMap<any>}
14083 */
14084 class YXmlHook extends YMap {
14085 /**
14086 * @param {string} hookName nodeName of the Dom Node.
14087 */
14088 constructor (hookName) {
14089 super();
14090 /**
14091 * @type {string}
14092 */
14093 this.hookName = hookName;
14094 }
14095
14096 /**
14097 * Creates an Item with the same effect as this Item (without position effect)
14098 */
14099 _copy () {
14100 return new YXmlHook(this.hookName)
14101 }
14102
14103 /**
14104 * @return {YXmlHook}
14105 */
14106 clone () {
14107 const el = new YXmlHook(this.hookName);
14108 this.forEach((value, key) => {
14109 el.set(key, value);
14110 });
14111 return el
14112 }
14113
14114 /**
14115 * Creates a Dom Element that mirrors this YXmlElement.
14116 *
14117 * @param {Document} [_document=document] The document object (you must define
14118 * this when calling this method in
14119 * nodejs)
14120 * @param {Object.<string, any>} [hooks] Optional property to customize how hooks
14121 * are presented in the DOM
14122 * @param {any} [binding] You should not set this property. This is
14123 * used if DomBinding wants to create a
14124 * association to the created DOM type
14125 * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
14126 *
14127 * @public
14128 */
14129 toDOM (_document = document, hooks = {}, binding) {
14130 const hook = hooks[this.hookName];
14131 let dom;
14132 if (hook !== undefined) {
14133 dom = hook.createDom(this);
14134 } else {
14135 dom = document.createElement(this.hookName);
14136 }
14137 dom.setAttribute('data-yjs-hook', this.hookName);
14138 if (binding !== undefined) {
14139 binding._createAssociation(dom, this);
14140 }
14141 return dom
14142 }
14143
14144 /**
14145 * Transform the properties of this type to binary and write it to an
14146 * BinaryEncoder.
14147 *
14148 * This is called when this Item is sent to a remote peer.
14149 *
14150 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
14151 */
14152 _write (encoder) {
14153 encoder.writeTypeRef(YXmlHookRefID);
14154 encoder.writeKey(this.hookName);
14155 }
14156 }
14157
14158 /**
14159 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14160 * @return {YXmlHook}
14161 *
14162 * @private
14163 * @function
14164 */
14165 const readYXmlHook = decoder =>
14166 new YXmlHook(decoder.readKey());
14167
14168 /**
14169 * Represents text in a Dom Element. In the future this type will also handle
14170 * simple formatting information like bold and italic.
14171 */
14172 class YXmlText extends YText {
14173 /**
14174 * @type {YXmlElement|YXmlText|null}
14175 */
14176 get nextSibling () {
14177 const n = this._item ? this._item.next : null;
14178 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
14179 }
14180
14181 /**
14182 * @type {YXmlElement|YXmlText|null}
14183 */
14184 get prevSibling () {
14185 const n = this._item ? this._item.prev : null;
14186 return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null
14187 }
14188
14189 _copy () {
14190 return new YXmlText()
14191 }
14192
14193 /**
14194 * @return {YXmlText}
14195 */
14196 clone () {
14197 const text = new YXmlText();
14198 text.applyDelta(this.toDelta());
14199 return text
14200 }
14201
14202 /**
14203 * Creates a Dom Element that mirrors this YXmlText.
14204 *
14205 * @param {Document} [_document=document] The document object (you must define
14206 * this when calling this method in
14207 * nodejs)
14208 * @param {Object<string, any>} [hooks] Optional property to customize how hooks
14209 * are presented in the DOM
14210 * @param {any} [binding] You should not set this property. This is
14211 * used if DomBinding wants to create a
14212 * association to the created DOM type.
14213 * @return {Text} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
14214 *
14215 * @public
14216 */
14217 toDOM (_document = document, hooks, binding) {
14218 const dom = _document.createTextNode(this.toString());
14219 if (binding !== undefined) {
14220 binding._createAssociation(dom, this);
14221 }
14222 return dom
14223 }
14224
14225 toString () {
14226 // @ts-ignore
14227 return this.toDelta().map(delta => {
14228 const nestedNodes = [];
14229 for (const nodeName in delta.attributes) {
14230 const attrs = [];
14231 for (const key in delta.attributes[nodeName]) {
14232 attrs.push({ key, value: delta.attributes[nodeName][key] });
14233 }
14234 // sort attributes to get a unique order
14235 attrs.sort((a, b) => a.key < b.key ? -1 : 1);
14236 nestedNodes.push({ nodeName, attrs });
14237 }
14238 // sort node order to get a unique order
14239 nestedNodes.sort((a, b) => a.nodeName < b.nodeName ? -1 : 1);
14240 // now convert to dom string
14241 let str = '';
14242 for (let i = 0; i < nestedNodes.length; i++) {
14243 const node = nestedNodes[i];
14244 str += `<${node.nodeName}`;
14245 for (let j = 0; j < node.attrs.length; j++) {
14246 const attr = node.attrs[j];
14247 str += ` ${attr.key}="${attr.value}"`;
14248 }
14249 str += '>';
14250 }
14251 str += delta.insert;
14252 for (let i = nestedNodes.length - 1; i >= 0; i--) {
14253 str += `</${nestedNodes[i].nodeName}>`;
14254 }
14255 return str
14256 }).join('')
14257 }
14258
14259 /**
14260 * @return {string}
14261 */
14262 toJSON () {
14263 return this.toString()
14264 }
14265
14266 /**
14267 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14268 */
14269 _write (encoder) {
14270 encoder.writeTypeRef(YXmlTextRefID);
14271 }
14272 }
14273
14274 /**
14275 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14276 * @return {YXmlText}
14277 *
14278 * @private
14279 * @function
14280 */
14281 const readYXmlText = decoder => new YXmlText();
14282
14283 class AbstractStruct {
14284 /**
14285 * @param {ID} id
14286 * @param {number} length
14287 */
14288 constructor (id, length) {
14289 this.id = id;
14290 this.length = length;
14291 }
14292
14293 /**
14294 * @type {boolean}
14295 */
14296 get deleted () {
14297 throw methodUnimplemented()
14298 }
14299
14300 /**
14301 * Merge this struct with the item to the right.
14302 * This method is already assuming that `this.id.clock + this.length === this.id.clock`.
14303 * Also this method does *not* remove right from StructStore!
14304 * @param {AbstractStruct} right
14305 * @return {boolean} wether this merged with right
14306 */
14307 mergeWith (right) {
14308 return false
14309 }
14310
14311 /**
14312 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
14313 * @param {number} offset
14314 * @param {number} encodingRef
14315 */
14316 write (encoder, offset, encodingRef) {
14317 throw methodUnimplemented()
14318 }
14319
14320 /**
14321 * @param {Transaction} transaction
14322 * @param {number} offset
14323 */
14324 integrate (transaction, offset) {
14325 throw methodUnimplemented()
14326 }
14327 }
14328
14329 const structGCRefNumber = 0;
14330
14331 /**
14332 * @private
14333 */
14334 class GC extends AbstractStruct {
14335 get deleted () {
14336 return true
14337 }
14338
14339 delete () {}
14340
14341 /**
14342 * @param {GC} right
14343 * @return {boolean}
14344 */
14345 mergeWith (right) {
14346 if (this.constructor !== right.constructor) {
14347 return false
14348 }
14349 this.length += right.length;
14350 return true
14351 }
14352
14353 /**
14354 * @param {Transaction} transaction
14355 * @param {number} offset
14356 */
14357 integrate (transaction, offset) {
14358 if (offset > 0) {
14359 this.id.clock += offset;
14360 this.length -= offset;
14361 }
14362 addStruct(transaction.doc.store, this);
14363 }
14364
14365 /**
14366 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14367 * @param {number} offset
14368 */
14369 write (encoder, offset) {
14370 encoder.writeInfo(structGCRefNumber);
14371 encoder.writeLen(this.length - offset);
14372 }
14373
14374 /**
14375 * @param {Transaction} transaction
14376 * @param {StructStore} store
14377 * @return {null | number}
14378 */
14379 getMissing (transaction, store) {
14380 return null
14381 }
14382 }
14383
14384 class ContentBinary {
14385 /**
14386 * @param {Uint8Array} content
14387 */
14388 constructor (content) {
14389 this.content = content;
14390 }
14391
14392 /**
14393 * @return {number}
14394 */
14395 getLength () {
14396 return 1
14397 }
14398
14399 /**
14400 * @return {Array<any>}
14401 */
14402 getContent () {
14403 return [this.content]
14404 }
14405
14406 /**
14407 * @return {boolean}
14408 */
14409 isCountable () {
14410 return true
14411 }
14412
14413 /**
14414 * @return {ContentBinary}
14415 */
14416 copy () {
14417 return new ContentBinary(this.content)
14418 }
14419
14420 /**
14421 * @param {number} offset
14422 * @return {ContentBinary}
14423 */
14424 splice (offset) {
14425 throw methodUnimplemented()
14426 }
14427
14428 /**
14429 * @param {ContentBinary} right
14430 * @return {boolean}
14431 */
14432 mergeWith (right) {
14433 return false
14434 }
14435
14436 /**
14437 * @param {Transaction} transaction
14438 * @param {Item} item
14439 */
14440 integrate (transaction, item) {}
14441 /**
14442 * @param {Transaction} transaction
14443 */
14444 delete (transaction) {}
14445 /**
14446 * @param {StructStore} store
14447 */
14448 gc (store) {}
14449 /**
14450 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14451 * @param {number} offset
14452 */
14453 write (encoder, offset) {
14454 encoder.writeBuf(this.content);
14455 }
14456
14457 /**
14458 * @return {number}
14459 */
14460 getRef () {
14461 return 3
14462 }
14463 }
14464
14465 /**
14466 * @param {UpdateDecoderV1 | UpdateDecoderV2 } decoder
14467 * @return {ContentBinary}
14468 */
14469 const readContentBinary = decoder => new ContentBinary(decoder.readBuf());
14470
14471 class ContentDeleted {
14472 /**
14473 * @param {number} len
14474 */
14475 constructor (len) {
14476 this.len = len;
14477 }
14478
14479 /**
14480 * @return {number}
14481 */
14482 getLength () {
14483 return this.len
14484 }
14485
14486 /**
14487 * @return {Array<any>}
14488 */
14489 getContent () {
14490 return []
14491 }
14492
14493 /**
14494 * @return {boolean}
14495 */
14496 isCountable () {
14497 return false
14498 }
14499
14500 /**
14501 * @return {ContentDeleted}
14502 */
14503 copy () {
14504 return new ContentDeleted(this.len)
14505 }
14506
14507 /**
14508 * @param {number} offset
14509 * @return {ContentDeleted}
14510 */
14511 splice (offset) {
14512 const right = new ContentDeleted(this.len - offset);
14513 this.len = offset;
14514 return right
14515 }
14516
14517 /**
14518 * @param {ContentDeleted} right
14519 * @return {boolean}
14520 */
14521 mergeWith (right) {
14522 this.len += right.len;
14523 return true
14524 }
14525
14526 /**
14527 * @param {Transaction} transaction
14528 * @param {Item} item
14529 */
14530 integrate (transaction, item) {
14531 addToDeleteSet(transaction.deleteSet, item.id.client, item.id.clock, this.len);
14532 item.markDeleted();
14533 }
14534
14535 /**
14536 * @param {Transaction} transaction
14537 */
14538 delete (transaction) {}
14539 /**
14540 * @param {StructStore} store
14541 */
14542 gc (store) {}
14543 /**
14544 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14545 * @param {number} offset
14546 */
14547 write (encoder, offset) {
14548 encoder.writeLen(this.len - offset);
14549 }
14550
14551 /**
14552 * @return {number}
14553 */
14554 getRef () {
14555 return 1
14556 }
14557 }
14558
14559 /**
14560 * @private
14561 *
14562 * @param {UpdateDecoderV1 | UpdateDecoderV2 } decoder
14563 * @return {ContentDeleted}
14564 */
14565 const readContentDeleted = decoder => new ContentDeleted(decoder.readLen());
14566
14567 /**
14568 * @param {string} guid
14569 * @param {Object<string, any>} opts
14570 */
14571 const createDocFromOpts = (guid, opts) => new Doc({ guid, ...opts, shouldLoad: opts.shouldLoad || opts.autoLoad || false });
14572
14573 /**
14574 * @private
14575 */
14576 class ContentDoc {
14577 /**
14578 * @param {Doc} doc
14579 */
14580 constructor (doc) {
14581 if (doc._item) {
14582 console.error('This document was already integrated as a sub-document. You should create a second instance instead with the same guid.');
14583 }
14584 /**
14585 * @type {Doc}
14586 */
14587 this.doc = doc;
14588 /**
14589 * @type {any}
14590 */
14591 const opts = {};
14592 this.opts = opts;
14593 if (!doc.gc) {
14594 opts.gc = false;
14595 }
14596 if (doc.autoLoad) {
14597 opts.autoLoad = true;
14598 }
14599 if (doc.meta !== null) {
14600 opts.meta = doc.meta;
14601 }
14602 }
14603
14604 /**
14605 * @return {number}
14606 */
14607 getLength () {
14608 return 1
14609 }
14610
14611 /**
14612 * @return {Array<any>}
14613 */
14614 getContent () {
14615 return [this.doc]
14616 }
14617
14618 /**
14619 * @return {boolean}
14620 */
14621 isCountable () {
14622 return true
14623 }
14624
14625 /**
14626 * @return {ContentDoc}
14627 */
14628 copy () {
14629 return new ContentDoc(createDocFromOpts(this.doc.guid, this.opts))
14630 }
14631
14632 /**
14633 * @param {number} offset
14634 * @return {ContentDoc}
14635 */
14636 splice (offset) {
14637 throw methodUnimplemented()
14638 }
14639
14640 /**
14641 * @param {ContentDoc} right
14642 * @return {boolean}
14643 */
14644 mergeWith (right) {
14645 return false
14646 }
14647
14648 /**
14649 * @param {Transaction} transaction
14650 * @param {Item} item
14651 */
14652 integrate (transaction, item) {
14653 // this needs to be reflected in doc.destroy as well
14654 this.doc._item = item;
14655 transaction.subdocsAdded.add(this.doc);
14656 if (this.doc.shouldLoad) {
14657 transaction.subdocsLoaded.add(this.doc);
14658 }
14659 }
14660
14661 /**
14662 * @param {Transaction} transaction
14663 */
14664 delete (transaction) {
14665 if (transaction.subdocsAdded.has(this.doc)) {
14666 transaction.subdocsAdded.delete(this.doc);
14667 } else {
14668 transaction.subdocsRemoved.add(this.doc);
14669 }
14670 }
14671
14672 /**
14673 * @param {StructStore} store
14674 */
14675 gc (store) { }
14676
14677 /**
14678 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14679 * @param {number} offset
14680 */
14681 write (encoder, offset) {
14682 encoder.writeString(this.doc.guid);
14683 encoder.writeAny(this.opts);
14684 }
14685
14686 /**
14687 * @return {number}
14688 */
14689 getRef () {
14690 return 9
14691 }
14692 }
14693
14694 /**
14695 * @private
14696 *
14697 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14698 * @return {ContentDoc}
14699 */
14700 const readContentDoc = decoder => new ContentDoc(createDocFromOpts(decoder.readString(), decoder.readAny()));
14701
14702 /**
14703 * @private
14704 */
14705 class ContentEmbed {
14706 /**
14707 * @param {Object} embed
14708 */
14709 constructor (embed) {
14710 this.embed = embed;
14711 }
14712
14713 /**
14714 * @return {number}
14715 */
14716 getLength () {
14717 return 1
14718 }
14719
14720 /**
14721 * @return {Array<any>}
14722 */
14723 getContent () {
14724 return [this.embed]
14725 }
14726
14727 /**
14728 * @return {boolean}
14729 */
14730 isCountable () {
14731 return true
14732 }
14733
14734 /**
14735 * @return {ContentEmbed}
14736 */
14737 copy () {
14738 return new ContentEmbed(this.embed)
14739 }
14740
14741 /**
14742 * @param {number} offset
14743 * @return {ContentEmbed}
14744 */
14745 splice (offset) {
14746 throw methodUnimplemented()
14747 }
14748
14749 /**
14750 * @param {ContentEmbed} right
14751 * @return {boolean}
14752 */
14753 mergeWith (right) {
14754 return false
14755 }
14756
14757 /**
14758 * @param {Transaction} transaction
14759 * @param {Item} item
14760 */
14761 integrate (transaction, item) {}
14762 /**
14763 * @param {Transaction} transaction
14764 */
14765 delete (transaction) {}
14766 /**
14767 * @param {StructStore} store
14768 */
14769 gc (store) {}
14770 /**
14771 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14772 * @param {number} offset
14773 */
14774 write (encoder, offset) {
14775 encoder.writeJSON(this.embed);
14776 }
14777
14778 /**
14779 * @return {number}
14780 */
14781 getRef () {
14782 return 5
14783 }
14784 }
14785
14786 /**
14787 * @private
14788 *
14789 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14790 * @return {ContentEmbed}
14791 */
14792 const readContentEmbed = decoder => new ContentEmbed(decoder.readJSON());
14793
14794 /**
14795 * @private
14796 */
14797 class ContentFormat {
14798 /**
14799 * @param {string} key
14800 * @param {Object} value
14801 */
14802 constructor (key, value) {
14803 this.key = key;
14804 this.value = value;
14805 }
14806
14807 /**
14808 * @return {number}
14809 */
14810 getLength () {
14811 return 1
14812 }
14813
14814 /**
14815 * @return {Array<any>}
14816 */
14817 getContent () {
14818 return []
14819 }
14820
14821 /**
14822 * @return {boolean}
14823 */
14824 isCountable () {
14825 return false
14826 }
14827
14828 /**
14829 * @return {ContentFormat}
14830 */
14831 copy () {
14832 return new ContentFormat(this.key, this.value)
14833 }
14834
14835 /**
14836 * @param {number} _offset
14837 * @return {ContentFormat}
14838 */
14839 splice (_offset) {
14840 throw methodUnimplemented()
14841 }
14842
14843 /**
14844 * @param {ContentFormat} _right
14845 * @return {boolean}
14846 */
14847 mergeWith (_right) {
14848 return false
14849 }
14850
14851 /**
14852 * @param {Transaction} _transaction
14853 * @param {Item} item
14854 */
14855 integrate (_transaction, item) {
14856 // @todo searchmarker are currently unsupported for rich text documents
14857 const p = /** @type {YText} */ (item.parent);
14858 p._searchMarker = null;
14859 p._hasFormatting = true;
14860 }
14861
14862 /**
14863 * @param {Transaction} transaction
14864 */
14865 delete (transaction) {}
14866 /**
14867 * @param {StructStore} store
14868 */
14869 gc (store) {}
14870 /**
14871 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14872 * @param {number} offset
14873 */
14874 write (encoder, offset) {
14875 encoder.writeKey(this.key);
14876 encoder.writeJSON(this.value);
14877 }
14878
14879 /**
14880 * @return {number}
14881 */
14882 getRef () {
14883 return 6
14884 }
14885 }
14886
14887 /**
14888 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14889 * @return {ContentFormat}
14890 */
14891 const readContentFormat = decoder => new ContentFormat(decoder.readKey(), decoder.readJSON());
14892
14893 /**
14894 * @private
14895 */
14896 class ContentJSON {
14897 /**
14898 * @param {Array<any>} arr
14899 */
14900 constructor (arr) {
14901 /**
14902 * @type {Array<any>}
14903 */
14904 this.arr = arr;
14905 }
14906
14907 /**
14908 * @return {number}
14909 */
14910 getLength () {
14911 return this.arr.length
14912 }
14913
14914 /**
14915 * @return {Array<any>}
14916 */
14917 getContent () {
14918 return this.arr
14919 }
14920
14921 /**
14922 * @return {boolean}
14923 */
14924 isCountable () {
14925 return true
14926 }
14927
14928 /**
14929 * @return {ContentJSON}
14930 */
14931 copy () {
14932 return new ContentJSON(this.arr)
14933 }
14934
14935 /**
14936 * @param {number} offset
14937 * @return {ContentJSON}
14938 */
14939 splice (offset) {
14940 const right = new ContentJSON(this.arr.slice(offset));
14941 this.arr = this.arr.slice(0, offset);
14942 return right
14943 }
14944
14945 /**
14946 * @param {ContentJSON} right
14947 * @return {boolean}
14948 */
14949 mergeWith (right) {
14950 this.arr = this.arr.concat(right.arr);
14951 return true
14952 }
14953
14954 /**
14955 * @param {Transaction} transaction
14956 * @param {Item} item
14957 */
14958 integrate (transaction, item) {}
14959 /**
14960 * @param {Transaction} transaction
14961 */
14962 delete (transaction) {}
14963 /**
14964 * @param {StructStore} store
14965 */
14966 gc (store) {}
14967 /**
14968 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
14969 * @param {number} offset
14970 */
14971 write (encoder, offset) {
14972 const len = this.arr.length;
14973 encoder.writeLen(len - offset);
14974 for (let i = offset; i < len; i++) {
14975 const c = this.arr[i];
14976 encoder.writeString(c === undefined ? 'undefined' : JSON.stringify(c));
14977 }
14978 }
14979
14980 /**
14981 * @return {number}
14982 */
14983 getRef () {
14984 return 2
14985 }
14986 }
14987
14988 /**
14989 * @private
14990 *
14991 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
14992 * @return {ContentJSON}
14993 */
14994 const readContentJSON = decoder => {
14995 const len = decoder.readLen();
14996 const cs = [];
14997 for (let i = 0; i < len; i++) {
14998 const c = decoder.readString();
14999 if (c === 'undefined') {
15000 cs.push(undefined);
15001 } else {
15002 cs.push(JSON.parse(c));
15003 }
15004 }
15005 return new ContentJSON(cs)
15006 };
15007
15008 class ContentAny {
15009 /**
15010 * @param {Array<any>} arr
15011 */
15012 constructor (arr) {
15013 /**
15014 * @type {Array<any>}
15015 */
15016 this.arr = arr;
15017 }
15018
15019 /**
15020 * @return {number}
15021 */
15022 getLength () {
15023 return this.arr.length
15024 }
15025
15026 /**
15027 * @return {Array<any>}
15028 */
15029 getContent () {
15030 return this.arr
15031 }
15032
15033 /**
15034 * @return {boolean}
15035 */
15036 isCountable () {
15037 return true
15038 }
15039
15040 /**
15041 * @return {ContentAny}
15042 */
15043 copy () {
15044 return new ContentAny(this.arr)
15045 }
15046
15047 /**
15048 * @param {number} offset
15049 * @return {ContentAny}
15050 */
15051 splice (offset) {
15052 const right = new ContentAny(this.arr.slice(offset));
15053 this.arr = this.arr.slice(0, offset);
15054 return right
15055 }
15056
15057 /**
15058 * @param {ContentAny} right
15059 * @return {boolean}
15060 */
15061 mergeWith (right) {
15062 this.arr = this.arr.concat(right.arr);
15063 return true
15064 }
15065
15066 /**
15067 * @param {Transaction} transaction
15068 * @param {Item} item
15069 */
15070 integrate (transaction, item) {}
15071 /**
15072 * @param {Transaction} transaction
15073 */
15074 delete (transaction) {}
15075 /**
15076 * @param {StructStore} store
15077 */
15078 gc (store) {}
15079 /**
15080 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
15081 * @param {number} offset
15082 */
15083 write (encoder, offset) {
15084 const len = this.arr.length;
15085 encoder.writeLen(len - offset);
15086 for (let i = offset; i < len; i++) {
15087 const c = this.arr[i];
15088 encoder.writeAny(c);
15089 }
15090 }
15091
15092 /**
15093 * @return {number}
15094 */
15095 getRef () {
15096 return 8
15097 }
15098 }
15099
15100 /**
15101 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
15102 * @return {ContentAny}
15103 */
15104 const readContentAny = decoder => {
15105 const len = decoder.readLen();
15106 const cs = [];
15107 for (let i = 0; i < len; i++) {
15108 cs.push(decoder.readAny());
15109 }
15110 return new ContentAny(cs)
15111 };
15112
15113 /**
15114 * @private
15115 */
15116 class ContentString {
15117 /**
15118 * @param {string} str
15119 */
15120 constructor (str) {
15121 /**
15122 * @type {string}
15123 */
15124 this.str = str;
15125 }
15126
15127 /**
15128 * @return {number}
15129 */
15130 getLength () {
15131 return this.str.length
15132 }
15133
15134 /**
15135 * @return {Array<any>}
15136 */
15137 getContent () {
15138 return this.str.split('')
15139 }
15140
15141 /**
15142 * @return {boolean}
15143 */
15144 isCountable () {
15145 return true
15146 }
15147
15148 /**
15149 * @return {ContentString}
15150 */
15151 copy () {
15152 return new ContentString(this.str)
15153 }
15154
15155 /**
15156 * @param {number} offset
15157 * @return {ContentString}
15158 */
15159 splice (offset) {
15160 const right = new ContentString(this.str.slice(offset));
15161 this.str = this.str.slice(0, offset);
15162
15163 // Prevent encoding invalid documents because of splitting of surrogate pairs: https://github.com/yjs/yjs/issues/248
15164 const firstCharCode = this.str.charCodeAt(offset - 1);
15165 if (firstCharCode >= 0xD800 && firstCharCode <= 0xDBFF) {
15166 // Last character of the left split is the start of a surrogate utf16/ucs2 pair.
15167 // We don't support splitting of surrogate pairs because this may lead to invalid documents.
15168 // Replace the invalid character with a unicode replacement character (� / U+FFFD)
15169 this.str = this.str.slice(0, offset - 1) + '�';
15170 // replace right as well
15171 right.str = '�' + right.str.slice(1);
15172 }
15173 return right
15174 }
15175
15176 /**
15177 * @param {ContentString} right
15178 * @return {boolean}
15179 */
15180 mergeWith (right) {
15181 this.str += right.str;
15182 return true
15183 }
15184
15185 /**
15186 * @param {Transaction} transaction
15187 * @param {Item} item
15188 */
15189 integrate (transaction, item) {}
15190 /**
15191 * @param {Transaction} transaction
15192 */
15193 delete (transaction) {}
15194 /**
15195 * @param {StructStore} store
15196 */
15197 gc (store) {}
15198 /**
15199 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
15200 * @param {number} offset
15201 */
15202 write (encoder, offset) {
15203 encoder.writeString(offset === 0 ? this.str : this.str.slice(offset));
15204 }
15205
15206 /**
15207 * @return {number}
15208 */
15209 getRef () {
15210 return 4
15211 }
15212 }
15213
15214 /**
15215 * @private
15216 *
15217 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
15218 * @return {ContentString}
15219 */
15220 const readContentString = decoder => new ContentString(decoder.readString());
15221
15222 /**
15223 * @type {Array<function(UpdateDecoderV1 | UpdateDecoderV2):AbstractType<any>>}
15224 * @private
15225 */
15226 const typeRefs = [
15227 readYArray,
15228 readYMap,
15229 readYText,
15230 readYXmlElement,
15231 readYXmlFragment,
15232 readYXmlHook,
15233 readYXmlText
15234 ];
15235
15236 const YArrayRefID = 0;
15237 const YMapRefID = 1;
15238 const YTextRefID = 2;
15239 const YXmlElementRefID = 3;
15240 const YXmlFragmentRefID = 4;
15241 const YXmlHookRefID = 5;
15242 const YXmlTextRefID = 6;
15243
15244 /**
15245 * @private
15246 */
15247 class ContentType {
15248 /**
15249 * @param {AbstractType<any>} type
15250 */
15251 constructor (type) {
15252 /**
15253 * @type {AbstractType<any>}
15254 */
15255 this.type = type;
15256 }
15257
15258 /**
15259 * @return {number}
15260 */
15261 getLength () {
15262 return 1
15263 }
15264
15265 /**
15266 * @return {Array<any>}
15267 */
15268 getContent () {
15269 return [this.type]
15270 }
15271
15272 /**
15273 * @return {boolean}
15274 */
15275 isCountable () {
15276 return true
15277 }
15278
15279 /**
15280 * @return {ContentType}
15281 */
15282 copy () {
15283 return new ContentType(this.type._copy())
15284 }
15285
15286 /**
15287 * @param {number} offset
15288 * @return {ContentType}
15289 */
15290 splice (offset) {
15291 throw methodUnimplemented()
15292 }
15293
15294 /**
15295 * @param {ContentType} right
15296 * @return {boolean}
15297 */
15298 mergeWith (right) {
15299 return false
15300 }
15301
15302 /**
15303 * @param {Transaction} transaction
15304 * @param {Item} item
15305 */
15306 integrate (transaction, item) {
15307 this.type._integrate(transaction.doc, item);
15308 }
15309
15310 /**
15311 * @param {Transaction} transaction
15312 */
15313 delete (transaction) {
15314 let item = this.type._start;
15315 while (item !== null) {
15316 if (!item.deleted) {
15317 item.delete(transaction);
15318 } else if (item.id.clock < (transaction.beforeState.get(item.id.client) || 0)) {
15319 // This will be gc'd later and we want to merge it if possible
15320 // We try to merge all deleted items after each transaction,
15321 // but we have no knowledge about that this needs to be merged
15322 // since it is not in transaction.ds. Hence we add it to transaction._mergeStructs
15323 transaction._mergeStructs.push(item);
15324 }
15325 item = item.right;
15326 }
15327 this.type._map.forEach(item => {
15328 if (!item.deleted) {
15329 item.delete(transaction);
15330 } else if (item.id.clock < (transaction.beforeState.get(item.id.client) || 0)) {
15331 // same as above
15332 transaction._mergeStructs.push(item);
15333 }
15334 });
15335 transaction.changed.delete(this.type);
15336 }
15337
15338 /**
15339 * @param {StructStore} store
15340 */
15341 gc (store) {
15342 let item = this.type._start;
15343 while (item !== null) {
15344 item.gc(store, true);
15345 item = item.right;
15346 }
15347 this.type._start = null;
15348 this.type._map.forEach(/** @param {Item | null} item */ (item) => {
15349 while (item !== null) {
15350 item.gc(store, true);
15351 item = item.left;
15352 }
15353 });
15354 this.type._map = new Map();
15355 }
15356
15357 /**
15358 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
15359 * @param {number} offset
15360 */
15361 write (encoder, offset) {
15362 this.type._write(encoder);
15363 }
15364
15365 /**
15366 * @return {number}
15367 */
15368 getRef () {
15369 return 7
15370 }
15371 }
15372
15373 /**
15374 * @private
15375 *
15376 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
15377 * @return {ContentType}
15378 */
15379 const readContentType = decoder => new ContentType(typeRefs[decoder.readTypeRef()](decoder));
15380
15381 /**
15382 * @todo This should return several items
15383 *
15384 * @param {StructStore} store
15385 * @param {ID} id
15386 * @return {{item:Item, diff:number}}
15387 */
15388 const followRedone = (store, id) => {
15389 /**
15390 * @type {ID|null}
15391 */
15392 let nextID = id;
15393 let diff = 0;
15394 let item;
15395 do {
15396 if (diff > 0) {
15397 nextID = createID(nextID.client, nextID.clock + diff);
15398 }
15399 item = getItem(store, nextID);
15400 diff = nextID.clock - item.id.clock;
15401 nextID = item.redone;
15402 } while (nextID !== null && item instanceof Item)
15403 return {
15404 item, diff
15405 }
15406 };
15407
15408 /**
15409 * Make sure that neither item nor any of its parents is ever deleted.
15410 *
15411 * This property does not persist when storing it into a database or when
15412 * sending it to other peers
15413 *
15414 * @param {Item|null} item
15415 * @param {boolean} keep
15416 */
15417 const keepItem = (item, keep) => {
15418 while (item !== null && item.keep !== keep) {
15419 item.keep = keep;
15420 item = /** @type {AbstractType<any>} */ (item.parent)._item;
15421 }
15422 };
15423
15424 /**
15425 * Split leftItem into two items
15426 * @param {Transaction} transaction
15427 * @param {Item} leftItem
15428 * @param {number} diff
15429 * @return {Item}
15430 *
15431 * @function
15432 * @private
15433 */
15434 const splitItem = (transaction, leftItem, diff) => {
15435 // create rightItem
15436 const { client, clock } = leftItem.id;
15437 const rightItem = new Item(
15438 createID(client, clock + diff),
15439 leftItem,
15440 createID(client, clock + diff - 1),
15441 leftItem.right,
15442 leftItem.rightOrigin,
15443 leftItem.parent,
15444 leftItem.parentSub,
15445 leftItem.content.splice(diff)
15446 );
15447 if (leftItem.deleted) {
15448 rightItem.markDeleted();
15449 }
15450 if (leftItem.keep) {
15451 rightItem.keep = true;
15452 }
15453 if (leftItem.redone !== null) {
15454 rightItem.redone = createID(leftItem.redone.client, leftItem.redone.clock + diff);
15455 }
15456 // update left (do not set leftItem.rightOrigin as it will lead to problems when syncing)
15457 leftItem.right = rightItem;
15458 // update right
15459 if (rightItem.right !== null) {
15460 rightItem.right.left = rightItem;
15461 }
15462 // right is more specific.
15463 transaction._mergeStructs.push(rightItem);
15464 // update parent._map
15465 if (rightItem.parentSub !== null && rightItem.right === null) {
15466 /** @type {AbstractType<any>} */ (rightItem.parent)._map.set(rightItem.parentSub, rightItem);
15467 }
15468 leftItem.length = diff;
15469 return rightItem
15470 };
15471
15472 /**
15473 * @param {Array<StackItem>} stack
15474 * @param {ID} id
15475 */
15476 const isDeletedByUndoStack = (stack, id) => array.some(stack, /** @param {StackItem} s */ s => isDeleted(s.deletions, id));
15477
15478 /**
15479 * Redoes the effect of this operation.
15480 *
15481 * @param {Transaction} transaction The Yjs instance.
15482 * @param {Item} item
15483 * @param {Set<Item>} redoitems
15484 * @param {DeleteSet} itemsToDelete
15485 * @param {boolean} ignoreRemoteMapChanges
15486 * @param {import('../utils/UndoManager.js').UndoManager} um
15487 *
15488 * @return {Item|null}
15489 *
15490 * @private
15491 */
15492 const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) => {
15493 const doc = transaction.doc;
15494 const store = doc.store;
15495 const ownClientID = doc.clientID;
15496 const redone = item.redone;
15497 if (redone !== null) {
15498 return getItemCleanStart(transaction, redone)
15499 }
15500 let parentItem = /** @type {AbstractType<any>} */ (item.parent)._item;
15501 /**
15502 * @type {Item|null}
15503 */
15504 let left = null;
15505 /**
15506 * @type {Item|null}
15507 */
15508 let right;
15509 // make sure that parent is redone
15510 if (parentItem !== null && parentItem.deleted === true) {
15511 // try to undo parent if it will be undone anyway
15512 if (parentItem.redone === null && (!redoitems.has(parentItem) || redoItem(transaction, parentItem, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) === null)) {
15513 return null
15514 }
15515 while (parentItem.redone !== null) {
15516 parentItem = getItemCleanStart(transaction, parentItem.redone);
15517 }
15518 }
15519 const parentType = parentItem === null ? /** @type {AbstractType<any>} */ (item.parent) : /** @type {ContentType} */ (parentItem.content).type;
15520
15521 if (item.parentSub === null) {
15522 // Is an array item. Insert at the old position
15523 left = item.left;
15524 right = item;
15525 // find next cloned_redo items
15526 while (left !== null) {
15527 /**
15528 * @type {Item|null}
15529 */
15530 let leftTrace = left;
15531 // trace redone until parent matches
15532 while (leftTrace !== null && /** @type {AbstractType<any>} */ (leftTrace.parent)._item !== parentItem) {
15533 leftTrace = leftTrace.redone === null ? null : getItemCleanStart(transaction, leftTrace.redone);
15534 }
15535 if (leftTrace !== null && /** @type {AbstractType<any>} */ (leftTrace.parent)._item === parentItem) {
15536 left = leftTrace;
15537 break
15538 }
15539 left = left.left;
15540 }
15541 while (right !== null) {
15542 /**
15543 * @type {Item|null}
15544 */
15545 let rightTrace = right;
15546 // trace redone until parent matches
15547 while (rightTrace !== null && /** @type {AbstractType<any>} */ (rightTrace.parent)._item !== parentItem) {
15548 rightTrace = rightTrace.redone === null ? null : getItemCleanStart(transaction, rightTrace.redone);
15549 }
15550 if (rightTrace !== null && /** @type {AbstractType<any>} */ (rightTrace.parent)._item === parentItem) {
15551 right = rightTrace;
15552 break
15553 }
15554 right = right.right;
15555 }
15556 } else {
15557 right = null;
15558 if (item.right && !ignoreRemoteMapChanges) {
15559 left = item;
15560 // Iterate right while right is in itemsToDelete
15561 // If it is intended to delete right while item is redone, we can expect that item should replace right.
15562 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))) {
15563 left = left.right;
15564 // follow redone
15565 while (left.redone) left = getItemCleanStart(transaction, left.redone);
15566 }
15567 if (left && left.right !== null) {
15568 // It is not possible to redo this item because it conflicts with a
15569 // change from another client
15570 return null
15571 }
15572 } else {
15573 left = parentType._map.get(item.parentSub) || null;
15574 }
15575 }
15576 const nextClock = getState(store, ownClientID);
15577 const nextId = createID(ownClientID, nextClock);
15578 const redoneItem = new Item(
15579 nextId,
15580 left, left && left.lastId,
15581 right, right && right.id,
15582 parentType,
15583 item.parentSub,
15584 item.content.copy()
15585 );
15586 item.redone = nextId;
15587 keepItem(redoneItem, true);
15588 redoneItem.integrate(transaction, 0);
15589 return redoneItem
15590 };
15591
15592 /**
15593 * Abstract class that represents any content.
15594 */
15595 class Item extends AbstractStruct {
15596 /**
15597 * @param {ID} id
15598 * @param {Item | null} left
15599 * @param {ID | null} origin
15600 * @param {Item | null} right
15601 * @param {ID | null} rightOrigin
15602 * @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.
15603 * @param {string | null} parentSub
15604 * @param {AbstractContent} content
15605 */
15606 constructor (id, left, origin, right, rightOrigin, parent, parentSub, content) {
15607 super(id, content.getLength());
15608 /**
15609 * The item that was originally to the left of this item.
15610 * @type {ID | null}
15611 */
15612 this.origin = origin;
15613 /**
15614 * The item that is currently to the left of this item.
15615 * @type {Item | null}
15616 */
15617 this.left = left;
15618 /**
15619 * The item that is currently to the right of this item.
15620 * @type {Item | null}
15621 */
15622 this.right = right;
15623 /**
15624 * The item that was originally to the right of this item.
15625 * @type {ID | null}
15626 */
15627 this.rightOrigin = rightOrigin;
15628 /**
15629 * @type {AbstractType<any>|ID|null}
15630 */
15631 this.parent = parent;
15632 /**
15633 * If the parent refers to this item with some kind of key (e.g. YMap, the
15634 * key is specified here. The key is then used to refer to the list in which
15635 * to insert this item. If `parentSub = null` type._start is the list in
15636 * which to insert to. Otherwise it is `parent._map`.
15637 * @type {String | null}
15638 */
15639 this.parentSub = parentSub;
15640 /**
15641 * If this type's effect is redone this type refers to the type that undid
15642 * this operation.
15643 * @type {ID | null}
15644 */
15645 this.redone = null;
15646 /**
15647 * @type {AbstractContent}
15648 */
15649 this.content = content;
15650 /**
15651 * bit1: keep
15652 * bit2: countable
15653 * bit3: deleted
15654 * bit4: mark - mark node as fast-search-marker
15655 * @type {number} byte
15656 */
15657 this.info = this.content.isCountable() ? BIT2 : 0;
15658 }
15659
15660 /**
15661 * This is used to mark the item as an indexed fast-search marker
15662 *
15663 * @type {boolean}
15664 */
15665 set marker (isMarked) {
15666 if (((this.info & BIT4) > 0) !== isMarked) {
15667 this.info ^= BIT4;
15668 }
15669 }
15670
15671 get marker () {
15672 return (this.info & BIT4) > 0
15673 }
15674
15675 /**
15676 * If true, do not garbage collect this Item.
15677 */
15678 get keep () {
15679 return (this.info & BIT1) > 0
15680 }
15681
15682 set keep (doKeep) {
15683 if (this.keep !== doKeep) {
15684 this.info ^= BIT1;
15685 }
15686 }
15687
15688 get countable () {
15689 return (this.info & BIT2) > 0
15690 }
15691
15692 /**
15693 * Whether this item was deleted or not.
15694 * @type {Boolean}
15695 */
15696 get deleted () {
15697 return (this.info & BIT3) > 0
15698 }
15699
15700 set deleted (doDelete) {
15701 if (this.deleted !== doDelete) {
15702 this.info ^= BIT3;
15703 }
15704 }
15705
15706 markDeleted () {
15707 this.info |= BIT3;
15708 }
15709
15710 /**
15711 * Return the creator clientID of the missing op or define missing items and return null.
15712 *
15713 * @param {Transaction} transaction
15714 * @param {StructStore} store
15715 * @return {null | number}
15716 */
15717 getMissing (transaction, store) {
15718 if (this.origin && this.origin.client !== this.id.client && this.origin.clock >= getState(store, this.origin.client)) {
15719 return this.origin.client
15720 }
15721 if (this.rightOrigin && this.rightOrigin.client !== this.id.client && this.rightOrigin.clock >= getState(store, this.rightOrigin.client)) {
15722 return this.rightOrigin.client
15723 }
15724 if (this.parent && this.parent.constructor === ID && this.id.client !== this.parent.client && this.parent.clock >= getState(store, this.parent.client)) {
15725 return this.parent.client
15726 }
15727
15728 // We have all missing ids, now find the items
15729
15730 if (this.origin) {
15731 this.left = getItemCleanEnd(transaction, store, this.origin);
15732 this.origin = this.left.lastId;
15733 }
15734 if (this.rightOrigin) {
15735 this.right = getItemCleanStart(transaction, this.rightOrigin);
15736 this.rightOrigin = this.right.id;
15737 }
15738 if ((this.left && this.left.constructor === GC) || (this.right && this.right.constructor === GC)) {
15739 this.parent = null;
15740 }
15741 // only set parent if this shouldn't be garbage collected
15742 if (!this.parent) {
15743 if (this.left && this.left.constructor === Item) {
15744 this.parent = this.left.parent;
15745 this.parentSub = this.left.parentSub;
15746 }
15747 if (this.right && this.right.constructor === Item) {
15748 this.parent = this.right.parent;
15749 this.parentSub = this.right.parentSub;
15750 }
15751 } else if (this.parent.constructor === ID) {
15752 const parentItem = getItem(store, this.parent);
15753 if (parentItem.constructor === GC) {
15754 this.parent = null;
15755 } else {
15756 this.parent = /** @type {ContentType} */ (parentItem.content).type;
15757 }
15758 }
15759 return null
15760 }
15761
15762 /**
15763 * @param {Transaction} transaction
15764 * @param {number} offset
15765 */
15766 integrate (transaction, offset) {
15767 if (offset > 0) {
15768 this.id.clock += offset;
15769 this.left = getItemCleanEnd(transaction, transaction.doc.store, createID(this.id.client, this.id.clock - 1));
15770 this.origin = this.left.lastId;
15771 this.content = this.content.splice(offset);
15772 this.length -= offset;
15773 }
15774
15775 if (this.parent) {
15776 if ((!this.left && (!this.right || this.right.left !== null)) || (this.left && this.left.right !== this.right)) {
15777 /**
15778 * @type {Item|null}
15779 */
15780 let left = this.left;
15781
15782 /**
15783 * @type {Item|null}
15784 */
15785 let o;
15786 // set o to the first conflicting item
15787 if (left !== null) {
15788 o = left.right;
15789 } else if (this.parentSub !== null) {
15790 o = /** @type {AbstractType<any>} */ (this.parent)._map.get(this.parentSub) || null;
15791 while (o !== null && o.left !== null) {
15792 o = o.left;
15793 }
15794 } else {
15795 o = /** @type {AbstractType<any>} */ (this.parent)._start;
15796 }
15797 // TODO: use something like DeleteSet here (a tree implementation would be best)
15798 // @todo use global set definitions
15799 /**
15800 * @type {Set<Item>}
15801 */
15802 const conflictingItems = new Set();
15803 /**
15804 * @type {Set<Item>}
15805 */
15806 const itemsBeforeOrigin = new Set();
15807 // Let c in conflictingItems, b in itemsBeforeOrigin
15808 // ***{origin}bbbb{this}{c,b}{c,b}{o}***
15809 // Note that conflictingItems is a subset of itemsBeforeOrigin
15810 while (o !== null && o !== this.right) {
15811 itemsBeforeOrigin.add(o);
15812 conflictingItems.add(o);
15813 if (compareIDs(this.origin, o.origin)) {
15814 // case 1
15815 if (o.id.client < this.id.client) {
15816 left = o;
15817 conflictingItems.clear();
15818 } else if (compareIDs(this.rightOrigin, o.rightOrigin)) {
15819 // this and o are conflicting and point to the same integration points. The id decides which item comes first.
15820 // Since this is to the left of o, we can break here
15821 break
15822 } // else, o might be integrated before an item that this conflicts with. If so, we will find it in the next iterations
15823 } 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.
15824 // case 2
15825 if (!conflictingItems.has(getItem(transaction.doc.store, o.origin))) {
15826 left = o;
15827 conflictingItems.clear();
15828 }
15829 } else {
15830 break
15831 }
15832 o = o.right;
15833 }
15834 this.left = left;
15835 }
15836 // reconnect left/right + update parent map/start if necessary
15837 if (this.left !== null) {
15838 const right = this.left.right;
15839 this.right = right;
15840 this.left.right = this;
15841 } else {
15842 let r;
15843 if (this.parentSub !== null) {
15844 r = /** @type {AbstractType<any>} */ (this.parent)._map.get(this.parentSub) || null;
15845 while (r !== null && r.left !== null) {
15846 r = r.left;
15847 }
15848 } else {
15849 r = /** @type {AbstractType<any>} */ (this.parent)._start
15850 ;/** @type {AbstractType<any>} */ (this.parent)._start = this;
15851 }
15852 this.right = r;
15853 }
15854 if (this.right !== null) {
15855 this.right.left = this;
15856 } else if (this.parentSub !== null) {
15857 // set as current parent value if right === null and this is parentSub
15858 /** @type {AbstractType<any>} */ (this.parent)._map.set(this.parentSub, this);
15859 if (this.left !== null) {
15860 // this is the current attribute value of parent. delete right
15861 this.left.delete(transaction);
15862 }
15863 }
15864 // adjust length of parent
15865 if (this.parentSub === null && this.countable && !this.deleted) {
15866 /** @type {AbstractType<any>} */ (this.parent)._length += this.length;
15867 }
15868 addStruct(transaction.doc.store, this);
15869 this.content.integrate(transaction, this);
15870 // add parent to transaction.changed
15871 addChangedTypeToTransaction(transaction, /** @type {AbstractType<any>} */ (this.parent), this.parentSub);
15872 if ((/** @type {AbstractType<any>} */ (this.parent)._item !== null && /** @type {AbstractType<any>} */ (this.parent)._item.deleted) || (this.parentSub !== null && this.right !== null)) {
15873 // delete if parent is deleted or if this is not the current attribute value of parent
15874 this.delete(transaction);
15875 }
15876 } else {
15877 // parent is not defined. Integrate GC struct instead
15878 new GC(this.id, this.length).integrate(transaction, 0);
15879 }
15880 }
15881
15882 /**
15883 * Returns the next non-deleted item
15884 */
15885 get next () {
15886 let n = this.right;
15887 while (n !== null && n.deleted) {
15888 n = n.right;
15889 }
15890 return n
15891 }
15892
15893 /**
15894 * Returns the previous non-deleted item
15895 */
15896 get prev () {
15897 let n = this.left;
15898 while (n !== null && n.deleted) {
15899 n = n.left;
15900 }
15901 return n
15902 }
15903
15904 /**
15905 * Computes the last content address of this Item.
15906 */
15907 get lastId () {
15908 // allocating ids is pretty costly because of the amount of ids created, so we try to reuse whenever possible
15909 return this.length === 1 ? this.id : createID(this.id.client, this.id.clock + this.length - 1)
15910 }
15911
15912 /**
15913 * Try to merge two items
15914 *
15915 * @param {Item} right
15916 * @return {boolean}
15917 */
15918 mergeWith (right) {
15919 if (
15920 this.constructor === right.constructor &&
15921 compareIDs(right.origin, this.lastId) &&
15922 this.right === right &&
15923 compareIDs(this.rightOrigin, right.rightOrigin) &&
15924 this.id.client === right.id.client &&
15925 this.id.clock + this.length === right.id.clock &&
15926 this.deleted === right.deleted &&
15927 this.redone === null &&
15928 right.redone === null &&
15929 this.content.constructor === right.content.constructor &&
15930 this.content.mergeWith(right.content)
15931 ) {
15932 const searchMarker = /** @type {AbstractType<any>} */ (this.parent)._searchMarker;
15933 if (searchMarker) {
15934 searchMarker.forEach(marker => {
15935 if (marker.p === right) {
15936 // right is going to be "forgotten" so we need to update the marker
15937 marker.p = this;
15938 // adjust marker index
15939 if (!this.deleted && this.countable) {
15940 marker.index -= this.length;
15941 }
15942 }
15943 });
15944 }
15945 if (right.keep) {
15946 this.keep = true;
15947 }
15948 this.right = right.right;
15949 if (this.right !== null) {
15950 this.right.left = this;
15951 }
15952 this.length += right.length;
15953 return true
15954 }
15955 return false
15956 }
15957
15958 /**
15959 * Mark this Item as deleted.
15960 *
15961 * @param {Transaction} transaction
15962 */
15963 delete (transaction) {
15964 if (!this.deleted) {
15965 const parent = /** @type {AbstractType<any>} */ (this.parent);
15966 // adjust the length of parent
15967 if (this.countable && this.parentSub === null) {
15968 parent._length -= this.length;
15969 }
15970 this.markDeleted();
15971 addToDeleteSet(transaction.deleteSet, this.id.client, this.id.clock, this.length);
15972 addChangedTypeToTransaction(transaction, parent, this.parentSub);
15973 this.content.delete(transaction);
15974 }
15975 }
15976
15977 /**
15978 * @param {StructStore} store
15979 * @param {boolean} parentGCd
15980 */
15981 gc (store, parentGCd) {
15982 if (!this.deleted) {
15983 throw unexpectedCase()
15984 }
15985 this.content.gc(store);
15986 if (parentGCd) {
15987 replaceStruct(store, this, new GC(this.id, this.length));
15988 } else {
15989 this.content = new ContentDeleted(this.length);
15990 }
15991 }
15992
15993 /**
15994 * Transform the properties of this type to binary and write it to an
15995 * BinaryEncoder.
15996 *
15997 * This is called when this Item is sent to a remote peer.
15998 *
15999 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
16000 * @param {number} offset
16001 */
16002 write (encoder, offset) {
16003 const origin = offset > 0 ? createID(this.id.client, this.id.clock + offset - 1) : this.origin;
16004 const rightOrigin = this.rightOrigin;
16005 const parentSub = this.parentSub;
16006 const info = (this.content.getRef() & BITS5) |
16007 (origin === null ? 0 : BIT8) | // origin is defined
16008 (rightOrigin === null ? 0 : BIT7) | // right origin is defined
16009 (parentSub === null ? 0 : BIT6); // parentSub is non-null
16010 encoder.writeInfo(info);
16011 if (origin !== null) {
16012 encoder.writeLeftID(origin);
16013 }
16014 if (rightOrigin !== null) {
16015 encoder.writeRightID(rightOrigin);
16016 }
16017 if (origin === null && rightOrigin === null) {
16018 const parent = /** @type {AbstractType<any>} */ (this.parent);
16019 if (parent._item !== undefined) {
16020 const parentItem = parent._item;
16021 if (parentItem === null) {
16022 // parent type on y._map
16023 // find the correct key
16024 const ykey = findRootTypeKey(parent);
16025 encoder.writeParentInfo(true); // write parentYKey
16026 encoder.writeString(ykey);
16027 } else {
16028 encoder.writeParentInfo(false); // write parent id
16029 encoder.writeLeftID(parentItem.id);
16030 }
16031 } else if (parent.constructor === String) { // this edge case was added by differential updates
16032 encoder.writeParentInfo(true); // write parentYKey
16033 encoder.writeString(parent);
16034 } else if (parent.constructor === ID) {
16035 encoder.writeParentInfo(false); // write parent id
16036 encoder.writeLeftID(parent);
16037 } else {
16038 unexpectedCase();
16039 }
16040 if (parentSub !== null) {
16041 encoder.writeString(parentSub);
16042 }
16043 }
16044 this.content.write(encoder, offset);
16045 }
16046 }
16047
16048 /**
16049 * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
16050 * @param {number} info
16051 */
16052 const readItemContent = (decoder, info) => contentRefs[info & BITS5](decoder);
16053
16054 /**
16055 * A lookup map for reading Item content.
16056 *
16057 * @type {Array<function(UpdateDecoderV1 | UpdateDecoderV2):AbstractContent>}
16058 */
16059 const contentRefs = [
16060 () => { unexpectedCase(); }, // GC is not ItemContent
16061 readContentDeleted, // 1
16062 readContentJSON, // 2
16063 readContentBinary, // 3
16064 readContentString, // 4
16065 readContentEmbed, // 5
16066 readContentFormat, // 6
16067 readContentType, // 7
16068 readContentAny, // 8
16069 readContentDoc, // 9
16070 () => { unexpectedCase(); } // 10 - Skip is not ItemContent
16071 ];
16072
16073 const structSkipRefNumber = 10;
16074
16075 /**
16076 * @private
16077 */
16078 class Skip extends AbstractStruct {
16079 get deleted () {
16080 return true
16081 }
16082
16083 delete () {}
16084
16085 /**
16086 * @param {Skip} right
16087 * @return {boolean}
16088 */
16089 mergeWith (right) {
16090 if (this.constructor !== right.constructor) {
16091 return false
16092 }
16093 this.length += right.length;
16094 return true
16095 }
16096
16097 /**
16098 * @param {Transaction} transaction
16099 * @param {number} offset
16100 */
16101 integrate (transaction, offset) {
16102 // skip structs cannot be integrated
16103 unexpectedCase();
16104 }
16105
16106 /**
16107 * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
16108 * @param {number} offset
16109 */
16110 write (encoder, offset) {
16111 encoder.writeInfo(structSkipRefNumber);
16112 // write as VarUint because Skips can't make use of predictable length-encoding
16113 writeVarUint(encoder.restEncoder, this.length - offset);
16114 }
16115
16116 /**
16117 * @param {Transaction} transaction
16118 * @param {StructStore} store
16119 * @return {null | number}
16120 */
16121 getMissing (transaction, store) {
16122 return null
16123 }
16124 }
16125
16126 /** eslint-env browser */
16127
16128 const glo = /** @type {any} */ (typeof globalThis !== 'undefined'
16129 ? globalThis
16130 : typeof window !== 'undefined'
16131 ? window
16132 // @ts-ignore
16133 : typeof global !== 'undefined' ? global : {});
16134
16135 const importIdentifier = '__ $YJS$ __';
16136
16137 if (glo[importIdentifier] === true) {
16138 /**
16139 * Dear reader of this message. Please take this seriously.
16140 *
16141 * If you see this message, make sure that you only import one version of Yjs. In many cases,
16142 * your package manager installs two versions of Yjs that are used by different packages within your project.
16143 * Another reason for this message is that some parts of your project use the commonjs version of Yjs
16144 * and others use the EcmaScript version of Yjs.
16145 *
16146 * This often leads to issues that are hard to debug. We often need to perform constructor checks,
16147 * e.g. `struct instanceof GC`. If you imported different versions of Yjs, it is impossible for us to
16148 * do the constructor checks anymore - which might break the CRDT algorithm.
16149 *
16150 * https://github.com/yjs/yjs/issues/438
16151 */
16152 console.error('Yjs was already imported. This breaks constructor checks and will lead to issues! - https://github.com/yjs/yjs/issues/438');
16153 }
16154 glo[importIdentifier] = true;
16155
16156
16157 //# sourceMappingURL=yjs.mjs.map
16158
16159 ;// CONCATENATED MODULE: ./packages/sync/build-module/provider.js
16160 /**
16161 * External dependencies
16162 */
16163 // @ts-ignore
16164
16165
16166 /** @typedef {import('./types').ObjectType} ObjectType */
16167 /** @typedef {import('./types').ObjectID} ObjectID */
16168 /** @typedef {import('./types').ObjectConfig} ObjectConfig */
16169 /** @typedef {import('./types').CRDTDoc} CRDTDoc */
16170 /** @typedef {import('./types').ConnectDoc} ConnectDoc */
16171 /** @typedef {import('./types').SyncProvider} SyncProvider */
16172
16173 /**
16174 * Create a sync provider.
16175 *
16176 * @param {ConnectDoc} connectLocal Connect the document to a local database.
16177 * @param {ConnectDoc} connectRemote Connect the document to a remote sync connection.
16178 * @return {SyncProvider} Sync provider.
16179 */
16180 const createSyncProvider = (connectLocal, connectRemote) => {
16181 /**
16182 * @type {Record<string,ObjectConfig>}
16183 */
16184 const config = {};
16185
16186 /**
16187 * @type {Record<string,Record<string,()=>void>>}
16188 */
16189 const listeners = {};
16190
16191 /**
16192 * @type {Record<string,Record<string,CRDTDoc>>}
16193 */
16194 const docs = {};
16195
16196 /**
16197 * Registeres an object type.
16198 *
16199 * @param {ObjectType} objectType Object type to register.
16200 * @param {ObjectConfig} objectConfig Object config.
16201 */
16202 function register(objectType, objectConfig) {
16203 config[objectType] = objectConfig;
16204 }
16205
16206 /**
16207 * Fetch data from local database or remote source.
16208 *
16209 * @param {ObjectType} objectType Object type to load.
16210 * @param {ObjectID} objectId Object ID to load.
16211 * @param {Function} handleChanges Callback to call when data changes.
16212 */
16213 async function bootstrap(objectType, objectId, handleChanges) {
16214 const doc = new Doc();
16215 docs[objectType] = docs[objectType] || {};
16216 docs[objectType][objectId] = doc;
16217 const updateHandler = () => {
16218 const data = config[objectType].fromCRDTDoc(doc);
16219 handleChanges(data);
16220 };
16221 doc.on('update', updateHandler);
16222
16223 // connect to locally saved database.
16224 const destroyLocalConnection = await connectLocal(objectId, objectType, doc);
16225
16226 // Once the database syncing is done, start the remote syncing
16227 if (connectRemote) {
16228 await connectRemote(objectId, objectType, doc);
16229 }
16230 const loadRemotely = config[objectType].fetch;
16231 if (loadRemotely) {
16232 loadRemotely(objectId).then(data => {
16233 doc.transact(() => {
16234 config[objectType].applyChangesToDoc(doc, data);
16235 });
16236 });
16237 }
16238 listeners[objectType] = listeners[objectType] || {};
16239 listeners[objectType][objectId] = () => {
16240 destroyLocalConnection();
16241 doc.off('update', updateHandler);
16242 };
16243 }
16244
16245 /**
16246 * Fetch data from local database or remote source.
16247 *
16248 * @param {ObjectType} objectType Object type to load.
16249 * @param {ObjectID} objectId Object ID to load.
16250 * @param {any} data Updates to make.
16251 */
16252 async function update(objectType, objectId, data) {
16253 const doc = docs[objectType][objectId];
16254 if (!doc) {
16255 throw 'Error doc ' + objectType + ' ' + objectId + ' not found';
16256 }
16257 doc.transact(() => {
16258 config[objectType].applyChangesToDoc(doc, data);
16259 });
16260 }
16261
16262 /**
16263 * Stop updating a document and discard it.
16264 *
16265 * @param {ObjectType} objectType Object type to load.
16266 * @param {ObjectID} objectId Object ID to load.
16267 */
16268 async function discard(objectType, objectId) {
16269 if (listeners?.[objectType]?.[objectId]) {
16270 listeners[objectType][objectId]();
16271 }
16272 }
16273 return {
16274 register,
16275 bootstrap,
16276 update,
16277 discard
16278 };
16279 };
16280
16281 ;// CONCATENATED MODULE: ./node_modules/lib0/indexeddb.js
16282 /* eslint-env browser */
16283
16284 /**
16285 * Helpers to work with IndexedDB.
16286 *
16287 * @module indexeddb
16288 */
16289
16290
16291
16292
16293 /* c8 ignore start */
16294
16295 /**
16296 * IDB Request to Promise transformer
16297 *
16298 * @param {IDBRequest} request
16299 * @return {Promise<any>}
16300 */
16301 const rtop = request => promise_create((resolve, reject) => {
16302 // @ts-ignore
16303 request.onerror = event => reject(new Error(event.target.error))
16304 // @ts-ignore
16305 request.onsuccess = event => resolve(event.target.result)
16306 })
16307
16308 /**
16309 * @param {string} name
16310 * @param {function(IDBDatabase):any} initDB Called when the database is first created
16311 * @return {Promise<IDBDatabase>}
16312 */
16313 const openDB = (name, initDB) => promise_create((resolve, reject) => {
16314 const request = indexedDB.open(name)
16315 /**
16316 * @param {any} event
16317 */
16318 request.onupgradeneeded = event => initDB(event.target.result)
16319 /**
16320 * @param {any} event
16321 */
16322 request.onerror = event => reject(error_create(event.target.error))
16323 /**
16324 * @param {any} event
16325 */
16326 request.onsuccess = event => {
16327 /**
16328 * @type {IDBDatabase}
16329 */
16330 const db = event.target.result
16331 db.onversionchange = () => { db.close() }
16332 if (typeof addEventListener !== 'undefined') {
16333 addEventListener('unload', () => db.close())
16334 }
16335 resolve(db)
16336 }
16337 })
16338
16339 /**
16340 * @param {string} name
16341 */
16342 const deleteDB = name => rtop(indexedDB.deleteDatabase(name))
16343
16344 /**
16345 * @param {IDBDatabase} db
16346 * @param {Array<Array<string>|Array<string|IDBObjectStoreParameters|undefined>>} definitions
16347 */
16348 const createStores = (db, definitions) => definitions.forEach(d =>
16349 // @ts-ignore
16350 db.createObjectStore.apply(db, d)
16351 )
16352
16353 /**
16354 * @param {IDBDatabase} db
16355 * @param {Array<string>} stores
16356 * @param {"readwrite"|"readonly"} [access]
16357 * @return {Array<IDBObjectStore>}
16358 */
16359 const indexeddb_transact = (db, stores, access = 'readwrite') => {
16360 const transaction = db.transaction(stores, access)
16361 return stores.map(store => getStore(transaction, store))
16362 }
16363
16364 /**
16365 * @param {IDBObjectStore} store
16366 * @param {IDBKeyRange} [range]
16367 * @return {Promise<number>}
16368 */
16369 const count = (store, range) =>
16370 rtop(store.count(range))
16371
16372 /**
16373 * @param {IDBObjectStore} store
16374 * @param {String | number | ArrayBuffer | Date | Array<any> } key
16375 * @return {Promise<String | number | ArrayBuffer | Date | Array<any>>}
16376 */
16377 const get = (store, key) =>
16378 rtop(store.get(key))
16379
16380 /**
16381 * @param {IDBObjectStore} store
16382 * @param {String | number | ArrayBuffer | Date | IDBKeyRange | Array<any> } key
16383 */
16384 const del = (store, key) =>
16385 rtop(store.delete(key))
16386
16387 /**
16388 * @param {IDBObjectStore} store
16389 * @param {String | number | ArrayBuffer | Date | boolean} item
16390 * @param {String | number | ArrayBuffer | Date | Array<any>} [key]
16391 */
16392 const put = (store, item, key) =>
16393 rtop(store.put(item, key))
16394
16395 /**
16396 * @param {IDBObjectStore} store
16397 * @param {String | number | ArrayBuffer | Date | boolean} item
16398 * @param {String | number | ArrayBuffer | Date | Array<any>} key
16399 * @return {Promise<any>}
16400 */
16401 const indexeddb_add = (store, item, key) =>
16402 rtop(store.add(item, key))
16403
16404 /**
16405 * @param {IDBObjectStore} store
16406 * @param {String | number | ArrayBuffer | Date} item
16407 * @return {Promise<number>} Returns the generated key
16408 */
16409 const addAutoKey = (store, item) =>
16410 rtop(store.add(item))
16411
16412 /**
16413 * @param {IDBObjectStore} store
16414 * @param {IDBKeyRange} [range]
16415 * @param {number} [limit]
16416 * @return {Promise<Array<any>>}
16417 */
16418 const getAll = (store, range, limit) =>
16419 rtop(store.getAll(range, limit))
16420
16421 /**
16422 * @param {IDBObjectStore} store
16423 * @param {IDBKeyRange} [range]
16424 * @param {number} [limit]
16425 * @return {Promise<Array<any>>}
16426 */
16427 const getAllKeys = (store, range, limit) =>
16428 rtop(store.getAllKeys(range, limit))
16429
16430 /**
16431 * @param {IDBObjectStore} store
16432 * @param {IDBKeyRange|null} query
16433 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction
16434 * @return {Promise<any>}
16435 */
16436 const queryFirst = (store, query, direction) => {
16437 /**
16438 * @type {any}
16439 */
16440 let first = null
16441 return iterateKeys(store, query, key => {
16442 first = key
16443 return false
16444 }, direction).then(() => first)
16445 }
16446
16447 /**
16448 * @param {IDBObjectStore} store
16449 * @param {IDBKeyRange?} [range]
16450 * @return {Promise<any>}
16451 */
16452 const getLastKey = (store, range = null) => queryFirst(store, range, 'prev')
16453
16454 /**
16455 * @param {IDBObjectStore} store
16456 * @param {IDBKeyRange?} [range]
16457 * @return {Promise<any>}
16458 */
16459 const getFirstKey = (store, range = null) => queryFirst(store, range, 'next')
16460
16461 /**
16462 * @typedef KeyValuePair
16463 * @type {Object}
16464 * @property {any} k key
16465 * @property {any} v Value
16466 */
16467
16468 /**
16469 * @param {IDBObjectStore} store
16470 * @param {IDBKeyRange} [range]
16471 * @param {number} [limit]
16472 * @return {Promise<Array<KeyValuePair>>}
16473 */
16474 const getAllKeysValues = (store, range, limit) =>
16475 // @ts-ignore
16476 promise.all([getAllKeys(store, range, limit), getAll(store, range, limit)]).then(([ks, vs]) => ks.map((k, i) => ({ k, v: vs[i] })))
16477
16478 /**
16479 * @param {any} request
16480 * @param {function(IDBCursorWithValue):void|boolean|Promise<void|boolean>} f
16481 * @return {Promise<void>}
16482 */
16483 const iterateOnRequest = (request, f) => promise_create((resolve, reject) => {
16484 request.onerror = reject
16485 /**
16486 * @param {any} event
16487 */
16488 request.onsuccess = async event => {
16489 const cursor = event.target.result
16490 if (cursor === null || (await f(cursor)) === false) {
16491 return resolve()
16492 }
16493 cursor.continue()
16494 }
16495 })
16496
16497 /**
16498 * Iterate on keys and values
16499 * @param {IDBObjectStore} store
16500 * @param {IDBKeyRange|null} keyrange
16501 * @param {function(any,any):void|boolean|Promise<void|boolean>} f Callback that receives (value, key)
16502 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction
16503 */
16504 const iterate = (store, keyrange, f, direction = 'next') =>
16505 iterateOnRequest(store.openCursor(keyrange, direction), cursor => f(cursor.value, cursor.key))
16506
16507 /**
16508 * Iterate on the keys (no values)
16509 *
16510 * @param {IDBObjectStore} store
16511 * @param {IDBKeyRange|null} keyrange
16512 * @param {function(any):void|boolean|Promise<void|boolean>} f callback that receives the key
16513 * @param {'next'|'prev'|'nextunique'|'prevunique'} direction
16514 */
16515 const iterateKeys = (store, keyrange, f, direction = 'next') =>
16516 iterateOnRequest(store.openKeyCursor(keyrange, direction), cursor => f(cursor.key))
16517
16518 /**
16519 * Open store from transaction
16520 * @param {IDBTransaction} t
16521 * @param {String} store
16522 * @returns {IDBObjectStore}
16523 */
16524 const getStore = (t, store) => t.objectStore(store)
16525
16526 /**
16527 * @param {any} lower
16528 * @param {any} upper
16529 * @param {boolean} lowerOpen
16530 * @param {boolean} upperOpen
16531 */
16532 const createIDBKeyRangeBound = (lower, upper, lowerOpen, upperOpen) => IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen)
16533
16534 /**
16535 * @param {any} upper
16536 * @param {boolean} upperOpen
16537 */
16538 const createIDBKeyRangeUpperBound = (upper, upperOpen) => IDBKeyRange.upperBound(upper, upperOpen)
16539
16540 /**
16541 * @param {any} lower
16542 * @param {boolean} lowerOpen
16543 */
16544 const createIDBKeyRangeLowerBound = (lower, lowerOpen) => IDBKeyRange.lowerBound(lower, lowerOpen)
16545
16546 /* c8 ignore stop */
16547
16548 ;// CONCATENATED MODULE: ./node_modules/y-indexeddb/src/y-indexeddb.js
16549
16550
16551
16552
16553
16554 const customStoreName = 'custom'
16555 const updatesStoreName = 'updates'
16556
16557 const PREFERRED_TRIM_SIZE = 500
16558
16559 /**
16560 * @param {IndexeddbPersistence} idbPersistence
16561 * @param {function(IDBObjectStore):void} [beforeApplyUpdatesCallback]
16562 * @param {function(IDBObjectStore):void} [afterApplyUpdatesCallback]
16563 */
16564 const fetchUpdates = (idbPersistence, beforeApplyUpdatesCallback = () => {}, afterApplyUpdatesCallback = () => {}) => {
16565 const [updatesStore] = indexeddb_transact(/** @type {IDBDatabase} */ (idbPersistence.db), [updatesStoreName]) // , 'readonly')
16566 return getAll(updatesStore, createIDBKeyRangeLowerBound(idbPersistence._dbref, false)).then(updates => {
16567 if (!idbPersistence._destroyed) {
16568 beforeApplyUpdatesCallback(updatesStore)
16569 transact(idbPersistence.doc, () => {
16570 updates.forEach(val => applyUpdate(idbPersistence.doc, val))
16571 }, idbPersistence, false)
16572 afterApplyUpdatesCallback(updatesStore)
16573 }
16574 })
16575 .then(() => getLastKey(updatesStore).then(lastKey => { idbPersistence._dbref = lastKey + 1 }))
16576 .then(() => count(updatesStore).then(cnt => { idbPersistence._dbsize = cnt }))
16577 .then(() => updatesStore)
16578 }
16579
16580 /**
16581 * @param {IndexeddbPersistence} idbPersistence
16582 * @param {boolean} forceStore
16583 */
16584 const storeState = (idbPersistence, forceStore = true) =>
16585 fetchUpdates(idbPersistence)
16586 .then(updatesStore => {
16587 if (forceStore || idbPersistence._dbsize >= PREFERRED_TRIM_SIZE) {
16588 addAutoKey(updatesStore, encodeStateAsUpdate(idbPersistence.doc))
16589 .then(() => del(updatesStore, createIDBKeyRangeUpperBound(idbPersistence._dbref, true)))
16590 .then(() => count(updatesStore).then(cnt => { idbPersistence._dbsize = cnt }))
16591 }
16592 })
16593
16594 /**
16595 * @param {string} name
16596 */
16597 const clearDocument = name => idb.deleteDB(name)
16598
16599 /**
16600 * @extends Observable<string>
16601 */
16602 class IndexeddbPersistence extends observable_Observable {
16603 /**
16604 * @param {string} name
16605 * @param {Y.Doc} doc
16606 */
16607 constructor (name, doc) {
16608 super()
16609 this.doc = doc
16610 this.name = name
16611 this._dbref = 0
16612 this._dbsize = 0
16613 this._destroyed = false
16614 /**
16615 * @type {IDBDatabase|null}
16616 */
16617 this.db = null
16618 this.synced = false
16619 this._db = openDB(name, db =>
16620 createStores(db, [
16621 ['updates', { autoIncrement: true }],
16622 ['custom']
16623 ])
16624 )
16625 /**
16626 * @type {Promise<IndexeddbPersistence>}
16627 */
16628 this.whenSynced = promise_create(resolve => this.on('synced', () => resolve(this)))
16629
16630 this._db.then(db => {
16631 this.db = db
16632 /**
16633 * @param {IDBObjectStore} updatesStore
16634 */
16635 const beforeApplyUpdatesCallback = (updatesStore) => addAutoKey(updatesStore, encodeStateAsUpdate(doc))
16636 const afterApplyUpdatesCallback = () => {
16637 if (this._destroyed) return this
16638 this.synced = true
16639 this.emit('synced', [this])
16640 }
16641 fetchUpdates(this, beforeApplyUpdatesCallback, afterApplyUpdatesCallback)
16642 })
16643 /**
16644 * Timeout in ms untill data is merged and persisted in idb.
16645 */
16646 this._storeTimeout = 1000
16647 /**
16648 * @type {any}
16649 */
16650 this._storeTimeoutId = null
16651 /**
16652 * @param {Uint8Array} update
16653 * @param {any} origin
16654 */
16655 this._storeUpdate = (update, origin) => {
16656 if (this.db && origin !== this) {
16657 const [updatesStore] = indexeddb_transact(/** @type {IDBDatabase} */ (this.db), [updatesStoreName])
16658 addAutoKey(updatesStore, update)
16659 if (++this._dbsize >= PREFERRED_TRIM_SIZE) {
16660 // debounce store call
16661 if (this._storeTimeoutId !== null) {
16662 clearTimeout(this._storeTimeoutId)
16663 }
16664 this._storeTimeoutId = setTimeout(() => {
16665 storeState(this, false)
16666 this._storeTimeoutId = null
16667 }, this._storeTimeout)
16668 }
16669 }
16670 }
16671 doc.on('update', this._storeUpdate)
16672 this.destroy = this.destroy.bind(this)
16673 doc.on('destroy', this.destroy)
16674 }
16675
16676 destroy () {
16677 if (this._storeTimeoutId) {
16678 clearTimeout(this._storeTimeoutId)
16679 }
16680 this.doc.off('update', this._storeUpdate)
16681 this.doc.off('destroy', this.destroy)
16682 this._destroyed = true
16683 return this._db.then(db => {
16684 db.close()
16685 })
16686 }
16687
16688 /**
16689 * Destroys this instance and removes all data from indexeddb.
16690 *
16691 * @return {Promise<void>}
16692 */
16693 clearData () {
16694 return this.destroy().then(() => {
16695 deleteDB(this.name)
16696 })
16697 }
16698
16699 /**
16700 * @param {String | number | ArrayBuffer | Date} key
16701 * @return {Promise<String | number | ArrayBuffer | Date | any>}
16702 */
16703 get (key) {
16704 return this._db.then(db => {
16705 const [custom] = indexeddb_transact(db, [customStoreName], 'readonly')
16706 return get(custom, key)
16707 })
16708 }
16709
16710 /**
16711 * @param {String | number | ArrayBuffer | Date} key
16712 * @param {String | number | ArrayBuffer | Date} value
16713 * @return {Promise<String | number | ArrayBuffer | Date>}
16714 */
16715 set (key, value) {
16716 return this._db.then(db => {
16717 const [custom] = indexeddb_transact(db, [customStoreName])
16718 return put(custom, value, key)
16719 })
16720 }
16721
16722 /**
16723 * @param {String | number | ArrayBuffer | Date} key
16724 * @return {Promise<undefined>}
16725 */
16726 del (key) {
16727 return this._db.then(db => {
16728 const [custom] = indexeddb_transact(db, [customStoreName])
16729 return del(custom, key)
16730 })
16731 }
16732 }
16733
16734 ;// CONCATENATED MODULE: ./packages/sync/build-module/connect-indexdb.js
16735 /**
16736 * External dependencies
16737 */
16738 // @ts-ignore
16739
16740
16741 /** @typedef {import('./types').ObjectType} ObjectType */
16742 /** @typedef {import('./types').ObjectID} ObjectID */
16743 /** @typedef {import('./types').CRDTDoc} CRDTDoc */
16744 /** @typedef {import('./types').ConnectDoc} ConnectDoc */
16745 /** @typedef {import('./types').SyncProvider} SyncProvider */
16746
16747 /**
16748 * Connect function to the IndexedDB persistence provider.
16749 *
16750 * @param {ObjectID} objectId The object ID.
16751 * @param {ObjectType} objectType The object type.
16752 * @param {CRDTDoc} doc The CRDT document.
16753 *
16754 * @return {Promise<() => void>} Promise that resolves when the connection is established.
16755 */
16756 function connectIndexDb(objectId, objectType, doc) {
16757 const roomName = `${objectType}-${objectId}`;
16758 const provider = new IndexeddbPersistence(roomName, doc);
16759 return new Promise(resolve => {
16760 provider.on('synced', () => {
16761 resolve(() => provider.destroy());
16762 });
16763 });
16764 }
16765
16766 ;// CONCATENATED MODULE: ./node_modules/lib0/websocket.js
16767 /* eslint-env browser */
16768
16769 /**
16770 * Tiny websocket connection handler.
16771 *
16772 * Implements exponential backoff reconnects, ping/pong, and a nice event system using [lib0/observable].
16773 *
16774 * @module websocket
16775 */
16776
16777
16778
16779
16780
16781 const reconnectTimeoutBase = 1200
16782 const maxReconnectTimeout = 2500
16783 // @todo - this should depend on awareness.outdatedTime
16784 const messageReconnectTimeout = 30000
16785
16786 /**
16787 * @param {WebsocketClient} wsclient
16788 */
16789 const setupWS = (wsclient) => {
16790 if (wsclient.shouldConnect && wsclient.ws === null) {
16791 const websocket = new WebSocket(wsclient.url)
16792 const binaryType = wsclient.binaryType
16793 /**
16794 * @type {any}
16795 */
16796 let pingTimeout = null
16797 if (binaryType) {
16798 websocket.binaryType = binaryType
16799 }
16800 wsclient.ws = websocket
16801 wsclient.connecting = true
16802 wsclient.connected = false
16803 websocket.onmessage = event => {
16804 wsclient.lastMessageReceived = getUnixTime()
16805 const data = event.data
16806 const message = typeof data === 'string' ? JSON.parse(data) : data
16807 if (message && message.type === 'pong') {
16808 clearTimeout(pingTimeout)
16809 pingTimeout = setTimeout(sendPing, messageReconnectTimeout / 2)
16810 }
16811 wsclient.emit('message', [message, wsclient])
16812 }
16813 /**
16814 * @param {any} error
16815 */
16816 const onclose = error => {
16817 if (wsclient.ws !== null) {
16818 wsclient.ws = null
16819 wsclient.connecting = false
16820 if (wsclient.connected) {
16821 wsclient.connected = false
16822 wsclient.emit('disconnect', [{ type: 'disconnect', error }, wsclient])
16823 } else {
16824 wsclient.unsuccessfulReconnects++
16825 }
16826 // Start with no reconnect timeout and increase timeout by
16827 // log10(wsUnsuccessfulReconnects).
16828 // The idea is to increase reconnect timeout slowly and have no reconnect
16829 // timeout at the beginning (log(1) = 0)
16830 setTimeout(setupWS, min(log10(wsclient.unsuccessfulReconnects + 1) * reconnectTimeoutBase, maxReconnectTimeout), wsclient)
16831 }
16832 clearTimeout(pingTimeout)
16833 }
16834 const sendPing = () => {
16835 if (wsclient.ws === websocket) {
16836 wsclient.send({
16837 type: 'ping'
16838 })
16839 }
16840 }
16841 websocket.onclose = () => onclose(null)
16842 websocket.onerror = error => onclose(error)
16843 websocket.onopen = () => {
16844 wsclient.lastMessageReceived = getUnixTime()
16845 wsclient.connecting = false
16846 wsclient.connected = true
16847 wsclient.unsuccessfulReconnects = 0
16848 wsclient.emit('connect', [{ type: 'connect' }, wsclient])
16849 // set ping
16850 pingTimeout = setTimeout(sendPing, messageReconnectTimeout / 2)
16851 }
16852 }
16853 }
16854
16855 /**
16856 * @extends Observable<string>
16857 */
16858 class WebsocketClient extends observable_Observable {
16859 /**
16860 * @param {string} url
16861 * @param {object} opts
16862 * @param {'arraybuffer' | 'blob' | null} [opts.binaryType] Set `ws.binaryType`
16863 */
16864 constructor (url, { binaryType } = {}) {
16865 super()
16866 this.url = url
16867 /**
16868 * @type {WebSocket?}
16869 */
16870 this.ws = null
16871 this.binaryType = binaryType || null
16872 this.connected = false
16873 this.connecting = false
16874 this.unsuccessfulReconnects = 0
16875 this.lastMessageReceived = 0
16876 /**
16877 * Whether to connect to other peers or not
16878 * @type {boolean}
16879 */
16880 this.shouldConnect = true
16881 this._checkInterval = setInterval(() => {
16882 if (this.connected && messageReconnectTimeout < getUnixTime() - this.lastMessageReceived) {
16883 // no message received in a long time - not even your own awareness
16884 // updates (which are updated every 15 seconds)
16885 /** @type {WebSocket} */ (this.ws).close()
16886 }
16887 }, messageReconnectTimeout / 2)
16888 setupWS(this)
16889 }
16890
16891 /**
16892 * @param {any} message
16893 */
16894 send (message) {
16895 if (this.ws) {
16896 this.ws.send(JSON.stringify(message))
16897 }
16898 }
16899
16900 destroy () {
16901 clearInterval(this._checkInterval)
16902 this.disconnect()
16903 super.destroy()
16904 }
16905
16906 disconnect () {
16907 this.shouldConnect = false
16908 if (this.ws !== null) {
16909 this.ws.close()
16910 }
16911 }
16912
16913 connect () {
16914 this.shouldConnect = true
16915 if (!this.connected && this.ws === null) {
16916 setupWS(this)
16917 }
16918 }
16919 }
16920
16921 ;// CONCATENATED MODULE: ./node_modules/lib0/broadcastchannel.js
16922 /* eslint-env browser */
16923
16924 /**
16925 * Helpers for cross-tab communication using broadcastchannel with LocalStorage fallback.
16926 *
16927 * ```js
16928 * // In browser window A:
16929 * broadcastchannel.subscribe('my events', data => console.log(data))
16930 * broadcastchannel.publish('my events', 'Hello world!') // => A: 'Hello world!' fires synchronously in same tab
16931 *
16932 * // In browser window B:
16933 * broadcastchannel.publish('my events', 'hello from tab B') // => A: 'hello from tab B'
16934 * ```
16935 *
16936 * @module broadcastchannel
16937 */
16938
16939 // @todo before next major: use Uint8Array instead as buffer object
16940
16941
16942
16943
16944
16945
16946 /**
16947 * @typedef {Object} Channel
16948 * @property {Set<function(any, any):any>} Channel.subs
16949 * @property {any} Channel.bc
16950 */
16951
16952 /**
16953 * @type {Map<string, Channel>}
16954 */
16955 const channels = new Map()
16956
16957 /* c8 ignore start */
16958 class LocalStoragePolyfill {
16959 /**
16960 * @param {string} room
16961 */
16962 constructor (room) {
16963 this.room = room
16964 /**
16965 * @type {null|function({data:ArrayBuffer}):void}
16966 */
16967 this.onmessage = null
16968 /**
16969 * @param {any} e
16970 */
16971 this._onChange = e => e.key === room && this.onmessage !== null && this.onmessage({ data: fromBase64(e.newValue || '') })
16972 onChange(this._onChange)
16973 }
16974
16975 /**
16976 * @param {ArrayBuffer} buf
16977 */
16978 postMessage (buf) {
16979 varStorage.setItem(this.room, toBase64(createUint8ArrayFromArrayBuffer(buf)))
16980 }
16981
16982 close () {
16983 offChange(this._onChange)
16984 }
16985 }
16986 /* c8 ignore stop */
16987
16988 // Use BroadcastChannel or Polyfill
16989 /* c8 ignore next */
16990 const BC = typeof BroadcastChannel === 'undefined' ? LocalStoragePolyfill : BroadcastChannel
16991
16992 /**
16993 * @param {string} room
16994 * @return {Channel}
16995 */
16996 const getChannel = room =>
16997 setIfUndefined(channels, room, () => {
16998 const subs = set_create()
16999 const bc = new BC(room)
17000 /**
17001 * @param {{data:ArrayBuffer}} e
17002 */
17003 /* c8 ignore next */
17004 bc.onmessage = e => subs.forEach(sub => sub(e.data, 'broadcastchannel'))
17005 return {
17006 bc, subs
17007 }
17008 })
17009
17010 /**
17011 * Subscribe to global `publish` events.
17012 *
17013 * @function
17014 * @param {string} room
17015 * @param {function(any, any):any} f
17016 */
17017 const subscribe = (room, f) => {
17018 getChannel(room).subs.add(f)
17019 return f
17020 }
17021
17022 /**
17023 * Unsubscribe from `publish` global events.
17024 *
17025 * @function
17026 * @param {string} room
17027 * @param {function(any, any):any} f
17028 */
17029 const unsubscribe = (room, f) => {
17030 const channel = getChannel(room)
17031 const unsubscribed = channel.subs.delete(f)
17032 if (unsubscribed && channel.subs.size === 0) {
17033 channel.bc.close()
17034 channels.delete(room)
17035 }
17036 return unsubscribed
17037 }
17038
17039 /**
17040 * Publish data to all subscribers (including subscribers on this tab)
17041 *
17042 * @function
17043 * @param {string} room
17044 * @param {any} data
17045 * @param {any} [origin]
17046 */
17047 const publish = (room, data, origin = null) => {
17048 const c = getChannel(room)
17049 c.bc.postMessage(data)
17050 c.subs.forEach(sub => sub(data, origin))
17051 }
17052
17053 ;// CONCATENATED MODULE: ./node_modules/lib0/mutex.js
17054 /**
17055 * Mutual exclude for JavaScript.
17056 *
17057 * @module mutex
17058 */
17059
17060 /**
17061 * @callback mutex
17062 * @param {function():void} cb Only executed when this mutex is not in the current stack
17063 * @param {function():void} [elseCb] Executed when this mutex is in the current stack
17064 */
17065
17066 /**
17067 * Creates a mutual exclude function with the following property:
17068 *
17069 * ```js
17070 * const mutex = createMutex()
17071 * mutex(() => {
17072 * // This function is immediately executed
17073 * mutex(() => {
17074 * // This function is not executed, as the mutex is already active.
17075 * })
17076 * })
17077 * ```
17078 *
17079 * @return {mutex} A mutual exclude function
17080 * @public
17081 */
17082 const createMutex = () => {
17083 let token = true
17084 return (f, g) => {
17085 if (token) {
17086 token = false
17087 try {
17088 f()
17089 } finally {
17090 token = true
17091 }
17092 } else if (g !== undefined) {
17093 g()
17094 }
17095 }
17096 }
17097
17098 // EXTERNAL MODULE: ./node_modules/simple-peer/simplepeer.min.js
17099 var simplepeer_min = __webpack_require__(2248);
17100 var simplepeer_min_default = /*#__PURE__*/__webpack_require__.n(simplepeer_min);
17101 ;// CONCATENATED MODULE: ./node_modules/y-protocols/sync.js
17102 /**
17103 * @module sync-protocol
17104 */
17105
17106
17107
17108
17109
17110 /**
17111 * @typedef {Map<number, number>} StateMap
17112 */
17113
17114 /**
17115 * Core Yjs defines two message types:
17116 * • YjsSyncStep1: Includes the State Set of the sending client. When received, the client should reply with YjsSyncStep2.
17117 * • YjsSyncStep2: Includes all missing structs and the complete delete set. When received, the client is assured that it
17118 * received all information from the remote client.
17119 *
17120 * In a peer-to-peer network, you may want to introduce a SyncDone message type. Both parties should initiate the connection
17121 * with SyncStep1. When a client received SyncStep2, it should reply with SyncDone. When the local client received both
17122 * SyncStep2 and SyncDone, it is assured that it is synced to the remote client.
17123 *
17124 * In a client-server model, you want to handle this differently: The client should initiate the connection with SyncStep1.
17125 * When the server receives SyncStep1, it should reply with SyncStep2 immediately followed by SyncStep1. The client replies
17126 * with SyncStep2 when it receives SyncStep1. Optionally the server may send a SyncDone after it received SyncStep2, so the
17127 * client knows that the sync is finished. There are two reasons for this more elaborated sync model: 1. This protocol can
17128 * easily be implemented on top of http and websockets. 2. The server shoul only reply to requests, and not initiate them.
17129 * Therefore it is necesarry that the client initiates the sync.
17130 *
17131 * Construction of a message:
17132 * [messageType : varUint, message definition..]
17133 *
17134 * Note: A message does not include information about the room name. This must to be handled by the upper layer protocol!
17135 *
17136 * stringify[messageType] stringifies a message definition (messageType is already read from the bufffer)
17137 */
17138
17139 const messageYjsSyncStep1 = 0
17140 const messageYjsSyncStep2 = 1
17141 const messageYjsUpdate = 2
17142
17143 /**
17144 * Create a sync step 1 message based on the state of the current shared document.
17145 *
17146 * @param {encoding.Encoder} encoder
17147 * @param {Y.Doc} doc
17148 */
17149 const writeSyncStep1 = (encoder, doc) => {
17150 writeVarUint(encoder, messageYjsSyncStep1)
17151 const sv = encodeStateVector(doc)
17152 writeVarUint8Array(encoder, sv)
17153 }
17154
17155 /**
17156 * @param {encoding.Encoder} encoder
17157 * @param {Y.Doc} doc
17158 * @param {Uint8Array} [encodedStateVector]
17159 */
17160 const writeSyncStep2 = (encoder, doc, encodedStateVector) => {
17161 writeVarUint(encoder, messageYjsSyncStep2)
17162 writeVarUint8Array(encoder, encodeStateAsUpdate(doc, encodedStateVector))
17163 }
17164
17165 /**
17166 * Read SyncStep1 message and reply with SyncStep2.
17167 *
17168 * @param {decoding.Decoder} decoder The reply to the received message
17169 * @param {encoding.Encoder} encoder The received message
17170 * @param {Y.Doc} doc
17171 */
17172 const readSyncStep1 = (decoder, encoder, doc) =>
17173 writeSyncStep2(encoder, doc, readVarUint8Array(decoder))
17174
17175 /**
17176 * Read and apply Structs and then DeleteStore to a y instance.
17177 *
17178 * @param {decoding.Decoder} decoder
17179 * @param {Y.Doc} doc
17180 * @param {any} transactionOrigin
17181 */
17182 const readSyncStep2 = (decoder, doc, transactionOrigin) => {
17183 try {
17184 applyUpdate(doc, readVarUint8Array(decoder), transactionOrigin)
17185 } catch (error) {
17186 // This catches errors that are thrown by event handlers
17187 console.error('Caught error while handling a Yjs update', error)
17188 }
17189 }
17190
17191 /**
17192 * @param {encoding.Encoder} encoder
17193 * @param {Uint8Array} update
17194 */
17195 const writeUpdate = (encoder, update) => {
17196 writeVarUint(encoder, messageYjsUpdate)
17197 writeVarUint8Array(encoder, update)
17198 }
17199
17200 /**
17201 * Read and apply Structs and then DeleteStore to a y instance.
17202 *
17203 * @param {decoding.Decoder} decoder
17204 * @param {Y.Doc} doc
17205 * @param {any} transactionOrigin
17206 */
17207 const sync_readUpdate = readSyncStep2
17208
17209 /**
17210 * @param {decoding.Decoder} decoder A message received from another client
17211 * @param {encoding.Encoder} encoder The reply message. Will not be sent if empty.
17212 * @param {Y.Doc} doc
17213 * @param {any} transactionOrigin
17214 */
17215 const readSyncMessage = (decoder, encoder, doc, transactionOrigin) => {
17216 const messageType = readVarUint(decoder)
17217 switch (messageType) {
17218 case messageYjsSyncStep1:
17219 readSyncStep1(decoder, encoder, doc)
17220 break
17221 case messageYjsSyncStep2:
17222 readSyncStep2(decoder, doc, transactionOrigin)
17223 break
17224 case messageYjsUpdate:
17225 sync_readUpdate(decoder, doc, transactionOrigin)
17226 break
17227 default:
17228 throw new Error('Unknown message type')
17229 }
17230 return messageType
17231 }
17232
17233 ;// CONCATENATED MODULE: ./node_modules/y-protocols/awareness.js
17234 /**
17235 * @module awareness-protocol
17236 */
17237
17238
17239
17240
17241
17242
17243
17244 // eslint-disable-line
17245
17246 const outdatedTimeout = 30000
17247
17248 /**
17249 * @typedef {Object} MetaClientState
17250 * @property {number} MetaClientState.clock
17251 * @property {number} MetaClientState.lastUpdated unix timestamp
17252 */
17253
17254 /**
17255 * The Awareness class implements a simple shared state protocol that can be used for non-persistent data like awareness information
17256 * (cursor, username, status, ..). Each client can update its own local state and listen to state changes of
17257 * remote clients. Every client may set a state of a remote peer to `null` to mark the client as offline.
17258 *
17259 * Each client is identified by a unique client id (something we borrow from `doc.clientID`). A client can override
17260 * its own state by propagating a message with an increasing timestamp (`clock`). If such a message is received, it is
17261 * applied if the known state of that client is older than the new state (`clock < newClock`). If a client thinks that
17262 * a remote client is offline, it may propagate a message with
17263 * `{ clock: currentClientClock, state: null, client: remoteClient }`. If such a
17264 * message is received, and the known clock of that client equals the received clock, it will override the state with `null`.
17265 *
17266 * Before a client disconnects, it should propagate a `null` state with an updated clock.
17267 *
17268 * Awareness states must be updated every 30 seconds. Otherwise the Awareness instance will delete the client state.
17269 *
17270 * @extends {Observable<string>}
17271 */
17272 class Awareness extends observable_Observable {
17273 /**
17274 * @param {Y.Doc} doc
17275 */
17276 constructor (doc) {
17277 super()
17278 this.doc = doc
17279 /**
17280 * @type {number}
17281 */
17282 this.clientID = doc.clientID
17283 /**
17284 * Maps from client id to client state
17285 * @type {Map<number, Object<string, any>>}
17286 */
17287 this.states = new Map()
17288 /**
17289 * @type {Map<number, MetaClientState>}
17290 */
17291 this.meta = new Map()
17292 this._checkInterval = /** @type {any} */ (setInterval(() => {
17293 const now = getUnixTime()
17294 if (this.getLocalState() !== null && (outdatedTimeout / 2 <= now - /** @type {{lastUpdated:number}} */ (this.meta.get(this.clientID)).lastUpdated)) {
17295 // renew local clock
17296 this.setLocalState(this.getLocalState())
17297 }
17298 /**
17299 * @type {Array<number>}
17300 */
17301 const remove = []
17302 this.meta.forEach((meta, clientid) => {
17303 if (clientid !== this.clientID && outdatedTimeout <= now - meta.lastUpdated && this.states.has(clientid)) {
17304 remove.push(clientid)
17305 }
17306 })
17307 if (remove.length > 0) {
17308 removeAwarenessStates(this, remove, 'timeout')
17309 }
17310 }, floor(outdatedTimeout / 10)))
17311 doc.on('destroy', () => {
17312 this.destroy()
17313 })
17314 this.setLocalState({})
17315 }
17316
17317 destroy () {
17318 this.emit('destroy', [this])
17319 this.setLocalState(null)
17320 super.destroy()
17321 clearInterval(this._checkInterval)
17322 }
17323
17324 /**
17325 * @return {Object<string,any>|null}
17326 */
17327 getLocalState () {
17328 return this.states.get(this.clientID) || null
17329 }
17330
17331 /**
17332 * @param {Object<string,any>|null} state
17333 */
17334 setLocalState (state) {
17335 const clientID = this.clientID
17336 const currLocalMeta = this.meta.get(clientID)
17337 const clock = currLocalMeta === undefined ? 0 : currLocalMeta.clock + 1
17338 const prevState = this.states.get(clientID)
17339 if (state === null) {
17340 this.states.delete(clientID)
17341 } else {
17342 this.states.set(clientID, state)
17343 }
17344 this.meta.set(clientID, {
17345 clock,
17346 lastUpdated: getUnixTime()
17347 })
17348 const added = []
17349 const updated = []
17350 const filteredUpdated = []
17351 const removed = []
17352 if (state === null) {
17353 removed.push(clientID)
17354 } else if (prevState == null) {
17355 if (state != null) {
17356 added.push(clientID)
17357 }
17358 } else {
17359 updated.push(clientID)
17360 if (!equalityDeep(prevState, state)) {
17361 filteredUpdated.push(clientID)
17362 }
17363 }
17364 if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
17365 this.emit('change', [{ added, updated: filteredUpdated, removed }, 'local'])
17366 }
17367 this.emit('update', [{ added, updated, removed }, 'local'])
17368 }
17369
17370 /**
17371 * @param {string} field
17372 * @param {any} value
17373 */
17374 setLocalStateField (field, value) {
17375 const state = this.getLocalState()
17376 if (state !== null) {
17377 this.setLocalState({
17378 ...state,
17379 [field]: value
17380 })
17381 }
17382 }
17383
17384 /**
17385 * @return {Map<number,Object<string,any>>}
17386 */
17387 getStates () {
17388 return this.states
17389 }
17390 }
17391
17392 /**
17393 * Mark (remote) clients as inactive and remove them from the list of active peers.
17394 * This change will be propagated to remote clients.
17395 *
17396 * @param {Awareness} awareness
17397 * @param {Array<number>} clients
17398 * @param {any} origin
17399 */
17400 const removeAwarenessStates = (awareness, clients, origin) => {
17401 const removed = []
17402 for (let i = 0; i < clients.length; i++) {
17403 const clientID = clients[i]
17404 if (awareness.states.has(clientID)) {
17405 awareness.states.delete(clientID)
17406 if (clientID === awareness.clientID) {
17407 const curMeta = /** @type {MetaClientState} */ (awareness.meta.get(clientID))
17408 awareness.meta.set(clientID, {
17409 clock: curMeta.clock + 1,
17410 lastUpdated: getUnixTime()
17411 })
17412 }
17413 removed.push(clientID)
17414 }
17415 }
17416 if (removed.length > 0) {
17417 awareness.emit('change', [{ added: [], updated: [], removed }, origin])
17418 awareness.emit('update', [{ added: [], updated: [], removed }, origin])
17419 }
17420 }
17421
17422 /**
17423 * @param {Awareness} awareness
17424 * @param {Array<number>} clients
17425 * @return {Uint8Array}
17426 */
17427 const encodeAwarenessUpdate = (awareness, clients, states = awareness.states) => {
17428 const len = clients.length
17429 const encoder = createEncoder()
17430 writeVarUint(encoder, len)
17431 for (let i = 0; i < len; i++) {
17432 const clientID = clients[i]
17433 const state = states.get(clientID) || null
17434 const clock = /** @type {MetaClientState} */ (awareness.meta.get(clientID)).clock
17435 writeVarUint(encoder, clientID)
17436 writeVarUint(encoder, clock)
17437 writeVarString(encoder, JSON.stringify(state))
17438 }
17439 return toUint8Array(encoder)
17440 }
17441
17442 /**
17443 * Modify the content of an awareness update before re-encoding it to an awareness update.
17444 *
17445 * This might be useful when you have a central server that wants to ensure that clients
17446 * cant hijack somebody elses identity.
17447 *
17448 * @param {Uint8Array} update
17449 * @param {function(any):any} modify
17450 * @return {Uint8Array}
17451 */
17452 const modifyAwarenessUpdate = (update, modify) => {
17453 const decoder = decoding.createDecoder(update)
17454 const encoder = encoding.createEncoder()
17455 const len = decoding.readVarUint(decoder)
17456 encoding.writeVarUint(encoder, len)
17457 for (let i = 0; i < len; i++) {
17458 const clientID = decoding.readVarUint(decoder)
17459 const clock = decoding.readVarUint(decoder)
17460 const state = JSON.parse(decoding.readVarString(decoder))
17461 const modifiedState = modify(state)
17462 encoding.writeVarUint(encoder, clientID)
17463 encoding.writeVarUint(encoder, clock)
17464 encoding.writeVarString(encoder, JSON.stringify(modifiedState))
17465 }
17466 return encoding.toUint8Array(encoder)
17467 }
17468
17469 /**
17470 * @param {Awareness} awareness
17471 * @param {Uint8Array} update
17472 * @param {any} origin This will be added to the emitted change event
17473 */
17474 const applyAwarenessUpdate = (awareness, update, origin) => {
17475 const decoder = createDecoder(update)
17476 const timestamp = getUnixTime()
17477 const added = []
17478 const updated = []
17479 const filteredUpdated = []
17480 const removed = []
17481 const len = readVarUint(decoder)
17482 for (let i = 0; i < len; i++) {
17483 const clientID = readVarUint(decoder)
17484 let clock = readVarUint(decoder)
17485 const state = JSON.parse(readVarString(decoder))
17486 const clientMeta = awareness.meta.get(clientID)
17487 const prevState = awareness.states.get(clientID)
17488 const currClock = clientMeta === undefined ? 0 : clientMeta.clock
17489 if (currClock < clock || (currClock === clock && state === null && awareness.states.has(clientID))) {
17490 if (state === null) {
17491 // never let a remote client remove this local state
17492 if (clientID === awareness.clientID && awareness.getLocalState() != null) {
17493 // remote client removed the local state. Do not remote state. Broadcast a message indicating
17494 // that this client still exists by increasing the clock
17495 clock++
17496 } else {
17497 awareness.states.delete(clientID)
17498 }
17499 } else {
17500 awareness.states.set(clientID, state)
17501 }
17502 awareness.meta.set(clientID, {
17503 clock,
17504 lastUpdated: timestamp
17505 })
17506 if (clientMeta === undefined && state !== null) {
17507 added.push(clientID)
17508 } else if (clientMeta !== undefined && state === null) {
17509 removed.push(clientID)
17510 } else if (state !== null) {
17511 if (!equalityDeep(state, prevState)) {
17512 filteredUpdated.push(clientID)
17513 }
17514 updated.push(clientID)
17515 }
17516 }
17517 }
17518 if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
17519 awareness.emit('change', [{
17520 added, updated: filteredUpdated, removed
17521 }, origin])
17522 }
17523 if (added.length > 0 || updated.length > 0 || removed.length > 0) {
17524 awareness.emit('update', [{
17525 added, updated, removed
17526 }, origin])
17527 }
17528 }
17529
17530 ;// CONCATENATED MODULE: ./packages/sync/build-module/y-webrtc/crypto.js
17531 // File copied as is from the y-webrtc package.
17532 /* eslint-disable eslint-comments/disable-enable-pair */
17533 /* eslint-disable eslint-comments/no-unlimited-disable */
17534 /* eslint-disable */
17535 // @ts-nocheck
17536 /* eslint-env browser */
17537
17538
17539
17540
17541
17542
17543
17544 /**
17545 * @param {string} secret
17546 * @param {string} roomName
17547 * @return {PromiseLike<CryptoKey>}
17548 */
17549 const deriveKey = (secret, roomName) => {
17550 const secretBuffer = encodeUtf8(secret).buffer;
17551 const salt = encodeUtf8(roomName).buffer;
17552 return crypto.subtle.importKey('raw', secretBuffer, 'PBKDF2', false, ['deriveKey']).then(keyMaterial => crypto.subtle.deriveKey({
17553 name: 'PBKDF2',
17554 salt,
17555 iterations: 100000,
17556 hash: 'SHA-256'
17557 }, keyMaterial, {
17558 name: 'AES-GCM',
17559 length: 256
17560 }, true, ['encrypt', 'decrypt']));
17561 };
17562
17563 /**
17564 * @param {Uint8Array} data data to be encrypted
17565 * @param {CryptoKey?} key
17566 * @return {PromiseLike<Uint8Array>} encrypted, base64 encoded message
17567 */
17568 const encrypt = (data, key) => {
17569 if (!key) {
17570 return /** @type {PromiseLike<Uint8Array>} */(
17571 resolve(data)
17572 );
17573 }
17574 const iv = crypto.getRandomValues(new Uint8Array(12));
17575 return crypto.subtle.encrypt({
17576 name: 'AES-GCM',
17577 iv
17578 }, key, data).then(cipher => {
17579 const encryptedDataEncoder = createEncoder();
17580 writeVarString(encryptedDataEncoder, 'AES-GCM');
17581 writeVarUint8Array(encryptedDataEncoder, iv);
17582 writeVarUint8Array(encryptedDataEncoder, new Uint8Array(cipher));
17583 return toUint8Array(encryptedDataEncoder);
17584 });
17585 };
17586
17587 /**
17588 * @param {Object} data data to be encrypted
17589 * @param {CryptoKey?} key
17590 * @return {PromiseLike<Uint8Array>} encrypted data, if key is provided
17591 */
17592 const encryptJson = (data, key) => {
17593 const dataEncoder = createEncoder();
17594 writeAny(dataEncoder, data);
17595 return encrypt(toUint8Array(dataEncoder), key);
17596 };
17597
17598 /**
17599 * @param {Uint8Array} data
17600 * @param {CryptoKey?} key
17601 * @return {PromiseLike<Uint8Array>} decrypted buffer
17602 */
17603 const decrypt = (data, key) => {
17604 if (!key) {
17605 return /** @type {PromiseLike<Uint8Array>} */(
17606 resolve(data)
17607 );
17608 }
17609 const dataDecoder = createDecoder(data);
17610 const algorithm = readVarString(dataDecoder);
17611 if (algorithm !== 'AES-GCM') {
17612 reject(error_create('Unknown encryption algorithm'));
17613 }
17614 const iv = readVarUint8Array(dataDecoder);
17615 const cipher = readVarUint8Array(dataDecoder);
17616 return crypto.subtle.decrypt({
17617 name: 'AES-GCM',
17618 iv
17619 }, key, cipher).then(data => new Uint8Array(data));
17620 };
17621
17622 /**
17623 * @param {Uint8Array} data
17624 * @param {CryptoKey?} key
17625 * @return {PromiseLike<Object>} decrypted object
17626 */
17627 const decryptJson = (data, key) => decrypt(data, key).then(decryptedValue => readAny(createDecoder(new Uint8Array(decryptedValue))));
17628
17629 ;// CONCATENATED MODULE: ./packages/sync/build-module/y-webrtc/y-webrtc.js
17630 // File copied as is from the y-webrtc package with only exports
17631 // added to the following vars/functions: signalingConns,rooms, publishSignalingMessage, log.
17632 /* eslint-disable eslint-comments/disable-enable-pair */
17633 /* eslint-disable eslint-comments/no-unlimited-disable */
17634 /* eslint-disable */
17635 // @ts-nocheck
17636
17637
17638
17639
17640
17641
17642
17643
17644
17645
17646
17647
17648
17649
17650 // eslint-disable-line
17651
17652
17653
17654
17655 const y_webrtc_log = logging_createModuleLogger('y-webrtc');
17656 const messageSync = 0;
17657 const messageQueryAwareness = 3;
17658 const messageAwareness = 1;
17659 const messageBcPeerId = 4;
17660
17661 /**
17662 * @type {Map<string, SignalingConn>}
17663 */
17664 const signalingConns = new Map();
17665
17666 /**
17667 * @type {Map<string,Room>}
17668 */
17669 const rooms = new Map();
17670
17671 /**
17672 * @param {Room} room
17673 */
17674 const checkIsSynced = room => {
17675 let synced = true;
17676 room.webrtcConns.forEach(peer => {
17677 if (!peer.synced) {
17678 synced = false;
17679 }
17680 });
17681 if (!synced && room.synced || synced && !room.synced) {
17682 room.synced = synced;
17683 room.provider.emit('synced', [{
17684 synced
17685 }]);
17686 y_webrtc_log('synced ', BOLD, room.name, UNBOLD, ' with all peers');
17687 }
17688 };
17689
17690 /**
17691 * @param {Room} room
17692 * @param {Uint8Array} buf
17693 * @param {function} syncedCallback
17694 * @return {encoding.Encoder?}
17695 */
17696 const readMessage = (room, buf, syncedCallback) => {
17697 const decoder = createDecoder(buf);
17698 const encoder = createEncoder();
17699 const messageType = readVarUint(decoder);
17700 if (room === undefined) {
17701 return null;
17702 }
17703 const awareness = room.awareness;
17704 const doc = room.doc;
17705 let sendReply = false;
17706 switch (messageType) {
17707 case messageSync:
17708 {
17709 writeVarUint(encoder, messageSync);
17710 const syncMessageType = readSyncMessage(decoder, encoder, doc, room);
17711 if (syncMessageType === messageYjsSyncStep2 && !room.synced) {
17712 syncedCallback();
17713 }
17714 if (syncMessageType === messageYjsSyncStep1) {
17715 sendReply = true;
17716 }
17717 break;
17718 }
17719 case messageQueryAwareness:
17720 writeVarUint(encoder, messageAwareness);
17721 writeVarUint8Array(encoder, encodeAwarenessUpdate(awareness, Array.from(awareness.getStates().keys())));
17722 sendReply = true;
17723 break;
17724 case messageAwareness:
17725 applyAwarenessUpdate(awareness, readVarUint8Array(decoder), room);
17726 break;
17727 case messageBcPeerId:
17728 {
17729 const add = readUint8(decoder) === 1;
17730 const peerName = readVarString(decoder);
17731 if (peerName !== room.peerId && (room.bcConns.has(peerName) && !add || !room.bcConns.has(peerName) && add)) {
17732 const removed = [];
17733 const added = [];
17734 if (add) {
17735 room.bcConns.add(peerName);
17736 added.push(peerName);
17737 } else {
17738 room.bcConns.delete(peerName);
17739 removed.push(peerName);
17740 }
17741 room.provider.emit('peers', [{
17742 added,
17743 removed,
17744 webrtcPeers: Array.from(room.webrtcConns.keys()),
17745 bcPeers: Array.from(room.bcConns)
17746 }]);
17747 broadcastBcPeerId(room);
17748 }
17749 break;
17750 }
17751 default:
17752 console.error('Unable to compute message');
17753 return encoder;
17754 }
17755 if (!sendReply) {
17756 // nothing has been written, no answer created
17757 return null;
17758 }
17759 return encoder;
17760 };
17761
17762 /**
17763 * @param {WebrtcConn} peerConn
17764 * @param {Uint8Array} buf
17765 * @return {encoding.Encoder?}
17766 */
17767 const readPeerMessage = (peerConn, buf) => {
17768 const room = peerConn.room;
17769 y_webrtc_log('received message from ', BOLD, peerConn.remotePeerId, GREY, ' (', room.name, ')', UNBOLD, UNCOLOR);
17770 return readMessage(room, buf, () => {
17771 peerConn.synced = true;
17772 y_webrtc_log('synced ', BOLD, room.name, UNBOLD, ' with ', BOLD, peerConn.remotePeerId);
17773 checkIsSynced(room);
17774 });
17775 };
17776
17777 /**
17778 * @param {WebrtcConn} webrtcConn
17779 * @param {encoding.Encoder} encoder
17780 */
17781 const sendWebrtcConn = (webrtcConn, encoder) => {
17782 y_webrtc_log('send message to ', BOLD, webrtcConn.remotePeerId, UNBOLD, GREY, ' (', webrtcConn.room.name, ')', UNCOLOR);
17783 try {
17784 webrtcConn.peer.send(toUint8Array(encoder));
17785 } catch (e) {}
17786 };
17787
17788 /**
17789 * @param {Room} room
17790 * @param {Uint8Array} m
17791 */
17792 const broadcastWebrtcConn = (room, m) => {
17793 y_webrtc_log('broadcast message in ', BOLD, room.name, UNBOLD);
17794 room.webrtcConns.forEach(conn => {
17795 try {
17796 conn.peer.send(m);
17797 } catch (e) {}
17798 });
17799 };
17800 class WebrtcConn {
17801 /**
17802 * @param {SignalingConn} signalingConn
17803 * @param {boolean} initiator
17804 * @param {string} remotePeerId
17805 * @param {Room} room
17806 */
17807 constructor(signalingConn, initiator, remotePeerId, room) {
17808 y_webrtc_log('establishing connection to ', BOLD, remotePeerId);
17809 this.room = room;
17810 this.remotePeerId = remotePeerId;
17811 this.glareToken = undefined;
17812 this.closed = false;
17813 this.connected = false;
17814 this.synced = false;
17815 /**
17816 * @type {any}
17817 */
17818 this.peer = new (simplepeer_min_default())({
17819 initiator,
17820 ...room.provider.peerOpts
17821 });
17822 this.peer.on('signal', signal => {
17823 if (this.glareToken === undefined) {
17824 // add some randomness to the timestamp of the offer
17825 this.glareToken = Date.now() + Math.random();
17826 }
17827 publishSignalingMessage(signalingConn, room, {
17828 to: remotePeerId,
17829 from: room.peerId,
17830 type: 'signal',
17831 token: this.glareToken,
17832 signal
17833 });
17834 });
17835 this.peer.on('connect', () => {
17836 y_webrtc_log('connected to ', BOLD, remotePeerId);
17837 this.connected = true;
17838 // send sync step 1
17839 const provider = room.provider;
17840 const doc = provider.doc;
17841 const awareness = room.awareness;
17842 const encoder = createEncoder();
17843 writeVarUint(encoder, messageSync);
17844 writeSyncStep1(encoder, doc);
17845 sendWebrtcConn(this, encoder);
17846 const awarenessStates = awareness.getStates();
17847 if (awarenessStates.size > 0) {
17848 const encoder = createEncoder();
17849 writeVarUint(encoder, messageAwareness);
17850 writeVarUint8Array(encoder, encodeAwarenessUpdate(awareness, Array.from(awarenessStates.keys())));
17851 sendWebrtcConn(this, encoder);
17852 }
17853 });
17854 this.peer.on('close', () => {
17855 this.connected = false;
17856 this.closed = true;
17857 if (room.webrtcConns.has(this.remotePeerId)) {
17858 room.webrtcConns.delete(this.remotePeerId);
17859 room.provider.emit('peers', [{
17860 removed: [this.remotePeerId],
17861 added: [],
17862 webrtcPeers: Array.from(room.webrtcConns.keys()),
17863 bcPeers: Array.from(room.bcConns)
17864 }]);
17865 }
17866 checkIsSynced(room);
17867 this.peer.destroy();
17868 y_webrtc_log('closed connection to ', BOLD, remotePeerId);
17869 announceSignalingInfo(room);
17870 });
17871 this.peer.on('error', err => {
17872 y_webrtc_log('Error in connection to ', BOLD, remotePeerId, ': ', err);
17873 announceSignalingInfo(room);
17874 });
17875 this.peer.on('data', data => {
17876 const answer = readPeerMessage(this, data);
17877 if (answer !== null) {
17878 sendWebrtcConn(this, answer);
17879 }
17880 });
17881 }
17882 destroy() {
17883 this.peer.destroy();
17884 }
17885 }
17886
17887 /**
17888 * @param {Room} room
17889 * @param {Uint8Array} m
17890 */
17891 const broadcastBcMessage = (room, m) => encrypt(m, room.key).then(data => room.mux(() => publish(room.name, data)));
17892
17893 /**
17894 * @param {Room} room
17895 * @param {Uint8Array} m
17896 */
17897 const broadcastRoomMessage = (room, m) => {
17898 if (room.bcconnected) {
17899 broadcastBcMessage(room, m);
17900 }
17901 broadcastWebrtcConn(room, m);
17902 };
17903
17904 /**
17905 * @param {Room} room
17906 */
17907 const announceSignalingInfo = room => {
17908 signalingConns.forEach(conn => {
17909 // only subscribe if connection is established, otherwise the conn automatically subscribes to all rooms
17910 if (conn.connected) {
17911 conn.send({
17912 type: 'subscribe',
17913 topics: [room.name]
17914 });
17915 if (room.webrtcConns.size < room.provider.maxConns) {
17916 publishSignalingMessage(conn, room, {
17917 type: 'announce',
17918 from: room.peerId
17919 });
17920 }
17921 }
17922 });
17923 };
17924
17925 /**
17926 * @param {Room} room
17927 */
17928 const broadcastBcPeerId = room => {
17929 if (room.provider.filterBcConns) {
17930 // broadcast peerId via broadcastchannel
17931 const encoderPeerIdBc = createEncoder();
17932 writeVarUint(encoderPeerIdBc, messageBcPeerId);
17933 writeUint8(encoderPeerIdBc, 1);
17934 writeVarString(encoderPeerIdBc, room.peerId);
17935 broadcastBcMessage(room, toUint8Array(encoderPeerIdBc));
17936 }
17937 };
17938 class Room {
17939 /**
17940 * @param {Y.Doc} doc
17941 * @param {WebrtcProvider} provider
17942 * @param {string} name
17943 * @param {CryptoKey|null} key
17944 */
17945 constructor(doc, provider, name, key) {
17946 /**
17947 * Do not assume that peerId is unique. This is only meant for sending signaling messages.
17948 *
17949 * @type {string}
17950 */
17951 this.peerId = uuidv4();
17952 this.doc = doc;
17953 /**
17954 * @type {awarenessProtocol.Awareness}
17955 */
17956 this.awareness = provider.awareness;
17957 this.provider = provider;
17958 this.synced = false;
17959 this.name = name;
17960 // @todo make key secret by scoping
17961 this.key = key;
17962 /**
17963 * @type {Map<string, WebrtcConn>}
17964 */
17965 this.webrtcConns = new Map();
17966 /**
17967 * @type {Set<string>}
17968 */
17969 this.bcConns = new Set();
17970 this.mux = createMutex();
17971 this.bcconnected = false;
17972 /**
17973 * @param {ArrayBuffer} data
17974 */
17975 this._bcSubscriber = data => decrypt(new Uint8Array(data), key).then(m => this.mux(() => {
17976 const reply = readMessage(this, m, () => {});
17977 if (reply) {
17978 broadcastBcMessage(this, toUint8Array(reply));
17979 }
17980 }));
17981 /**
17982 * Listens to Yjs updates and sends them to remote peers
17983 *
17984 * @param {Uint8Array} update
17985 * @param {any} origin
17986 */
17987 this._docUpdateHandler = (update, origin) => {
17988 const encoder = createEncoder();
17989 writeVarUint(encoder, messageSync);
17990 writeUpdate(encoder, update);
17991 broadcastRoomMessage(this, toUint8Array(encoder));
17992 };
17993 /**
17994 * Listens to Awareness updates and sends them to remote peers
17995 *
17996 * @param {any} changed
17997 * @param {any} origin
17998 */
17999 this._awarenessUpdateHandler = ({
18000 added,
18001 updated,
18002 removed
18003 }, origin) => {
18004 const changedClients = added.concat(updated).concat(removed);
18005 const encoderAwareness = createEncoder();
18006 writeVarUint(encoderAwareness, messageAwareness);
18007 writeVarUint8Array(encoderAwareness, encodeAwarenessUpdate(this.awareness, changedClients));
18008 broadcastRoomMessage(this, toUint8Array(encoderAwareness));
18009 };
18010 this._beforeUnloadHandler = () => {
18011 removeAwarenessStates(this.awareness, [doc.clientID], 'window unload');
18012 rooms.forEach(room => {
18013 room.disconnect();
18014 });
18015 };
18016 if (typeof window !== 'undefined') {
18017 window.addEventListener('beforeunload', this._beforeUnloadHandler);
18018 } else if (typeof process !== 'undefined') {
18019 process.on('exit', this._beforeUnloadHandler);
18020 }
18021 }
18022 connect() {
18023 this.doc.on('update', this._docUpdateHandler);
18024 this.awareness.on('update', this._awarenessUpdateHandler);
18025 // signal through all available signaling connections
18026 announceSignalingInfo(this);
18027 const roomName = this.name;
18028 subscribe(roomName, this._bcSubscriber);
18029 this.bcconnected = true;
18030 // broadcast peerId via broadcastchannel
18031 broadcastBcPeerId(this);
18032 // write sync step 1
18033 const encoderSync = createEncoder();
18034 writeVarUint(encoderSync, messageSync);
18035 writeSyncStep1(encoderSync, this.doc);
18036 broadcastBcMessage(this, toUint8Array(encoderSync));
18037 // broadcast local state
18038 const encoderState = createEncoder();
18039 writeVarUint(encoderState, messageSync);
18040 writeSyncStep2(encoderState, this.doc);
18041 broadcastBcMessage(this, toUint8Array(encoderState));
18042 // write queryAwareness
18043 const encoderAwarenessQuery = createEncoder();
18044 writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
18045 broadcastBcMessage(this, toUint8Array(encoderAwarenessQuery));
18046 // broadcast local awareness state
18047 const encoderAwarenessState = createEncoder();
18048 writeVarUint(encoderAwarenessState, messageAwareness);
18049 writeVarUint8Array(encoderAwarenessState, encodeAwarenessUpdate(this.awareness, [this.doc.clientID]));
18050 broadcastBcMessage(this, toUint8Array(encoderAwarenessState));
18051 }
18052 disconnect() {
18053 // signal through all available signaling connections
18054 signalingConns.forEach(conn => {
18055 if (conn.connected) {
18056 conn.send({
18057 type: 'unsubscribe',
18058 topics: [this.name]
18059 });
18060 }
18061 });
18062 removeAwarenessStates(this.awareness, [this.doc.clientID], 'disconnect');
18063 // broadcast peerId removal via broadcastchannel
18064 const encoderPeerIdBc = createEncoder();
18065 writeVarUint(encoderPeerIdBc, messageBcPeerId);
18066 writeUint8(encoderPeerIdBc, 0); // remove peerId from other bc peers
18067 writeVarString(encoderPeerIdBc, this.peerId);
18068 broadcastBcMessage(this, toUint8Array(encoderPeerIdBc));
18069 unsubscribe(this.name, this._bcSubscriber);
18070 this.bcconnected = false;
18071 this.doc.off('update', this._docUpdateHandler);
18072 this.awareness.off('update', this._awarenessUpdateHandler);
18073 this.webrtcConns.forEach(conn => conn.destroy());
18074 }
18075 destroy() {
18076 this.disconnect();
18077 if (typeof window !== 'undefined') {
18078 window.removeEventListener('beforeunload', this._beforeUnloadHandler);
18079 } else if (typeof process !== 'undefined') {
18080 process.off('exit', this._beforeUnloadHandler);
18081 }
18082 }
18083 }
18084
18085 /**
18086 * @param {Y.Doc} doc
18087 * @param {WebrtcProvider} provider
18088 * @param {string} name
18089 * @param {CryptoKey|null} key
18090 * @return {Room}
18091 */
18092 const openRoom = (doc, provider, name, key) => {
18093 // there must only be one room
18094 if (rooms.has(name)) {
18095 throw error_create(`A Yjs Doc connected to room "${name}" already exists!`);
18096 }
18097 const room = new Room(doc, provider, name, key);
18098 rooms.set(name, /** @type {Room} */room);
18099 return room;
18100 };
18101
18102 /**
18103 * @param {SignalingConn} conn
18104 * @param {Room} room
18105 * @param {any} data
18106 */
18107 const publishSignalingMessage = (conn, room, data) => {
18108 if (room.key) {
18109 encryptJson(data, room.key).then(data => {
18110 conn.send({
18111 type: 'publish',
18112 topic: room.name,
18113 data: toBase64(data)
18114 });
18115 });
18116 } else {
18117 conn.send({
18118 type: 'publish',
18119 topic: room.name,
18120 data
18121 });
18122 }
18123 };
18124 class SignalingConn extends WebsocketClient {
18125 constructor(url) {
18126 super(url);
18127 /**
18128 * @type {Set<WebrtcProvider>}
18129 */
18130 this.providers = new Set();
18131 this.on('connect', () => {
18132 y_webrtc_log(`connected (${url})`);
18133 const topics = Array.from(rooms.keys());
18134 this.send({
18135 type: 'subscribe',
18136 topics
18137 });
18138 rooms.forEach(room => publishSignalingMessage(this, room, {
18139 type: 'announce',
18140 from: room.peerId
18141 }));
18142 });
18143 this.on('message', m => {
18144 switch (m.type) {
18145 case 'publish':
18146 {
18147 const roomName = m.topic;
18148 const room = rooms.get(roomName);
18149 if (room == null || typeof roomName !== 'string') {
18150 return;
18151 }
18152 const execMessage = data => {
18153 const webrtcConns = room.webrtcConns;
18154 const peerId = room.peerId;
18155 if (data == null || data.from === peerId || data.to !== undefined && data.to !== peerId || room.bcConns.has(data.from)) {
18156 // ignore messages that are not addressed to this conn, or from clients that are connected via broadcastchannel
18157 return;
18158 }
18159 const emitPeerChange = webrtcConns.has(data.from) ? () => {} : () => room.provider.emit('peers', [{
18160 removed: [],
18161 added: [data.from],
18162 webrtcPeers: Array.from(room.webrtcConns.keys()),
18163 bcPeers: Array.from(room.bcConns)
18164 }]);
18165 switch (data.type) {
18166 case 'announce':
18167 if (webrtcConns.size < room.provider.maxConns) {
18168 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(this, true, data.from, room));
18169 emitPeerChange();
18170 }
18171 break;
18172 case 'signal':
18173 if (data.signal.type === 'offer') {
18174 const existingConn = webrtcConns.get(data.from);
18175 if (existingConn) {
18176 const remoteToken = data.token;
18177 const localToken = existingConn.glareToken;
18178 if (localToken && localToken > remoteToken) {
18179 y_webrtc_log('offer rejected: ', data.from);
18180 return;
18181 }
18182 // if we don't reject the offer, we will be accepting it and answering it
18183 existingConn.glareToken = undefined;
18184 }
18185 }
18186 if (data.signal.type === 'answer') {
18187 y_webrtc_log('offer answered by: ', data.from);
18188 const existingConn = webrtcConns.get(data.from);
18189 existingConn.glareToken = undefined;
18190 }
18191 if (data.to === peerId) {
18192 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(this, false, data.from, room)).peer.signal(data.signal);
18193 emitPeerChange();
18194 }
18195 break;
18196 }
18197 };
18198 if (room.key) {
18199 if (typeof m.data === 'string') {
18200 decryptJson(fromBase64(m.data), room.key).then(execMessage);
18201 }
18202 } else {
18203 execMessage(m.data);
18204 }
18205 }
18206 }
18207 });
18208 this.on('disconnect', () => y_webrtc_log(`disconnect (${url})`));
18209 }
18210 }
18211
18212 /**
18213 * @typedef {Object} ProviderOptions
18214 * @property {Array<string>} [signaling]
18215 * @property {string} [password]
18216 * @property {awarenessProtocol.Awareness} [awareness]
18217 * @property {number} [maxConns]
18218 * @property {boolean} [filterBcConns]
18219 * @property {any} [peerOpts]
18220 */
18221
18222 /**
18223 * @extends Observable<string>
18224 */
18225 class WebrtcProvider extends observable_Observable {
18226 /**
18227 * @param {string} roomName
18228 * @param {Y.Doc} doc
18229 * @param {ProviderOptions?} opts
18230 */
18231 constructor(roomName, doc, {
18232 signaling = ['wss://y-webrtc-eu.fly.dev'],
18233 password = null,
18234 awareness = new Awareness(doc),
18235 maxConns = 20 + floor(rand() * 15),
18236 // the random factor reduces the chance that n clients form a cluster
18237 filterBcConns = true,
18238 peerOpts = {} // simple-peer options. See https://github.com/feross/simple-peer#peer--new-peeropts
18239 } = {}) {
18240 super();
18241 this.roomName = roomName;
18242 this.doc = doc;
18243 this.filterBcConns = filterBcConns;
18244 /**
18245 * @type {awarenessProtocol.Awareness}
18246 */
18247 this.awareness = awareness;
18248 this.shouldConnect = false;
18249 this.signalingUrls = signaling;
18250 this.signalingConns = [];
18251 this.maxConns = maxConns;
18252 this.peerOpts = peerOpts;
18253 /**
18254 * @type {PromiseLike<CryptoKey | null>}
18255 */
18256 this.key = password ? deriveKey(password, roomName) : ( /** @type {PromiseLike<null>} */resolve(null));
18257 /**
18258 * @type {Room|null}
18259 */
18260 this.room = null;
18261 this.key.then(key => {
18262 this.room = openRoom(doc, this, roomName, key);
18263 if (this.shouldConnect) {
18264 this.room.connect();
18265 } else {
18266 this.room.disconnect();
18267 }
18268 });
18269 this.connect();
18270 this.destroy = this.destroy.bind(this);
18271 doc.on('destroy', this.destroy);
18272 }
18273
18274 /**
18275 * @type {boolean}
18276 */
18277 get connected() {
18278 return this.room !== null && this.shouldConnect;
18279 }
18280 connect() {
18281 this.shouldConnect = true;
18282 this.signalingUrls.forEach(url => {
18283 const signalingConn = setIfUndefined(signalingConns, url, () => new SignalingConn(url));
18284 this.signalingConns.push(signalingConn);
18285 signalingConn.providers.add(this);
18286 });
18287 if (this.room) {
18288 this.room.connect();
18289 }
18290 }
18291 disconnect() {
18292 this.shouldConnect = false;
18293 this.signalingConns.forEach(conn => {
18294 conn.providers.delete(this);
18295 if (conn.providers.size === 0) {
18296 conn.destroy();
18297 signalingConns.delete(conn.url);
18298 }
18299 });
18300 if (this.room) {
18301 this.room.disconnect();
18302 }
18303 }
18304 destroy() {
18305 this.doc.off('destroy', this.destroy);
18306 // need to wait for key before deleting room
18307 this.key.then(() => {
18308 /** @type {Room} */this.room.destroy();
18309 rooms.delete(this.roomName);
18310 });
18311 super.destroy();
18312 }
18313 }
18314
18315 ;// CONCATENATED MODULE: ./packages/sync/build-module/webrtc-http-stream-signaling.js
18316 /**
18317 * External dependencies
18318 */
18319 /**
18320 * Internal dependencies
18321 */
18322
18323
18324
18325
18326
18327
18328 /**
18329 * WordPress dependencies
18330 */
18331
18332
18333 /**
18334 * Method copied as is from the SignalingConn constructor.
18335 * Setups the needed event handlers for an http signaling connection.
18336 *
18337 * @param {HttpSignalingConn} signalCon The signaling connection.
18338 * @param {string} url The url.
18339 */
18340 function setupSignalEventHandlers(signalCon, url) {
18341 signalCon.on('connect', () => {
18342 y_webrtc_log(`connected (${url})`);
18343 const topics = Array.from(rooms.keys());
18344 signalCon.send({
18345 type: 'subscribe',
18346 topics
18347 });
18348 rooms.forEach(room => publishSignalingMessage(signalCon, room, {
18349 type: 'announce',
18350 from: room.peerId
18351 }));
18352 });
18353 signalCon.on('message', ( /** @type {{ type: any; topic: any; data: string; }} */m) => {
18354 switch (m.type) {
18355 case 'publish':
18356 {
18357 const roomName = m.topic;
18358 const room = rooms.get(roomName);
18359 if (room === null || typeof roomName !== 'string' || room === undefined) {
18360 return;
18361 }
18362 const execMessage = ( /** @type {any} */data) => {
18363 const webrtcConns = room.webrtcConns;
18364 const peerId = room.peerId;
18365 if (data === null || data.from === peerId || data.to !== undefined && data.to !== peerId || room.bcConns.has(data.from)) {
18366 // ignore messages that are not addressed to this conn, or from clients that are connected via broadcastchannel
18367 return;
18368 }
18369 const emitPeerChange = webrtcConns.has(data.from) ? () => {} : () => room.provider.emit('peers', [{
18370 removed: [],
18371 added: [data.from],
18372 webrtcPeers: Array.from(room.webrtcConns.keys()),
18373 bcPeers: Array.from(room.bcConns)
18374 }]);
18375 switch (data.type) {
18376 case 'announce':
18377 if (webrtcConns.size < room.provider.maxConns) {
18378 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(signalCon, true, data.from, room));
18379 emitPeerChange();
18380 }
18381 break;
18382 case 'signal':
18383 if (data.signal.type === 'offer') {
18384 const existingConn = webrtcConns.get(data.from);
18385 if (existingConn) {
18386 const remoteToken = data.token;
18387 const localToken = existingConn.glareToken;
18388 if (localToken && localToken > remoteToken) {
18389 y_webrtc_log('offer rejected: ', data.from);
18390 return;
18391 }
18392 // if we don't reject the offer, we will be accepting it and answering it
18393 existingConn.glareToken = undefined;
18394 }
18395 }
18396 if (data.signal.type === 'answer') {
18397 y_webrtc_log('offer answered by: ', data.from);
18398 const existingConn = webrtcConns.get(data.from);
18399 if (existingConn) {
18400 existingConn.glareToken = undefined;
18401 }
18402 }
18403 if (data.to === peerId) {
18404 setIfUndefined(webrtcConns, data.from, () => new WebrtcConn(signalCon, false, data.from, room)).peer.signal(data.signal);
18405 emitPeerChange();
18406 }
18407 break;
18408 }
18409 };
18410 if (room.key) {
18411 if (typeof m.data === 'string') {
18412 decryptJson(fromBase64(m.data), room.key).then(execMessage);
18413 }
18414 } else {
18415 execMessage(m.data);
18416 }
18417 }
18418 }
18419 });
18420 signalCon.on('disconnect', () => y_webrtc_log(`disconnect (${url})`));
18421 }
18422
18423 /**
18424 * Method that instantiates the http signaling connection.
18425 * Tries to implement the same methods a websocket provides using ajax requests
18426 * to send messages and EventSource to retrieve messages.
18427 *
18428 * @param {HttpSignalingConn} httpClient The signaling connection.
18429 */
18430 function setupHttpSignal(httpClient) {
18431 if (httpClient.shouldConnect && httpClient.ws === null) {
18432 // eslint-disable-next-line no-restricted-syntax
18433 const subscriberId = Math.floor(100000 + Math.random() * 900000);
18434 const url = httpClient.url;
18435 const eventSource = new window.EventSource((0,external_wp_url_namespaceObject.addQueryArgs)(url, {
18436 subscriber_id: subscriberId,
18437 action: 'gutenberg_signaling_server'
18438 }));
18439 /**
18440 * @type {any}
18441 */
18442 let pingTimeout = null;
18443 eventSource.onmessage = event => {
18444 httpClient.lastMessageReceived = Date.now();
18445 const data = event.data;
18446 if (data) {
18447 const messages = JSON.parse(data);
18448 if (Array.isArray(messages)) {
18449 messages.forEach(onSingleMessage);
18450 }
18451 }
18452 };
18453 // @ts-ignore
18454 httpClient.ws = eventSource;
18455 httpClient.connecting = true;
18456 httpClient.connected = false;
18457 const onSingleMessage = ( /** @type {any} */message) => {
18458 if (message && message.type === 'pong') {
18459 clearTimeout(pingTimeout);
18460 pingTimeout = setTimeout(sendPing, webrtc_http_stream_signaling_messageReconnectTimeout / 2);
18461 }
18462 httpClient.emit('message', [message, httpClient]);
18463 };
18464
18465 /**
18466 * @param {any} error
18467 */
18468 const onclose = error => {
18469 if (httpClient.ws !== null) {
18470 httpClient.ws.close();
18471 httpClient.ws = null;
18472 httpClient.connecting = false;
18473 if (httpClient.connected) {
18474 httpClient.connected = false;
18475 httpClient.emit('disconnect', [{
18476 type: 'disconnect',
18477 error
18478 }, httpClient]);
18479 } else {
18480 httpClient.unsuccessfulReconnects++;
18481 }
18482 }
18483 clearTimeout(pingTimeout);
18484 };
18485 const sendPing = () => {
18486 if (httpClient.ws && httpClient.ws.readyState === window.EventSource.OPEN) {
18487 httpClient.send({
18488 type: 'ping'
18489 });
18490 }
18491 };
18492 if (httpClient.ws) {
18493 httpClient.ws.onclose = () => {
18494 onclose(null);
18495 };
18496 httpClient.ws.send = function send( /** @type {string} */message) {
18497 window.fetch(url, {
18498 body: new URLSearchParams({
18499 subscriber_id: subscriberId.toString(),
18500 action: 'gutenberg_signaling_server',
18501 message
18502 }),
18503 method: 'POST'
18504 }).catch(() => {
18505 y_webrtc_log('Error sending to server with message: ' + message);
18506 });
18507 };
18508 }
18509 eventSource.onerror = () => {
18510 // Todo: add an error handler
18511 };
18512 eventSource.onopen = () => {
18513 if (httpClient.connected) {
18514 return;
18515 }
18516 if (eventSource.readyState === window.EventSource.OPEN) {
18517 httpClient.lastMessageReceived = Date.now();
18518 httpClient.connecting = false;
18519 httpClient.connected = true;
18520 httpClient.unsuccessfulReconnects = 0;
18521 httpClient.emit('connect', [{
18522 type: 'connect'
18523 }, httpClient]);
18524 // set ping
18525 pingTimeout = setTimeout(sendPing, webrtc_http_stream_signaling_messageReconnectTimeout / 2);
18526 }
18527 };
18528 }
18529 }
18530 const webrtc_http_stream_signaling_messageReconnectTimeout = 30000;
18531
18532 /**
18533 * @augments Observable<string>
18534 */
18535 class HttpSignalingConn extends observable_Observable {
18536 /**
18537 * @param {string} url
18538 */
18539 constructor(url) {
18540 super();
18541
18542 //WebsocketClient from lib0/websocket.js
18543 this.url = url;
18544 /**
18545 * @type {WebSocket?}
18546 */
18547 this.ws = null;
18548 // @ts-ignore
18549 this.binaryType = null; // this.binaryType = binaryType
18550 this.connected = false;
18551 this.connecting = false;
18552 this.unsuccessfulReconnects = 0;
18553 this.lastMessageReceived = 0;
18554 /**
18555 * Whether to connect to other peers or not
18556 *
18557 * @type {boolean}
18558 */
18559 this.shouldConnect = true;
18560 this._checkInterval = setInterval(() => {
18561 if (this.connected && webrtc_http_stream_signaling_messageReconnectTimeout < Date.now() - this.lastMessageReceived && this.ws) {
18562 // no message received in a long time - not even your own awareness
18563 // updates (which are updated every 15 seconds)
18564 this.ws.close();
18565 }
18566 }, webrtc_http_stream_signaling_messageReconnectTimeout / 2);
18567 //setupWS( this );
18568 setupHttpSignal(this);
18569
18570 // From SignalingConn
18571 /**
18572 * @type {Set<WebrtcProvider>}
18573 */
18574 this.providers = new Set();
18575 setupSignalEventHandlers(this, url);
18576 }
18577
18578 /**
18579 * @param {any} message
18580 */
18581 send(message) {
18582 if (this.ws) {
18583 this.ws.send(JSON.stringify(message));
18584 }
18585 }
18586 destroy() {
18587 clearInterval(this._checkInterval);
18588 this.disconnect();
18589 super.destroy();
18590 }
18591 disconnect() {
18592 this.shouldConnect = false;
18593 if (this.ws !== null) {
18594 this.ws.close();
18595 }
18596 }
18597 connect() {
18598 this.shouldConnect = true;
18599 if (!this.connected && this.ws === null) {
18600 setupHttpSignal(this);
18601 }
18602 }
18603 }
18604 class WebrtcProviderWithHttpSignaling extends WebrtcProvider {
18605 connect() {
18606 this.shouldConnect = true;
18607 this.signalingUrls.forEach(( /** @type {string} */url) => {
18608 const signalingConn = setIfUndefined(signalingConns, url,
18609 // Only this conditional logic to create a normal websocket connection or
18610 // an http signaling connection was added to the constructor when compared
18611 // with the base class.
18612 url.startsWith('ws://') || url.startsWith('wss://') ? () => new SignalingConn(url) : () => new HttpSignalingConn(url));
18613 this.signalingConns.push(signalingConn);
18614 signalingConn.providers.add(this);
18615 });
18616 if (this.room) {
18617 this.room.connect();
18618 }
18619 }
18620 }
18621
18622 ;// CONCATENATED MODULE: ./packages/sync/build-module/create-webrtc-connection.js
18623 /**
18624 * External dependencies
18625 */
18626 // import { WebrtcProvider } from 'y-webrtc';
18627
18628 /**
18629 * Internal dependencies
18630 */
18631
18632
18633 /** @typedef {import('./types').ObjectType} ObjectType */
18634 /** @typedef {import('./types').ObjectID} ObjectID */
18635 /** @typedef {import('./types').CRDTDoc} CRDTDoc */
18636
18637 /**
18638 * Function that creates a new WebRTC Connection.
18639 *
18640 * @param {Object} config The object ID.
18641 *
18642 * @param {Array<string>} config.signaling
18643 * @param {string} config.password
18644 * @return {Function} Promise that resolves when the connection is established.
18645 */
18646 function createWebRTCConnection({
18647 signaling,
18648 password
18649 }) {
18650 return function ( /** @type {string} */objectId, /** @type {string} */objectType, /** @type {import("yjs").Doc} */doc) {
18651 const roomName = `${objectType}-${objectId}`;
18652 new WebrtcProviderWithHttpSignaling(roomName, doc, {
18653 signaling,
18654 // @ts-ignore
18655 password
18656 });
18657 return Promise.resolve(() => true);
18658 };
18659 }
18660
18661 ;// CONCATENATED MODULE: ./packages/core-data/build-module/sync.js
18662 /**
18663 * WordPress dependencies
18664 */
18665
18666 let syncProvider;
18667 function getSyncProvider() {
18668 if (!syncProvider) {
18669 syncProvider = createSyncProvider(connectIndexDb, createWebRTCConnection({
18670 signaling: [
18671 //'ws://localhost:4444',
18672 window?.wp?.ajax?.settings?.url],
18673 password: window?.__experimentalCollaborativeEditingSecret
18674 }));
18675 }
18676 return syncProvider;
18677 }
18678
18679 ;// CONCATENATED MODULE: ./packages/core-data/build-module/actions.js
18680 /**
18681 * External dependencies
18682 */
18683
18684
18685
18686 /**
18687 * WordPress dependencies
18688 */
18689
18690
18691
18692
18693 /**
18694 * Internal dependencies
18695 */
18696
18697
18698
18699
18700
18701
18702
18703 /**
18704 * Returns an action object used in signalling that authors have been received.
18705 * Ignored from documentation as it's internal to the data store.
18706 *
18707 * @ignore
18708 *
18709 * @param {string} queryID Query ID.
18710 * @param {Array|Object} users Users received.
18711 *
18712 * @return {Object} Action object.
18713 */
18714 function receiveUserQuery(queryID, users) {
18715 return {
18716 type: 'RECEIVE_USER_QUERY',
18717 users: Array.isArray(users) ? users : [users],
18718 queryID
18719 };
18720 }
18721
18722 /**
18723 * Returns an action used in signalling that the current user has been received.
18724 * Ignored from documentation as it's internal to the data store.
18725 *
18726 * @ignore
18727 *
18728 * @param {Object} currentUser Current user object.
18729 *
18730 * @return {Object} Action object.
18731 */
18732 function receiveCurrentUser(currentUser) {
18733 return {
18734 type: 'RECEIVE_CURRENT_USER',
18735 currentUser
18736 };
18737 }
18738
18739 /**
18740 * Returns an action object used in adding new entities.
18741 *
18742 * @param {Array} entities Entities received.
18743 *
18744 * @return {Object} Action object.
18745 */
18746 function addEntities(entities) {
18747 return {
18748 type: 'ADD_ENTITIES',
18749 entities
18750 };
18751 }
18752
18753 /**
18754 * Returns an action object used in signalling that entity records have been received.
18755 *
18756 * @param {string} kind Kind of the received entity record.
18757 * @param {string} name Name of the received entity record.
18758 * @param {Array|Object} records Records received.
18759 * @param {?Object} query Query Object.
18760 * @param {?boolean} invalidateCache Should invalidate query caches.
18761 * @param {?Object} edits Edits to reset.
18762 * @param {?Object} meta Meta information about pagination.
18763 * @return {Object} Action object.
18764 */
18765 function receiveEntityRecords(kind, name, records, query, invalidateCache = false, edits, meta) {
18766 // Auto drafts should not have titles, but some plugins rely on them so we can't filter this
18767 // on the server.
18768 if (kind === 'postType') {
18769 records = (Array.isArray(records) ? records : [records]).map(record => record.status === 'auto-draft' ? {
18770 ...record,
18771 title: ''
18772 } : record);
18773 }
18774 let action;
18775 if (query) {
18776 action = receiveQueriedItems(records, query, edits, meta);
18777 } else {
18778 action = receiveItems(records, edits, meta);
18779 }
18780 return {
18781 ...action,
18782 kind,
18783 name,
18784 invalidateCache
18785 };
18786 }
18787
18788 /**
18789 * Returns an action object used in signalling that the current theme has been received.
18790 * Ignored from documentation as it's internal to the data store.
18791 *
18792 * @ignore
18793 *
18794 * @param {Object} currentTheme The current theme.
18795 *
18796 * @return {Object} Action object.
18797 */
18798 function receiveCurrentTheme(currentTheme) {
18799 return {
18800 type: 'RECEIVE_CURRENT_THEME',
18801 currentTheme
18802 };
18803 }
18804
18805 /**
18806 * Returns an action object used in signalling that the current global styles id has been received.
18807 * Ignored from documentation as it's internal to the data store.
18808 *
18809 * @ignore
18810 *
18811 * @param {string} currentGlobalStylesId The current global styles id.
18812 *
18813 * @return {Object} Action object.
18814 */
18815 function __experimentalReceiveCurrentGlobalStylesId(currentGlobalStylesId) {
18816 return {
18817 type: 'RECEIVE_CURRENT_GLOBAL_STYLES_ID',
18818 id: currentGlobalStylesId
18819 };
18820 }
18821
18822 /**
18823 * Returns an action object used in signalling that the theme base global styles have been received
18824 * Ignored from documentation as it's internal to the data store.
18825 *
18826 * @ignore
18827 *
18828 * @param {string} stylesheet The theme's identifier
18829 * @param {Object} globalStyles The global styles object.
18830 *
18831 * @return {Object} Action object.
18832 */
18833 function __experimentalReceiveThemeBaseGlobalStyles(stylesheet, globalStyles) {
18834 return {
18835 type: 'RECEIVE_THEME_GLOBAL_STYLES',
18836 stylesheet,
18837 globalStyles
18838 };
18839 }
18840
18841 /**
18842 * Returns an action object used in signalling that the theme global styles variations have been received.
18843 * Ignored from documentation as it's internal to the data store.
18844 *
18845 * @ignore
18846 *
18847 * @param {string} stylesheet The theme's identifier
18848 * @param {Array} variations The global styles variations.
18849 *
18850 * @return {Object} Action object.
18851 */
18852 function __experimentalReceiveThemeGlobalStyleVariations(stylesheet, variations) {
18853 return {
18854 type: 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS',
18855 stylesheet,
18856 variations
18857 };
18858 }
18859
18860 /**
18861 * Returns an action object used in signalling that the index has been received.
18862 *
18863 * @deprecated since WP 5.9, this is not useful anymore, use the selector direclty.
18864 *
18865 * @return {Object} Action object.
18866 */
18867 function receiveThemeSupports() {
18868 external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveThemeSupports", {
18869 since: '5.9'
18870 });
18871 return {
18872 type: 'DO_NOTHING'
18873 };
18874 }
18875
18876 /**
18877 * Returns an action object used in signalling that the theme global styles CPT post revisions have been received.
18878 * Ignored from documentation as it's internal to the data store.
18879 *
18880 * @deprecated since WordPress 6.5.0. Callers should use `dispatch( 'core' ).receiveRevision` instead.
18881 *
18882 * @ignore
18883 *
18884 * @param {number} currentId The post id.
18885 * @param {Array} revisions The global styles revisions.
18886 *
18887 * @return {Object} Action object.
18888 */
18889 function receiveThemeGlobalStyleRevisions(currentId, revisions) {
18890 external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveThemeGlobalStyleRevisions()", {
18891 since: '6.5.0',
18892 alternative: "wp.data.dispatch( 'core' ).receiveRevisions"
18893 });
18894 return {
18895 type: 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS',
18896 currentId,
18897 revisions
18898 };
18899 }
18900
18901 /**
18902 * Returns an action object used in signalling that the preview data for
18903 * a given URl has been received.
18904 * Ignored from documentation as it's internal to the data store.
18905 *
18906 * @ignore
18907 *
18908 * @param {string} url URL to preview the embed for.
18909 * @param {*} preview Preview data.
18910 *
18911 * @return {Object} Action object.
18912 */
18913 function receiveEmbedPreview(url, preview) {
18914 return {
18915 type: 'RECEIVE_EMBED_PREVIEW',
18916 url,
18917 preview
18918 };
18919 }
18920
18921 /**
18922 * Action triggered to delete an entity record.
18923 *
18924 * @param {string} kind Kind of the deleted entity.
18925 * @param {string} name Name of the deleted entity.
18926 * @param {string} recordId Record ID of the deleted entity.
18927 * @param {?Object} query Special query parameters for the
18928 * DELETE API call.
18929 * @param {Object} [options] Delete options.
18930 * @param {Function} [options.__unstableFetch] Internal use only. Function to
18931 * call instead of `apiFetch()`.
18932 * Must return a promise.
18933 * @param {boolean} [options.throwOnError=false] If false, this action suppresses all
18934 * the exceptions. Defaults to false.
18935 */
18936 const deleteEntityRecord = (kind, name, recordId, query, {
18937 __unstableFetch = (external_wp_apiFetch_default()),
18938 throwOnError = false
18939 } = {}) => async ({
18940 dispatch
18941 }) => {
18942 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
18943 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
18944 let error;
18945 let deletedRecord = false;
18946 if (!entityConfig) {
18947 return;
18948 }
18949 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, recordId], {
18950 exclusive: true
18951 });
18952 try {
18953 dispatch({
18954 type: 'DELETE_ENTITY_RECORD_START',
18955 kind,
18956 name,
18957 recordId
18958 });
18959 let hasError = false;
18960 try {
18961 let path = `${entityConfig.baseURL}/${recordId}`;
18962 if (query) {
18963 path = (0,external_wp_url_namespaceObject.addQueryArgs)(path, query);
18964 }
18965 deletedRecord = await __unstableFetch({
18966 path,
18967 method: 'DELETE'
18968 });
18969 await dispatch(removeItems(kind, name, recordId, true));
18970 } catch (_error) {
18971 hasError = true;
18972 error = _error;
18973 }
18974 dispatch({
18975 type: 'DELETE_ENTITY_RECORD_FINISH',
18976 kind,
18977 name,
18978 recordId,
18979 error
18980 });
18981 if (hasError && throwOnError) {
18982 throw error;
18983 }
18984 return deletedRecord;
18985 } finally {
18986 dispatch.__unstableReleaseStoreLock(lock);
18987 }
18988 };
18989
18990 /**
18991 * Returns an action object that triggers an
18992 * edit to an entity record.
18993 *
18994 * @param {string} kind Kind of the edited entity record.
18995 * @param {string} name Name of the edited entity record.
18996 * @param {number|string} recordId Record ID of the edited entity record.
18997 * @param {Object} edits The edits.
18998 * @param {Object} options Options for the edit.
18999 * @param {boolean} [options.undoIgnore] Whether to ignore the edit in undo history or not.
19000 *
19001 * @return {Object} Action object.
19002 */
19003 const editEntityRecord = (kind, name, recordId, edits, options = {}) => ({
19004 select,
19005 dispatch
19006 }) => {
19007 const entityConfig = select.getEntityConfig(kind, name);
19008 if (!entityConfig) {
19009 throw new Error(`The entity being edited (${kind}, ${name}) does not have a loaded config.`);
19010 }
19011 const {
19012 mergedEdits = {}
19013 } = entityConfig;
19014 const record = select.getRawEntityRecord(kind, name, recordId);
19015 const editedRecord = select.getEditedEntityRecord(kind, name, recordId);
19016 const edit = {
19017 kind,
19018 name,
19019 recordId,
19020 // Clear edits when they are equal to their persisted counterparts
19021 // so that the property is not considered dirty.
19022 edits: Object.keys(edits).reduce((acc, key) => {
19023 const recordValue = record[key];
19024 const editedRecordValue = editedRecord[key];
19025 const value = mergedEdits[key] ? {
19026 ...editedRecordValue,
19027 ...edits[key]
19028 } : edits[key];
19029 acc[key] = es6_default()(recordValue, value) ? undefined : value;
19030 return acc;
19031 }, {})
19032 };
19033 if (window.__experimentalEnableSync && entityConfig.syncConfig) {
19034 if (true) {
19035 const objectId = entityConfig.getSyncObjectId(recordId);
19036 getSyncProvider().update(entityConfig.syncObjectType + '--edit', objectId, edit.edits);
19037 }
19038 } else {
19039 if (!options.undoIgnore) {
19040 select.getUndoManager().addRecord([{
19041 id: {
19042 kind,
19043 name,
19044 recordId
19045 },
19046 changes: Object.keys(edits).reduce((acc, key) => {
19047 acc[key] = {
19048 from: editedRecord[key],
19049 to: edits[key]
19050 };
19051 return acc;
19052 }, {})
19053 }], options.isCached);
19054 }
19055 dispatch({
19056 type: 'EDIT_ENTITY_RECORD',
19057 ...edit
19058 });
19059 }
19060 };
19061
19062 /**
19063 * Action triggered to undo the last edit to
19064 * an entity record, if any.
19065 */
19066 const undo = () => ({
19067 select,
19068 dispatch
19069 }) => {
19070 const undoRecord = select.getUndoManager().undo();
19071 if (!undoRecord) {
19072 return;
19073 }
19074 dispatch({
19075 type: 'UNDO',
19076 record: undoRecord
19077 });
19078 };
19079
19080 /**
19081 * Action triggered to redo the last undoed
19082 * edit to an entity record, if any.
19083 */
19084 const redo = () => ({
19085 select,
19086 dispatch
19087 }) => {
19088 const redoRecord = select.getUndoManager().redo();
19089 if (!redoRecord) {
19090 return;
19091 }
19092 dispatch({
19093 type: 'REDO',
19094 record: redoRecord
19095 });
19096 };
19097
19098 /**
19099 * Forces the creation of a new undo level.
19100 *
19101 * @return {Object} Action object.
19102 */
19103 const __unstableCreateUndoLevel = () => ({
19104 select
19105 }) => {
19106 select.getUndoManager().addRecord();
19107 };
19108
19109 /**
19110 * Action triggered to save an entity record.
19111 *
19112 * @param {string} kind Kind of the received entity.
19113 * @param {string} name Name of the received entity.
19114 * @param {Object} record Record to be saved.
19115 * @param {Object} options Saving options.
19116 * @param {boolean} [options.isAutosave=false] Whether this is an autosave.
19117 * @param {Function} [options.__unstableFetch] Internal use only. Function to
19118 * call instead of `apiFetch()`.
19119 * Must return a promise.
19120 * @param {boolean} [options.throwOnError=false] If false, this action suppresses all
19121 * the exceptions. Defaults to false.
19122 */
19123 const saveEntityRecord = (kind, name, record, {
19124 isAutosave = false,
19125 __unstableFetch = (external_wp_apiFetch_default()),
19126 throwOnError = false
19127 } = {}) => async ({
19128 select,
19129 resolveSelect,
19130 dispatch
19131 }) => {
19132 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
19133 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19134 if (!entityConfig) {
19135 return;
19136 }
19137 const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY;
19138 const recordId = record[entityIdKey];
19139 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, recordId || esm_browser_v4()], {
19140 exclusive: true
19141 });
19142 try {
19143 // Evaluate optimized edits.
19144 // (Function edits that should be evaluated on save to avoid expensive computations on every edit.)
19145 for (const [key, value] of Object.entries(record)) {
19146 if (typeof value === 'function') {
19147 const evaluatedValue = value(select.getEditedEntityRecord(kind, name, recordId));
19148 dispatch.editEntityRecord(kind, name, recordId, {
19149 [key]: evaluatedValue
19150 }, {
19151 undoIgnore: true
19152 });
19153 record[key] = evaluatedValue;
19154 }
19155 }
19156 dispatch({
19157 type: 'SAVE_ENTITY_RECORD_START',
19158 kind,
19159 name,
19160 recordId,
19161 isAutosave
19162 });
19163 let updatedRecord;
19164 let error;
19165 let hasError = false;
19166 try {
19167 const path = `${entityConfig.baseURL}${recordId ? '/' + recordId : ''}`;
19168 const persistedRecord = select.getRawEntityRecord(kind, name, recordId);
19169 if (isAutosave) {
19170 // Most of this autosave logic is very specific to posts.
19171 // This is fine for now as it is the only supported autosave,
19172 // but ideally this should all be handled in the back end,
19173 // so the client just sends and receives objects.
19174 const currentUser = select.getCurrentUser();
19175 const currentUserId = currentUser ? currentUser.id : undefined;
19176 const autosavePost = await resolveSelect.getAutosave(persistedRecord.type, persistedRecord.id, currentUserId);
19177 // Autosaves need all expected fields to be present.
19178 // So we fallback to the previous autosave and then
19179 // to the actual persisted entity if the edits don't
19180 // have a value.
19181 let data = {
19182 ...persistedRecord,
19183 ...autosavePost,
19184 ...record
19185 };
19186 data = Object.keys(data).reduce((acc, key) => {
19187 if (['title', 'excerpt', 'content', 'meta'].includes(key)) {
19188 acc[key] = data[key];
19189 }
19190 return acc;
19191 }, {
19192 // Do not update the `status` if we have edited it when auto saving.
19193 // It's very important to let the user explicitly save this change,
19194 // because it can lead to unexpected results. An example would be to
19195 // have a draft post and change the status to publish.
19196 status: data.status === 'auto-draft' ? 'draft' : undefined
19197 });
19198 updatedRecord = await __unstableFetch({
19199 path: `${path}/autosaves`,
19200 method: 'POST',
19201 data
19202 });
19203
19204 // An autosave may be processed by the server as a regular save
19205 // when its update is requested by the author and the post had
19206 // draft or auto-draft status.
19207 if (persistedRecord.id === updatedRecord.id) {
19208 let newRecord = {
19209 ...persistedRecord,
19210 ...data,
19211 ...updatedRecord
19212 };
19213 newRecord = Object.keys(newRecord).reduce((acc, key) => {
19214 // These properties are persisted in autosaves.
19215 if (['title', 'excerpt', 'content'].includes(key)) {
19216 acc[key] = newRecord[key];
19217 } else if (key === 'status') {
19218 // Status is only persisted in autosaves when going from
19219 // "auto-draft" to "draft".
19220 acc[key] = persistedRecord.status === 'auto-draft' && newRecord.status === 'draft' ? newRecord.status : persistedRecord.status;
19221 } else {
19222 // These properties are not persisted in autosaves.
19223 acc[key] = persistedRecord[key];
19224 }
19225 return acc;
19226 }, {});
19227 dispatch.receiveEntityRecords(kind, name, newRecord, undefined, true);
19228 } else {
19229 dispatch.receiveAutosaves(persistedRecord.id, updatedRecord);
19230 }
19231 } else {
19232 let edits = record;
19233 if (entityConfig.__unstablePrePersist) {
19234 edits = {
19235 ...edits,
19236 ...entityConfig.__unstablePrePersist(persistedRecord, edits)
19237 };
19238 }
19239 updatedRecord = await __unstableFetch({
19240 path,
19241 method: recordId ? 'PUT' : 'POST',
19242 data: edits
19243 });
19244 dispatch.receiveEntityRecords(kind, name, updatedRecord, undefined, true, edits);
19245 }
19246 } catch (_error) {
19247 hasError = true;
19248 error = _error;
19249 }
19250 dispatch({
19251 type: 'SAVE_ENTITY_RECORD_FINISH',
19252 kind,
19253 name,
19254 recordId,
19255 error,
19256 isAutosave
19257 });
19258 if (hasError && throwOnError) {
19259 throw error;
19260 }
19261 return updatedRecord;
19262 } finally {
19263 dispatch.__unstableReleaseStoreLock(lock);
19264 }
19265 };
19266
19267 /**
19268 * Runs multiple core-data actions at the same time using one API request.
19269 *
19270 * Example:
19271 *
19272 * ```
19273 * const [ savedRecord, updatedRecord, deletedRecord ] =
19274 * await dispatch( 'core' ).__experimentalBatch( [
19275 * ( { saveEntityRecord } ) => saveEntityRecord( 'root', 'widget', widget ),
19276 * ( { saveEditedEntityRecord } ) => saveEntityRecord( 'root', 'widget', 123 ),
19277 * ( { deleteEntityRecord } ) => deleteEntityRecord( 'root', 'widget', 123, null ),
19278 * ] );
19279 * ```
19280 *
19281 * @param {Array} requests Array of functions which are invoked simultaneously.
19282 * Each function is passed an object containing
19283 * `saveEntityRecord`, `saveEditedEntityRecord`, and
19284 * `deleteEntityRecord`.
19285 *
19286 * @return {(thunkArgs: Object) => Promise} A promise that resolves to an array containing the return
19287 * values of each function given in `requests`.
19288 */
19289 const __experimentalBatch = requests => async ({
19290 dispatch
19291 }) => {
19292 const batch = createBatch();
19293 const api = {
19294 saveEntityRecord(kind, name, record, options) {
19295 return batch.add(add => dispatch.saveEntityRecord(kind, name, record, {
19296 ...options,
19297 __unstableFetch: add
19298 }));
19299 },
19300 saveEditedEntityRecord(kind, name, recordId, options) {
19301 return batch.add(add => dispatch.saveEditedEntityRecord(kind, name, recordId, {
19302 ...options,
19303 __unstableFetch: add
19304 }));
19305 },
19306 deleteEntityRecord(kind, name, recordId, query, options) {
19307 return batch.add(add => dispatch.deleteEntityRecord(kind, name, recordId, query, {
19308 ...options,
19309 __unstableFetch: add
19310 }));
19311 }
19312 };
19313 const resultPromises = requests.map(request => request(api));
19314 const [, ...results] = await Promise.all([batch.run(), ...resultPromises]);
19315 return results;
19316 };
19317
19318 /**
19319 * Action triggered to save an entity record's edits.
19320 *
19321 * @param {string} kind Kind of the entity.
19322 * @param {string} name Name of the entity.
19323 * @param {Object} recordId ID of the record.
19324 * @param {Object=} options Saving options.
19325 */
19326 const saveEditedEntityRecord = (kind, name, recordId, options) => async ({
19327 select,
19328 dispatch
19329 }) => {
19330 if (!select.hasEditsForEntityRecord(kind, name, recordId)) {
19331 return;
19332 }
19333 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
19334 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19335 if (!entityConfig) {
19336 return;
19337 }
19338 const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY;
19339 const edits = select.getEntityRecordNonTransientEdits(kind, name, recordId);
19340 const record = {
19341 [entityIdKey]: recordId,
19342 ...edits
19343 };
19344 return await dispatch.saveEntityRecord(kind, name, record, options);
19345 };
19346
19347 /**
19348 * Action triggered to save only specified properties for the entity.
19349 *
19350 * @param {string} kind Kind of the entity.
19351 * @param {string} name Name of the entity.
19352 * @param {Object} recordId ID of the record.
19353 * @param {Array} itemsToSave List of entity properties or property paths to save.
19354 * @param {Object} options Saving options.
19355 */
19356 const __experimentalSaveSpecifiedEntityEdits = (kind, name, recordId, itemsToSave, options) => async ({
19357 select,
19358 dispatch
19359 }) => {
19360 if (!select.hasEditsForEntityRecord(kind, name, recordId)) {
19361 return;
19362 }
19363 const edits = select.getEntityRecordNonTransientEdits(kind, name, recordId);
19364 const editsToSave = {};
19365 for (const item of itemsToSave) {
19366 setNestedValue(editsToSave, item, getNestedValue(edits, item));
19367 }
19368 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
19369 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19370 const entityIdKey = entityConfig?.key || DEFAULT_ENTITY_KEY;
19371
19372 // If a record key is provided then update the existing record.
19373 // This necessitates providing `recordKey` to saveEntityRecord as part of the
19374 // `record` argument (here called `editsToSave`) to stop that action creating
19375 // a new record and instead cause it to update the existing record.
19376 if (recordId) {
19377 editsToSave[entityIdKey] = recordId;
19378 }
19379 return await dispatch.saveEntityRecord(kind, name, editsToSave, options);
19380 };
19381
19382 /**
19383 * Returns an action object used in signalling that Upload permissions have been received.
19384 *
19385 * @deprecated since WP 5.9, use receiveUserPermission instead.
19386 *
19387 * @param {boolean} hasUploadPermissions Does the user have permission to upload files?
19388 *
19389 * @return {Object} Action object.
19390 */
19391 function receiveUploadPermissions(hasUploadPermissions) {
19392 external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveUploadPermissions", {
19393 since: '5.9',
19394 alternative: 'receiveUserPermission'
19395 });
19396 return receiveUserPermission('create/media', hasUploadPermissions);
19397 }
19398
19399 /**
19400 * Returns an action object used in signalling that the current user has
19401 * permission to perform an action on a REST resource.
19402 * Ignored from documentation as it's internal to the data store.
19403 *
19404 * @ignore
19405 *
19406 * @param {string} key A key that represents the action and REST resource.
19407 * @param {boolean} isAllowed Whether or not the user can perform the action.
19408 *
19409 * @return {Object} Action object.
19410 */
19411 function receiveUserPermission(key, isAllowed) {
19412 return {
19413 type: 'RECEIVE_USER_PERMISSION',
19414 key,
19415 isAllowed
19416 };
19417 }
19418
19419 /**
19420 * Returns an action object used in signalling that the autosaves for a
19421 * post have been received.
19422 * Ignored from documentation as it's internal to the data store.
19423 *
19424 * @ignore
19425 *
19426 * @param {number} postId The id of the post that is parent to the autosave.
19427 * @param {Array|Object} autosaves An array of autosaves or singular autosave object.
19428 *
19429 * @return {Object} Action object.
19430 */
19431 function receiveAutosaves(postId, autosaves) {
19432 return {
19433 type: 'RECEIVE_AUTOSAVES',
19434 postId,
19435 autosaves: Array.isArray(autosaves) ? autosaves : [autosaves]
19436 };
19437 }
19438
19439 /**
19440 * Returns an action object signalling that the fallback Navigation
19441 * Menu id has been received.
19442 *
19443 * @param {integer} fallbackId the id of the fallback Navigation Menu
19444 * @return {Object} Action object.
19445 */
19446 function receiveNavigationFallbackId(fallbackId) {
19447 return {
19448 type: 'RECEIVE_NAVIGATION_FALLBACK_ID',
19449 fallbackId
19450 };
19451 }
19452
19453 /**
19454 * Returns an action object used to set the template for a given query.
19455 *
19456 * @param {Object} query The lookup query.
19457 * @param {string} templateId The resolved template id.
19458 *
19459 * @return {Object} Action object.
19460 */
19461 function receiveDefaultTemplateId(query, templateId) {
19462 return {
19463 type: 'RECEIVE_DEFAULT_TEMPLATE',
19464 query,
19465 templateId
19466 };
19467 }
19468
19469 /**
19470 * Action triggered to receive revision items.
19471 *
19472 * @param {string} kind Kind of the received entity record revisions.
19473 * @param {string} name Name of the received entity record revisions.
19474 * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
19475 * @param {Array|Object} records Revisions received.
19476 * @param {?Object} query Query Object.
19477 * @param {?boolean} invalidateCache Should invalidate query caches.
19478 * @param {?Object} meta Meta information about pagination.
19479 */
19480 const receiveRevisions = (kind, name, recordKey, records, query, invalidateCache = false, meta) => async ({
19481 dispatch
19482 }) => {
19483 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
19484 const entityConfig = configs.find(config => config.kind === kind && config.name === name);
19485 const key = entityConfig && entityConfig?.revisionKey ? entityConfig.revisionKey : DEFAULT_ENTITY_KEY;
19486 dispatch({
19487 type: 'RECEIVE_ITEM_REVISIONS',
19488 key,
19489 items: Array.isArray(records) ? records : [records],
19490 recordKey,
19491 meta,
19492 query,
19493 kind,
19494 name,
19495 invalidateCache
19496 });
19497 };
19498
19499 ;// CONCATENATED MODULE: ./packages/core-data/build-module/entities.js
19500 /**
19501 * External dependencies
19502 */
19503
19504
19505 /**
19506 * WordPress dependencies
19507 */
19508
19509
19510
19511
19512 /**
19513 * Internal dependencies
19514 */
19515
19516
19517 const DEFAULT_ENTITY_KEY = 'id';
19518 const POST_RAW_ATTRIBUTES = ['title', 'excerpt', 'content'];
19519 const rootEntitiesConfig = [{
19520 label: (0,external_wp_i18n_namespaceObject.__)('Base'),
19521 kind: 'root',
19522 name: '__unstableBase',
19523 baseURL: '/',
19524 baseURLParams: {
19525 _fields: ['description', 'gmt_offset', 'home', 'name', 'site_icon', 'site_icon_url', 'site_logo', 'timezone_string', 'url'].join(',')
19526 },
19527 // The entity doesn't support selecting multiple records.
19528 // The property is maintained for backward compatibility.
19529 plural: '__unstableBases',
19530 syncConfig: {
19531 fetch: async () => {
19532 return external_wp_apiFetch_default()({
19533 path: '/'
19534 });
19535 },
19536 applyChangesToDoc: (doc, changes) => {
19537 const document = doc.getMap('document');
19538 Object.entries(changes).forEach(([key, value]) => {
19539 if (document.get(key) !== value) {
19540 document.set(key, value);
19541 }
19542 });
19543 },
19544 fromCRDTDoc: doc => {
19545 return doc.getMap('document').toJSON();
19546 }
19547 },
19548 syncObjectType: 'root/base',
19549 getSyncObjectId: () => 'index'
19550 }, {
19551 label: (0,external_wp_i18n_namespaceObject.__)('Post Type'),
19552 name: 'postType',
19553 kind: 'root',
19554 key: 'slug',
19555 baseURL: '/wp/v2/types',
19556 baseURLParams: {
19557 context: 'edit'
19558 },
19559 plural: 'postTypes',
19560 syncConfig: {
19561 fetch: async id => {
19562 return external_wp_apiFetch_default()({
19563 path: `/wp/v2/types/${id}?context=edit`
19564 });
19565 },
19566 applyChangesToDoc: (doc, changes) => {
19567 const document = doc.getMap('document');
19568 Object.entries(changes).forEach(([key, value]) => {
19569 if (document.get(key) !== value) {
19570 document.set(key, value);
19571 }
19572 });
19573 },
19574 fromCRDTDoc: doc => {
19575 return doc.getMap('document').toJSON();
19576 }
19577 },
19578 syncObjectType: 'root/postType',
19579 getSyncObjectId: id => id
19580 }, {
19581 name: 'media',
19582 kind: 'root',
19583 baseURL: '/wp/v2/media',
19584 baseURLParams: {
19585 context: 'edit'
19586 },
19587 plural: 'mediaItems',
19588 label: (0,external_wp_i18n_namespaceObject.__)('Media'),
19589 rawAttributes: ['caption', 'title', 'description'],
19590 supportsPagination: true
19591 }, {
19592 name: 'taxonomy',
19593 kind: 'root',
19594 key: 'slug',
19595 baseURL: '/wp/v2/taxonomies',
19596 baseURLParams: {
19597 context: 'edit'
19598 },
19599 plural: 'taxonomies',
19600 label: (0,external_wp_i18n_namespaceObject.__)('Taxonomy')
19601 }, {
19602 name: 'sidebar',
19603 kind: 'root',
19604 baseURL: '/wp/v2/sidebars',
19605 baseURLParams: {
19606 context: 'edit'
19607 },
19608 plural: 'sidebars',
19609 transientEdits: {
19610 blocks: true
19611 },
19612 label: (0,external_wp_i18n_namespaceObject.__)('Widget areas')
19613 }, {
19614 name: 'widget',
19615 kind: 'root',
19616 baseURL: '/wp/v2/widgets',
19617 baseURLParams: {
19618 context: 'edit'
19619 },
19620 plural: 'widgets',
19621 transientEdits: {
19622 blocks: true
19623 },
19624 label: (0,external_wp_i18n_namespaceObject.__)('Widgets')
19625 }, {
19626 name: 'widgetType',
19627 kind: 'root',
19628 baseURL: '/wp/v2/widget-types',
19629 baseURLParams: {
19630 context: 'edit'
19631 },
19632 plural: 'widgetTypes',
19633 label: (0,external_wp_i18n_namespaceObject.__)('Widget types')
19634 }, {
19635 label: (0,external_wp_i18n_namespaceObject.__)('User'),
19636 name: 'user',
19637 kind: 'root',
19638 baseURL: '/wp/v2/users',
19639 baseURLParams: {
19640 context: 'edit'
19641 },
19642 plural: 'users'
19643 }, {
19644 name: 'comment',
19645 kind: 'root',
19646 baseURL: '/wp/v2/comments',
19647 baseURLParams: {
19648 context: 'edit'
19649 },
19650 plural: 'comments',
19651 label: (0,external_wp_i18n_namespaceObject.__)('Comment')
19652 }, {
19653 name: 'menu',
19654 kind: 'root',
19655 baseURL: '/wp/v2/menus',
19656 baseURLParams: {
19657 context: 'edit'
19658 },
19659 plural: 'menus',
19660 label: (0,external_wp_i18n_namespaceObject.__)('Menu')
19661 }, {
19662 name: 'menuItem',
19663 kind: 'root',
19664 baseURL: '/wp/v2/menu-items',
19665 baseURLParams: {
19666 context: 'edit'
19667 },
19668 plural: 'menuItems',
19669 label: (0,external_wp_i18n_namespaceObject.__)('Menu Item'),
19670 rawAttributes: ['title']
19671 }, {
19672 name: 'menuLocation',
19673 kind: 'root',
19674 baseURL: '/wp/v2/menu-locations',
19675 baseURLParams: {
19676 context: 'edit'
19677 },
19678 plural: 'menuLocations',
19679 label: (0,external_wp_i18n_namespaceObject.__)('Menu Location'),
19680 key: 'name'
19681 }, {
19682 label: (0,external_wp_i18n_namespaceObject.__)('Global Styles'),
19683 name: 'globalStyles',
19684 kind: 'root',
19685 baseURL: '/wp/v2/global-styles',
19686 baseURLParams: {
19687 context: 'edit'
19688 },
19689 plural: 'globalStylesVariations',
19690 // Should be different from name.
19691 getTitle: record => record?.title?.rendered || record?.title,
19692 getRevisionsUrl: (parentId, revisionId) => `/wp/v2/global-styles/${parentId}/revisions${revisionId ? '/' + revisionId : ''}`,
19693 supportsPagination: true
19694 }, {
19695 label: (0,external_wp_i18n_namespaceObject.__)('Themes'),
19696 name: 'theme',
19697 kind: 'root',
19698 baseURL: '/wp/v2/themes',
19699 baseURLParams: {
19700 context: 'edit'
19701 },
19702 plural: 'themes',
19703 key: 'stylesheet'
19704 }, {
19705 label: (0,external_wp_i18n_namespaceObject.__)('Plugins'),
19706 name: 'plugin',
19707 kind: 'root',
19708 baseURL: '/wp/v2/plugins',
19709 baseURLParams: {
19710 context: 'edit'
19711 },
19712 plural: 'plugins',
19713 key: 'plugin'
19714 }, {
19715 label: (0,external_wp_i18n_namespaceObject.__)('Status'),
19716 name: 'status',
19717 kind: 'root',
19718 baseURL: '/wp/v2/statuses',
19719 baseURLParams: {
19720 context: 'edit'
19721 },
19722 plural: 'statuses',
19723 key: 'slug'
19724 }];
19725 const additionalEntityConfigLoaders = [{
19726 kind: 'postType',
19727 loadEntities: loadPostTypeEntities
19728 }, {
19729 kind: 'taxonomy',
19730 loadEntities: loadTaxonomyEntities
19731 }, {
19732 kind: 'root',
19733 name: 'site',
19734 plural: 'sites',
19735 loadEntities: loadSiteEntity
19736 }];
19737
19738 /**
19739 * Returns a function to be used to retrieve extra edits to apply before persisting a post type.
19740 *
19741 * @param {Object} persistedRecord Already persisted Post
19742 * @param {Object} edits Edits.
19743 * @return {Object} Updated edits.
19744 */
19745 const prePersistPostType = (persistedRecord, edits) => {
19746 const newEdits = {};
19747 if (persistedRecord?.status === 'auto-draft') {
19748 // Saving an auto-draft should create a draft by default.
19749 if (!edits.status && !newEdits.status) {
19750 newEdits.status = 'draft';
19751 }
19752
19753 // Fix the auto-draft default title.
19754 if ((!edits.title || edits.title === 'Auto Draft') && !newEdits.title && (!persistedRecord?.title || persistedRecord?.title === 'Auto Draft')) {
19755 newEdits.title = '';
19756 }
19757 }
19758 return newEdits;
19759 };
19760 const serialisableBlocksCache = new WeakMap();
19761 function makeBlockAttributesSerializable(attributes) {
19762 const newAttributes = {
19763 ...attributes
19764 };
19765 for (const [key, value] of Object.entries(attributes)) {
19766 if (value instanceof external_wp_richText_namespaceObject.RichTextData) {
19767 newAttributes[key] = value.valueOf();
19768 }
19769 }
19770 return newAttributes;
19771 }
19772 function makeBlocksSerializable(blocks) {
19773 return blocks.map(block => {
19774 const {
19775 innerBlocks,
19776 attributes,
19777 ...rest
19778 } = block;
19779 return {
19780 ...rest,
19781 attributes: makeBlockAttributesSerializable(attributes),
19782 innerBlocks: makeBlocksSerializable(innerBlocks)
19783 };
19784 });
19785 }
19786
19787 /**
19788 * Returns the list of post type entities.
19789 *
19790 * @return {Promise} Entities promise
19791 */
19792 async function loadPostTypeEntities() {
19793 const postTypes = await external_wp_apiFetch_default()({
19794 path: '/wp/v2/types?context=view'
19795 });
19796 return Object.entries(postTypes !== null && postTypes !== void 0 ? postTypes : {}).map(([name, postType]) => {
19797 var _postType$rest_namesp;
19798 const isTemplate = ['wp_template', 'wp_template_part'].includes(name);
19799 const namespace = (_postType$rest_namesp = postType?.rest_namespace) !== null && _postType$rest_namesp !== void 0 ? _postType$rest_namesp : 'wp/v2';
19800 return {
19801 kind: 'postType',
19802 baseURL: `/${namespace}/${postType.rest_base}`,
19803 baseURLParams: {
19804 context: 'edit'
19805 },
19806 name,
19807 label: postType.name,
19808 transientEdits: {
19809 blocks: true,
19810 selection: true
19811 },
19812 mergedEdits: {
19813 meta: true
19814 },
19815 rawAttributes: POST_RAW_ATTRIBUTES,
19816 getTitle: record => {
19817 var _record$slug;
19818 return record?.title?.rendered || record?.title || (isTemplate ? capitalCase((_record$slug = record.slug) !== null && _record$slug !== void 0 ? _record$slug : '') : String(record.id));
19819 },
19820 __unstablePrePersist: isTemplate ? undefined : prePersistPostType,
19821 __unstable_rest_base: postType.rest_base,
19822 syncConfig: {
19823 fetch: async id => {
19824 return external_wp_apiFetch_default()({
19825 path: `/${namespace}/${postType.rest_base}/${id}?context=edit`
19826 });
19827 },
19828 applyChangesToDoc: (doc, changes) => {
19829 const document = doc.getMap('document');
19830 Object.entries(changes).forEach(([key, value]) => {
19831 if (typeof value !== 'function') {
19832 if (key === 'blocks') {
19833 if (!serialisableBlocksCache.has(value)) {
19834 serialisableBlocksCache.set(value, makeBlocksSerializable(value));
19835 }
19836 value = serialisableBlocksCache.get(value);
19837 }
19838 if (document.get(key) !== value) {
19839 document.set(key, value);
19840 }
19841 }
19842 });
19843 },
19844 fromCRDTDoc: doc => {
19845 return doc.getMap('document').toJSON();
19846 }
19847 },
19848 syncObjectType: 'postType/' + postType.name,
19849 getSyncObjectId: id => id,
19850 supportsPagination: true,
19851 getRevisionsUrl: (parentId, revisionId) => `/${namespace}/${postType.rest_base}/${parentId}/revisions${revisionId ? '/' + revisionId : ''}`,
19852 revisionKey: isTemplate ? 'wp_id' : DEFAULT_ENTITY_KEY
19853 };
19854 });
19855 }
19856
19857 /**
19858 * Returns the list of the taxonomies entities.
19859 *
19860 * @return {Promise} Entities promise
19861 */
19862 async function loadTaxonomyEntities() {
19863 const taxonomies = await external_wp_apiFetch_default()({
19864 path: '/wp/v2/taxonomies?context=view'
19865 });
19866 return Object.entries(taxonomies !== null && taxonomies !== void 0 ? taxonomies : {}).map(([name, taxonomy]) => {
19867 var _taxonomy$rest_namesp;
19868 const namespace = (_taxonomy$rest_namesp = taxonomy?.rest_namespace) !== null && _taxonomy$rest_namesp !== void 0 ? _taxonomy$rest_namesp : 'wp/v2';
19869 return {
19870 kind: 'taxonomy',
19871 baseURL: `/${namespace}/${taxonomy.rest_base}`,
19872 baseURLParams: {
19873 context: 'edit'
19874 },
19875 name,
19876 label: taxonomy.name
19877 };
19878 });
19879 }
19880
19881 /**
19882 * Returns the Site entity.
19883 *
19884 * @return {Promise} Entity promise
19885 */
19886 async function loadSiteEntity() {
19887 var _site$schema$properti;
19888 const entity = {
19889 label: (0,external_wp_i18n_namespaceObject.__)('Site'),
19890 name: 'site',
19891 kind: 'root',
19892 baseURL: '/wp/v2/settings',
19893 syncConfig: {
19894 fetch: async () => {
19895 return external_wp_apiFetch_default()({
19896 path: '/wp/v2/settings'
19897 });
19898 },
19899 applyChangesToDoc: (doc, changes) => {
19900 const document = doc.getMap('document');
19901 Object.entries(changes).forEach(([key, value]) => {
19902 if (document.get(key) !== value) {
19903 document.set(key, value);
19904 }
19905 });
19906 },
19907 fromCRDTDoc: doc => {
19908 return doc.getMap('document').toJSON();
19909 }
19910 },
19911 syncObjectType: 'root/site',
19912 getSyncObjectId: () => 'index',
19913 meta: {}
19914 };
19915 const site = await external_wp_apiFetch_default()({
19916 path: entity.baseURL,
19917 method: 'OPTIONS'
19918 });
19919 const labels = {};
19920 Object.entries((_site$schema$properti = site?.schema?.properties) !== null && _site$schema$properti !== void 0 ? _site$schema$properti : {}).forEach(([key, value]) => {
19921 // Ignore properties `title` and `type` keys.
19922 if (typeof value === 'object' && value.title) {
19923 labels[key] = value.title;
19924 }
19925 });
19926 return [{
19927 ...entity,
19928 meta: {
19929 labels
19930 }
19931 }];
19932 }
19933
19934 /**
19935 * Returns the entity's getter method name given its kind and name or plural name.
19936 *
19937 * @example
19938 * ```js
19939 * const nameSingular = getMethodName( 'root', 'theme', 'get' );
19940 * // nameSingular is getRootTheme
19941 *
19942 * const namePlural = getMethodName( 'root', 'themes', 'set' );
19943 * // namePlural is setRootThemes
19944 * ```
19945 *
19946 * @param {string} kind Entity kind.
19947 * @param {string} name Entity name or plural name.
19948 * @param {string} prefix Function prefix.
19949 *
19950 * @return {string} Method name
19951 */
19952 const getMethodName = (kind, name, prefix = 'get') => {
19953 const kindPrefix = kind === 'root' ? '' : pascalCase(kind);
19954 const suffix = pascalCase(name);
19955 return `${prefix}${kindPrefix}${suffix}`;
19956 };
19957 function registerSyncConfigs(configs) {
19958 configs.forEach(({
19959 syncObjectType,
19960 syncConfig
19961 }) => {
19962 getSyncProvider().register(syncObjectType, syncConfig);
19963 const editSyncConfig = {
19964 ...syncConfig
19965 };
19966 delete editSyncConfig.fetch;
19967 getSyncProvider().register(syncObjectType + '--edit', editSyncConfig);
19968 });
19969 }
19970
19971 /**
19972 * Loads the entities into the store.
19973 *
19974 * Note: The `name` argument is used for `root` entities requiring additional server data.
19975 *
19976 * @param {string} kind Kind
19977 * @param {string} name Name
19978 * @return {(thunkArgs: object) => Promise<Array>} Entities
19979 */
19980 const getOrLoadEntitiesConfig = (kind, name) => async ({
19981 select,
19982 dispatch
19983 }) => {
19984 let configs = select.getEntitiesConfig(kind);
19985 const hasConfig = !!select.getEntityConfig(kind, name);
19986 if (configs?.length > 0 && hasConfig) {
19987 if (window.__experimentalEnableSync) {
19988 if (true) {
19989 registerSyncConfigs(configs);
19990 }
19991 }
19992 return configs;
19993 }
19994 const loader = additionalEntityConfigLoaders.find(l => {
19995 if (!name || !l.name) {
19996 return l.kind === kind;
19997 }
19998 return l.kind === kind && l.name === name;
19999 });
20000 if (!loader) {
20001 return [];
20002 }
20003 configs = await loader.loadEntities();
20004 if (window.__experimentalEnableSync) {
20005 if (true) {
20006 registerSyncConfigs(configs);
20007 }
20008 }
20009 dispatch(addEntities(configs));
20010 return configs;
20011 };
20012
20013 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/get-normalized-comma-separable.js
20014 /**
20015 * Given a value which can be specified as one or the other of a comma-separated
20016 * string or an array, returns a value normalized to an array of strings, or
20017 * null if the value cannot be interpreted as either.
20018 *
20019 * @param {string|string[]|*} value
20020 *
20021 * @return {?(string[])} Normalized field value.
20022 */
20023 function getNormalizedCommaSeparable(value) {
20024 if (typeof value === 'string') {
20025 return value.split(',');
20026 } else if (Array.isArray(value)) {
20027 return value;
20028 }
20029 return null;
20030 }
20031 /* harmony default export */ const get_normalized_comma_separable = (getNormalizedCommaSeparable);
20032
20033 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/with-weak-map-cache.js
20034 /**
20035 * Given a function, returns an enhanced function which caches the result and
20036 * tracks in WeakMap. The result is only cached if the original function is
20037 * passed a valid object-like argument (requirement for WeakMap key).
20038 *
20039 * @param {Function} fn Original function.
20040 *
20041 * @return {Function} Enhanced caching function.
20042 */
20043 function withWeakMapCache(fn) {
20044 const cache = new WeakMap();
20045 return key => {
20046 let value;
20047 if (cache.has(key)) {
20048 value = cache.get(key);
20049 } else {
20050 value = fn(key);
20051
20052 // Can reach here if key is not valid for WeakMap, since `has`
20053 // will return false for invalid key. Since `set` will throw,
20054 // ensure that key is valid before setting into cache.
20055 if (key !== null && typeof key === 'object') {
20056 cache.set(key, value);
20057 }
20058 }
20059 return value;
20060 };
20061 }
20062 /* harmony default export */ const with_weak_map_cache = (withWeakMapCache);
20063
20064 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/get-query-parts.js
20065 /**
20066 * WordPress dependencies
20067 */
20068
20069
20070 /**
20071 * Internal dependencies
20072 */
20073
20074
20075 /**
20076 * An object of properties describing a specific query.
20077 *
20078 * @typedef {Object} WPQueriedDataQueryParts
20079 *
20080 * @property {number} page The query page (1-based index, default 1).
20081 * @property {number} perPage Items per page for query (default 10).
20082 * @property {string} stableKey An encoded stable string of all non-
20083 * pagination, non-fields query parameters.
20084 * @property {?(string[])} fields Target subset of fields to derive from
20085 * item objects.
20086 * @property {?(number[])} include Specific item IDs to include.
20087 * @property {string} context Scope under which the request is made;
20088 * determines returned fields in response.
20089 */
20090
20091 /**
20092 * Given a query object, returns an object of parts, including pagination
20093 * details (`page` and `perPage`, or default values). All other properties are
20094 * encoded into a stable (idempotent) `stableKey` value.
20095 *
20096 * @param {Object} query Optional query object.
20097 *
20098 * @return {WPQueriedDataQueryParts} Query parts.
20099 */
20100 function getQueryParts(query) {
20101 /**
20102 * @type {WPQueriedDataQueryParts}
20103 */
20104 const parts = {
20105 stableKey: '',
20106 page: 1,
20107 perPage: 10,
20108 fields: null,
20109 include: null,
20110 context: 'default'
20111 };
20112
20113 // Ensure stable key by sorting keys. Also more efficient for iterating.
20114 const keys = Object.keys(query).sort();
20115 for (let i = 0; i < keys.length; i++) {
20116 const key = keys[i];
20117 let value = query[key];
20118 switch (key) {
20119 case 'page':
20120 parts[key] = Number(value);
20121 break;
20122 case 'per_page':
20123 parts.perPage = Number(value);
20124 break;
20125 case 'context':
20126 parts.context = value;
20127 break;
20128 default:
20129 // While in theory, we could exclude "_fields" from the stableKey
20130 // because two request with different fields have the same results
20131 // We're not able to ensure that because the server can decide to omit
20132 // fields from the response even if we explicitly asked for it.
20133 // Example: Asking for titles in posts without title support.
20134 if (key === '_fields') {
20135 var _getNormalizedCommaSe;
20136 parts.fields = (_getNormalizedCommaSe = get_normalized_comma_separable(value)) !== null && _getNormalizedCommaSe !== void 0 ? _getNormalizedCommaSe : [];
20137 // Make sure to normalize value for `stableKey`
20138 value = parts.fields.join();
20139 }
20140
20141 // Two requests with different include values cannot have same results.
20142 if (key === 'include') {
20143 var _getNormalizedCommaSe2;
20144 if (typeof value === 'number') {
20145 value = value.toString();
20146 }
20147 parts.include = ((_getNormalizedCommaSe2 = get_normalized_comma_separable(value)) !== null && _getNormalizedCommaSe2 !== void 0 ? _getNormalizedCommaSe2 : []).map(Number);
20148 // Normalize value for `stableKey`.
20149 value = parts.include.join();
20150 }
20151
20152 // While it could be any deterministic string, for simplicity's
20153 // sake mimic querystring encoding for stable key.
20154 //
20155 // TODO: For consistency with PHP implementation, addQueryArgs
20156 // should accept a key value pair, which may optimize its
20157 // implementation for our use here, vs. iterating an object
20158 // with only a single key.
20159 parts.stableKey += (parts.stableKey ? '&' : '') + (0,external_wp_url_namespaceObject.addQueryArgs)('', {
20160 [key]: value
20161 }).slice(1);
20162 }
20163 }
20164 return parts;
20165 }
20166 /* harmony default export */ const get_query_parts = (with_weak_map_cache(getQueryParts));
20167
20168 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/reducer.js
20169 /**
20170 * WordPress dependencies
20171 */
20172
20173
20174
20175 /**
20176 * Internal dependencies
20177 */
20178
20179
20180
20181 function getContextFromAction(action) {
20182 const {
20183 query
20184 } = action;
20185 if (!query) {
20186 return 'default';
20187 }
20188 const queryParts = get_query_parts(query);
20189 return queryParts.context;
20190 }
20191
20192 /**
20193 * Returns a merged array of item IDs, given details of the received paginated
20194 * items. The array is sparse-like with `undefined` entries where holes exist.
20195 *
20196 * @param {?Array<number>} itemIds Original item IDs (default empty array).
20197 * @param {number[]} nextItemIds Item IDs to merge.
20198 * @param {number} page Page of items merged.
20199 * @param {number} perPage Number of items per page.
20200 *
20201 * @return {number[]} Merged array of item IDs.
20202 */
20203 function getMergedItemIds(itemIds, nextItemIds, page, perPage) {
20204 var _itemIds$length;
20205 const receivedAllIds = page === 1 && perPage === -1;
20206 if (receivedAllIds) {
20207 return nextItemIds;
20208 }
20209 const nextItemIdsStartIndex = (page - 1) * perPage;
20210
20211 // If later page has already been received, default to the larger known
20212 // size of the existing array, else calculate as extending the existing.
20213 const size = Math.max((_itemIds$length = itemIds?.length) !== null && _itemIds$length !== void 0 ? _itemIds$length : 0, nextItemIdsStartIndex + nextItemIds.length);
20214
20215 // Preallocate array since size is known.
20216 const mergedItemIds = new Array(size);
20217 for (let i = 0; i < size; i++) {
20218 // Preserve existing item ID except for subset of range of next items.
20219 // We need to check against the possible maximum upper boundary because
20220 // a page could receive fewer than what was previously stored.
20221 const isInNextItemsRange = i >= nextItemIdsStartIndex && i < nextItemIdsStartIndex + perPage;
20222 mergedItemIds[i] = isInNextItemsRange ? nextItemIds[i - nextItemIdsStartIndex] : itemIds?.[i];
20223 }
20224 return mergedItemIds;
20225 }
20226
20227 /**
20228 * Helper function to filter out entities with certain IDs.
20229 * Entities are keyed by their ID.
20230 *
20231 * @param {Object} entities Entity objects, keyed by entity ID.
20232 * @param {Array} ids Entity IDs to filter out.
20233 *
20234 * @return {Object} Filtered entities.
20235 */
20236 function removeEntitiesById(entities, ids) {
20237 return Object.fromEntries(Object.entries(entities).filter(([id]) => !ids.some(itemId => {
20238 if (Number.isInteger(itemId)) {
20239 return itemId === +id;
20240 }
20241 return itemId === id;
20242 })));
20243 }
20244
20245 /**
20246 * Reducer tracking items state, keyed by ID. Items are assumed to be normal,
20247 * where identifiers are common across all queries.
20248 *
20249 * @param {Object} state Current state.
20250 * @param {Object} action Dispatched action.
20251 *
20252 * @return {Object} Next state.
20253 */
20254 function items(state = {}, action) {
20255 switch (action.type) {
20256 case 'RECEIVE_ITEMS':
20257 {
20258 const context = getContextFromAction(action);
20259 const key = action.key || DEFAULT_ENTITY_KEY;
20260 return {
20261 ...state,
20262 [context]: {
20263 ...state[context],
20264 ...action.items.reduce((accumulator, value) => {
20265 const itemId = value?.[key];
20266 accumulator[itemId] = conservativeMapItem(state?.[context]?.[itemId], value);
20267 return accumulator;
20268 }, {})
20269 }
20270 };
20271 }
20272 case 'REMOVE_ITEMS':
20273 return Object.fromEntries(Object.entries(state).map(([itemId, contextState]) => [itemId, removeEntitiesById(contextState, action.itemIds)]));
20274 }
20275 return state;
20276 }
20277
20278 /**
20279 * Reducer tracking item completeness, keyed by ID. A complete item is one for
20280 * which all fields are known. This is used in supporting `_fields` queries,
20281 * where not all properties associated with an entity are necessarily returned.
20282 * In such cases, completeness is used as an indication of whether it would be
20283 * safe to use queried data for a non-`_fields`-limited request.
20284 *
20285 * @param {Object<string,Object<string,boolean>>} state Current state.
20286 * @param {Object} action Dispatched action.
20287 *
20288 * @return {Object<string,Object<string,boolean>>} Next state.
20289 */
20290 function itemIsComplete(state = {}, action) {
20291 switch (action.type) {
20292 case 'RECEIVE_ITEMS':
20293 {
20294 const context = getContextFromAction(action);
20295 const {
20296 query,
20297 key = DEFAULT_ENTITY_KEY
20298 } = action;
20299
20300 // An item is considered complete if it is received without an associated
20301 // fields query. Ideally, this would be implemented in such a way where the
20302 // complete aggregate of all fields would satisfy completeness. Since the
20303 // fields are not consistent across all entities, this would require
20304 // introspection on the REST schema for each entity to know which fields
20305 // compose a complete item for that entity.
20306 const queryParts = query ? get_query_parts(query) : {};
20307 const isCompleteQuery = !query || !Array.isArray(queryParts.fields);
20308 return {
20309 ...state,
20310 [context]: {
20311 ...state[context],
20312 ...action.items.reduce((result, item) => {
20313 const itemId = item?.[key];
20314
20315 // Defer to completeness if already assigned. Technically the
20316 // data may be outdated if receiving items for a field subset.
20317 result[itemId] = state?.[context]?.[itemId] || isCompleteQuery;
20318 return result;
20319 }, {})
20320 }
20321 };
20322 }
20323 case 'REMOVE_ITEMS':
20324 return Object.fromEntries(Object.entries(state).map(([itemId, contextState]) => [itemId, removeEntitiesById(contextState, action.itemIds)]));
20325 }
20326 return state;
20327 }
20328
20329 /**
20330 * Reducer tracking queries state, keyed by stable query key. Each reducer
20331 * query object includes `itemIds` and `requestingPageByPerPage`.
20332 *
20333 * @param {Object} state Current state.
20334 * @param {Object} action Dispatched action.
20335 *
20336 * @return {Object} Next state.
20337 */
20338 const receiveQueries = (0,external_wp_compose_namespaceObject.compose)([
20339 // Limit to matching action type so we don't attempt to replace action on
20340 // an unhandled action.
20341 if_matching_action(action => 'query' in action),
20342 // Inject query parts into action for use both in `onSubKey` and reducer.
20343 replace_action(action => {
20344 // `ifMatchingAction` still passes on initialization, where state is
20345 // undefined and a query is not assigned. Avoid attempting to parse
20346 // parts. `onSubKey` will omit by lack of `stableKey`.
20347 if (action.query) {
20348 return {
20349 ...action,
20350 ...get_query_parts(action.query)
20351 };
20352 }
20353 return action;
20354 }), on_sub_key('context'),
20355 // Queries shape is shared, but keyed by query `stableKey` part. Original
20356 // reducer tracks only a single query object.
20357 on_sub_key('stableKey')])((state = {}, action) => {
20358 const {
20359 type,
20360 page,
20361 perPage,
20362 key = DEFAULT_ENTITY_KEY
20363 } = action;
20364 if (type !== 'RECEIVE_ITEMS') {
20365 return state;
20366 }
20367 return {
20368 itemIds: getMergedItemIds(state?.itemIds || [], action.items.map(item => item?.[key]).filter(Boolean), page, perPage),
20369 meta: action.meta
20370 };
20371 });
20372
20373 /**
20374 * Reducer tracking queries state.
20375 *
20376 * @param {Object} state Current state.
20377 * @param {Object} action Dispatched action.
20378 *
20379 * @return {Object} Next state.
20380 */
20381 const queries = (state = {}, action) => {
20382 switch (action.type) {
20383 case 'RECEIVE_ITEMS':
20384 return receiveQueries(state, action);
20385 case 'REMOVE_ITEMS':
20386 const removedItems = action.itemIds.reduce((result, itemId) => {
20387 result[itemId] = true;
20388 return result;
20389 }, {});
20390 return Object.fromEntries(Object.entries(state).map(([queryGroup, contextQueries]) => [queryGroup, Object.fromEntries(Object.entries(contextQueries).map(([query, queryItems]) => [query, {
20391 ...queryItems,
20392 itemIds: queryItems.itemIds.filter(queryId => !removedItems[queryId])
20393 }]))]));
20394 default:
20395 return state;
20396 }
20397 };
20398 /* harmony default export */ const reducer = ((0,external_wp_data_namespaceObject.combineReducers)({
20399 items,
20400 itemIsComplete,
20401 queries
20402 }));
20403
20404 ;// CONCATENATED MODULE: ./packages/core-data/build-module/reducer.js
20405 /**
20406 * External dependencies
20407 */
20408
20409
20410 /**
20411 * WordPress dependencies
20412 */
20413
20414
20415
20416
20417 /**
20418 * Internal dependencies
20419 */
20420
20421
20422
20423
20424 /** @typedef {import('./types').AnyFunction} AnyFunction */
20425
20426 /**
20427 * Reducer managing terms state. Keyed by taxonomy slug, the value is either
20428 * undefined (if no request has been made for given taxonomy), null (if a
20429 * request is in-flight for given taxonomy), or the array of terms for the
20430 * taxonomy.
20431 *
20432 * @param {Object} state Current state.
20433 * @param {Object} action Dispatched action.
20434 *
20435 * @return {Object} Updated state.
20436 */
20437 function terms(state = {}, action) {
20438 switch (action.type) {
20439 case 'RECEIVE_TERMS':
20440 return {
20441 ...state,
20442 [action.taxonomy]: action.terms
20443 };
20444 }
20445 return state;
20446 }
20447
20448 /**
20449 * Reducer managing authors state. Keyed by id.
20450 *
20451 * @param {Object} state Current state.
20452 * @param {Object} action Dispatched action.
20453 *
20454 * @return {Object} Updated state.
20455 */
20456 function users(state = {
20457 byId: {},
20458 queries: {}
20459 }, action) {
20460 switch (action.type) {
20461 case 'RECEIVE_USER_QUERY':
20462 return {
20463 byId: {
20464 ...state.byId,
20465 // Key users by their ID.
20466 ...action.users.reduce((newUsers, user) => ({
20467 ...newUsers,
20468 [user.id]: user
20469 }), {})
20470 },
20471 queries: {
20472 ...state.queries,
20473 [action.queryID]: action.users.map(user => user.id)
20474 }
20475 };
20476 }
20477 return state;
20478 }
20479
20480 /**
20481 * Reducer managing current user state.
20482 *
20483 * @param {Object} state Current state.
20484 * @param {Object} action Dispatched action.
20485 *
20486 * @return {Object} Updated state.
20487 */
20488 function currentUser(state = {}, action) {
20489 switch (action.type) {
20490 case 'RECEIVE_CURRENT_USER':
20491 return action.currentUser;
20492 }
20493 return state;
20494 }
20495
20496 /**
20497 * Reducer managing taxonomies.
20498 *
20499 * @param {Object} state Current state.
20500 * @param {Object} action Dispatched action.
20501 *
20502 * @return {Object} Updated state.
20503 */
20504 function taxonomies(state = [], action) {
20505 switch (action.type) {
20506 case 'RECEIVE_TAXONOMIES':
20507 return action.taxonomies;
20508 }
20509 return state;
20510 }
20511
20512 /**
20513 * Reducer managing the current theme.
20514 *
20515 * @param {string|undefined} state Current state.
20516 * @param {Object} action Dispatched action.
20517 *
20518 * @return {string|undefined} Updated state.
20519 */
20520 function currentTheme(state = undefined, action) {
20521 switch (action.type) {
20522 case 'RECEIVE_CURRENT_THEME':
20523 return action.currentTheme.stylesheet;
20524 }
20525 return state;
20526 }
20527
20528 /**
20529 * Reducer managing the current global styles id.
20530 *
20531 * @param {string|undefined} state Current state.
20532 * @param {Object} action Dispatched action.
20533 *
20534 * @return {string|undefined} Updated state.
20535 */
20536 function currentGlobalStylesId(state = undefined, action) {
20537 switch (action.type) {
20538 case 'RECEIVE_CURRENT_GLOBAL_STYLES_ID':
20539 return action.id;
20540 }
20541 return state;
20542 }
20543
20544 /**
20545 * Reducer managing the theme base global styles.
20546 *
20547 * @param {Record<string, object>} state Current state.
20548 * @param {Object} action Dispatched action.
20549 *
20550 * @return {Record<string, object>} Updated state.
20551 */
20552 function themeBaseGlobalStyles(state = {}, action) {
20553 switch (action.type) {
20554 case 'RECEIVE_THEME_GLOBAL_STYLES':
20555 return {
20556 ...state,
20557 [action.stylesheet]: action.globalStyles
20558 };
20559 }
20560 return state;
20561 }
20562
20563 /**
20564 * Reducer managing the theme global styles variations.
20565 *
20566 * @param {Record<string, object>} state Current state.
20567 * @param {Object} action Dispatched action.
20568 *
20569 * @return {Record<string, object>} Updated state.
20570 */
20571 function themeGlobalStyleVariations(state = {}, action) {
20572 switch (action.type) {
20573 case 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS':
20574 return {
20575 ...state,
20576 [action.stylesheet]: action.variations
20577 };
20578 }
20579 return state;
20580 }
20581 const withMultiEntityRecordEdits = reducer => (state, action) => {
20582 if (action.type === 'UNDO' || action.type === 'REDO') {
20583 const {
20584 record
20585 } = action;
20586 let newState = state;
20587 record.forEach(({
20588 id: {
20589 kind,
20590 name,
20591 recordId
20592 },
20593 changes
20594 }) => {
20595 newState = reducer(newState, {
20596 type: 'EDIT_ENTITY_RECORD',
20597 kind,
20598 name,
20599 recordId,
20600 edits: Object.entries(changes).reduce((acc, [key, value]) => {
20601 acc[key] = action.type === 'UNDO' ? value.from : value.to;
20602 return acc;
20603 }, {})
20604 });
20605 });
20606 return newState;
20607 }
20608 return reducer(state, action);
20609 };
20610
20611 /**
20612 * Higher Order Reducer for a given entity config. It supports:
20613 *
20614 * - Fetching
20615 * - Editing
20616 * - Saving
20617 *
20618 * @param {Object} entityConfig Entity config.
20619 *
20620 * @return {AnyFunction} Reducer.
20621 */
20622 function entity(entityConfig) {
20623 return (0,external_wp_compose_namespaceObject.compose)([withMultiEntityRecordEdits,
20624 // Limit to matching action type so we don't attempt to replace action on
20625 // an unhandled action.
20626 if_matching_action(action => action.name && action.kind && action.name === entityConfig.name && action.kind === entityConfig.kind),
20627 // Inject the entity config into the action.
20628 replace_action(action => {
20629 return {
20630 key: entityConfig.key || DEFAULT_ENTITY_KEY,
20631 ...action
20632 };
20633 })])((0,external_wp_data_namespaceObject.combineReducers)({
20634 queriedData: reducer,
20635 edits: (state = {}, action) => {
20636 var _action$query$context;
20637 switch (action.type) {
20638 case 'RECEIVE_ITEMS':
20639 const context = (_action$query$context = action?.query?.context) !== null && _action$query$context !== void 0 ? _action$query$context : 'default';
20640 if (context !== 'default') {
20641 return state;
20642 }
20643 const nextState = {
20644 ...state
20645 };
20646 for (const record of action.items) {
20647 const recordId = record?.[action.key];
20648 const edits = nextState[recordId];
20649 if (!edits) {
20650 continue;
20651 }
20652 const nextEdits = Object.keys(edits).reduce((acc, key) => {
20653 var _record$key$raw;
20654 // If the edited value is still different to the persisted value,
20655 // keep the edited value in edits.
20656 if (
20657 // Edits are the "raw" attribute values, but records may have
20658 // objects with more properties, so we use `get` here for the
20659 // comparison.
20660 !es6_default()(edits[key], (_record$key$raw = record[key]?.raw) !== null && _record$key$raw !== void 0 ? _record$key$raw : record[key]) && (
20661 // Sometimes the server alters the sent value which means
20662 // we need to also remove the edits before the api request.
20663 !action.persistedEdits || !es6_default()(edits[key], action.persistedEdits[key]))) {
20664 acc[key] = edits[key];
20665 }
20666 return acc;
20667 }, {});
20668 if (Object.keys(nextEdits).length) {
20669 nextState[recordId] = nextEdits;
20670 } else {
20671 delete nextState[recordId];
20672 }
20673 }
20674 return nextState;
20675 case 'EDIT_ENTITY_RECORD':
20676 const nextEdits = {
20677 ...state[action.recordId],
20678 ...action.edits
20679 };
20680 Object.keys(nextEdits).forEach(key => {
20681 // Delete cleared edits so that the properties
20682 // are not considered dirty.
20683 if (nextEdits[key] === undefined) {
20684 delete nextEdits[key];
20685 }
20686 });
20687 return {
20688 ...state,
20689 [action.recordId]: nextEdits
20690 };
20691 }
20692 return state;
20693 },
20694 saving: (state = {}, action) => {
20695 switch (action.type) {
20696 case 'SAVE_ENTITY_RECORD_START':
20697 case 'SAVE_ENTITY_RECORD_FINISH':
20698 return {
20699 ...state,
20700 [action.recordId]: {
20701 pending: action.type === 'SAVE_ENTITY_RECORD_START',
20702 error: action.error,
20703 isAutosave: action.isAutosave
20704 }
20705 };
20706 }
20707 return state;
20708 },
20709 deleting: (state = {}, action) => {
20710 switch (action.type) {
20711 case 'DELETE_ENTITY_RECORD_START':
20712 case 'DELETE_ENTITY_RECORD_FINISH':
20713 return {
20714 ...state,
20715 [action.recordId]: {
20716 pending: action.type === 'DELETE_ENTITY_RECORD_START',
20717 error: action.error
20718 }
20719 };
20720 }
20721 return state;
20722 },
20723 revisions: (state = {}, action) => {
20724 // Use the same queriedDataReducer shape for revisions.
20725 if (action.type === 'RECEIVE_ITEM_REVISIONS') {
20726 const recordKey = action.recordKey;
20727 delete action.recordKey;
20728 const newState = reducer(state[recordKey], {
20729 ...action,
20730 type: 'RECEIVE_ITEMS'
20731 });
20732 return {
20733 ...state,
20734 [recordKey]: newState
20735 };
20736 }
20737 if (action.type === 'REMOVE_ITEMS') {
20738 return Object.fromEntries(Object.entries(state).filter(([id]) => !action.itemIds.some(itemId => {
20739 if (Number.isInteger(itemId)) {
20740 return itemId === +id;
20741 }
20742 return itemId === id;
20743 })));
20744 }
20745 return state;
20746 }
20747 }));
20748 }
20749
20750 /**
20751 * Reducer keeping track of the registered entities.
20752 *
20753 * @param {Object} state Current state.
20754 * @param {Object} action Dispatched action.
20755 *
20756 * @return {Object} Updated state.
20757 */
20758 function entitiesConfig(state = rootEntitiesConfig, action) {
20759 switch (action.type) {
20760 case 'ADD_ENTITIES':
20761 return [...state, ...action.entities];
20762 }
20763 return state;
20764 }
20765
20766 /**
20767 * Reducer keeping track of the registered entities config and data.
20768 *
20769 * @param {Object} state Current state.
20770 * @param {Object} action Dispatched action.
20771 *
20772 * @return {Object} Updated state.
20773 */
20774 const entities = (state = {}, action) => {
20775 const newConfig = entitiesConfig(state.config, action);
20776
20777 // Generates a dynamic reducer for the entities.
20778 let entitiesDataReducer = state.reducer;
20779 if (!entitiesDataReducer || newConfig !== state.config) {
20780 const entitiesByKind = newConfig.reduce((acc, record) => {
20781 const {
20782 kind
20783 } = record;
20784 if (!acc[kind]) {
20785 acc[kind] = [];
20786 }
20787 acc[kind].push(record);
20788 return acc;
20789 }, {});
20790 entitiesDataReducer = (0,external_wp_data_namespaceObject.combineReducers)(Object.entries(entitiesByKind).reduce((memo, [kind, subEntities]) => {
20791 const kindReducer = (0,external_wp_data_namespaceObject.combineReducers)(subEntities.reduce((kindMemo, entityConfig) => ({
20792 ...kindMemo,
20793 [entityConfig.name]: entity(entityConfig)
20794 }), {}));
20795 memo[kind] = kindReducer;
20796 return memo;
20797 }, {}));
20798 }
20799 const newData = entitiesDataReducer(state.records, action);
20800 if (newData === state.records && newConfig === state.config && entitiesDataReducer === state.reducer) {
20801 return state;
20802 }
20803 return {
20804 reducer: entitiesDataReducer,
20805 records: newData,
20806 config: newConfig
20807 };
20808 };
20809
20810 /**
20811 * @type {UndoManager}
20812 */
20813 function undoManager(state = createUndoManager()) {
20814 return state;
20815 }
20816 function editsReference(state = {}, action) {
20817 switch (action.type) {
20818 case 'EDIT_ENTITY_RECORD':
20819 case 'UNDO':
20820 case 'REDO':
20821 return {};
20822 }
20823 return state;
20824 }
20825
20826 /**
20827 * Reducer managing embed preview data.
20828 *
20829 * @param {Object} state Current state.
20830 * @param {Object} action Dispatched action.
20831 *
20832 * @return {Object} Updated state.
20833 */
20834 function embedPreviews(state = {}, action) {
20835 switch (action.type) {
20836 case 'RECEIVE_EMBED_PREVIEW':
20837 const {
20838 url,
20839 preview
20840 } = action;
20841 return {
20842 ...state,
20843 [url]: preview
20844 };
20845 }
20846 return state;
20847 }
20848
20849 /**
20850 * State which tracks whether the user can perform an action on a REST
20851 * resource.
20852 *
20853 * @param {Object} state Current state.
20854 * @param {Object} action Dispatched action.
20855 *
20856 * @return {Object} Updated state.
20857 */
20858 function userPermissions(state = {}, action) {
20859 switch (action.type) {
20860 case 'RECEIVE_USER_PERMISSION':
20861 return {
20862 ...state,
20863 [action.key]: action.isAllowed
20864 };
20865 }
20866 return state;
20867 }
20868
20869 /**
20870 * Reducer returning autosaves keyed by their parent's post id.
20871 *
20872 * @param {Object} state Current state.
20873 * @param {Object} action Dispatched action.
20874 *
20875 * @return {Object} Updated state.
20876 */
20877 function autosaves(state = {}, action) {
20878 switch (action.type) {
20879 case 'RECEIVE_AUTOSAVES':
20880 const {
20881 postId,
20882 autosaves: autosavesData
20883 } = action;
20884 return {
20885 ...state,
20886 [postId]: autosavesData
20887 };
20888 }
20889 return state;
20890 }
20891 function blockPatterns(state = [], action) {
20892 switch (action.type) {
20893 case 'RECEIVE_BLOCK_PATTERNS':
20894 return action.patterns;
20895 }
20896 return state;
20897 }
20898 function blockPatternCategories(state = [], action) {
20899 switch (action.type) {
20900 case 'RECEIVE_BLOCK_PATTERN_CATEGORIES':
20901 return action.categories;
20902 }
20903 return state;
20904 }
20905 function userPatternCategories(state = [], action) {
20906 switch (action.type) {
20907 case 'RECEIVE_USER_PATTERN_CATEGORIES':
20908 return action.patternCategories;
20909 }
20910 return state;
20911 }
20912 function navigationFallbackId(state = null, action) {
20913 switch (action.type) {
20914 case 'RECEIVE_NAVIGATION_FALLBACK_ID':
20915 return action.fallbackId;
20916 }
20917 return state;
20918 }
20919
20920 /**
20921 * Reducer managing the theme global styles revisions.
20922 *
20923 * @param {Record<string, object>} state Current state.
20924 * @param {Object} action Dispatched action.
20925 *
20926 * @return {Record<string, object>} Updated state.
20927 */
20928 function themeGlobalStyleRevisions(state = {}, action) {
20929 switch (action.type) {
20930 case 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS':
20931 return {
20932 ...state,
20933 [action.currentId]: action.revisions
20934 };
20935 }
20936 return state;
20937 }
20938
20939 /**
20940 * Reducer managing the template lookup per query.
20941 *
20942 * @param {Record<string, string>} state Current state.
20943 * @param {Object} action Dispatched action.
20944 *
20945 * @return {Record<string, string>} Updated state.
20946 */
20947 function defaultTemplates(state = {}, action) {
20948 switch (action.type) {
20949 case 'RECEIVE_DEFAULT_TEMPLATE':
20950 return {
20951 ...state,
20952 [JSON.stringify(action.query)]: action.templateId
20953 };
20954 }
20955 return state;
20956 }
20957 /* harmony default export */ const build_module_reducer = ((0,external_wp_data_namespaceObject.combineReducers)({
20958 terms,
20959 users,
20960 currentTheme,
20961 currentGlobalStylesId,
20962 currentUser,
20963 themeGlobalStyleVariations,
20964 themeBaseGlobalStyles,
20965 themeGlobalStyleRevisions,
20966 taxonomies,
20967 entities,
20968 editsReference,
20969 undoManager,
20970 embedPreviews,
20971 userPermissions,
20972 autosaves,
20973 blockPatterns,
20974 blockPatternCategories,
20975 userPatternCategories,
20976 navigationFallbackId,
20977 defaultTemplates
20978 }));
20979
20980 // EXTERNAL MODULE: ./node_modules/equivalent-key-map/equivalent-key-map.js
20981 var equivalent_key_map = __webpack_require__(2167);
20982 var equivalent_key_map_default = /*#__PURE__*/__webpack_require__.n(equivalent_key_map);
20983 ;// CONCATENATED MODULE: ./packages/core-data/build-module/queried-data/selectors.js
20984 /**
20985 * External dependencies
20986 */
20987
20988
20989 /**
20990 * WordPress dependencies
20991 */
20992
20993
20994 /**
20995 * Internal dependencies
20996 */
20997
20998
20999
21000 /**
21001 * Cache of state keys to EquivalentKeyMap where the inner map tracks queries
21002 * to their resulting items set. WeakMap allows garbage collection on expired
21003 * state references.
21004 *
21005 * @type {WeakMap<Object,EquivalentKeyMap>}
21006 */
21007 const queriedItemsCacheByState = new WeakMap();
21008
21009 /**
21010 * Returns items for a given query, or null if the items are not known.
21011 *
21012 * @param {Object} state State object.
21013 * @param {?Object} query Optional query.
21014 *
21015 * @return {?Array} Query items.
21016 */
21017 function getQueriedItemsUncached(state, query) {
21018 const {
21019 stableKey,
21020 page,
21021 perPage,
21022 include,
21023 fields,
21024 context
21025 } = get_query_parts(query);
21026 let itemIds;
21027 if (state.queries?.[context]?.[stableKey]) {
21028 itemIds = state.queries[context][stableKey].itemIds;
21029 }
21030 if (!itemIds) {
21031 return null;
21032 }
21033 const startOffset = perPage === -1 ? 0 : (page - 1) * perPage;
21034 const endOffset = perPage === -1 ? itemIds.length : Math.min(startOffset + perPage, itemIds.length);
21035 const items = [];
21036 for (let i = startOffset; i < endOffset; i++) {
21037 const itemId = itemIds[i];
21038 if (Array.isArray(include) && !include.includes(itemId)) {
21039 continue;
21040 }
21041 if (itemId === undefined) {
21042 continue;
21043 }
21044 // Having a target item ID doesn't guarantee that this object has been queried.
21045 if (!state.items[context]?.hasOwnProperty(itemId)) {
21046 return null;
21047 }
21048 const item = state.items[context][itemId];
21049 let filteredItem;
21050 if (Array.isArray(fields)) {
21051 filteredItem = {};
21052 for (let f = 0; f < fields.length; f++) {
21053 const field = fields[f].split('.');
21054 let value = item;
21055 field.forEach(fieldName => {
21056 value = value?.[fieldName];
21057 });
21058 setNestedValue(filteredItem, field, value);
21059 }
21060 } else {
21061 // If expecting a complete item, validate that completeness, or
21062 // otherwise abort.
21063 if (!state.itemIsComplete[context]?.[itemId]) {
21064 return null;
21065 }
21066 filteredItem = item;
21067 }
21068 items.push(filteredItem);
21069 }
21070 return items;
21071 }
21072
21073 /**
21074 * Returns items for a given query, or null if the items are not known. Caches
21075 * result both per state (by reference) and per query (by deep equality).
21076 * The caching approach is intended to be durable to query objects which are
21077 * deeply but not referentially equal, since otherwise:
21078 *
21079 * `getQueriedItems( state, {} ) !== getQueriedItems( state, {} )`
21080 *
21081 * @param {Object} state State object.
21082 * @param {?Object} query Optional query.
21083 *
21084 * @return {?Array} Query items.
21085 */
21086 const getQueriedItems = (0,external_wp_data_namespaceObject.createSelector)((state, query = {}) => {
21087 let queriedItemsCache = queriedItemsCacheByState.get(state);
21088 if (queriedItemsCache) {
21089 const queriedItems = queriedItemsCache.get(query);
21090 if (queriedItems !== undefined) {
21091 return queriedItems;
21092 }
21093 } else {
21094 queriedItemsCache = new (equivalent_key_map_default())();
21095 queriedItemsCacheByState.set(state, queriedItemsCache);
21096 }
21097 const items = getQueriedItemsUncached(state, query);
21098 queriedItemsCache.set(query, items);
21099 return items;
21100 });
21101 function getQueriedTotalItems(state, query = {}) {
21102 var _state$queries$contex;
21103 const {
21104 stableKey,
21105 context
21106 } = get_query_parts(query);
21107 return (_state$queries$contex = state.queries?.[context]?.[stableKey]?.meta?.totalItems) !== null && _state$queries$contex !== void 0 ? _state$queries$contex : null;
21108 }
21109 function getQueriedTotalPages(state, query = {}) {
21110 var _state$queries$contex2;
21111 const {
21112 stableKey,
21113 context
21114 } = get_query_parts(query);
21115 return (_state$queries$contex2 = state.queries?.[context]?.[stableKey]?.meta?.totalPages) !== null && _state$queries$contex2 !== void 0 ? _state$queries$contex2 : null;
21116 }
21117
21118 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/is-numeric-id.js
21119 /**
21120 * Checks argument to determine if it's a numeric ID.
21121 * For example, '123' is a numeric ID, but '123abc' is not.
21122 *
21123 * @param {any} id the argument to determine if it's a numeric ID.
21124 * @return {boolean} true if the string is a numeric ID, false otherwise.
21125 */
21126 function isNumericID(id) {
21127 return /^\s*\d+\s*$/.test(id);
21128 }
21129
21130 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/is-raw-attribute.js
21131 /**
21132 * Checks whether the attribute is a "raw" attribute or not.
21133 *
21134 * @param {Object} entity Entity record.
21135 * @param {string} attribute Attribute name.
21136 *
21137 * @return {boolean} Is the attribute raw
21138 */
21139 function isRawAttribute(entity, attribute) {
21140 return (entity.rawAttributes || []).includes(attribute);
21141 }
21142
21143 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/user-permissions.js
21144 const ALLOWED_RESOURCE_ACTIONS = ['create', 'read', 'update', 'delete'];
21145 function getUserPermissionsFromResponse(response) {
21146 const permissions = {};
21147
21148 // Optional chaining operator is used here because the API requests don't
21149 // return the expected result in the React native version. Instead, API requests
21150 // only return the result, without including response properties like the headers.
21151 const allowedMethods = response.headers?.get('allow') || '';
21152 const methods = {
21153 create: 'POST',
21154 read: 'GET',
21155 update: 'PUT',
21156 delete: 'DELETE'
21157 };
21158 for (const [actionName, methodName] of Object.entries(methods)) {
21159 permissions[actionName] = allowedMethods.includes(methodName);
21160 }
21161 return permissions;
21162 }
21163 function getUserPermissionCacheKey(action, resource, id) {
21164 const key = (typeof resource === 'object' ? [action, resource.kind, resource.name, resource.id] : [action, resource, id]).filter(Boolean).join('/');
21165 return key;
21166 }
21167
21168 ;// CONCATENATED MODULE: ./packages/core-data/build-module/selectors.js
21169 /**
21170 * WordPress dependencies
21171 */
21172
21173
21174
21175
21176 /**
21177 * Internal dependencies
21178 */
21179
21180
21181
21182
21183
21184 // This is an incomplete, high-level approximation of the State type.
21185 // It makes the selectors slightly more safe, but is intended to evolve
21186 // into a more detailed representation over time.
21187 // See https://github.com/WordPress/gutenberg/pull/40025#discussion_r865410589 for more context.
21188
21189 /**
21190 * HTTP Query parameters sent with the API request to fetch the entity records.
21191 */
21192
21193 /**
21194 * Arguments for EntityRecord selectors.
21195 */
21196
21197 /**
21198 * Shared reference to an empty object for cases where it is important to avoid
21199 * returning a new object reference on every invocation, as in a connected or
21200 * other pure component which performs `shouldComponentUpdate` check on props.
21201 * This should be used as a last resort, since the normalized data should be
21202 * maintained by the reducer result in state.
21203 */
21204 const EMPTY_OBJECT = {};
21205
21206 /**
21207 * Returns true if a request is in progress for embed preview data, or false
21208 * otherwise.
21209 *
21210 * @param state Data state.
21211 * @param url URL the preview would be for.
21212 *
21213 * @return Whether a request is in progress for an embed preview.
21214 */
21215 const isRequestingEmbedPreview = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, url) => {
21216 return select(STORE_NAME).isResolving('getEmbedPreview', [url]);
21217 });
21218
21219 /**
21220 * Returns all available authors.
21221 *
21222 * @deprecated since 11.3. Callers should use `select( 'core' ).getUsers({ who: 'authors' })` instead.
21223 *
21224 * @param state Data state.
21225 * @param query Optional object of query parameters to
21226 * 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).
21227 * @return Authors list.
21228 */
21229 function getAuthors(state, query) {
21230 external_wp_deprecated_default()("select( 'core' ).getAuthors()", {
21231 since: '5.9',
21232 alternative: "select( 'core' ).getUsers({ who: 'authors' })"
21233 });
21234 const path = (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/users/?who=authors&per_page=100', query);
21235 return getUserQueryResults(state, path);
21236 }
21237
21238 /**
21239 * Returns the current user.
21240 *
21241 * @param state Data state.
21242 *
21243 * @return Current user object.
21244 */
21245 function getCurrentUser(state) {
21246 return state.currentUser;
21247 }
21248
21249 /**
21250 * Returns all the users returned by a query ID.
21251 *
21252 * @param state Data state.
21253 * @param queryID Query ID.
21254 *
21255 * @return Users list.
21256 */
21257 const getUserQueryResults = (0,external_wp_data_namespaceObject.createSelector)((state, queryID) => {
21258 var _state$users$queries$;
21259 const queryResults = (_state$users$queries$ = state.users.queries[queryID]) !== null && _state$users$queries$ !== void 0 ? _state$users$queries$ : [];
21260 return queryResults.map(id => state.users.byId[id]);
21261 }, (state, queryID) => [state.users.queries[queryID], state.users.byId]);
21262
21263 /**
21264 * Returns the loaded entities for the given kind.
21265 *
21266 * @deprecated since WordPress 6.0. Use getEntitiesConfig instead
21267 * @param state Data state.
21268 * @param kind Entity kind.
21269 *
21270 * @return Array of entities with config matching kind.
21271 */
21272 function getEntitiesByKind(state, kind) {
21273 external_wp_deprecated_default()("wp.data.select( 'core' ).getEntitiesByKind()", {
21274 since: '6.0',
21275 alternative: "wp.data.select( 'core' ).getEntitiesConfig()"
21276 });
21277 return getEntitiesConfig(state, kind);
21278 }
21279
21280 /**
21281 * Returns the loaded entities for the given kind.
21282 *
21283 * @param state Data state.
21284 * @param kind Entity kind.
21285 *
21286 * @return Array of entities with config matching kind.
21287 */
21288 const getEntitiesConfig = (0,external_wp_data_namespaceObject.createSelector)((state, kind) => state.entities.config.filter(entity => entity.kind === kind), /* eslint-disable @typescript-eslint/no-unused-vars */
21289 (state, kind) => state.entities.config
21290 /* eslint-enable @typescript-eslint/no-unused-vars */);
21291 /**
21292 * Returns the entity config given its kind and name.
21293 *
21294 * @deprecated since WordPress 6.0. Use getEntityConfig instead
21295 * @param state Data state.
21296 * @param kind Entity kind.
21297 * @param name Entity name.
21298 *
21299 * @return Entity config
21300 */
21301 function getEntity(state, kind, name) {
21302 external_wp_deprecated_default()("wp.data.select( 'core' ).getEntity()", {
21303 since: '6.0',
21304 alternative: "wp.data.select( 'core' ).getEntityConfig()"
21305 });
21306 return getEntityConfig(state, kind, name);
21307 }
21308
21309 /**
21310 * Returns the entity config given its kind and name.
21311 *
21312 * @param state Data state.
21313 * @param kind Entity kind.
21314 * @param name Entity name.
21315 *
21316 * @return Entity config
21317 */
21318 function getEntityConfig(state, kind, name) {
21319 return state.entities.config?.find(config => config.kind === kind && config.name === name);
21320 }
21321
21322 /**
21323 * GetEntityRecord is declared as a *callable interface* with
21324 * two signatures to work around the fact that TypeScript doesn't
21325 * allow currying generic functions:
21326 *
21327 * ```ts
21328 * type CurriedState = F extends ( state: any, ...args: infer P ) => infer R
21329 * ? ( ...args: P ) => R
21330 * : F;
21331 * type Selector = <K extends string | number>(
21332 * state: any,
21333 * kind: K,
21334 * key: K extends string ? 'string value' : false
21335 * ) => K;
21336 * type BadlyInferredSignature = CurriedState< Selector >
21337 * // BadlyInferredSignature evaluates to:
21338 * // (kind: string number, key: false | "string value") => string number
21339 * ```
21340 *
21341 * The signature without the state parameter shipped as CurriedSignature
21342 * is used in the return value of `select( coreStore )`.
21343 *
21344 * See https://github.com/WordPress/gutenberg/pull/41578 for more details.
21345 */
21346
21347 /**
21348 * Returns the Entity's record object by key. Returns `null` if the value is not
21349 * yet received, undefined if the value entity is known to not exist, or the
21350 * entity object if it exists and is received.
21351 *
21352 * @param state State tree
21353 * @param kind Entity kind.
21354 * @param name Entity name.
21355 * @param key Record's key
21356 * @param query Optional query. If requesting specific
21357 * 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]".
21358 *
21359 * @return Record.
21360 */
21361 const getEntityRecord = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, key, query) => {
21362 var _query$context;
21363 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21364 if (!queriedState) {
21365 return undefined;
21366 }
21367 const context = (_query$context = query?.context) !== null && _query$context !== void 0 ? _query$context : 'default';
21368 if (query === undefined) {
21369 // If expecting a complete item, validate that completeness.
21370 if (!queriedState.itemIsComplete[context]?.[key]) {
21371 return undefined;
21372 }
21373 return queriedState.items[context][key];
21374 }
21375 const item = queriedState.items[context]?.[key];
21376 if (item && query._fields) {
21377 var _getNormalizedCommaSe;
21378 const filteredItem = {};
21379 const fields = (_getNormalizedCommaSe = get_normalized_comma_separable(query._fields)) !== null && _getNormalizedCommaSe !== void 0 ? _getNormalizedCommaSe : [];
21380 for (let f = 0; f < fields.length; f++) {
21381 const field = fields[f].split('.');
21382 let value = item;
21383 field.forEach(fieldName => {
21384 value = value?.[fieldName];
21385 });
21386 setNestedValue(filteredItem, field, value);
21387 }
21388 return filteredItem;
21389 }
21390 return item;
21391 }, (state, kind, name, recordId, query) => {
21392 var _query$context2;
21393 const context = (_query$context2 = query?.context) !== null && _query$context2 !== void 0 ? _query$context2 : 'default';
21394 return [state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]];
21395 });
21396
21397 /**
21398 * Normalizes `recordKey`s that look like numeric IDs to numbers.
21399 *
21400 * @param args EntityRecordArgs the selector arguments.
21401 * @return EntityRecordArgs the normalized arguments.
21402 */
21403 getEntityRecord.__unstableNormalizeArgs = args => {
21404 const newArgs = [...args];
21405 const recordKey = newArgs?.[2];
21406
21407 // If recordKey looks to be a numeric ID then coerce to number.
21408 newArgs[2] = isNumericID(recordKey) ? Number(recordKey) : recordKey;
21409 return newArgs;
21410 };
21411
21412 /**
21413 * 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.
21414 *
21415 * @param state State tree
21416 * @param kind Entity kind.
21417 * @param name Entity name.
21418 * @param key Record's key
21419 *
21420 * @return Record.
21421 */
21422 function __experimentalGetEntityRecordNoResolver(state, kind, name, key) {
21423 return getEntityRecord(state, kind, name, key);
21424 }
21425
21426 /**
21427 * Returns the entity's record object by key,
21428 * with its attributes mapped to their raw values.
21429 *
21430 * @param state State tree.
21431 * @param kind Entity kind.
21432 * @param name Entity name.
21433 * @param key Record's key.
21434 *
21435 * @return Object with the entity's raw attributes.
21436 */
21437 const getRawEntityRecord = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, key) => {
21438 const record = getEntityRecord(state, kind, name, key);
21439 return record && Object.keys(record).reduce((accumulator, _key) => {
21440 if (isRawAttribute(getEntityConfig(state, kind, name), _key)) {
21441 var _record$_key$raw;
21442 // Because edits are the "raw" attribute values,
21443 // we return those from record selectors to make rendering,
21444 // comparisons, and joins with edits easier.
21445 accumulator[_key] = (_record$_key$raw = record[_key]?.raw) !== null && _record$_key$raw !== void 0 ? _record$_key$raw : record[_key];
21446 } else {
21447 accumulator[_key] = record[_key];
21448 }
21449 return accumulator;
21450 }, {});
21451 }, (state, kind, name, recordId, query) => {
21452 var _query$context3;
21453 const context = (_query$context3 = query?.context) !== null && _query$context3 !== void 0 ? _query$context3 : 'default';
21454 return [state.entities.config, state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]];
21455 });
21456
21457 /**
21458 * Returns true if records have been received for the given set of parameters,
21459 * or false otherwise.
21460 *
21461 * @param state State tree
21462 * @param kind Entity kind.
21463 * @param name Entity name.
21464 * @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".
21465 *
21466 * @return Whether entity records have been received.
21467 */
21468 function hasEntityRecords(state, kind, name, query) {
21469 return Array.isArray(getEntityRecords(state, kind, name, query));
21470 }
21471
21472 /**
21473 * GetEntityRecord is declared as a *callable interface* with
21474 * two signatures to work around the fact that TypeScript doesn't
21475 * allow currying generic functions.
21476 *
21477 * @see GetEntityRecord
21478 * @see https://github.com/WordPress/gutenberg/pull/41578
21479 */
21480
21481 /**
21482 * Returns the Entity's records.
21483 *
21484 * @param state State tree
21485 * @param kind Entity kind.
21486 * @param name Entity name.
21487 * @param query Optional terms query. If requesting specific
21488 * 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".
21489 *
21490 * @return Records.
21491 */
21492 const getEntityRecords = (state, kind, name, query) => {
21493 // Queried data state is prepopulated for all known entities. If this is not
21494 // assigned for the given parameters, then it is known to not exist.
21495 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21496 if (!queriedState) {
21497 return null;
21498 }
21499 return getQueriedItems(queriedState, query);
21500 };
21501
21502 /**
21503 * Returns the Entity's total available records for a given query (ignoring pagination).
21504 *
21505 * @param state State tree
21506 * @param kind Entity kind.
21507 * @param name Entity name.
21508 * @param query Optional terms query. If requesting specific
21509 * 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".
21510 *
21511 * @return number | null.
21512 */
21513 const getEntityRecordsTotalItems = (state, kind, name, query) => {
21514 // Queried data state is prepopulated for all known entities. If this is not
21515 // assigned for the given parameters, then it is known to not exist.
21516 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21517 if (!queriedState) {
21518 return null;
21519 }
21520 return getQueriedTotalItems(queriedState, query);
21521 };
21522
21523 /**
21524 * Returns the number of available pages for the given query.
21525 *
21526 * @param state State tree
21527 * @param kind Entity kind.
21528 * @param name Entity name.
21529 * @param query Optional terms query. If requesting specific
21530 * 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".
21531 *
21532 * @return number | null.
21533 */
21534 const getEntityRecordsTotalPages = (state, kind, name, query) => {
21535 // Queried data state is prepopulated for all known entities. If this is not
21536 // assigned for the given parameters, then it is known to not exist.
21537 const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
21538 if (!queriedState) {
21539 return null;
21540 }
21541 if (query.per_page === -1) {
21542 return 1;
21543 }
21544 const totalItems = getQueriedTotalItems(queriedState, query);
21545 if (!totalItems) {
21546 return totalItems;
21547 }
21548 // If `per_page` is not set and the query relies on the defaults of the
21549 // REST endpoint, get the info from query's meta.
21550 if (!query.per_page) {
21551 return getQueriedTotalPages(queriedState, query);
21552 }
21553 return Math.ceil(totalItems / query.per_page);
21554 };
21555 /**
21556 * Returns the list of dirty entity records.
21557 *
21558 * @param state State tree.
21559 *
21560 * @return The list of updated records
21561 */
21562 const __experimentalGetDirtyEntityRecords = (0,external_wp_data_namespaceObject.createSelector)(state => {
21563 const {
21564 entities: {
21565 records
21566 }
21567 } = state;
21568 const dirtyRecords = [];
21569 Object.keys(records).forEach(kind => {
21570 Object.keys(records[kind]).forEach(name => {
21571 const primaryKeys = Object.keys(records[kind][name].edits).filter(primaryKey =>
21572 // The entity record must exist (not be deleted),
21573 // and it must have edits.
21574 getEntityRecord(state, kind, name, primaryKey) && hasEditsForEntityRecord(state, kind, name, primaryKey));
21575 if (primaryKeys.length) {
21576 const entityConfig = getEntityConfig(state, kind, name);
21577 primaryKeys.forEach(primaryKey => {
21578 const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey);
21579 dirtyRecords.push({
21580 // We avoid using primaryKey because it's transformed into a string
21581 // when it's used as an object key.
21582 key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined,
21583 title: entityConfig?.getTitle?.(entityRecord) || '',
21584 name,
21585 kind
21586 });
21587 });
21588 }
21589 });
21590 });
21591 return dirtyRecords;
21592 }, state => [state.entities.records]);
21593
21594 /**
21595 * Returns the list of entities currently being saved.
21596 *
21597 * @param state State tree.
21598 *
21599 * @return The list of records being saved.
21600 */
21601 const __experimentalGetEntitiesBeingSaved = (0,external_wp_data_namespaceObject.createSelector)(state => {
21602 const {
21603 entities: {
21604 records
21605 }
21606 } = state;
21607 const recordsBeingSaved = [];
21608 Object.keys(records).forEach(kind => {
21609 Object.keys(records[kind]).forEach(name => {
21610 const primaryKeys = Object.keys(records[kind][name].saving).filter(primaryKey => isSavingEntityRecord(state, kind, name, primaryKey));
21611 if (primaryKeys.length) {
21612 const entityConfig = getEntityConfig(state, kind, name);
21613 primaryKeys.forEach(primaryKey => {
21614 const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey);
21615 recordsBeingSaved.push({
21616 // We avoid using primaryKey because it's transformed into a string
21617 // when it's used as an object key.
21618 key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined,
21619 title: entityConfig?.getTitle?.(entityRecord) || '',
21620 name,
21621 kind
21622 });
21623 });
21624 }
21625 });
21626 });
21627 return recordsBeingSaved;
21628 }, state => [state.entities.records]);
21629
21630 /**
21631 * Returns the specified entity record's edits.
21632 *
21633 * @param state State tree.
21634 * @param kind Entity kind.
21635 * @param name Entity name.
21636 * @param recordId Record ID.
21637 *
21638 * @return The entity record's edits.
21639 */
21640 function getEntityRecordEdits(state, kind, name, recordId) {
21641 return state.entities.records?.[kind]?.[name]?.edits?.[recordId];
21642 }
21643
21644 /**
21645 * Returns the specified entity record's non transient edits.
21646 *
21647 * Transient edits don't create an undo level, and
21648 * are not considered for change detection.
21649 * They are defined in the entity's config.
21650 *
21651 * @param state State tree.
21652 * @param kind Entity kind.
21653 * @param name Entity name.
21654 * @param recordId Record ID.
21655 *
21656 * @return The entity record's non transient edits.
21657 */
21658 const getEntityRecordNonTransientEdits = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, recordId) => {
21659 const {
21660 transientEdits
21661 } = getEntityConfig(state, kind, name) || {};
21662 const edits = getEntityRecordEdits(state, kind, name, recordId) || {};
21663 if (!transientEdits) {
21664 return edits;
21665 }
21666 return Object.keys(edits).reduce((acc, key) => {
21667 if (!transientEdits[key]) {
21668 acc[key] = edits[key];
21669 }
21670 return acc;
21671 }, {});
21672 }, (state, kind, name, recordId) => [state.entities.config, state.entities.records?.[kind]?.[name]?.edits?.[recordId]]);
21673
21674 /**
21675 * Returns true if the specified entity record has edits,
21676 * and false otherwise.
21677 *
21678 * @param state State tree.
21679 * @param kind Entity kind.
21680 * @param name Entity name.
21681 * @param recordId Record ID.
21682 *
21683 * @return Whether the entity record has edits or not.
21684 */
21685 function hasEditsForEntityRecord(state, kind, name, recordId) {
21686 return isSavingEntityRecord(state, kind, name, recordId) || Object.keys(getEntityRecordNonTransientEdits(state, kind, name, recordId)).length > 0;
21687 }
21688
21689 /**
21690 * Returns the specified entity record, merged with its edits.
21691 *
21692 * @param state State tree.
21693 * @param kind Entity kind.
21694 * @param name Entity name.
21695 * @param recordId Record ID.
21696 *
21697 * @return The entity record, merged with its edits.
21698 */
21699 const getEditedEntityRecord = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, recordId) => {
21700 const raw = getRawEntityRecord(state, kind, name, recordId);
21701 const edited = getEntityRecordEdits(state, kind, name, recordId);
21702 // Never return a non-falsy empty object. Unfortunately we can't return
21703 // undefined or null because we were previously returning an empty
21704 // object, so trying to read properties from the result would throw.
21705 // Using false here is a workaround to avoid breaking changes.
21706 if (!raw && !edited) {
21707 return false;
21708 }
21709 return {
21710 ...raw,
21711 ...edited
21712 };
21713 }, (state, kind, name, recordId, query) => {
21714 var _query$context4;
21715 const context = (_query$context4 = query?.context) !== null && _query$context4 !== void 0 ? _query$context4 : 'default';
21716 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]];
21717 });
21718
21719 /**
21720 * Returns true if the specified entity record is autosaving, and false otherwise.
21721 *
21722 * @param state State tree.
21723 * @param kind Entity kind.
21724 * @param name Entity name.
21725 * @param recordId Record ID.
21726 *
21727 * @return Whether the entity record is autosaving or not.
21728 */
21729 function isAutosavingEntityRecord(state, kind, name, recordId) {
21730 var _state$entities$recor;
21731 const {
21732 pending,
21733 isAutosave
21734 } = (_state$entities$recor = state.entities.records?.[kind]?.[name]?.saving?.[recordId]) !== null && _state$entities$recor !== void 0 ? _state$entities$recor : {};
21735 return Boolean(pending && isAutosave);
21736 }
21737
21738 /**
21739 * Returns true if the specified entity record is saving, and false otherwise.
21740 *
21741 * @param state State tree.
21742 * @param kind Entity kind.
21743 * @param name Entity name.
21744 * @param recordId Record ID.
21745 *
21746 * @return Whether the entity record is saving or not.
21747 */
21748 function isSavingEntityRecord(state, kind, name, recordId) {
21749 var _state$entities$recor2;
21750 return (_state$entities$recor2 = state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.pending) !== null && _state$entities$recor2 !== void 0 ? _state$entities$recor2 : false;
21751 }
21752
21753 /**
21754 * Returns true if the specified entity record is deleting, and false otherwise.
21755 *
21756 * @param state State tree.
21757 * @param kind Entity kind.
21758 * @param name Entity name.
21759 * @param recordId Record ID.
21760 *
21761 * @return Whether the entity record is deleting or not.
21762 */
21763 function isDeletingEntityRecord(state, kind, name, recordId) {
21764 var _state$entities$recor3;
21765 return (_state$entities$recor3 = state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.pending) !== null && _state$entities$recor3 !== void 0 ? _state$entities$recor3 : false;
21766 }
21767
21768 /**
21769 * Returns the specified entity record's last save error.
21770 *
21771 * @param state State tree.
21772 * @param kind Entity kind.
21773 * @param name Entity name.
21774 * @param recordId Record ID.
21775 *
21776 * @return The entity record's save error.
21777 */
21778 function getLastEntitySaveError(state, kind, name, recordId) {
21779 return state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.error;
21780 }
21781
21782 /**
21783 * Returns the specified entity record's last delete error.
21784 *
21785 * @param state State tree.
21786 * @param kind Entity kind.
21787 * @param name Entity name.
21788 * @param recordId Record ID.
21789 *
21790 * @return The entity record's save error.
21791 */
21792 function getLastEntityDeleteError(state, kind, name, recordId) {
21793 return state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.error;
21794 }
21795
21796 /* eslint-disable @typescript-eslint/no-unused-vars */
21797 /**
21798 * Returns the previous edit from the current undo offset
21799 * for the entity records edits history, if any.
21800 *
21801 * @deprecated since 6.3
21802 *
21803 * @param state State tree.
21804 *
21805 * @return The edit.
21806 */
21807 function getUndoEdit(state) {
21808 external_wp_deprecated_default()("select( 'core' ).getUndoEdit()", {
21809 since: '6.3'
21810 });
21811 return undefined;
21812 }
21813 /* eslint-enable @typescript-eslint/no-unused-vars */
21814
21815 /* eslint-disable @typescript-eslint/no-unused-vars */
21816 /**
21817 * Returns the next edit from the current undo offset
21818 * for the entity records edits history, if any.
21819 *
21820 * @deprecated since 6.3
21821 *
21822 * @param state State tree.
21823 *
21824 * @return The edit.
21825 */
21826 function getRedoEdit(state) {
21827 external_wp_deprecated_default()("select( 'core' ).getRedoEdit()", {
21828 since: '6.3'
21829 });
21830 return undefined;
21831 }
21832 /* eslint-enable @typescript-eslint/no-unused-vars */
21833
21834 /**
21835 * Returns true if there is a previous edit from the current undo offset
21836 * for the entity records edits history, and false otherwise.
21837 *
21838 * @param state State tree.
21839 *
21840 * @return Whether there is a previous edit or not.
21841 */
21842 function hasUndo(state) {
21843 return state.undoManager.hasUndo();
21844 }
21845
21846 /**
21847 * Returns true if there is a next edit from the current undo offset
21848 * for the entity records edits history, and false otherwise.
21849 *
21850 * @param state State tree.
21851 *
21852 * @return Whether there is a next edit or not.
21853 */
21854 function hasRedo(state) {
21855 return state.undoManager.hasRedo();
21856 }
21857
21858 /**
21859 * Return the current theme.
21860 *
21861 * @param state Data state.
21862 *
21863 * @return The current theme.
21864 */
21865 function getCurrentTheme(state) {
21866 if (!state.currentTheme) {
21867 return null;
21868 }
21869 return getEntityRecord(state, 'root', 'theme', state.currentTheme);
21870 }
21871
21872 /**
21873 * Return the ID of the current global styles object.
21874 *
21875 * @param state Data state.
21876 *
21877 * @return The current global styles ID.
21878 */
21879 function __experimentalGetCurrentGlobalStylesId(state) {
21880 return state.currentGlobalStylesId;
21881 }
21882
21883 /**
21884 * Return theme supports data in the index.
21885 *
21886 * @param state Data state.
21887 *
21888 * @return Index data.
21889 */
21890 function getThemeSupports(state) {
21891 var _getCurrentTheme$them;
21892 return (_getCurrentTheme$them = getCurrentTheme(state)?.theme_supports) !== null && _getCurrentTheme$them !== void 0 ? _getCurrentTheme$them : EMPTY_OBJECT;
21893 }
21894
21895 /**
21896 * Returns the embed preview for the given URL.
21897 *
21898 * @param state Data state.
21899 * @param url Embedded URL.
21900 *
21901 * @return Undefined if the preview has not been fetched, otherwise, the preview fetched from the embed preview API.
21902 */
21903 function getEmbedPreview(state, url) {
21904 return state.embedPreviews[url];
21905 }
21906
21907 /**
21908 * Determines if the returned preview is an oEmbed link fallback.
21909 *
21910 * WordPress can be configured to return a simple link to a URL if it is not embeddable.
21911 * We need to be able to determine if a URL is embeddable or not, based on what we
21912 * get back from the oEmbed preview API.
21913 *
21914 * @param state Data state.
21915 * @param url Embedded URL.
21916 *
21917 * @return Is the preview for the URL an oEmbed link fallback.
21918 */
21919 function isPreviewEmbedFallback(state, url) {
21920 const preview = state.embedPreviews[url];
21921 const oEmbedLinkCheck = '<a href="' + url + '">' + url + '</a>';
21922 if (!preview) {
21923 return false;
21924 }
21925 return preview.html === oEmbedLinkCheck;
21926 }
21927
21928 /**
21929 * Returns whether the current user can perform the given action on the given
21930 * REST resource.
21931 *
21932 * Calling this may trigger an OPTIONS request to the REST API via the
21933 * `canUser()` resolver.
21934 *
21935 * https://developer.wordpress.org/rest-api/reference/
21936 *
21937 * @param state Data state.
21938 * @param action Action to check. One of: 'create', 'read', 'update', 'delete'.
21939 * @param resource Entity resource to check. Accepts entity object `{ kind: 'root', name: 'media', id: 1 }`
21940 * or REST base as a string - `media`.
21941 * @param id Optional ID of the rest resource to check.
21942 *
21943 * @return Whether or not the user can perform the action,
21944 * or `undefined` if the OPTIONS request is still being made.
21945 */
21946 function canUser(state, action, resource, id) {
21947 const isEntity = typeof resource === 'object';
21948 if (isEntity && (!resource.kind || !resource.name)) {
21949 return false;
21950 }
21951 const key = getUserPermissionCacheKey(action, resource, id);
21952 return state.userPermissions[key];
21953 }
21954
21955 /**
21956 * Returns whether the current user can edit the given entity.
21957 *
21958 * Calling this may trigger an OPTIONS request to the REST API via the
21959 * `canUser()` resolver.
21960 *
21961 * https://developer.wordpress.org/rest-api/reference/
21962 *
21963 * @param state Data state.
21964 * @param kind Entity kind.
21965 * @param name Entity name.
21966 * @param recordId Record's id.
21967 * @return Whether or not the user can edit,
21968 * or `undefined` if the OPTIONS request is still being made.
21969 */
21970 function canUserEditEntityRecord(state, kind, name, recordId) {
21971 external_wp_deprecated_default()(`wp.data.select( 'core' ).canUserEditEntityRecord()`, {
21972 since: '6.7',
21973 alternative: `wp.data.select( 'core' ).canUser( 'update', { kind, name, id } )`
21974 });
21975 return canUser(state, 'update', {
21976 kind,
21977 name,
21978 id: recordId
21979 });
21980 }
21981
21982 /**
21983 * Returns the latest autosaves for the post.
21984 *
21985 * May return multiple autosaves since the backend stores one autosave per
21986 * author for each post.
21987 *
21988 * @param state State tree.
21989 * @param postType The type of the parent post.
21990 * @param postId The id of the parent post.
21991 *
21992 * @return An array of autosaves for the post, or undefined if there is none.
21993 */
21994 function getAutosaves(state, postType, postId) {
21995 return state.autosaves[postId];
21996 }
21997
21998 /**
21999 * Returns the autosave for the post and author.
22000 *
22001 * @param state State tree.
22002 * @param postType The type of the parent post.
22003 * @param postId The id of the parent post.
22004 * @param authorId The id of the author.
22005 *
22006 * @return The autosave for the post and author.
22007 */
22008 function getAutosave(state, postType, postId, authorId) {
22009 if (authorId === undefined) {
22010 return;
22011 }
22012 const autosaves = state.autosaves[postId];
22013 return autosaves?.find(autosave => autosave.author === authorId);
22014 }
22015
22016 /**
22017 * Returns true if the REST request for autosaves has completed.
22018 *
22019 * @param state State tree.
22020 * @param postType The type of the parent post.
22021 * @param postId The id of the parent post.
22022 *
22023 * @return True if the REST request was completed. False otherwise.
22024 */
22025 const hasFetchedAutosaves = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, postType, postId) => {
22026 return select(STORE_NAME).hasFinishedResolution('getAutosaves', [postType, postId]);
22027 });
22028
22029 /**
22030 * Returns a new reference when edited values have changed. This is useful in
22031 * inferring where an edit has been made between states by comparison of the
22032 * return values using strict equality.
22033 *
22034 * @example
22035 *
22036 * ```
22037 * const hasEditOccurred = (
22038 * getReferenceByDistinctEdits( beforeState ) !==
22039 * getReferenceByDistinctEdits( afterState )
22040 * );
22041 * ```
22042 *
22043 * @param state Editor state.
22044 *
22045 * @return A value whose reference will change only when an edit occurs.
22046 */
22047 function getReferenceByDistinctEdits(state) {
22048 return state.editsReference;
22049 }
22050
22051 /**
22052 * Retrieve the frontend template used for a given link.
22053 *
22054 * @param state Editor state.
22055 * @param link Link.
22056 *
22057 * @return The template record.
22058 */
22059 function __experimentalGetTemplateForLink(state, link) {
22060 const records = getEntityRecords(state, 'postType', 'wp_template', {
22061 'find-template': link
22062 });
22063 if (records?.length) {
22064 return getEditedEntityRecord(state, 'postType', 'wp_template', records[0].id);
22065 }
22066 return null;
22067 }
22068
22069 /**
22070 * Retrieve the current theme's base global styles
22071 *
22072 * @param state Editor state.
22073 *
22074 * @return The Global Styles object.
22075 */
22076 function __experimentalGetCurrentThemeBaseGlobalStyles(state) {
22077 const currentTheme = getCurrentTheme(state);
22078 if (!currentTheme) {
22079 return null;
22080 }
22081 return state.themeBaseGlobalStyles[currentTheme.stylesheet];
22082 }
22083
22084 /**
22085 * Return the ID of the current global styles object.
22086 *
22087 * @param state Data state.
22088 *
22089 * @return The current global styles ID.
22090 */
22091 function __experimentalGetCurrentThemeGlobalStylesVariations(state) {
22092 const currentTheme = getCurrentTheme(state);
22093 if (!currentTheme) {
22094 return null;
22095 }
22096 return state.themeGlobalStyleVariations[currentTheme.stylesheet];
22097 }
22098
22099 /**
22100 * Retrieve the list of registered block patterns.
22101 *
22102 * @param state Data state.
22103 *
22104 * @return Block pattern list.
22105 */
22106 function getBlockPatterns(state) {
22107 return state.blockPatterns;
22108 }
22109
22110 /**
22111 * Retrieve the list of registered block pattern categories.
22112 *
22113 * @param state Data state.
22114 *
22115 * @return Block pattern category list.
22116 */
22117 function getBlockPatternCategories(state) {
22118 return state.blockPatternCategories;
22119 }
22120
22121 /**
22122 * Retrieve the registered user pattern categories.
22123 *
22124 * @param state Data state.
22125 *
22126 * @return User patterns category array.
22127 */
22128
22129 function getUserPatternCategories(state) {
22130 return state.userPatternCategories;
22131 }
22132
22133 /**
22134 * Returns the revisions of the current global styles theme.
22135 *
22136 * @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.
22137 *
22138 * @param state Data state.
22139 *
22140 * @return The current global styles.
22141 */
22142 function getCurrentThemeGlobalStylesRevisions(state) {
22143 external_wp_deprecated_default()("select( 'core' ).getCurrentThemeGlobalStylesRevisions()", {
22144 since: '6.5.0',
22145 alternative: "select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )"
22146 });
22147 const currentGlobalStylesId = __experimentalGetCurrentGlobalStylesId(state);
22148 if (!currentGlobalStylesId) {
22149 return null;
22150 }
22151 return state.themeGlobalStyleRevisions[currentGlobalStylesId];
22152 }
22153
22154 /**
22155 * Returns the default template use to render a given query.
22156 *
22157 * @param state Data state.
22158 * @param query Query.
22159 *
22160 * @return The default template id for the given query.
22161 */
22162 function getDefaultTemplateId(state, query) {
22163 return state.defaultTemplates[JSON.stringify(query)];
22164 }
22165
22166 /**
22167 * Returns an entity's revisions.
22168 *
22169 * @param state State tree
22170 * @param kind Entity kind.
22171 * @param name Entity name.
22172 * @param recordKey The key of the entity record whose revisions you want to fetch.
22173 * @param query Optional query. If requesting specific
22174 * 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]".
22175 *
22176 * @return Record.
22177 */
22178 const getRevisions = (state, kind, name, recordKey, query) => {
22179 const queriedStateRevisions = state.entities.records?.[kind]?.[name]?.revisions?.[recordKey];
22180 if (!queriedStateRevisions) {
22181 return null;
22182 }
22183 return getQueriedItems(queriedStateRevisions, query);
22184 };
22185
22186 /**
22187 * Returns a single, specific revision of a parent entity.
22188 *
22189 * @param state State tree
22190 * @param kind Entity kind.
22191 * @param name Entity name.
22192 * @param recordKey The key of the entity record whose revisions you want to fetch.
22193 * @param revisionKey The revision's key.
22194 * @param query Optional query. If requesting specific
22195 * 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]".
22196 *
22197 * @return Record.
22198 */
22199 const getRevision = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, recordKey, revisionKey, query) => {
22200 var _query$context5;
22201 const queriedState = state.entities.records?.[kind]?.[name]?.revisions?.[recordKey];
22202 if (!queriedState) {
22203 return undefined;
22204 }
22205 const context = (_query$context5 = query?.context) !== null && _query$context5 !== void 0 ? _query$context5 : 'default';
22206 if (query === undefined) {
22207 // If expecting a complete item, validate that completeness.
22208 if (!queriedState.itemIsComplete[context]?.[revisionKey]) {
22209 return undefined;
22210 }
22211 return queriedState.items[context][revisionKey];
22212 }
22213 const item = queriedState.items[context]?.[revisionKey];
22214 if (item && query._fields) {
22215 var _getNormalizedCommaSe2;
22216 const filteredItem = {};
22217 const fields = (_getNormalizedCommaSe2 = get_normalized_comma_separable(query._fields)) !== null && _getNormalizedCommaSe2 !== void 0 ? _getNormalizedCommaSe2 : [];
22218 for (let f = 0; f < fields.length; f++) {
22219 const field = fields[f].split('.');
22220 let value = item;
22221 field.forEach(fieldName => {
22222 value = value?.[fieldName];
22223 });
22224 setNestedValue(filteredItem, field, value);
22225 }
22226 return filteredItem;
22227 }
22228 return item;
22229 }, (state, kind, name, recordKey, revisionKey, query) => {
22230 var _query$context6;
22231 const context = (_query$context6 = query?.context) !== null && _query$context6 !== void 0 ? _query$context6 : 'default';
22232 return [state.entities.records?.[kind]?.[name]?.revisions?.[recordKey]?.items?.[context]?.[revisionKey], state.entities.records?.[kind]?.[name]?.revisions?.[recordKey]?.itemIsComplete?.[context]?.[revisionKey]];
22233 });
22234
22235 ;// CONCATENATED MODULE: ./packages/core-data/build-module/private-selectors.js
22236 /**
22237 * WordPress dependencies
22238 */
22239
22240
22241 /**
22242 * Internal dependencies
22243 */
22244
22245
22246 /**
22247 * Returns the previous edit from the current undo offset
22248 * for the entity records edits history, if any.
22249 *
22250 * @param state State tree.
22251 *
22252 * @return The undo manager.
22253 */
22254 function getUndoManager(state) {
22255 return state.undoManager;
22256 }
22257
22258 /**
22259 * Retrieve the fallback Navigation.
22260 *
22261 * @param state Data state.
22262 * @return The ID for the fallback Navigation post.
22263 */
22264 function getNavigationFallbackId(state) {
22265 return state.navigationFallbackId;
22266 }
22267 const getBlockPatternsForPostType = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (0,external_wp_data_namespaceObject.createSelector)((state, postType) => select(STORE_NAME).getBlockPatterns().filter(({
22268 postTypes
22269 }) => !postTypes || Array.isArray(postTypes) && postTypes.includes(postType)), () => [select(STORE_NAME).getBlockPatterns()]));
22270
22271 ;// CONCATENATED MODULE: ./node_modules/camel-case/dist.es2015/index.js
22272
22273
22274 function camelCaseTransform(input, index) {
22275 if (index === 0)
22276 return input.toLowerCase();
22277 return pascalCaseTransform(input, index);
22278 }
22279 function camelCaseTransformMerge(input, index) {
22280 if (index === 0)
22281 return input.toLowerCase();
22282 return pascalCaseTransformMerge(input);
22283 }
22284 function camelCase(input, options) {
22285 if (options === void 0) { options = {}; }
22286 return pascalCase(input, __assign({ transform: camelCaseTransform }, options));
22287 }
22288
22289 ;// CONCATENATED MODULE: external ["wp","htmlEntities"]
22290 const external_wp_htmlEntities_namespaceObject = window["wp"]["htmlEntities"];
22291 ;// CONCATENATED MODULE: ./packages/core-data/build-module/utils/forward-resolver.js
22292 /**
22293 * Higher-order function which forward the resolution to another resolver with the same arguments.
22294 *
22295 * @param {string} resolverName forwarded resolver.
22296 *
22297 * @return {Function} Enhanced resolver.
22298 */
22299 const forwardResolver = resolverName => (...args) => async ({
22300 resolveSelect
22301 }) => {
22302 await resolveSelect[resolverName](...args);
22303 };
22304 /* harmony default export */ const forward_resolver = (forwardResolver);
22305
22306 ;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/__experimental-fetch-link-suggestions.js
22307 /**
22308 * WordPress dependencies
22309 */
22310
22311
22312
22313
22314 /**
22315 * Fetches link suggestions from the WordPress API.
22316 *
22317 * WordPress does not support searching multiple tables at once, e.g. posts and terms, so we
22318 * perform multiple queries at the same time and then merge the results together.
22319 *
22320 * @param search
22321 * @param searchOptions
22322 * @param editorSettings
22323 *
22324 * @example
22325 * ```js
22326 * import { __experimentalFetchLinkSuggestions as fetchLinkSuggestions } from '@wordpress/core-data';
22327 *
22328 * //...
22329 *
22330 * export function initialize( id, settings ) {
22331 *
22332 * settings.__experimentalFetchLinkSuggestions = (
22333 * search,
22334 * searchOptions
22335 * ) => fetchLinkSuggestions( search, searchOptions, settings );
22336 * ```
22337 */
22338 async function fetchLinkSuggestions(search, searchOptions = {}, editorSettings = {}) {
22339 const searchOptionsToUse = searchOptions.isInitialSuggestions && searchOptions.initialSuggestionsSearchOptions ? {
22340 ...searchOptions,
22341 ...searchOptions.initialSuggestionsSearchOptions
22342 } : searchOptions;
22343 const {
22344 type,
22345 subtype,
22346 page,
22347 perPage = searchOptions.isInitialSuggestions ? 3 : 20
22348 } = searchOptionsToUse;
22349 const {
22350 disablePostFormats = false
22351 } = editorSettings;
22352 const queries = [];
22353 if (!type || type === 'post') {
22354 queries.push(external_wp_apiFetch_default()({
22355 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
22356 search,
22357 page,
22358 per_page: perPage,
22359 type: 'post',
22360 subtype
22361 })
22362 }).then(results => {
22363 return results.map(result => {
22364 return {
22365 id: result.id,
22366 url: result.url,
22367 title: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(result.title || '') || (0,external_wp_i18n_namespaceObject.__)('(no title)'),
22368 type: result.subtype || result.type,
22369 kind: 'post-type'
22370 };
22371 });
22372 }).catch(() => []) // Fail by returning no results.
22373 );
22374 }
22375 if (!type || type === 'term') {
22376 queries.push(external_wp_apiFetch_default()({
22377 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
22378 search,
22379 page,
22380 per_page: perPage,
22381 type: 'term',
22382 subtype
22383 })
22384 }).then(results => {
22385 return results.map(result => {
22386 return {
22387 id: result.id,
22388 url: result.url,
22389 title: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(result.title || '') || (0,external_wp_i18n_namespaceObject.__)('(no title)'),
22390 type: result.subtype || result.type,
22391 kind: 'taxonomy'
22392 };
22393 });
22394 }).catch(() => []) // Fail by returning no results.
22395 );
22396 }
22397 if (!disablePostFormats && (!type || type === 'post-format')) {
22398 queries.push(external_wp_apiFetch_default()({
22399 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
22400 search,
22401 page,
22402 per_page: perPage,
22403 type: 'post-format',
22404 subtype
22405 })
22406 }).then(results => {
22407 return results.map(result => {
22408 return {
22409 id: result.id,
22410 url: result.url,
22411 title: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(result.title || '') || (0,external_wp_i18n_namespaceObject.__)('(no title)'),
22412 type: result.subtype || result.type,
22413 kind: 'taxonomy'
22414 };
22415 });
22416 }).catch(() => []) // Fail by returning no results.
22417 );
22418 }
22419 if (!type || type === 'attachment') {
22420 queries.push(external_wp_apiFetch_default()({
22421 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/media', {
22422 search,
22423 page,
22424 per_page: perPage
22425 })
22426 }).then(results => {
22427 return results.map(result => {
22428 return {
22429 id: result.id,
22430 url: result.source_url,
22431 title: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(result.title.rendered || '') || (0,external_wp_i18n_namespaceObject.__)('(no title)'),
22432 type: result.type,
22433 kind: 'media'
22434 };
22435 });
22436 }).catch(() => []) // Fail by returning no results.
22437 );
22438 }
22439 const responses = await Promise.all(queries);
22440 let results = responses.flat();
22441 results = results.filter(result => !!result.id);
22442 results = sortResults(results, search);
22443 results = results.slice(0, perPage);
22444 return results;
22445 }
22446
22447 /**
22448 * Sort search results by relevance to the given query.
22449 *
22450 * Sorting is necessary as we're querying multiple endpoints and merging the results. For example
22451 * a taxonomy title might be more relevant than a post title, but by default taxonomy results will
22452 * be ordered after all the (potentially irrelevant) post results.
22453 *
22454 * We sort by scoring each result, where the score is the number of tokens in the title that are
22455 * also in the search query, divided by the total number of tokens in the title. This gives us a
22456 * score between 0 and 1, where 1 is a perfect match.
22457 *
22458 * @param results
22459 * @param search
22460 */
22461 function sortResults(results, search) {
22462 const searchTokens = tokenize(search);
22463 const scores = {};
22464 for (const result of results) {
22465 if (result.title) {
22466 const titleTokens = tokenize(result.title);
22467 const matchingTokens = titleTokens.filter(titleToken => searchTokens.some(searchToken => titleToken.includes(searchToken)));
22468 scores[result.id] = matchingTokens.length / titleTokens.length;
22469 } else {
22470 scores[result.id] = 0;
22471 }
22472 }
22473 return results.sort((a, b) => scores[b.id] - scores[a.id]);
22474 }
22475
22476 /**
22477 * Turns text into an array of tokens, with whitespace and punctuation removed.
22478 *
22479 * For example, `"I'm having a ball."` becomes `[ "im", "having", "a", "ball" ]`.
22480 *
22481 * @param text
22482 */
22483 function tokenize(text) {
22484 // \p{L} matches any kind of letter from any language.
22485 // \p{N} matches any kind of numeric character.
22486 return text.toLowerCase().match(/[\p{L}\p{N}]+/gu) || [];
22487 }
22488
22489 ;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/__experimental-fetch-url-data.js
22490 /**
22491 * WordPress dependencies
22492 */
22493
22494
22495
22496 /**
22497 * A simple in-memory cache for requests.
22498 * This avoids repeat HTTP requests which may be beneficial
22499 * for those wishing to preserve low-bandwidth.
22500 */
22501 const CACHE = new Map();
22502
22503 /**
22504 * @typedef WPRemoteUrlData
22505 *
22506 * @property {string} title contents of the remote URL's `<title>` tag.
22507 */
22508
22509 /**
22510 * Fetches data about a remote URL.
22511 * eg: <title> tag, favicon...etc.
22512 *
22513 * @async
22514 * @param {string} url the URL to request details from.
22515 * @param {Object?} options any options to pass to the underlying fetch.
22516 * @example
22517 * ```js
22518 * import { __experimentalFetchUrlData as fetchUrlData } from '@wordpress/core-data';
22519 *
22520 * //...
22521 *
22522 * export function initialize( id, settings ) {
22523 *
22524 * settings.__experimentalFetchUrlData = (
22525 * url
22526 * ) => fetchUrlData( url );
22527 * ```
22528 * @return {Promise< WPRemoteUrlData[] >} Remote URL data.
22529 */
22530 const fetchUrlData = async (url, options = {}) => {
22531 const endpoint = '/wp-block-editor/v1/url-details';
22532 const args = {
22533 url: (0,external_wp_url_namespaceObject.prependHTTP)(url)
22534 };
22535 if (!(0,external_wp_url_namespaceObject.isURL)(url)) {
22536 return Promise.reject(`${url} is not a valid URL.`);
22537 }
22538
22539 // Test for "http" based URL as it is possible for valid
22540 // yet unusable URLs such as `tel:123456` to be passed.
22541 const protocol = (0,external_wp_url_namespaceObject.getProtocol)(url);
22542 if (!protocol || !(0,external_wp_url_namespaceObject.isValidProtocol)(protocol) || !protocol.startsWith('http') || !/^https?:\/\/[^\/\s]/i.test(url)) {
22543 return Promise.reject(`${url} does not have a valid protocol. URLs must be "http" based`);
22544 }
22545 if (CACHE.has(url)) {
22546 return CACHE.get(url);
22547 }
22548 return external_wp_apiFetch_default()({
22549 path: (0,external_wp_url_namespaceObject.addQueryArgs)(endpoint, args),
22550 ...options
22551 }).then(res => {
22552 CACHE.set(url, res);
22553 return res;
22554 });
22555 };
22556 /* harmony default export */ const _experimental_fetch_url_data = (fetchUrlData);
22557
22558 ;// CONCATENATED MODULE: ./packages/core-data/build-module/fetch/index.js
22559 /**
22560 * External dependencies
22561 */
22562
22563
22564 /**
22565 * WordPress dependencies
22566 */
22567
22568
22569
22570 async function fetchBlockPatterns() {
22571 const restPatterns = await external_wp_apiFetch_default()({
22572 path: '/wp/v2/block-patterns/patterns'
22573 });
22574 if (!restPatterns) {
22575 return [];
22576 }
22577 return restPatterns.map(pattern => Object.fromEntries(Object.entries(pattern).map(([key, value]) => [camelCase(key), value])));
22578 }
22579
22580 ;// CONCATENATED MODULE: ./packages/core-data/build-module/resolvers.js
22581 /**
22582 * External dependencies
22583 */
22584
22585
22586 /**
22587 * WordPress dependencies
22588 */
22589
22590
22591
22592
22593 /**
22594 * Internal dependencies
22595 */
22596
22597
22598
22599
22600
22601
22602 /**
22603 * Requests authors from the REST API.
22604 *
22605 * @param {Object|undefined} query Optional object of query parameters to
22606 * include with request.
22607 */
22608 const resolvers_getAuthors = query => async ({
22609 dispatch
22610 }) => {
22611 const path = (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/users/?who=authors&per_page=100', query);
22612 const users = await external_wp_apiFetch_default()({
22613 path
22614 });
22615 dispatch.receiveUserQuery(path, users);
22616 };
22617
22618 /**
22619 * Requests the current user from the REST API.
22620 */
22621 const resolvers_getCurrentUser = () => async ({
22622 dispatch
22623 }) => {
22624 const currentUser = await external_wp_apiFetch_default()({
22625 path: '/wp/v2/users/me'
22626 });
22627 dispatch.receiveCurrentUser(currentUser);
22628 };
22629
22630 /**
22631 * Requests an entity's record from the REST API.
22632 *
22633 * @param {string} kind Entity kind.
22634 * @param {string} name Entity name.
22635 * @param {number|string} key Record's key
22636 * @param {Object|undefined} query Optional object of query parameters to
22637 * include with request. If requesting specific
22638 * fields, fields must always include the ID.
22639 */
22640 const resolvers_getEntityRecord = (kind, name, key = '', query) => async ({
22641 select,
22642 dispatch,
22643 registry
22644 }) => {
22645 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
22646 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
22647 if (!entityConfig) {
22648 return;
22649 }
22650 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, key], {
22651 exclusive: false
22652 });
22653 try {
22654 // Entity supports configs,
22655 // use the sync algorithm instead of the old fetch behavior.
22656 if (window.__experimentalEnableSync && entityConfig.syncConfig && !query) {
22657 if (true) {
22658 const objectId = entityConfig.getSyncObjectId(key);
22659
22660 // Loads the persisted document.
22661 await getSyncProvider().bootstrap(entityConfig.syncObjectType, objectId, record => {
22662 dispatch.receiveEntityRecords(kind, name, record, query);
22663 });
22664
22665 // Boostraps the edited document as well (and load from peers).
22666 await getSyncProvider().bootstrap(entityConfig.syncObjectType + '--edit', objectId, record => {
22667 dispatch({
22668 type: 'EDIT_ENTITY_RECORD',
22669 kind,
22670 name,
22671 recordId: key,
22672 edits: record,
22673 meta: {
22674 undo: undefined
22675 }
22676 });
22677 });
22678 }
22679 } else {
22680 if (query !== undefined && query._fields) {
22681 // If requesting specific fields, items and query association to said
22682 // records are stored by ID reference. Thus, fields must always include
22683 // the ID.
22684 query = {
22685 ...query,
22686 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.key || DEFAULT_ENTITY_KEY])].join()
22687 };
22688 }
22689
22690 // Disable reason: While true that an early return could leave `path`
22691 // unused, it's important that path is derived using the query prior to
22692 // additional query modifications in the condition below, since those
22693 // modifications are relevant to how the data is tracked in state, and not
22694 // for how the request is made to the REST API.
22695
22696 // eslint-disable-next-line @wordpress/no-unused-vars-before-return
22697 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.baseURL + (key ? '/' + key : ''), {
22698 ...entityConfig.baseURLParams,
22699 ...query
22700 });
22701 if (query !== undefined) {
22702 query = {
22703 ...query,
22704 include: [key]
22705 };
22706
22707 // The resolution cache won't consider query as reusable based on the
22708 // fields, so it's tested here, prior to initiating the REST request,
22709 // and without causing `getEntityRecords` resolution to occur.
22710 const hasRecords = select.hasEntityRecords(kind, name, query);
22711 if (hasRecords) {
22712 return;
22713 }
22714 }
22715 const response = await external_wp_apiFetch_default()({
22716 path,
22717 parse: false
22718 });
22719 const record = await response.json();
22720 const permissions = getUserPermissionsFromResponse(response);
22721 registry.batch(() => {
22722 dispatch.receiveEntityRecords(kind, name, record, query);
22723 for (const action of ALLOWED_RESOURCE_ACTIONS) {
22724 const permissionKey = getUserPermissionCacheKey(action, {
22725 kind,
22726 name,
22727 id: key
22728 });
22729 dispatch.receiveUserPermission(permissionKey, permissions[action]);
22730 dispatch.finishResolution('canUser', [action, {
22731 kind,
22732 name,
22733 id: key
22734 }]);
22735 }
22736 });
22737 }
22738 } finally {
22739 dispatch.__unstableReleaseStoreLock(lock);
22740 }
22741 };
22742
22743 /**
22744 * Requests an entity's record from the REST API.
22745 */
22746 const resolvers_getRawEntityRecord = forward_resolver('getEntityRecord');
22747
22748 /**
22749 * Requests an entity's record from the REST API.
22750 */
22751 const resolvers_getEditedEntityRecord = forward_resolver('getEntityRecord');
22752
22753 /**
22754 * Requests the entity's records from the REST API.
22755 *
22756 * @param {string} kind Entity kind.
22757 * @param {string} name Entity name.
22758 * @param {Object?} query Query Object. If requesting specific fields, fields
22759 * must always include the ID.
22760 */
22761 const resolvers_getEntityRecords = (kind, name, query = {}) => async ({
22762 dispatch,
22763 registry
22764 }) => {
22765 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
22766 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
22767 if (!entityConfig) {
22768 return;
22769 }
22770 const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name], {
22771 exclusive: false
22772 });
22773 try {
22774 if (query._fields) {
22775 // If requesting specific fields, items and query association to said
22776 // records are stored by ID reference. Thus, fields must always include
22777 // the ID.
22778 query = {
22779 ...query,
22780 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.key || DEFAULT_ENTITY_KEY])].join()
22781 };
22782 }
22783 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.baseURL, {
22784 ...entityConfig.baseURLParams,
22785 ...query
22786 });
22787 let records, meta;
22788 if (entityConfig.supportsPagination && query.per_page !== -1) {
22789 const response = await external_wp_apiFetch_default()({
22790 path,
22791 parse: false
22792 });
22793 records = Object.values(await response.json());
22794 meta = {
22795 totalItems: parseInt(response.headers.get('X-WP-Total')),
22796 totalPages: parseInt(response.headers.get('X-WP-TotalPages'))
22797 };
22798 } else {
22799 records = Object.values(await external_wp_apiFetch_default()({
22800 path
22801 }));
22802 }
22803
22804 // If we request fields but the result doesn't contain the fields,
22805 // explicitly set these fields as "undefined"
22806 // that way we consider the query "fulfilled".
22807 if (query._fields) {
22808 records = records.map(record => {
22809 query._fields.split(',').forEach(field => {
22810 if (!record.hasOwnProperty(field)) {
22811 record[field] = undefined;
22812 }
22813 });
22814 return record;
22815 });
22816 }
22817 registry.batch(() => {
22818 dispatch.receiveEntityRecords(kind, name, records, query, false, undefined, meta);
22819
22820 // When requesting all fields, the list of results can be used to
22821 // resolve the `getEntityRecord` selector in addition to `getEntityRecords`.
22822 // See https://github.com/WordPress/gutenberg/pull/26575
22823 if (!query?._fields && !query.context) {
22824 const key = entityConfig.key || DEFAULT_ENTITY_KEY;
22825 const resolutionsArgs = records.filter(record => record?.[key]).map(record => [kind, name, record[key]]);
22826 dispatch.finishResolutions('getEntityRecord', resolutionsArgs);
22827 }
22828 dispatch.__unstableReleaseStoreLock(lock);
22829 });
22830 } catch (e) {
22831 dispatch.__unstableReleaseStoreLock(lock);
22832 }
22833 };
22834 resolvers_getEntityRecords.shouldInvalidate = (action, kind, name) => {
22835 return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && kind === action.kind && name === action.name;
22836 };
22837
22838 /**
22839 * Requests the current theme.
22840 */
22841 const resolvers_getCurrentTheme = () => async ({
22842 dispatch,
22843 resolveSelect
22844 }) => {
22845 const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', {
22846 status: 'active'
22847 });
22848 dispatch.receiveCurrentTheme(activeThemes[0]);
22849 };
22850
22851 /**
22852 * Requests theme supports data from the index.
22853 */
22854 const resolvers_getThemeSupports = forward_resolver('getCurrentTheme');
22855
22856 /**
22857 * Requests a preview from the Embed API.
22858 *
22859 * @param {string} url URL to get the preview for.
22860 */
22861 const resolvers_getEmbedPreview = url => async ({
22862 dispatch
22863 }) => {
22864 try {
22865 const embedProxyResponse = await external_wp_apiFetch_default()({
22866 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/oembed/1.0/proxy', {
22867 url
22868 })
22869 });
22870 dispatch.receiveEmbedPreview(url, embedProxyResponse);
22871 } catch (error) {
22872 // Embed API 404s if the URL cannot be embedded, so we have to catch the error from the apiRequest here.
22873 dispatch.receiveEmbedPreview(url, false);
22874 }
22875 };
22876
22877 /**
22878 * Checks whether the current user can perform the given action on the given
22879 * REST resource.
22880 *
22881 * @param {string} requestedAction Action to check. One of: 'create', 'read', 'update',
22882 * 'delete'.
22883 * @param {string|Object} resource Entity resource to check. Accepts entity object `{ kind: 'root', name: 'media', id: 1 }`
22884 * or REST base as a string - `media`.
22885 * @param {?string} id ID of the rest resource to check.
22886 */
22887 const resolvers_canUser = (requestedAction, resource, id) => async ({
22888 dispatch,
22889 registry
22890 }) => {
22891 if (!ALLOWED_RESOURCE_ACTIONS.includes(requestedAction)) {
22892 throw new Error(`'${requestedAction}' is not a valid action.`);
22893 }
22894 let resourcePath = null;
22895 if (typeof resource === 'object') {
22896 if (!resource.kind || !resource.name) {
22897 throw new Error('The entity resource object is not valid.');
22898 }
22899 const configs = await dispatch(getOrLoadEntitiesConfig(resource.kind, resource.name));
22900 const entityConfig = configs.find(config => config.name === resource.name && config.kind === resource.kind);
22901 if (!entityConfig) {
22902 return;
22903 }
22904 resourcePath = entityConfig.baseURL + (resource.id ? '/' + resource.id : '');
22905 } else {
22906 resourcePath = `/wp/v2/${resource}` + (id ? '/' + id : '');
22907 }
22908 const {
22909 hasStartedResolution
22910 } = registry.select(STORE_NAME);
22911
22912 // Prevent resolving the same resource twice.
22913 for (const relatedAction of ALLOWED_RESOURCE_ACTIONS) {
22914 if (relatedAction === requestedAction) {
22915 continue;
22916 }
22917 const isAlreadyResolving = hasStartedResolution('canUser', [relatedAction, resource, id]);
22918 if (isAlreadyResolving) {
22919 return;
22920 }
22921 }
22922 let response;
22923 try {
22924 response = await external_wp_apiFetch_default()({
22925 path: resourcePath,
22926 method: 'OPTIONS',
22927 parse: false
22928 });
22929 } catch (error) {
22930 // Do nothing if our OPTIONS request comes back with an API error (4xx or
22931 // 5xx). The previously determined isAllowed value will remain in the store.
22932 return;
22933 }
22934 const permissions = getUserPermissionsFromResponse(response);
22935 registry.batch(() => {
22936 for (const action of ALLOWED_RESOURCE_ACTIONS) {
22937 const key = getUserPermissionCacheKey(action, resource, id);
22938 dispatch.receiveUserPermission(key, permissions[action]);
22939
22940 // Mark related action resolutions as finished.
22941 if (action !== requestedAction) {
22942 dispatch.finishResolution('canUser', [action, resource, id]);
22943 }
22944 }
22945 });
22946 };
22947
22948 /**
22949 * Checks whether the current user can perform the given action on the given
22950 * REST resource.
22951 *
22952 * @param {string} kind Entity kind.
22953 * @param {string} name Entity name.
22954 * @param {string} recordId Record's id.
22955 */
22956 const resolvers_canUserEditEntityRecord = (kind, name, recordId) => async ({
22957 dispatch
22958 }) => {
22959 await dispatch(resolvers_canUser('update', {
22960 kind,
22961 name,
22962 id: recordId
22963 }));
22964 };
22965
22966 /**
22967 * Request autosave data from the REST API.
22968 *
22969 * @param {string} postType The type of the parent post.
22970 * @param {number} postId The id of the parent post.
22971 */
22972 const resolvers_getAutosaves = (postType, postId) => async ({
22973 dispatch,
22974 resolveSelect
22975 }) => {
22976 const {
22977 rest_base: restBase,
22978 rest_namespace: restNamespace = 'wp/v2'
22979 } = await resolveSelect.getPostType(postType);
22980 const autosaves = await external_wp_apiFetch_default()({
22981 path: `/${restNamespace}/${restBase}/${postId}/autosaves?context=edit`
22982 });
22983 if (autosaves && autosaves.length) {
22984 dispatch.receiveAutosaves(postId, autosaves);
22985 }
22986 };
22987
22988 /**
22989 * Request autosave data from the REST API.
22990 *
22991 * This resolver exists to ensure the underlying autosaves are fetched via
22992 * `getAutosaves` when a call to the `getAutosave` selector is made.
22993 *
22994 * @param {string} postType The type of the parent post.
22995 * @param {number} postId The id of the parent post.
22996 */
22997 const resolvers_getAutosave = (postType, postId) => async ({
22998 resolveSelect
22999 }) => {
23000 await resolveSelect.getAutosaves(postType, postId);
23001 };
23002
23003 /**
23004 * Retrieve the frontend template used for a given link.
23005 *
23006 * @param {string} link Link.
23007 */
23008 const resolvers_experimentalGetTemplateForLink = link => async ({
23009 dispatch,
23010 resolveSelect
23011 }) => {
23012 let template;
23013 try {
23014 // This is NOT calling a REST endpoint but rather ends up with a response from
23015 // an Ajax function which has a different shape from a WP_REST_Response.
23016 template = await external_wp_apiFetch_default()({
23017 url: (0,external_wp_url_namespaceObject.addQueryArgs)(link, {
23018 '_wp-find-template': true
23019 })
23020 }).then(({
23021 data
23022 }) => data);
23023 } catch (e) {
23024 // For non-FSE themes, it is possible that this request returns an error.
23025 }
23026 if (!template) {
23027 return;
23028 }
23029 const record = await resolveSelect.getEntityRecord('postType', 'wp_template', template.id);
23030 if (record) {
23031 dispatch.receiveEntityRecords('postType', 'wp_template', [record], {
23032 'find-template': link
23033 });
23034 }
23035 };
23036 resolvers_experimentalGetTemplateForLink.shouldInvalidate = action => {
23037 return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && action.kind === 'postType' && action.name === 'wp_template';
23038 };
23039 const resolvers_experimentalGetCurrentGlobalStylesId = () => async ({
23040 dispatch,
23041 resolveSelect
23042 }) => {
23043 const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', {
23044 status: 'active'
23045 });
23046 const globalStylesURL = activeThemes?.[0]?._links?.['wp:user-global-styles']?.[0]?.href;
23047 if (!globalStylesURL) {
23048 return;
23049 }
23050
23051 // Regex matches the ID at the end of a URL or immediately before
23052 // the query string.
23053 const matches = globalStylesURL.match(/\/(\d+)(?:\?|$)/);
23054 const id = matches ? Number(matches[1]) : null;
23055 if (id) {
23056 dispatch.__experimentalReceiveCurrentGlobalStylesId(id);
23057 }
23058 };
23059 const resolvers_experimentalGetCurrentThemeBaseGlobalStyles = () => async ({
23060 resolveSelect,
23061 dispatch
23062 }) => {
23063 const currentTheme = await resolveSelect.getCurrentTheme();
23064 const themeGlobalStyles = await external_wp_apiFetch_default()({
23065 path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}`
23066 });
23067 dispatch.__experimentalReceiveThemeBaseGlobalStyles(currentTheme.stylesheet, themeGlobalStyles);
23068 };
23069 const resolvers_experimentalGetCurrentThemeGlobalStylesVariations = () => async ({
23070 resolveSelect,
23071 dispatch
23072 }) => {
23073 const currentTheme = await resolveSelect.getCurrentTheme();
23074 const variations = await external_wp_apiFetch_default()({
23075 path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}/variations`
23076 });
23077 dispatch.__experimentalReceiveThemeGlobalStyleVariations(currentTheme.stylesheet, variations);
23078 };
23079
23080 /**
23081 * Fetches and returns the revisions of the current global styles theme.
23082 */
23083 const resolvers_getCurrentThemeGlobalStylesRevisions = () => async ({
23084 resolveSelect,
23085 dispatch
23086 }) => {
23087 const globalStylesId = await resolveSelect.__experimentalGetCurrentGlobalStylesId();
23088 const record = globalStylesId ? await resolveSelect.getEntityRecord('root', 'globalStyles', globalStylesId) : undefined;
23089 const revisionsURL = record?._links?.['version-history']?.[0]?.href;
23090 if (revisionsURL) {
23091 const resetRevisions = await external_wp_apiFetch_default()({
23092 url: revisionsURL
23093 });
23094 const revisions = resetRevisions?.map(revision => Object.fromEntries(Object.entries(revision).map(([key, value]) => [camelCase(key), value])));
23095 dispatch.receiveThemeGlobalStyleRevisions(globalStylesId, revisions);
23096 }
23097 };
23098 resolvers_getCurrentThemeGlobalStylesRevisions.shouldInvalidate = action => {
23099 return action.type === 'SAVE_ENTITY_RECORD_FINISH' && action.kind === 'root' && !action.error && action.name === 'globalStyles';
23100 };
23101 const resolvers_getBlockPatterns = () => async ({
23102 dispatch
23103 }) => {
23104 const patterns = await fetchBlockPatterns();
23105 dispatch({
23106 type: 'RECEIVE_BLOCK_PATTERNS',
23107 patterns
23108 });
23109 };
23110 const resolvers_getBlockPatternCategories = () => async ({
23111 dispatch
23112 }) => {
23113 const categories = await external_wp_apiFetch_default()({
23114 path: '/wp/v2/block-patterns/categories'
23115 });
23116 dispatch({
23117 type: 'RECEIVE_BLOCK_PATTERN_CATEGORIES',
23118 categories
23119 });
23120 };
23121 const resolvers_getUserPatternCategories = () => async ({
23122 dispatch,
23123 resolveSelect
23124 }) => {
23125 const patternCategories = await resolveSelect.getEntityRecords('taxonomy', 'wp_pattern_category', {
23126 per_page: -1,
23127 _fields: 'id,name,description,slug',
23128 context: 'view'
23129 });
23130 const mappedPatternCategories = patternCategories?.map(userCategory => ({
23131 ...userCategory,
23132 label: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(userCategory.name),
23133 name: userCategory.slug
23134 })) || [];
23135 dispatch({
23136 type: 'RECEIVE_USER_PATTERN_CATEGORIES',
23137 patternCategories: mappedPatternCategories
23138 });
23139 };
23140 const resolvers_getNavigationFallbackId = () => async ({
23141 dispatch,
23142 select
23143 }) => {
23144 const fallback = await external_wp_apiFetch_default()({
23145 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp-block-editor/v1/navigation-fallback', {
23146 _embed: true
23147 })
23148 });
23149 const record = fallback?._embedded?.self;
23150 dispatch.receiveNavigationFallbackId(fallback?.id);
23151 if (record) {
23152 // If the fallback is already in the store, don't invalidate navigation queries.
23153 // Otherwise, invalidate the cache for the scenario where there were no Navigation
23154 // posts in the state and the fallback created one.
23155 const existingFallbackEntityRecord = select.getEntityRecord('postType', 'wp_navigation', fallback.id);
23156 const invalidateNavigationQueries = !existingFallbackEntityRecord;
23157 dispatch.receiveEntityRecords('postType', 'wp_navigation', record, undefined, invalidateNavigationQueries);
23158
23159 // Resolve to avoid further network requests.
23160 dispatch.finishResolution('getEntityRecord', ['postType', 'wp_navigation', fallback.id]);
23161 }
23162 };
23163 const resolvers_getDefaultTemplateId = query => async ({
23164 dispatch
23165 }) => {
23166 const template = await external_wp_apiFetch_default()({
23167 path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/templates/lookup', query)
23168 });
23169 // Endpoint may return an empty object if no template is found.
23170 if (template?.id) {
23171 dispatch.receiveDefaultTemplateId(query, template.id);
23172 }
23173 };
23174
23175 /**
23176 * Requests an entity's revisions from the REST API.
23177 *
23178 * @param {string} kind Entity kind.
23179 * @param {string} name Entity name.
23180 * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
23181 * @param {Object|undefined} query Optional object of query parameters to
23182 * include with request. If requesting specific
23183 * fields, fields must always include the ID.
23184 */
23185 const resolvers_getRevisions = (kind, name, recordKey, query = {}) => async ({
23186 dispatch
23187 }) => {
23188 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
23189 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
23190 if (!entityConfig) {
23191 return;
23192 }
23193 if (query._fields) {
23194 // If requesting specific fields, items and query association to said
23195 // records are stored by ID reference. Thus, fields must always include
23196 // the ID.
23197 query = {
23198 ...query,
23199 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.revisionKey || DEFAULT_ENTITY_KEY])].join()
23200 };
23201 }
23202 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.getRevisionsUrl(recordKey), query);
23203 let records, response;
23204 const meta = {};
23205 const isPaginated = entityConfig.supportsPagination && query.per_page !== -1;
23206 try {
23207 response = await external_wp_apiFetch_default()({
23208 path,
23209 parse: !isPaginated
23210 });
23211 } catch (error) {
23212 // Do nothing if our request comes back with an API error.
23213 return;
23214 }
23215 if (response) {
23216 if (isPaginated) {
23217 records = Object.values(await response.json());
23218 meta.totalItems = parseInt(response.headers.get('X-WP-Total'));
23219 } else {
23220 records = Object.values(response);
23221 }
23222
23223 // If we request fields but the result doesn't contain the fields,
23224 // explicitly set these fields as "undefined"
23225 // that way we consider the query "fulfilled".
23226 if (query._fields) {
23227 records = records.map(record => {
23228 query._fields.split(',').forEach(field => {
23229 if (!record.hasOwnProperty(field)) {
23230 record[field] = undefined;
23231 }
23232 });
23233 return record;
23234 });
23235 }
23236 dispatch.receiveRevisions(kind, name, recordKey, records, query, false, meta);
23237
23238 // When requesting all fields, the list of results can be used to
23239 // resolve the `getRevision` selector in addition to `getRevisions`.
23240 if (!query?._fields && !query.context) {
23241 const key = entityConfig.key || DEFAULT_ENTITY_KEY;
23242 const resolutionsArgs = records.filter(record => record[key]).map(record => [kind, name, recordKey, record[key]]);
23243 dispatch.startResolutions('getRevision', resolutionsArgs);
23244 dispatch.finishResolutions('getRevision', resolutionsArgs);
23245 }
23246 }
23247 };
23248
23249 // Invalidate cache when a new revision is created.
23250 resolvers_getRevisions.shouldInvalidate = (action, kind, name, recordKey) => action.type === 'SAVE_ENTITY_RECORD_FINISH' && name === action.name && kind === action.kind && !action.error && recordKey === action.recordId;
23251
23252 /**
23253 * Requests a specific Entity revision from the REST API.
23254 *
23255 * @param {string} kind Entity kind.
23256 * @param {string} name Entity name.
23257 * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
23258 * @param {number|string} revisionKey The revision's key.
23259 * @param {Object|undefined} query Optional object of query parameters to
23260 * include with request. If requesting specific
23261 * fields, fields must always include the ID.
23262 */
23263 const resolvers_getRevision = (kind, name, recordKey, revisionKey, query) => async ({
23264 dispatch
23265 }) => {
23266 const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
23267 const entityConfig = configs.find(config => config.name === name && config.kind === kind);
23268 if (!entityConfig) {
23269 return;
23270 }
23271 if (query !== undefined && query._fields) {
23272 // If requesting specific fields, items and query association to said
23273 // records are stored by ID reference. Thus, fields must always include
23274 // the ID.
23275 query = {
23276 ...query,
23277 _fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.revisionKey || DEFAULT_ENTITY_KEY])].join()
23278 };
23279 }
23280 const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.getRevisionsUrl(recordKey, revisionKey), query);
23281 let record;
23282 try {
23283 record = await external_wp_apiFetch_default()({
23284 path
23285 });
23286 } catch (error) {
23287 // Do nothing if our request comes back with an API error.
23288 return;
23289 }
23290 if (record) {
23291 dispatch.receiveRevisions(kind, name, recordKey, record, query);
23292 }
23293 };
23294
23295 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/utils.js
23296 function deepCopyLocksTreePath(tree, path) {
23297 const newTree = {
23298 ...tree
23299 };
23300 let currentNode = newTree;
23301 for (const branchName of path) {
23302 currentNode.children = {
23303 ...currentNode.children,
23304 [branchName]: {
23305 locks: [],
23306 children: {},
23307 ...currentNode.children[branchName]
23308 }
23309 };
23310 currentNode = currentNode.children[branchName];
23311 }
23312 return newTree;
23313 }
23314 function getNode(tree, path) {
23315 let currentNode = tree;
23316 for (const branchName of path) {
23317 const nextNode = currentNode.children[branchName];
23318 if (!nextNode) {
23319 return null;
23320 }
23321 currentNode = nextNode;
23322 }
23323 return currentNode;
23324 }
23325 function* iteratePath(tree, path) {
23326 let currentNode = tree;
23327 yield currentNode;
23328 for (const branchName of path) {
23329 const nextNode = currentNode.children[branchName];
23330 if (!nextNode) {
23331 break;
23332 }
23333 yield nextNode;
23334 currentNode = nextNode;
23335 }
23336 }
23337 function* iterateDescendants(node) {
23338 const stack = Object.values(node.children);
23339 while (stack.length) {
23340 const childNode = stack.pop();
23341 yield childNode;
23342 stack.push(...Object.values(childNode.children));
23343 }
23344 }
23345 function hasConflictingLock({
23346 exclusive
23347 }, locks) {
23348 if (exclusive && locks.length) {
23349 return true;
23350 }
23351 if (!exclusive && locks.filter(lock => lock.exclusive).length) {
23352 return true;
23353 }
23354 return false;
23355 }
23356
23357 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/reducer.js
23358 /**
23359 * Internal dependencies
23360 */
23361
23362 const DEFAULT_STATE = {
23363 requests: [],
23364 tree: {
23365 locks: [],
23366 children: {}
23367 }
23368 };
23369
23370 /**
23371 * Reducer returning locks.
23372 *
23373 * @param {Object} state Current state.
23374 * @param {Object} action Dispatched action.
23375 *
23376 * @return {Object} Updated state.
23377 */
23378 function locks(state = DEFAULT_STATE, action) {
23379 switch (action.type) {
23380 case 'ENQUEUE_LOCK_REQUEST':
23381 {
23382 const {
23383 request
23384 } = action;
23385 return {
23386 ...state,
23387 requests: [request, ...state.requests]
23388 };
23389 }
23390 case 'GRANT_LOCK_REQUEST':
23391 {
23392 const {
23393 lock,
23394 request
23395 } = action;
23396 const {
23397 store,
23398 path
23399 } = request;
23400 const storePath = [store, ...path];
23401 const newTree = deepCopyLocksTreePath(state.tree, storePath);
23402 const node = getNode(newTree, storePath);
23403 node.locks = [...node.locks, lock];
23404 return {
23405 ...state,
23406 requests: state.requests.filter(r => r !== request),
23407 tree: newTree
23408 };
23409 }
23410 case 'RELEASE_LOCK':
23411 {
23412 const {
23413 lock
23414 } = action;
23415 const storePath = [lock.store, ...lock.path];
23416 const newTree = deepCopyLocksTreePath(state.tree, storePath);
23417 const node = getNode(newTree, storePath);
23418 node.locks = node.locks.filter(l => l !== lock);
23419 return {
23420 ...state,
23421 tree: newTree
23422 };
23423 }
23424 }
23425 return state;
23426 }
23427
23428 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/selectors.js
23429 /**
23430 * Internal dependencies
23431 */
23432
23433 function getPendingLockRequests(state) {
23434 return state.requests;
23435 }
23436 function isLockAvailable(state, store, path, {
23437 exclusive
23438 }) {
23439 const storePath = [store, ...path];
23440 const locks = state.tree;
23441
23442 // Validate all parents and the node itself
23443 for (const node of iteratePath(locks, storePath)) {
23444 if (hasConflictingLock({
23445 exclusive
23446 }, node.locks)) {
23447 return false;
23448 }
23449 }
23450
23451 // iteratePath terminates early if path is unreachable, let's
23452 // re-fetch the node and check it exists in the tree.
23453 const node = getNode(locks, storePath);
23454 if (!node) {
23455 return true;
23456 }
23457
23458 // Validate all nested nodes
23459 for (const descendant of iterateDescendants(node)) {
23460 if (hasConflictingLock({
23461 exclusive
23462 }, descendant.locks)) {
23463 return false;
23464 }
23465 }
23466 return true;
23467 }
23468
23469 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/engine.js
23470 /**
23471 * Internal dependencies
23472 */
23473
23474
23475 function createLocks() {
23476 let state = locks(undefined, {
23477 type: '@@INIT'
23478 });
23479 function processPendingLockRequests() {
23480 for (const request of getPendingLockRequests(state)) {
23481 const {
23482 store,
23483 path,
23484 exclusive,
23485 notifyAcquired
23486 } = request;
23487 if (isLockAvailable(state, store, path, {
23488 exclusive
23489 })) {
23490 const lock = {
23491 store,
23492 path,
23493 exclusive
23494 };
23495 state = locks(state, {
23496 type: 'GRANT_LOCK_REQUEST',
23497 lock,
23498 request
23499 });
23500 notifyAcquired(lock);
23501 }
23502 }
23503 }
23504 function acquire(store, path, exclusive) {
23505 return new Promise(resolve => {
23506 state = locks(state, {
23507 type: 'ENQUEUE_LOCK_REQUEST',
23508 request: {
23509 store,
23510 path,
23511 exclusive,
23512 notifyAcquired: resolve
23513 }
23514 });
23515 processPendingLockRequests();
23516 });
23517 }
23518 function release(lock) {
23519 state = locks(state, {
23520 type: 'RELEASE_LOCK',
23521 lock
23522 });
23523 processPendingLockRequests();
23524 }
23525 return {
23526 acquire,
23527 release
23528 };
23529 }
23530
23531 ;// CONCATENATED MODULE: ./packages/core-data/build-module/locks/actions.js
23532 /**
23533 * Internal dependencies
23534 */
23535
23536 function createLocksActions() {
23537 const locks = createLocks();
23538 function __unstableAcquireStoreLock(store, path, {
23539 exclusive
23540 }) {
23541 return () => locks.acquire(store, path, exclusive);
23542 }
23543 function __unstableReleaseStoreLock(lock) {
23544 return () => locks.release(lock);
23545 }
23546 return {
23547 __unstableAcquireStoreLock,
23548 __unstableReleaseStoreLock
23549 };
23550 }
23551
23552 ;// CONCATENATED MODULE: external ["wp","privateApis"]
23553 const external_wp_privateApis_namespaceObject = window["wp"]["privateApis"];
23554 ;// CONCATENATED MODULE: ./packages/core-data/build-module/private-apis.js
23555 /**
23556 * WordPress dependencies
23557 */
23558
23559 const {
23560 lock,
23561 unlock
23562 } = (0,external_wp_privateApis_namespaceObject.__dangerousOptInToUnstableAPIsOnlyForCoreModules)('I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.', '@wordpress/core-data');
23563
23564 ;// CONCATENATED MODULE: external ["wp","element"]
23565 const external_wp_element_namespaceObject = window["wp"]["element"];
23566 ;// CONCATENATED MODULE: ./packages/core-data/build-module/entity-context.js
23567 /**
23568 * WordPress dependencies
23569 */
23570
23571 const EntityContext = (0,external_wp_element_namespaceObject.createContext)({});
23572
23573 ;// CONCATENATED MODULE: external "ReactJSXRuntime"
23574 const external_ReactJSXRuntime_namespaceObject = window["ReactJSXRuntime"];
23575 ;// CONCATENATED MODULE: ./packages/core-data/build-module/entity-provider.js
23576 /**
23577 * WordPress dependencies
23578 */
23579
23580
23581 /**
23582 * Internal dependencies
23583 */
23584
23585
23586 /**
23587 * Context provider component for providing
23588 * an entity for a specific entity.
23589 *
23590 * @param {Object} props The component's props.
23591 * @param {string} props.kind The entity kind.
23592 * @param {string} props.type The entity name.
23593 * @param {number} props.id The entity ID.
23594 * @param {*} props.children The children to wrap.
23595 *
23596 * @return {Object} The provided children, wrapped with
23597 * the entity's context provider.
23598 */
23599
23600 function EntityProvider({
23601 kind,
23602 type: name,
23603 id,
23604 children
23605 }) {
23606 const parent = (0,external_wp_element_namespaceObject.useContext)(EntityContext);
23607 const childContext = (0,external_wp_element_namespaceObject.useMemo)(() => ({
23608 ...parent,
23609 [kind]: {
23610 ...parent?.[kind],
23611 [name]: id
23612 }
23613 }), [parent, kind, name, id]);
23614 return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(EntityContext.Provider, {
23615 value: childContext,
23616 children: children
23617 });
23618 }
23619
23620 ;// CONCATENATED MODULE: ./node_modules/memize/dist/index.js
23621 /**
23622 * Memize options object.
23623 *
23624 * @typedef MemizeOptions
23625 *
23626 * @property {number} [maxSize] Maximum size of the cache.
23627 */
23628
23629 /**
23630 * Internal cache entry.
23631 *
23632 * @typedef MemizeCacheNode
23633 *
23634 * @property {?MemizeCacheNode|undefined} [prev] Previous node.
23635 * @property {?MemizeCacheNode|undefined} [next] Next node.
23636 * @property {Array<*>} args Function arguments for cache
23637 * entry.
23638 * @property {*} val Function result.
23639 */
23640
23641 /**
23642 * Properties of the enhanced function for controlling cache.
23643 *
23644 * @typedef MemizeMemoizedFunction
23645 *
23646 * @property {()=>void} clear Clear the cache.
23647 */
23648
23649 /**
23650 * Accepts a function to be memoized, and returns a new memoized function, with
23651 * optional options.
23652 *
23653 * @template {(...args: any[]) => any} F
23654 *
23655 * @param {F} fn Function to memoize.
23656 * @param {MemizeOptions} [options] Options object.
23657 *
23658 * @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function.
23659 */
23660 function memize(fn, options) {
23661 var size = 0;
23662
23663 /** @type {?MemizeCacheNode|undefined} */
23664 var head;
23665
23666 /** @type {?MemizeCacheNode|undefined} */
23667 var tail;
23668
23669 options = options || {};
23670
23671 function memoized(/* ...args */) {
23672 var node = head,
23673 len = arguments.length,
23674 args,
23675 i;
23676
23677 searchCache: while (node) {
23678 // Perform a shallow equality test to confirm that whether the node
23679 // under test is a candidate for the arguments passed. Two arrays
23680 // are shallowly equal if their length matches and each entry is
23681 // strictly equal between the two sets. Avoid abstracting to a
23682 // function which could incur an arguments leaking deoptimization.
23683
23684 // Check whether node arguments match arguments length
23685 if (node.args.length !== arguments.length) {
23686 node = node.next;
23687 continue;
23688 }
23689
23690 // Check whether node arguments match arguments values
23691 for (i = 0; i < len; i++) {
23692 if (node.args[i] !== arguments[i]) {
23693 node = node.next;
23694 continue searchCache;
23695 }
23696 }
23697
23698 // At this point we can assume we've found a match
23699
23700 // Surface matched node to head if not already
23701 if (node !== head) {
23702 // As tail, shift to previous. Must only shift if not also
23703 // head, since if both head and tail, there is no previous.
23704 if (node === tail) {
23705 tail = node.prev;
23706 }
23707
23708 // Adjust siblings to point to each other. If node was tail,
23709 // this also handles new tail's empty `next` assignment.
23710 /** @type {MemizeCacheNode} */ (node.prev).next = node.next;
23711 if (node.next) {
23712 node.next.prev = node.prev;
23713 }
23714
23715 node.next = head;
23716 node.prev = null;
23717 /** @type {MemizeCacheNode} */ (head).prev = node;
23718 head = node;
23719 }
23720
23721 // Return immediately
23722 return node.val;
23723 }
23724
23725 // No cached value found. Continue to insertion phase:
23726
23727 // Create a copy of arguments (avoid leaking deoptimization)
23728 args = new Array(len);
23729 for (i = 0; i < len; i++) {
23730 args[i] = arguments[i];
23731 }
23732
23733 node = {
23734 args: args,
23735
23736 // Generate the result from original function
23737 val: fn.apply(null, args),
23738 };
23739
23740 // Don't need to check whether node is already head, since it would
23741 // have been returned above already if it was
23742
23743 // Shift existing head down list
23744 if (head) {
23745 head.prev = node;
23746 node.next = head;
23747 } else {
23748 // If no head, follows that there's no tail (at initial or reset)
23749 tail = node;
23750 }
23751
23752 // Trim tail if we're reached max size and are pending cache insertion
23753 if (size === /** @type {MemizeOptions} */ (options).maxSize) {
23754 tail = /** @type {MemizeCacheNode} */ (tail).prev;
23755 /** @type {MemizeCacheNode} */ (tail).next = null;
23756 } else {
23757 size++;
23758 }
23759
23760 head = node;
23761
23762 return node.val;
23763 }
23764
23765 memoized.clear = function () {
23766 head = null;
23767 tail = null;
23768 size = 0;
23769 };
23770
23771 // Ignore reason: There's not a clear solution to create an intersection of
23772 // the function with additional properties, where the goal is to retain the
23773 // function signature of the incoming argument and add control properties
23774 // on the return value.
23775
23776 // @ts-ignore
23777 return memoized;
23778 }
23779
23780
23781
23782 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/memoize.js
23783 /**
23784 * External dependencies
23785 */
23786
23787
23788 // re-export due to restrictive esModuleInterop setting
23789 /* harmony default export */ const memoize = (memize);
23790
23791 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/constants.js
23792 let Status = /*#__PURE__*/function (Status) {
23793 Status["Idle"] = "IDLE";
23794 Status["Resolving"] = "RESOLVING";
23795 Status["Error"] = "ERROR";
23796 Status["Success"] = "SUCCESS";
23797 return Status;
23798 }({});
23799
23800 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-query-select.js
23801 /**
23802 * WordPress dependencies
23803 */
23804
23805
23806 /**
23807 * Internal dependencies
23808 */
23809
23810
23811 const META_SELECTORS = ['getIsResolving', 'hasStartedResolution', 'hasFinishedResolution', 'isResolving', 'getCachedResolvers'];
23812 /**
23813 * Like useSelect, but the selectors return objects containing
23814 * both the original data AND the resolution info.
23815 *
23816 * @since 6.1.0 Introduced in WordPress core.
23817 * @private
23818 *
23819 * @param {Function} mapQuerySelect see useSelect
23820 * @param {Array} deps see useSelect
23821 *
23822 * @example
23823 * ```js
23824 * import { useQuerySelect } from '@wordpress/data';
23825 * import { store as coreDataStore } from '@wordpress/core-data';
23826 *
23827 * function PageTitleDisplay( { id } ) {
23828 * const { data: page, isResolving } = useQuerySelect( ( query ) => {
23829 * return query( coreDataStore ).getEntityRecord( 'postType', 'page', id )
23830 * }, [ id ] );
23831 *
23832 * if ( isResolving ) {
23833 * return 'Loading...';
23834 * }
23835 *
23836 * return page.title;
23837 * }
23838 *
23839 * // Rendered in the application:
23840 * // <PageTitleDisplay id={ 10 } />
23841 * ```
23842 *
23843 * In the above example, when `PageTitleDisplay` is rendered into an
23844 * application, the page and the resolution details will be retrieved from
23845 * the store state using the `mapSelect` callback on `useQuerySelect`.
23846 *
23847 * If the id prop changes then any page in the state for that id is
23848 * retrieved. If the id prop doesn't change and other props are passed in
23849 * that do change, the title will not change because the dependency is just
23850 * the id.
23851 * @see useSelect
23852 *
23853 * @return {QuerySelectResponse} Queried data.
23854 */
23855 function useQuerySelect(mapQuerySelect, deps) {
23856 return (0,external_wp_data_namespaceObject.useSelect)((select, registry) => {
23857 const resolve = store => enrichSelectors(select(store));
23858 return mapQuerySelect(resolve, registry);
23859 }, deps);
23860 }
23861 /**
23862 * Transform simple selectors into ones that return an object with the
23863 * original return value AND the resolution info.
23864 *
23865 * @param {Object} selectors Selectors to enrich
23866 * @return {EnrichedSelectors} Enriched selectors
23867 */
23868 const enrichSelectors = memoize(selectors => {
23869 const resolvers = {};
23870 for (const selectorName in selectors) {
23871 if (META_SELECTORS.includes(selectorName)) {
23872 continue;
23873 }
23874 Object.defineProperty(resolvers, selectorName, {
23875 get: () => (...args) => {
23876 const data = selectors[selectorName](...args);
23877 const resolutionStatus = selectors.getResolutionState(selectorName, args)?.status;
23878 let status;
23879 switch (resolutionStatus) {
23880 case 'resolving':
23881 status = Status.Resolving;
23882 break;
23883 case 'finished':
23884 status = Status.Success;
23885 break;
23886 case 'error':
23887 status = Status.Error;
23888 break;
23889 case undefined:
23890 status = Status.Idle;
23891 break;
23892 }
23893 return {
23894 data,
23895 status,
23896 isResolving: status === Status.Resolving,
23897 hasStarted: status !== Status.Idle,
23898 hasResolved: status === Status.Success || status === Status.Error
23899 };
23900 }
23901 });
23902 }
23903 return resolvers;
23904 });
23905
23906 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-entity-record.js
23907 /**
23908 * WordPress dependencies
23909 */
23910
23911
23912
23913
23914 /**
23915 * Internal dependencies
23916 */
23917
23918
23919 const use_entity_record_EMPTY_OBJECT = {};
23920
23921 /**
23922 * Resolves the specified entity record.
23923 *
23924 * @since 6.1.0 Introduced in WordPress core.
23925 *
23926 * @param kind Kind of the entity, e.g. `root` or a `postType`. See rootEntitiesConfig in ../entities.ts for a list of available kinds.
23927 * @param name Name of the entity, e.g. `plugin` or a `post`. See rootEntitiesConfig in ../entities.ts for a list of available names.
23928 * @param recordId ID of the requested entity record.
23929 * @param options Optional hook options.
23930 * @example
23931 * ```js
23932 * import { useEntityRecord } from '@wordpress/core-data';
23933 *
23934 * function PageTitleDisplay( { id } ) {
23935 * const { record, isResolving } = useEntityRecord( 'postType', 'page', id );
23936 *
23937 * if ( isResolving ) {
23938 * return 'Loading...';
23939 * }
23940 *
23941 * return record.title;
23942 * }
23943 *
23944 * // Rendered in the application:
23945 * // <PageTitleDisplay id={ 1 } />
23946 * ```
23947 *
23948 * In the above example, when `PageTitleDisplay` is rendered into an
23949 * application, the page and the resolution details will be retrieved from
23950 * the store state using `getEntityRecord()`, or resolved if missing.
23951 *
23952 * @example
23953 * ```js
23954 * import { useCallback } from 'react';
23955 * import { useDispatch } from '@wordpress/data';
23956 * import { __ } from '@wordpress/i18n';
23957 * import { TextControl } from '@wordpress/components';
23958 * import { store as noticeStore } from '@wordpress/notices';
23959 * import { useEntityRecord } from '@wordpress/core-data';
23960 *
23961 * function PageRenameForm( { id } ) {
23962 * const page = useEntityRecord( 'postType', 'page', id );
23963 * const { createSuccessNotice, createErrorNotice } =
23964 * useDispatch( noticeStore );
23965 *
23966 * const setTitle = useCallback( ( title ) => {
23967 * page.edit( { title } );
23968 * }, [ page.edit ] );
23969 *
23970 * if ( page.isResolving ) {
23971 * return 'Loading...';
23972 * }
23973 *
23974 * async function onRename( event ) {
23975 * event.preventDefault();
23976 * try {
23977 * await page.save();
23978 * createSuccessNotice( __( 'Page renamed.' ), {
23979 * type: 'snackbar',
23980 * } );
23981 * } catch ( error ) {
23982 * createErrorNotice( error.message, { type: 'snackbar' } );
23983 * }
23984 * }
23985 *
23986 * return (
23987 * <form onSubmit={ onRename }>
23988 * <TextControl
23989 * label={ __( 'Name' ) }
23990 * value={ page.editedRecord.title }
23991 * onChange={ setTitle }
23992 * />
23993 * <button type="submit">{ __( 'Save' ) }</button>
23994 * </form>
23995 * );
23996 * }
23997 *
23998 * // Rendered in the application:
23999 * // <PageRenameForm id={ 1 } />
24000 * ```
24001 *
24002 * In the above example, updating and saving the page title is handled
24003 * via the `edit()` and `save()` mutation helpers provided by
24004 * `useEntityRecord()`;
24005 *
24006 * @return Entity record data.
24007 * @template RecordType
24008 */
24009 function useEntityRecord(kind, name, recordId, options = {
24010 enabled: true
24011 }) {
24012 const {
24013 editEntityRecord,
24014 saveEditedEntityRecord
24015 } = (0,external_wp_data_namespaceObject.useDispatch)(store);
24016 const mutations = (0,external_wp_element_namespaceObject.useMemo)(() => ({
24017 edit: (record, editOptions = {}) => editEntityRecord(kind, name, recordId, record, editOptions),
24018 save: (saveOptions = {}) => saveEditedEntityRecord(kind, name, recordId, {
24019 throwOnError: true,
24020 ...saveOptions
24021 })
24022 }), [editEntityRecord, kind, name, recordId, saveEditedEntityRecord]);
24023 const {
24024 editedRecord,
24025 hasEdits,
24026 edits
24027 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
24028 if (!options.enabled) {
24029 return {
24030 editedRecord: use_entity_record_EMPTY_OBJECT,
24031 hasEdits: false,
24032 edits: use_entity_record_EMPTY_OBJECT
24033 };
24034 }
24035 return {
24036 editedRecord: select(store).getEditedEntityRecord(kind, name, recordId),
24037 hasEdits: select(store).hasEditsForEntityRecord(kind, name, recordId),
24038 edits: select(store).getEntityRecordNonTransientEdits(kind, name, recordId)
24039 };
24040 }, [kind, name, recordId, options.enabled]);
24041 const {
24042 data: record,
24043 ...querySelectRest
24044 } = useQuerySelect(query => {
24045 if (!options.enabled) {
24046 return {
24047 data: null
24048 };
24049 }
24050 return query(store).getEntityRecord(kind, name, recordId);
24051 }, [kind, name, recordId, options.enabled]);
24052 return {
24053 record,
24054 editedRecord,
24055 hasEdits,
24056 edits,
24057 ...querySelectRest,
24058 ...mutations
24059 };
24060 }
24061 function __experimentalUseEntityRecord(kind, name, recordId, options) {
24062 external_wp_deprecated_default()(`wp.data.__experimentalUseEntityRecord`, {
24063 alternative: 'wp.data.useEntityRecord',
24064 since: '6.1'
24065 });
24066 return useEntityRecord(kind, name, recordId, options);
24067 }
24068
24069 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-entity-records.js
24070 /**
24071 * WordPress dependencies
24072 */
24073
24074
24075
24076
24077 /**
24078 * Internal dependencies
24079 */
24080
24081
24082 const EMPTY_ARRAY = [];
24083
24084 /**
24085 * Resolves the specified entity records.
24086 *
24087 * @since 6.1.0 Introduced in WordPress core.
24088 *
24089 * @param kind Kind of the entity, e.g. `root` or a `postType`. See rootEntitiesConfig in ../entities.ts for a list of available kinds.
24090 * @param name Name of the entity, e.g. `plugin` or a `post`. See rootEntitiesConfig in ../entities.ts for a list of available names.
24091 * @param queryArgs Optional HTTP query description for how to fetch the data, passed to the requested API endpoint.
24092 * @param options Optional hook options.
24093 * @example
24094 * ```js
24095 * import { useEntityRecords } from '@wordpress/core-data';
24096 *
24097 * function PageTitlesList() {
24098 * const { records, isResolving } = useEntityRecords( 'postType', 'page' );
24099 *
24100 * if ( isResolving ) {
24101 * return 'Loading...';
24102 * }
24103 *
24104 * return (
24105 * <ul>
24106 * {records.map(( page ) => (
24107 * <li>{ page.title }</li>
24108 * ))}
24109 * </ul>
24110 * );
24111 * }
24112 *
24113 * // Rendered in the application:
24114 * // <PageTitlesList />
24115 * ```
24116 *
24117 * In the above example, when `PageTitlesList` is rendered into an
24118 * application, the list of records and the resolution details will be retrieved from
24119 * the store state using `getEntityRecords()`, or resolved if missing.
24120 *
24121 * @return Entity records data.
24122 * @template RecordType
24123 */
24124 function useEntityRecords(kind, name, queryArgs = {}, options = {
24125 enabled: true
24126 }) {
24127 // Serialize queryArgs to a string that can be safely used as a React dep.
24128 // We can't just pass queryArgs as one of the deps, because if it is passed
24129 // as an object literal, then it will be a different object on each call even
24130 // if the values remain the same.
24131 const queryAsString = (0,external_wp_url_namespaceObject.addQueryArgs)('', queryArgs);
24132 const {
24133 data: records,
24134 ...rest
24135 } = useQuerySelect(query => {
24136 if (!options.enabled) {
24137 return {
24138 // Avoiding returning a new reference on every execution.
24139 data: EMPTY_ARRAY
24140 };
24141 }
24142 return query(store).getEntityRecords(kind, name, queryArgs);
24143 }, [kind, name, queryAsString, options.enabled]);
24144 const {
24145 totalItems,
24146 totalPages
24147 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
24148 if (!options.enabled) {
24149 return {
24150 totalItems: null,
24151 totalPages: null
24152 };
24153 }
24154 return {
24155 totalItems: select(store).getEntityRecordsTotalItems(kind, name, queryArgs),
24156 totalPages: select(store).getEntityRecordsTotalPages(kind, name, queryArgs)
24157 };
24158 }, [kind, name, queryAsString, options.enabled]);
24159 return {
24160 records,
24161 totalItems,
24162 totalPages,
24163 ...rest
24164 };
24165 }
24166 function __experimentalUseEntityRecords(kind, name, queryArgs, options) {
24167 external_wp_deprecated_default()(`wp.data.__experimentalUseEntityRecords`, {
24168 alternative: 'wp.data.useEntityRecords',
24169 since: '6.1'
24170 });
24171 return useEntityRecords(kind, name, queryArgs, options);
24172 }
24173
24174 ;// CONCATENATED MODULE: external ["wp","warning"]
24175 const external_wp_warning_namespaceObject = window["wp"]["warning"];
24176 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-resource-permissions.js
24177 /**
24178 * WordPress dependencies
24179 */
24180
24181
24182
24183 /**
24184 * Internal dependencies
24185 */
24186
24187
24188
24189
24190 /**
24191 * Is the data resolved by now?
24192 */
24193
24194 /**
24195 * Resolves resource permissions.
24196 *
24197 * @since 6.1.0 Introduced in WordPress core.
24198 *
24199 * @param resource Entity resource to check. Accepts entity object `{ kind: 'root', name: 'media', id: 1 }`
24200 * or REST base as a string - `media`.
24201 * @param id Optional ID of the resource to check, e.g. 10. Note: This argument is discouraged
24202 * when using an entity object as a resource to check permissions and will be ignored.
24203 *
24204 * @example
24205 * ```js
24206 * import { useResourcePermissions } from '@wordpress/core-data';
24207 *
24208 * function PagesList() {
24209 * const { canCreate, isResolving } = useResourcePermissions( { kind: 'postType', name: 'page' } );
24210 *
24211 * if ( isResolving ) {
24212 * return 'Loading ...';
24213 * }
24214 *
24215 * return (
24216 * <div>
24217 * {canCreate ? (<button>+ Create a new page</button>) : false}
24218 * // ...
24219 * </div>
24220 * );
24221 * }
24222 *
24223 * // Rendered in the application:
24224 * // <PagesList />
24225 * ```
24226 *
24227 * @example
24228 * ```js
24229 * import { useResourcePermissions } from '@wordpress/core-data';
24230 *
24231 * function Page({ pageId }) {
24232 * const {
24233 * canCreate,
24234 * canUpdate,
24235 * canDelete,
24236 * isResolving
24237 * } = useResourcePermissions( { kind: 'postType', name: 'page', id: pageId } );
24238 *
24239 * if ( isResolving ) {
24240 * return 'Loading ...';
24241 * }
24242 *
24243 * return (
24244 * <div>
24245 * {canCreate ? (<button>+ Create a new page</button>) : false}
24246 * {canUpdate ? (<button>Edit page</button>) : false}
24247 * {canDelete ? (<button>Delete page</button>) : false}
24248 * // ...
24249 * </div>
24250 * );
24251 * }
24252 *
24253 * // Rendered in the application:
24254 * // <Page pageId={ 15 } />
24255 * ```
24256 *
24257 * In the above example, when `PagesList` is rendered into an
24258 * application, the appropriate permissions and the resolution details will be retrieved from
24259 * the store state using `canUser()`, or resolved if missing.
24260 *
24261 * @return Entity records data.
24262 * @template IdType
24263 */
24264 function useResourcePermissions(resource, id) {
24265 // Serialize `resource` to a string that can be safely used as a React dep.
24266 // We can't just pass `resource` as one of the deps, because if it is passed
24267 // as an object literal, then it will be a different object on each call even
24268 // if the values remain the same.
24269 const isEntity = typeof resource === 'object';
24270 const resourceAsString = isEntity ? JSON.stringify(resource) : resource;
24271 if (isEntity && typeof id !== 'undefined') {
24272 false ? 0 : void 0;
24273 }
24274 return useQuerySelect(resolve => {
24275 const hasId = isEntity ? !!resource.id : !!id;
24276 const {
24277 canUser
24278 } = resolve(store);
24279 const create = canUser('create', isEntity ? {
24280 kind: resource.kind,
24281 name: resource.name
24282 } : resource);
24283 if (!hasId) {
24284 const read = canUser('read', resource);
24285 const isResolving = create.isResolving || read.isResolving;
24286 const hasResolved = create.hasResolved && read.hasResolved;
24287 let status = Status.Idle;
24288 if (isResolving) {
24289 status = Status.Resolving;
24290 } else if (hasResolved) {
24291 status = Status.Success;
24292 }
24293 return {
24294 status,
24295 isResolving,
24296 hasResolved,
24297 canCreate: create.hasResolved && create.data,
24298 canRead: read.hasResolved && read.data
24299 };
24300 }
24301 const read = canUser('read', resource, id);
24302 const update = canUser('update', resource, id);
24303 const _delete = canUser('delete', resource, id);
24304 const isResolving = read.isResolving || create.isResolving || update.isResolving || _delete.isResolving;
24305 const hasResolved = read.hasResolved && create.hasResolved && update.hasResolved && _delete.hasResolved;
24306 let status = Status.Idle;
24307 if (isResolving) {
24308 status = Status.Resolving;
24309 } else if (hasResolved) {
24310 status = Status.Success;
24311 }
24312 return {
24313 status,
24314 isResolving,
24315 hasResolved,
24316 canRead: hasResolved && read.data,
24317 canCreate: hasResolved && create.data,
24318 canUpdate: hasResolved && update.data,
24319 canDelete: hasResolved && _delete.data
24320 };
24321 }, [resourceAsString, id]);
24322 }
24323 /* harmony default export */ const use_resource_permissions = (useResourcePermissions);
24324 function __experimentalUseResourcePermissions(resource, id) {
24325 external_wp_deprecated_default()(`wp.data.__experimentalUseResourcePermissions`, {
24326 alternative: 'wp.data.useResourcePermissions',
24327 since: '6.1'
24328 });
24329 return useResourcePermissions(resource, id);
24330 }
24331
24332 ;// CONCATENATED MODULE: external ["wp","blocks"]
24333 const external_wp_blocks_namespaceObject = window["wp"]["blocks"];
24334 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-entity-id.js
24335 /**
24336 * WordPress dependencies
24337 */
24338
24339
24340 /**
24341 * Internal dependencies
24342 */
24343
24344
24345 /**
24346 * Hook that returns the ID for the nearest
24347 * provided entity of the specified type.
24348 *
24349 * @param {string} kind The entity kind.
24350 * @param {string} name The entity name.
24351 */
24352 function useEntityId(kind, name) {
24353 const context = (0,external_wp_element_namespaceObject.useContext)(EntityContext);
24354 return context?.[kind]?.[name];
24355 }
24356
24357 ;// CONCATENATED MODULE: external ["wp","blockEditor"]
24358 const external_wp_blockEditor_namespaceObject = window["wp"]["blockEditor"];
24359 ;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/get-rich-text-values-cached.js
24360 /**
24361 * WordPress dependencies
24362 */
24363
24364
24365 /**
24366 * Internal dependencies
24367 */
24368
24369
24370 // TODO: The following line should have been:
24371 //
24372 // const unlockedApis = unlock( blockEditorPrivateApis );
24373 //
24374 // But there are hidden circular dependencies in RNMobile code, specifically in
24375 // certain native components in the `components` package that depend on
24376 // `block-editor`. What follows is a workaround that defers the `unlock` call
24377 // to prevent native code from failing.
24378 //
24379 // Fix once https://github.com/WordPress/gutenberg/issues/52692 is closed.
24380 let unlockedApis;
24381 const cache = new WeakMap();
24382 function getRichTextValuesCached(block) {
24383 if (!unlockedApis) {
24384 unlockedApis = unlock(external_wp_blockEditor_namespaceObject.privateApis);
24385 }
24386 if (!cache.has(block)) {
24387 const values = unlockedApis.getRichTextValues([block]);
24388 cache.set(block, values);
24389 }
24390 return cache.get(block);
24391 }
24392
24393 ;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/get-footnotes-order.js
24394 /**
24395 * Internal dependencies
24396 */
24397
24398 const get_footnotes_order_cache = new WeakMap();
24399 function getBlockFootnotesOrder(block) {
24400 if (!get_footnotes_order_cache.has(block)) {
24401 const order = [];
24402 for (const value of getRichTextValuesCached(block)) {
24403 if (!value) {
24404 continue;
24405 }
24406
24407 // replacements is a sparse array, use forEach to skip empty slots.
24408 value.replacements.forEach(({
24409 type,
24410 attributes
24411 }) => {
24412 if (type === 'core/footnote') {
24413 order.push(attributes['data-fn']);
24414 }
24415 });
24416 }
24417 get_footnotes_order_cache.set(block, order);
24418 }
24419 return get_footnotes_order_cache.get(block);
24420 }
24421 function getFootnotesOrder(blocks) {
24422 // We can only separate getting order from blocks at the root level. For
24423 // deeper inner blocks, this will not work since it's possible to have both
24424 // inner blocks and block attributes, so order needs to be computed from the
24425 // Edit functions as a whole.
24426 return blocks.flatMap(getBlockFootnotesOrder);
24427 }
24428
24429 ;// CONCATENATED MODULE: ./packages/core-data/build-module/footnotes/index.js
24430 /**
24431 * WordPress dependencies
24432 */
24433
24434
24435 /**
24436 * Internal dependencies
24437 */
24438
24439 let oldFootnotes = {};
24440 function updateFootnotesFromMeta(blocks, meta) {
24441 const output = {
24442 blocks
24443 };
24444 if (!meta) {
24445 return output;
24446 }
24447
24448 // If meta.footnotes is empty, it means the meta is not registered.
24449 if (meta.footnotes === undefined) {
24450 return output;
24451 }
24452 const newOrder = getFootnotesOrder(blocks);
24453 const footnotes = meta.footnotes ? JSON.parse(meta.footnotes) : [];
24454 const currentOrder = footnotes.map(fn => fn.id);
24455 if (currentOrder.join('') === newOrder.join('')) {
24456 return output;
24457 }
24458 const newFootnotes = newOrder.map(fnId => footnotes.find(fn => fn.id === fnId) || oldFootnotes[fnId] || {
24459 id: fnId,
24460 content: ''
24461 });
24462 function updateAttributes(attributes) {
24463 // Only attempt to update attributes, if attributes is an object.
24464 if (!attributes || Array.isArray(attributes) || typeof attributes !== 'object') {
24465 return attributes;
24466 }
24467 attributes = {
24468 ...attributes
24469 };
24470 for (const key in attributes) {
24471 const value = attributes[key];
24472 if (Array.isArray(value)) {
24473 attributes[key] = value.map(updateAttributes);
24474 continue;
24475 }
24476
24477 // To do, remove support for string values?
24478 if (typeof value !== 'string' && !(value instanceof external_wp_richText_namespaceObject.RichTextData)) {
24479 continue;
24480 }
24481 const richTextValue = typeof value === 'string' ? external_wp_richText_namespaceObject.RichTextData.fromHTMLString(value) : new external_wp_richText_namespaceObject.RichTextData(value);
24482 richTextValue.replacements.forEach(replacement => {
24483 if (replacement.type === 'core/footnote') {
24484 const id = replacement.attributes['data-fn'];
24485 const index = newOrder.indexOf(id);
24486 // The innerHTML contains the count wrapped in a link.
24487 const countValue = (0,external_wp_richText_namespaceObject.create)({
24488 html: replacement.innerHTML
24489 });
24490 countValue.text = String(index + 1);
24491 countValue.formats = Array.from({
24492 length: countValue.text.length
24493 }, () => countValue.formats[0]);
24494 countValue.replacements = Array.from({
24495 length: countValue.text.length
24496 }, () => countValue.replacements[0]);
24497 replacement.innerHTML = (0,external_wp_richText_namespaceObject.toHTMLString)({
24498 value: countValue
24499 });
24500 }
24501 });
24502 attributes[key] = typeof value === 'string' ? richTextValue.toHTMLString() : richTextValue;
24503 }
24504 return attributes;
24505 }
24506 function updateBlocksAttributes(__blocks) {
24507 return __blocks.map(block => {
24508 return {
24509 ...block,
24510 attributes: updateAttributes(block.attributes),
24511 innerBlocks: updateBlocksAttributes(block.innerBlocks)
24512 };
24513 });
24514 }
24515
24516 // We need to go through all block attributes deeply and update the
24517 // footnote anchor numbering (textContent) to match the new order.
24518 const newBlocks = updateBlocksAttributes(blocks);
24519 oldFootnotes = {
24520 ...oldFootnotes,
24521 ...footnotes.reduce((acc, fn) => {
24522 if (!newOrder.includes(fn.id)) {
24523 acc[fn.id] = fn;
24524 }
24525 return acc;
24526 }, {})
24527 };
24528 return {
24529 meta: {
24530 ...meta,
24531 footnotes: JSON.stringify(newFootnotes)
24532 },
24533 blocks: newBlocks
24534 };
24535 }
24536
24537 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-entity-block-editor.js
24538 /**
24539 * WordPress dependencies
24540 */
24541
24542
24543
24544
24545 /**
24546 * Internal dependencies
24547 */
24548
24549
24550
24551 const use_entity_block_editor_EMPTY_ARRAY = [];
24552 const parsedBlocksCache = new WeakMap();
24553
24554 /**
24555 * Hook that returns block content getters and setters for
24556 * the nearest provided entity of the specified type.
24557 *
24558 * The return value has the shape `[ blocks, onInput, onChange ]`.
24559 * `onInput` is for block changes that don't create undo levels
24560 * or dirty the post, non-persistent changes, and `onChange` is for
24561 * persistent changes. They map directly to the props of a
24562 * `BlockEditorProvider` and are intended to be used with it,
24563 * or similar components or hooks.
24564 *
24565 * @param {string} kind The entity kind.
24566 * @param {string} name The entity name.
24567 * @param {Object} options
24568 * @param {string} [options.id] An entity ID to use instead of the context-provided one.
24569 *
24570 * @return {[unknown[], Function, Function]} The block array and setters.
24571 */
24572 function useEntityBlockEditor(kind, name, {
24573 id: _id
24574 } = {}) {
24575 const providerId = useEntityId(kind, name);
24576 const id = _id !== null && _id !== void 0 ? _id : providerId;
24577 const {
24578 getEntityRecord,
24579 getEntityRecordEdits
24580 } = (0,external_wp_data_namespaceObject.useSelect)(STORE_NAME);
24581 const {
24582 content,
24583 editedBlocks,
24584 meta
24585 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
24586 if (!id) {
24587 return {};
24588 }
24589 const {
24590 getEditedEntityRecord
24591 } = select(STORE_NAME);
24592 const editedRecord = getEditedEntityRecord(kind, name, id);
24593 return {
24594 editedBlocks: editedRecord.blocks,
24595 content: editedRecord.content,
24596 meta: editedRecord.meta
24597 };
24598 }, [kind, name, id]);
24599 const {
24600 __unstableCreateUndoLevel,
24601 editEntityRecord
24602 } = (0,external_wp_data_namespaceObject.useDispatch)(STORE_NAME);
24603 const blocks = (0,external_wp_element_namespaceObject.useMemo)(() => {
24604 if (!id) {
24605 return undefined;
24606 }
24607 if (editedBlocks) {
24608 return editedBlocks;
24609 }
24610 if (!content || typeof content !== 'string') {
24611 return use_entity_block_editor_EMPTY_ARRAY;
24612 }
24613
24614 // If there's an edit, cache the parsed blocks by the edit.
24615 // If not, cache by the original enity record.
24616 const edits = getEntityRecordEdits(kind, name, id);
24617 const isUnedited = !edits || !Object.keys(edits).length;
24618 const cackeKey = isUnedited ? getEntityRecord(kind, name, id) : edits;
24619 let _blocks = parsedBlocksCache.get(cackeKey);
24620 if (!_blocks) {
24621 _blocks = (0,external_wp_blocks_namespaceObject.parse)(content);
24622 parsedBlocksCache.set(cackeKey, _blocks);
24623 }
24624 return _blocks;
24625 }, [kind, name, id, editedBlocks, content, getEntityRecord, getEntityRecordEdits]);
24626 const updateFootnotes = (0,external_wp_element_namespaceObject.useCallback)(_blocks => updateFootnotesFromMeta(_blocks, meta), [meta]);
24627 const onChange = (0,external_wp_element_namespaceObject.useCallback)((newBlocks, options) => {
24628 const noChange = blocks === newBlocks;
24629 if (noChange) {
24630 return __unstableCreateUndoLevel(kind, name, id);
24631 }
24632 const {
24633 selection,
24634 ...rest
24635 } = options;
24636
24637 // We create a new function here on every persistent edit
24638 // to make sure the edit makes the post dirty and creates
24639 // a new undo level.
24640 const edits = {
24641 selection,
24642 content: ({
24643 blocks: blocksForSerialization = []
24644 }) => (0,external_wp_blocks_namespaceObject.__unstableSerializeAndClean)(blocksForSerialization),
24645 ...updateFootnotes(newBlocks)
24646 };
24647 editEntityRecord(kind, name, id, edits, {
24648 isCached: false,
24649 ...rest
24650 });
24651 }, [kind, name, id, blocks, updateFootnotes, __unstableCreateUndoLevel, editEntityRecord]);
24652 const onInput = (0,external_wp_element_namespaceObject.useCallback)((newBlocks, options) => {
24653 const {
24654 selection,
24655 ...rest
24656 } = options;
24657 const footnotesChanges = updateFootnotes(newBlocks);
24658 const edits = {
24659 selection,
24660 ...footnotesChanges
24661 };
24662 editEntityRecord(kind, name, id, edits, {
24663 isCached: true,
24664 ...rest
24665 });
24666 }, [kind, name, id, updateFootnotes, editEntityRecord]);
24667 return [blocks, onInput, onChange];
24668 }
24669
24670 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/use-entity-prop.js
24671 /**
24672 * WordPress dependencies
24673 */
24674
24675
24676
24677 /**
24678 * Internal dependencies
24679 */
24680
24681
24682
24683 /**
24684 * Hook that returns the value and a setter for the
24685 * specified property of the nearest provided
24686 * entity of the specified type.
24687 *
24688 * @param {string} kind The entity kind.
24689 * @param {string} name The entity name.
24690 * @param {string} prop The property name.
24691 * @param {string} [_id] An entity ID to use instead of the context-provided one.
24692 *
24693 * @return {[*, Function, *]} An array where the first item is the
24694 * property value, the second is the
24695 * setter and the third is the full value
24696 * object from REST API containing more
24697 * information like `raw`, `rendered` and
24698 * `protected` props.
24699 */
24700 function useEntityProp(kind, name, prop, _id) {
24701 const providerId = useEntityId(kind, name);
24702 const id = _id !== null && _id !== void 0 ? _id : providerId;
24703 const {
24704 value,
24705 fullValue
24706 } = (0,external_wp_data_namespaceObject.useSelect)(select => {
24707 const {
24708 getEntityRecord,
24709 getEditedEntityRecord
24710 } = select(STORE_NAME);
24711 const record = getEntityRecord(kind, name, id); // Trigger resolver.
24712 const editedRecord = getEditedEntityRecord(kind, name, id);
24713 return record && editedRecord ? {
24714 value: editedRecord[prop],
24715 fullValue: record[prop]
24716 } : {};
24717 }, [kind, name, id, prop]);
24718 const {
24719 editEntityRecord
24720 } = (0,external_wp_data_namespaceObject.useDispatch)(STORE_NAME);
24721 const setValue = (0,external_wp_element_namespaceObject.useCallback)(newValue => {
24722 editEntityRecord(kind, name, id, {
24723 [prop]: newValue
24724 });
24725 }, [editEntityRecord, kind, name, id, prop]);
24726 return [value, setValue, fullValue];
24727 }
24728
24729 ;// CONCATENATED MODULE: ./packages/core-data/build-module/hooks/index.js
24730
24731
24732
24733
24734
24735
24736
24737 ;// CONCATENATED MODULE: ./packages/core-data/build-module/index.js
24738 /**
24739 * WordPress dependencies
24740 */
24741
24742
24743 /**
24744 * Internal dependencies
24745 */
24746
24747
24748
24749
24750
24751
24752
24753
24754
24755
24756 // The entity selectors/resolvers and actions are shortcuts to their generic equivalents
24757 // (getEntityRecord, getEntityRecords, updateEntityRecord, updateEntityRecords)
24758 // Instead of getEntityRecord, the consumer could use more user-friendly named selector: getPostType, getTaxonomy...
24759 // The "kind" and the "name" of the entity are combined to generate these shortcuts.
24760 const build_module_entitiesConfig = [...rootEntitiesConfig, ...additionalEntityConfigLoaders.filter(config => !!config.name)];
24761 const entitySelectors = build_module_entitiesConfig.reduce((result, entity) => {
24762 const {
24763 kind,
24764 name,
24765 plural
24766 } = entity;
24767 result[getMethodName(kind, name)] = (state, key, query) => getEntityRecord(state, kind, name, key, query);
24768 if (plural) {
24769 result[getMethodName(kind, plural, 'get')] = (state, query) => getEntityRecords(state, kind, name, query);
24770 }
24771 return result;
24772 }, {});
24773 const entityResolvers = build_module_entitiesConfig.reduce((result, entity) => {
24774 const {
24775 kind,
24776 name,
24777 plural
24778 } = entity;
24779 result[getMethodName(kind, name)] = (key, query) => resolvers_getEntityRecord(kind, name, key, query);
24780 if (plural) {
24781 const pluralMethodName = getMethodName(kind, plural, 'get');
24782 result[pluralMethodName] = (...args) => resolvers_getEntityRecords(kind, name, ...args);
24783 result[pluralMethodName].shouldInvalidate = action => resolvers_getEntityRecords.shouldInvalidate(action, kind, name);
24784 }
24785 return result;
24786 }, {});
24787 const entityActions = build_module_entitiesConfig.reduce((result, entity) => {
24788 const {
24789 kind,
24790 name
24791 } = entity;
24792 result[getMethodName(kind, name, 'save')] = (record, options) => saveEntityRecord(kind, name, record, options);
24793 result[getMethodName(kind, name, 'delete')] = (key, query, options) => deleteEntityRecord(kind, name, key, query, options);
24794 return result;
24795 }, {});
24796 const storeConfig = () => ({
24797 reducer: build_module_reducer,
24798 actions: {
24799 ...build_module_actions_namespaceObject,
24800 ...entityActions,
24801 ...createLocksActions()
24802 },
24803 selectors: {
24804 ...build_module_selectors_namespaceObject,
24805 ...entitySelectors
24806 },
24807 resolvers: {
24808 ...resolvers_namespaceObject,
24809 ...entityResolvers
24810 }
24811 });
24812
24813 /**
24814 * Store definition for the code data namespace.
24815 *
24816 * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore
24817 */
24818 const store = (0,external_wp_data_namespaceObject.createReduxStore)(STORE_NAME, storeConfig());
24819 unlock(store).registerPrivateSelectors(private_selectors_namespaceObject);
24820 (0,external_wp_data_namespaceObject.register)(store); // Register store after unlocking private selectors to allow resolvers to use them.
24821
24822
24823
24824
24825
24826
24827
24828 })();
24829
24830 (window.wp = window.wp || {}).coreData = __webpack_exports__;
24831 /******/ })()
24832 ;