@converse/skeletor 3.0.1 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /** Used for built-in method references. */
2
- var objectProto$l = Object.prototype;
2
+ var objectProto$m = Object.prototype;
3
3
 
4
4
  /**
5
5
  * Checks if `value` is likely a prototype object.
@@ -10,7 +10,7 @@ var objectProto$l = Object.prototype;
10
10
  */
11
11
  function isPrototype(value) {
12
12
  var Ctor = value && value.constructor,
13
- proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto$l;
13
+ proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto$m;
14
14
 
15
15
  return value === proto;
16
16
  }
@@ -33,10 +33,10 @@ function overArg(func, transform) {
33
33
  var nativeKeys = overArg(Object.keys, Object);
34
34
 
35
35
  /** Used for built-in method references. */
36
- var objectProto$k = Object.prototype;
36
+ var objectProto$l = Object.prototype;
37
37
 
38
38
  /** Used to check objects for own properties. */
39
- var hasOwnProperty$h = objectProto$k.hasOwnProperty;
39
+ var hasOwnProperty$i = objectProto$l.hasOwnProperty;
40
40
 
41
41
  /**
42
42
  * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
@@ -51,7 +51,7 @@ function baseKeys(object) {
51
51
  }
52
52
  var result = [];
53
53
  for (var key in Object(object)) {
54
- if (hasOwnProperty$h.call(object, key) && key != 'constructor') {
54
+ if (hasOwnProperty$i.call(object, key) && key != 'constructor') {
55
55
  result.push(key);
56
56
  }
57
57
  }
@@ -71,17 +71,17 @@ var root$1 = freeGlobal || freeSelf || Function('return this')();
71
71
  var Symbol$1 = root$1.Symbol;
72
72
 
73
73
  /** Used for built-in method references. */
74
- var objectProto$j = Object.prototype;
74
+ var objectProto$k = Object.prototype;
75
75
 
76
76
  /** Used to check objects for own properties. */
77
- var hasOwnProperty$g = objectProto$j.hasOwnProperty;
77
+ var hasOwnProperty$h = objectProto$k.hasOwnProperty;
78
78
 
79
79
  /**
80
80
  * Used to resolve the
81
81
  * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
82
82
  * of values.
83
83
  */
84
- var nativeObjectToString$2 = objectProto$j.toString;
84
+ var nativeObjectToString$2 = objectProto$k.toString;
85
85
 
86
86
  /** Built-in value references. */
87
87
  var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined;
@@ -94,7 +94,7 @@ var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined;
94
94
  * @returns {string} Returns the raw `toStringTag`.
95
95
  */
96
96
  function getRawTag(value) {
97
- var isOwn = hasOwnProperty$g.call(value, symToStringTag$1),
97
+ var isOwn = hasOwnProperty$h.call(value, symToStringTag$1),
98
98
  tag = value[symToStringTag$1];
99
99
 
100
100
  try {
@@ -114,14 +114,14 @@ function getRawTag(value) {
114
114
  }
115
115
 
116
116
  /** Used for built-in method references. */
117
- var objectProto$i = Object.prototype;
117
+ var objectProto$j = Object.prototype;
118
118
 
119
119
  /**
120
120
  * Used to resolve the
121
121
  * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
122
122
  * of values.
123
123
  */
124
- var nativeObjectToString$1 = objectProto$i.toString;
124
+ var nativeObjectToString$1 = objectProto$j.toString;
125
125
 
126
126
  /**
127
127
  * Converts `value` to a string using `Object.prototype.toString`.
@@ -276,17 +276,17 @@ var reIsHostCtor = /^\[object .+?Constructor\]$/;
276
276
 
277
277
  /** Used for built-in method references. */
278
278
  var funcProto$1 = Function.prototype,
279
- objectProto$h = Object.prototype;
279
+ objectProto$i = Object.prototype;
280
280
 
281
281
  /** Used to resolve the decompiled source of functions. */
282
282
  var funcToString$1 = funcProto$1.toString;
283
283
 
284
284
  /** Used to check objects for own properties. */
285
- var hasOwnProperty$f = objectProto$h.hasOwnProperty;
285
+ var hasOwnProperty$g = objectProto$i.hasOwnProperty;
286
286
 
287
287
  /** Used to detect if a method is native. */
288
288
  var reIsNative = RegExp('^' +
289
- funcToString$1.call(hasOwnProperty$f).replace(reRegExpChar, '\\$&')
289
+ funcToString$1.call(hasOwnProperty$g).replace(reRegExpChar, '\\$&')
290
290
  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
291
291
  );
292
292
 
@@ -335,16 +335,16 @@ function getNative(object, key) {
335
335
  var DataView = getNative(root$1, 'DataView');
336
336
 
337
337
  /* Built-in method references that are verified to be native. */
338
- var Map = getNative(root$1, 'Map');
338
+ var Map$1 = getNative(root$1, 'Map');
339
339
 
340
340
  /* Built-in method references that are verified to be native. */
341
341
  var Promise$1 = getNative(root$1, 'Promise');
342
342
 
343
343
  /* Built-in method references that are verified to be native. */
344
- var Set = getNative(root$1, 'Set');
344
+ var Set$1 = getNative(root$1, 'Set');
345
345
 
346
346
  /* Built-in method references that are verified to be native. */
347
- var WeakMap = getNative(root$1, 'WeakMap');
347
+ var WeakMap$1 = getNative(root$1, 'WeakMap');
348
348
 
349
349
  /** `Object#toString` result references. */
350
350
  var mapTag$6 = '[object Map]',
@@ -357,10 +357,10 @@ var dataViewTag$4 = '[object DataView]';
357
357
 
358
358
  /** Used to detect maps, sets, and weakmaps. */
359
359
  var dataViewCtorString = toSource(DataView),
360
- mapCtorString = toSource(Map),
360
+ mapCtorString = toSource(Map$1),
361
361
  promiseCtorString = toSource(Promise$1),
362
- setCtorString = toSource(Set),
363
- weakMapCtorString = toSource(WeakMap);
362
+ setCtorString = toSource(Set$1),
363
+ weakMapCtorString = toSource(WeakMap$1);
364
364
 
365
365
  /**
366
366
  * Gets the `toStringTag` of `value`.
@@ -373,10 +373,10 @@ var getTag = baseGetTag;
373
373
 
374
374
  // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
375
375
  if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag$4) ||
376
- (Map && getTag(new Map) != mapTag$6) ||
376
+ (Map$1 && getTag(new Map$1) != mapTag$6) ||
377
377
  (Promise$1 && getTag(Promise$1.resolve()) != promiseTag) ||
378
- (Set && getTag(new Set) != setTag$6) ||
379
- (WeakMap && getTag(new WeakMap) != weakMapTag$2)) {
378
+ (Set$1 && getTag(new Set$1) != setTag$6) ||
379
+ (WeakMap$1 && getTag(new WeakMap$1) != weakMapTag$2)) {
380
380
  getTag = function(value) {
381
381
  var result = baseGetTag(value),
382
382
  Ctor = result == objectTag$4 ? value.constructor : undefined,
@@ -438,13 +438,13 @@ function baseIsArguments(value) {
438
438
  }
439
439
 
440
440
  /** Used for built-in method references. */
441
- var objectProto$g = Object.prototype;
441
+ var objectProto$h = Object.prototype;
442
442
 
443
443
  /** Used to check objects for own properties. */
444
- var hasOwnProperty$e = objectProto$g.hasOwnProperty;
444
+ var hasOwnProperty$f = objectProto$h.hasOwnProperty;
445
445
 
446
446
  /** Built-in value references. */
447
- var propertyIsEnumerable$1 = objectProto$g.propertyIsEnumerable;
447
+ var propertyIsEnumerable$1 = objectProto$h.propertyIsEnumerable;
448
448
 
449
449
  /**
450
450
  * Checks if `value` is likely an `arguments` object.
@@ -465,7 +465,7 @@ var propertyIsEnumerable$1 = objectProto$g.propertyIsEnumerable;
465
465
  * // => false
466
466
  */
467
467
  var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
468
- return isObjectLike(value) && hasOwnProperty$e.call(value, 'callee') &&
468
+ return isObjectLike(value) && hasOwnProperty$f.call(value, 'callee') &&
469
469
  !propertyIsEnumerable$1.call(value, 'callee');
470
470
  };
471
471
 
@@ -730,10 +730,10 @@ var mapTag$4 = '[object Map]',
730
730
  setTag$4 = '[object Set]';
731
731
 
732
732
  /** Used for built-in method references. */
733
- var objectProto$f = Object.prototype;
733
+ var objectProto$g = Object.prototype;
734
734
 
735
735
  /** Used to check objects for own properties. */
736
- var hasOwnProperty$d = objectProto$f.hasOwnProperty;
736
+ var hasOwnProperty$e = objectProto$g.hasOwnProperty;
737
737
 
738
738
  /**
739
739
  * Checks if `value` is an empty object, collection, map, or set.
@@ -785,7 +785,7 @@ function isEmpty(value) {
785
785
  return !baseKeys(value).length;
786
786
  }
787
787
  for (var key in value) {
788
- if (hasOwnProperty$d.call(value, key)) {
788
+ if (hasOwnProperty$e.call(value, key)) {
789
789
  return false;
790
790
  }
791
791
  }
@@ -836,10 +836,10 @@ function isIndex(value, length) {
836
836
  }
837
837
 
838
838
  /** Used for built-in method references. */
839
- var objectProto$e = Object.prototype;
839
+ var objectProto$f = Object.prototype;
840
840
 
841
841
  /** Used to check objects for own properties. */
842
- var hasOwnProperty$c = objectProto$e.hasOwnProperty;
842
+ var hasOwnProperty$d = objectProto$f.hasOwnProperty;
843
843
 
844
844
  /**
845
845
  * Creates an array of the enumerable property names of the array-like `value`.
@@ -859,7 +859,7 @@ function arrayLikeKeys(value, inherited) {
859
859
  length = result.length;
860
860
 
861
861
  for (var key in value) {
862
- if ((inherited || hasOwnProperty$c.call(value, key)) &&
862
+ if ((inherited || hasOwnProperty$d.call(value, key)) &&
863
863
  !(skipIndexes && (
864
864
  // Safari 9 has enumerable `arguments.length` in strict mode.
865
865
  key == 'length' ||
@@ -1002,7 +1002,7 @@ function baseToString(value) {
1002
1002
  * _.toString([1, 2, 3]);
1003
1003
  * // => '1,2,3'
1004
1004
  */
1005
- function toString$2(value) {
1005
+ function toString$1(value) {
1006
1006
  return value == null ? '' : baseToString(value);
1007
1007
  }
1008
1008
 
@@ -1028,7 +1028,7 @@ var idCounter = 0;
1028
1028
  */
1029
1029
  function uniqueId(prefix) {
1030
1030
  var id = ++idCounter;
1031
- return toString$2(prefix) + id;
1031
+ return toString$1(prefix) + id;
1032
1032
  }
1033
1033
 
1034
1034
  /** Used to match a single whitespace character. */
@@ -1624,6 +1624,14 @@ function EventEmitter(Base) {
1624
1624
  eventsApi(triggerApi, this._events, name, undefined, args);
1625
1625
  return this;
1626
1626
  }
1627
+ /**
1628
+ * Subscribe to an event. Returns an unsubscribe function.
1629
+ * Compatible with `useSyncExternalStore` and other store-style APIs.
1630
+ */
1631
+ subscribe(event, callback, context) {
1632
+ this.on(event, callback, context);
1633
+ return () => this.off(event, callback, context);
1634
+ }
1627
1635
  };
1628
1636
  }
1629
1637
  /**
@@ -1631,7 +1639,7 @@ function EventEmitter(Base) {
1631
1639
  */
1632
1640
  const EventEmitterObject = EventEmitter(Object);
1633
1641
 
1634
- /*! *****************************************************************************
1642
+ /******************************************************************************
1635
1643
  Copyright (c) Microsoft Corporation.
1636
1644
 
1637
1645
  Permission to use, copy, modify, and/or distribute this software for any
@@ -1645,7 +1653,7 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1645
1653
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1646
1654
  PERFORMANCE OF THIS SOFTWARE.
1647
1655
  ***************************************************************************** */
1648
- /* global Reflect, Promise */
1656
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
1649
1657
 
1650
1658
 
1651
1659
  function __values(o) {
@@ -1658,7 +1666,25 @@ function __values(o) {
1658
1666
  }
1659
1667
  };
1660
1668
  throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
1661
- }
1669
+ }
1670
+
1671
+ function __classPrivateFieldGet(receiver, state, kind, f) {
1672
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
1673
+ 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");
1674
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
1675
+ }
1676
+
1677
+ function __classPrivateFieldSet(receiver, state, value, kind, f) {
1678
+ if (kind === "m") throw new TypeError("Private method is not writable");
1679
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
1680
+ 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");
1681
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
1682
+ }
1683
+
1684
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1685
+ var e = new Error(message);
1686
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1687
+ };
1662
1688
 
1663
1689
  /*!
1664
1690
  MIT License
@@ -1697,7 +1723,7 @@ SOFTWARE.
1697
1723
  * @param parts
1698
1724
  * @param properties
1699
1725
  */
1700
- function createBlob$1(parts, properties) {
1726
+ function createBlob(parts, properties) {
1701
1727
  /* global BlobBuilder,MSBlobBuilder,MozBlobBuilder,WebKitBlobBuilder */
1702
1728
  parts = parts || [];
1703
1729
  properties = properties || {};
@@ -1721,12 +1747,12 @@ function createBlob$1(parts, properties) {
1721
1747
  }
1722
1748
  }
1723
1749
 
1724
- var BLOB_TYPE_PREFIX_REGEX$1 = /^~~local_forage_type~([^~]+)~/;
1725
- var SERIALIZED_MARKER_LENGTH$1 = "__lfsc__:" /* SERIALIZED_MARKER */.length;
1726
- var TYPE_SERIALIZED_MARKER_LENGTH$1 = SERIALIZED_MARKER_LENGTH$1 + "arbf" /* TYPE_ARRAYBUFFER */.length;
1750
+ var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;
1751
+ var SERIALIZED_MARKER_LENGTH = "__lfsc__:" /* SERIALIZED_MARKER */.length;
1752
+ var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + "arbf" /* TYPE_ARRAYBUFFER */.length;
1727
1753
  //tslint:disable:no-magic-numbers no-bitwise prefer-switch no-unbound-method
1728
- var toString$1 = Object.prototype.toString;
1729
- function stringToBuffer$1(serializedString) {
1754
+ var toString = Object.prototype.toString;
1755
+ function stringToBuffer(serializedString) {
1730
1756
  // Fill the string into a ArrayBuffer.
1731
1757
  var bufferLength = serializedString.length * 0.75;
1732
1758
  var len = serializedString.length;
@@ -1753,7 +1779,7 @@ function stringToBuffer$1(serializedString) {
1753
1779
  * Converts a buffer to a string to store, serialized, in the backend
1754
1780
  * storage library.
1755
1781
  */
1756
- function bufferToString$1(buffer) {
1782
+ function bufferToString(buffer) {
1757
1783
  // base64-arraybuffer
1758
1784
  var bytes = new Uint8Array(buffer);
1759
1785
  var base64String = '';
@@ -1780,15 +1806,15 @@ function bufferToString$1(buffer) {
1780
1806
  * @param value
1781
1807
  * @param callback
1782
1808
  */
1783
- function serialize$2(value, callback) {
1809
+ function serialize$1(value, callback) {
1784
1810
  var valueType = '';
1785
1811
  if (value) {
1786
- valueType = toString$1.call(value);
1812
+ valueType = toString.call(value);
1787
1813
  }
1788
1814
  // Cannot use `value instanceof ArrayBuffer` or such here, as these
1789
1815
  // checks fail when running the tests using casper.js...
1790
1816
  if (value && (valueType === '[object ArrayBuffer]' ||
1791
- (value.buffer && toString$1.call(value.buffer) === '[object ArrayBuffer]'))) {
1817
+ (value.buffer && toString.call(value.buffer) === '[object ArrayBuffer]'))) {
1792
1818
  // Convert binary arrays to a string and prefix the string with
1793
1819
  // a special marker.
1794
1820
  var buffer = void 0;
@@ -1830,7 +1856,7 @@ function serialize$2(value, callback) {
1830
1856
  callback(new Error('Failed to get type for BinaryArray'));
1831
1857
  }
1832
1858
  }
1833
- callback(marker + bufferToString$1(buffer));
1859
+ callback(marker + bufferToString(buffer));
1834
1860
  }
1835
1861
  else if (valueType === '[object Blob]') {
1836
1862
  // Convert the blob to a binaryArray and then to a string.
@@ -1838,7 +1864,7 @@ function serialize$2(value, callback) {
1838
1864
  fileReader.onload = function () {
1839
1865
  // Backwards-compatible prefix for the blob type.
1840
1866
  //tslint:disable-next-line:restrict-plus-operands
1841
- var str = "~~local_forage_type~" /* BLOB_TYPE_PREFIX */ + value.type + "~" + bufferToString$1(this.result);
1867
+ var str = "~~local_forage_type~" /* BLOB_TYPE_PREFIX */ + value.type + "~" + bufferToString(this.result);
1842
1868
  callback("__lfsc__:" /* SERIALIZED_MARKER */ + "blob" /* TYPE_BLOB */ + str);
1843
1869
  };
1844
1870
  fileReader.readAsArrayBuffer(value);
@@ -1864,34 +1890,34 @@ function serialize$2(value, callback) {
1864
1890
  * some kind of arraybuffer/binary data/typed array out of the string.
1865
1891
  * @param value
1866
1892
  */
1867
- function deserialize$2(value) {
1893
+ function deserialize$1(value) {
1868
1894
  // If we haven't marked this string as being specially serialized (i.e.
1869
1895
  // something other than serialized JSON), we can just return it and be
1870
1896
  // done with it.
1871
- if (value.substring(0, SERIALIZED_MARKER_LENGTH$1) !== "__lfsc__:" /* SERIALIZED_MARKER */) {
1897
+ if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== "__lfsc__:" /* SERIALIZED_MARKER */) {
1872
1898
  return JSON.parse(value);
1873
1899
  }
1874
1900
  // The following code deals with deserializing some kind of Blob or
1875
1901
  // TypedArray. First we separate out the type of data we're dealing
1876
1902
  // with from the data itself.
1877
- var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH$1);
1878
- var type = value.substring(SERIALIZED_MARKER_LENGTH$1, TYPE_SERIALIZED_MARKER_LENGTH$1);
1903
+ var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
1904
+ var type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH);
1879
1905
  var blobType;
1880
1906
  // Backwards-compatible blob type serialization strategy.
1881
1907
  // DBs created with older versions of localForage will simply not have the blob type.
1882
- if (type === "blob" /* TYPE_BLOB */ && BLOB_TYPE_PREFIX_REGEX$1.test(serializedString)) {
1883
- var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX$1);
1908
+ if (type === "blob" /* TYPE_BLOB */ && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {
1909
+ var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);
1884
1910
  blobType = matcher[1];
1885
1911
  serializedString = serializedString.substring(matcher[0].length);
1886
1912
  }
1887
- var buffer = stringToBuffer$1(serializedString);
1913
+ var buffer = stringToBuffer(serializedString);
1888
1914
  // Return the right type based on the code/type set during
1889
1915
  // serialization.
1890
1916
  switch (type) {
1891
1917
  case "arbf" /* TYPE_ARRAYBUFFER */:
1892
1918
  return buffer;
1893
1919
  case "blob" /* TYPE_BLOB */:
1894
- return createBlob$1([buffer], { type: blobType });
1920
+ return createBlob([buffer], { type: blobType });
1895
1921
  case "si08" /* TYPE_INT8ARRAY */:
1896
1922
  return new Int8Array(buffer);
1897
1923
  case "ui08" /* TYPE_UINT8ARRAY */:
@@ -1945,7 +1971,7 @@ function getKeyPrefix(options, defaultConfig) {
1945
1971
  return (options.name || defaultConfig.name) + "/" + (options.storeName || defaultConfig.storeName) + "/";
1946
1972
  }
1947
1973
 
1948
- function executeCallback$2(promise, callback) {
1974
+ function executeCallback$1(promise, callback) {
1949
1975
  if (callback) {
1950
1976
  promise.then(function (result) {
1951
1977
  callback(null, result);
@@ -1998,10 +2024,10 @@ function normaliseKey(key) {
1998
2024
  }
1999
2025
 
2000
2026
  var serialiser = {
2001
- bufferToString: bufferToString$1,
2002
- deserialize: deserialize$2,
2003
- serialize: serialize$2,
2004
- stringToBuffer: stringToBuffer$1
2027
+ bufferToString: bufferToString,
2028
+ deserialize: deserialize$1,
2029
+ serialize: serialize$1,
2030
+ stringToBuffer: stringToBuffer
2005
2031
  };
2006
2032
 
2007
2033
  /*!
@@ -2086,7 +2112,7 @@ function clear$1(callback) {
2086
2112
  var promise = this.ready().then(function () {
2087
2113
  _this._dbInfo.mStore.clear();
2088
2114
  });
2089
- executeCallback$2(promise, callback);
2115
+ executeCallback$1(promise, callback);
2090
2116
  return promise;
2091
2117
  }
2092
2118
 
@@ -2095,7 +2121,7 @@ function dropInstance$1(_options, _cb) {
2095
2121
  var outPromise = promise.then(function (keyPrefix) {
2096
2122
  Store.resolve(keyPrefix).drop();
2097
2123
  });
2098
- executeCallback$2(outPromise, callback);
2124
+ executeCallback$1(outPromise, callback);
2099
2125
  return promise;
2100
2126
  }
2101
2127
 
@@ -2107,7 +2133,7 @@ function getItem$1(key$, callback) {
2107
2133
  // Deserialise if the result is not null or undefined
2108
2134
  return result == null ? null : _this._dbInfo.serializer.deserialize(result); //tslint:disable-line:triple-equals
2109
2135
  });
2110
- executeCallback$2(promise, callback);
2136
+ executeCallback$1(promise, callback);
2111
2137
  return promise;
2112
2138
  }
2113
2139
 
@@ -2131,7 +2157,7 @@ function iterate$1(iterator, callback) {
2131
2157
  }
2132
2158
  }
2133
2159
  });
2134
- executeCallback$2(promise, callback);
2160
+ executeCallback$1(promise, callback);
2135
2161
  return promise;
2136
2162
  }
2137
2163
 
@@ -2150,7 +2176,7 @@ function key$1(idx, callback) {
2150
2176
  }
2151
2177
  return result;
2152
2178
  });
2153
- executeCallback$2(promise, callback);
2179
+ executeCallback$1(promise, callback);
2154
2180
  return promise;
2155
2181
  }
2156
2182
 
@@ -2159,13 +2185,13 @@ function keys$1(callback) {
2159
2185
  var promise = this.ready().then(function () {
2160
2186
  return _this._dbInfo.mStore.keys();
2161
2187
  });
2162
- executeCallback$2(promise, callback);
2188
+ executeCallback$1(promise, callback);
2163
2189
  return promise;
2164
2190
  }
2165
2191
 
2166
2192
  function length$1(callback) {
2167
2193
  var promise = this.keys().then(function (keys$) { return keys$.length; });
2168
- executeCallback$2(promise, callback);
2194
+ executeCallback$1(promise, callback);
2169
2195
  return promise;
2170
2196
  }
2171
2197
 
@@ -2175,7 +2201,7 @@ function removeItem$1(key$, callback) {
2175
2201
  var promise = this.ready().then(function () {
2176
2202
  _this._dbInfo.mStore.rm(key$);
2177
2203
  });
2178
- executeCallback$2(promise, callback);
2204
+ executeCallback$1(promise, callback);
2179
2205
  return promise;
2180
2206
  }
2181
2207
 
@@ -2205,7 +2231,7 @@ function setItem$1(key$, value, callback) {
2205
2231
  });
2206
2232
  });
2207
2233
  });
2208
- executeCallback$2(promise, callback);
2234
+ executeCallback$1(promise, callback);
2209
2235
  return promise;
2210
2236
  }
2211
2237
 
@@ -2492,10 +2518,10 @@ function hashDelete(key) {
2492
2518
  var HASH_UNDEFINED$2 = '__lodash_hash_undefined__';
2493
2519
 
2494
2520
  /** Used for built-in method references. */
2495
- var objectProto$d = Object.prototype;
2521
+ var objectProto$e = Object.prototype;
2496
2522
 
2497
2523
  /** Used to check objects for own properties. */
2498
- var hasOwnProperty$b = objectProto$d.hasOwnProperty;
2524
+ var hasOwnProperty$c = objectProto$e.hasOwnProperty;
2499
2525
 
2500
2526
  /**
2501
2527
  * Gets the hash value for `key`.
@@ -2512,14 +2538,14 @@ function hashGet(key) {
2512
2538
  var result = data[key];
2513
2539
  return result === HASH_UNDEFINED$2 ? undefined : result;
2514
2540
  }
2515
- return hasOwnProperty$b.call(data, key) ? data[key] : undefined;
2541
+ return hasOwnProperty$c.call(data, key) ? data[key] : undefined;
2516
2542
  }
2517
2543
 
2518
2544
  /** Used for built-in method references. */
2519
- var objectProto$c = Object.prototype;
2545
+ var objectProto$d = Object.prototype;
2520
2546
 
2521
2547
  /** Used to check objects for own properties. */
2522
- var hasOwnProperty$a = objectProto$c.hasOwnProperty;
2548
+ var hasOwnProperty$b = objectProto$d.hasOwnProperty;
2523
2549
 
2524
2550
  /**
2525
2551
  * Checks if a hash value for `key` exists.
@@ -2532,7 +2558,7 @@ var hasOwnProperty$a = objectProto$c.hasOwnProperty;
2532
2558
  */
2533
2559
  function hashHas(key) {
2534
2560
  var data = this.__data__;
2535
- return nativeCreate ? (data[key] !== undefined) : hasOwnProperty$a.call(data, key);
2561
+ return nativeCreate ? (data[key] !== undefined) : hasOwnProperty$b.call(data, key);
2536
2562
  }
2537
2563
 
2538
2564
  /** Used to stand-in for `undefined` hash values. */
@@ -2591,7 +2617,7 @@ function mapCacheClear() {
2591
2617
  this.size = 0;
2592
2618
  this.__data__ = {
2593
2619
  'hash': new Hash,
2594
- 'map': new (Map || ListCache),
2620
+ 'map': new (Map$1 || ListCache),
2595
2621
  'string': new Hash
2596
2622
  };
2597
2623
  }
@@ -2727,7 +2753,7 @@ function stackSet(key, value) {
2727
2753
  var data = this.__data__;
2728
2754
  if (data instanceof ListCache) {
2729
2755
  var pairs = data.__data__;
2730
- if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
2756
+ if (!Map$1 || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
2731
2757
  pairs.push([key, value]);
2732
2758
  this.size = ++data.size;
2733
2759
  return this;
@@ -2810,10 +2836,10 @@ function baseAssignValue(object, key, value) {
2810
2836
  }
2811
2837
 
2812
2838
  /** Used for built-in method references. */
2813
- var objectProto$b = Object.prototype;
2839
+ var objectProto$c = Object.prototype;
2814
2840
 
2815
2841
  /** Used to check objects for own properties. */
2816
- var hasOwnProperty$9 = objectProto$b.hasOwnProperty;
2842
+ var hasOwnProperty$a = objectProto$c.hasOwnProperty;
2817
2843
 
2818
2844
  /**
2819
2845
  * Assigns `value` to `key` of `object` if the existing value is not equivalent
@@ -2827,7 +2853,7 @@ var hasOwnProperty$9 = objectProto$b.hasOwnProperty;
2827
2853
  */
2828
2854
  function assignValue(object, key, value) {
2829
2855
  var objValue = object[key];
2830
- if (!(hasOwnProperty$9.call(object, key) && eq(objValue, value)) ||
2856
+ if (!(hasOwnProperty$a.call(object, key) && eq(objValue, value)) ||
2831
2857
  (value === undefined && !(key in object))) {
2832
2858
  baseAssignValue(object, key, value);
2833
2859
  }
@@ -2900,10 +2926,10 @@ function nativeKeysIn(object) {
2900
2926
  }
2901
2927
 
2902
2928
  /** Used for built-in method references. */
2903
- var objectProto$a = Object.prototype;
2929
+ var objectProto$b = Object.prototype;
2904
2930
 
2905
2931
  /** Used to check objects for own properties. */
2906
- var hasOwnProperty$8 = objectProto$a.hasOwnProperty;
2932
+ var hasOwnProperty$9 = objectProto$b.hasOwnProperty;
2907
2933
 
2908
2934
  /**
2909
2935
  * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
@@ -2920,7 +2946,7 @@ function baseKeysIn(object) {
2920
2946
  result = [];
2921
2947
 
2922
2948
  for (var key in object) {
2923
- if (!(key == 'constructor' && (isProto || !hasOwnProperty$8.call(object, key)))) {
2949
+ if (!(key == 'constructor' && (isProto || !hasOwnProperty$9.call(object, key)))) {
2924
2950
  result.push(key);
2925
2951
  }
2926
2952
  }
@@ -3065,10 +3091,10 @@ function stubArray() {
3065
3091
  }
3066
3092
 
3067
3093
  /** Used for built-in method references. */
3068
- var objectProto$9 = Object.prototype;
3094
+ var objectProto$a = Object.prototype;
3069
3095
 
3070
3096
  /** Built-in value references. */
3071
- var propertyIsEnumerable = objectProto$9.propertyIsEnumerable;
3097
+ var propertyIsEnumerable = objectProto$a.propertyIsEnumerable;
3072
3098
 
3073
3099
  /* Built-in method references for those with the same name as other `lodash` methods. */
3074
3100
  var nativeGetSymbols$1 = Object.getOwnPropertySymbols;
@@ -3195,10 +3221,10 @@ function getAllKeysIn(object) {
3195
3221
  }
3196
3222
 
3197
3223
  /** Used for built-in method references. */
3198
- var objectProto$8 = Object.prototype;
3224
+ var objectProto$9 = Object.prototype;
3199
3225
 
3200
3226
  /** Used to check objects for own properties. */
3201
- var hasOwnProperty$7 = objectProto$8.hasOwnProperty;
3227
+ var hasOwnProperty$8 = objectProto$9.hasOwnProperty;
3202
3228
 
3203
3229
  /**
3204
3230
  * Initializes an array clone.
@@ -3212,7 +3238,7 @@ function initCloneArray(array) {
3212
3238
  result = new array.constructor(length);
3213
3239
 
3214
3240
  // Add properties assigned by `RegExp#exec`.
3215
- if (length && typeof array[0] == 'string' && hasOwnProperty$7.call(array, 'index')) {
3241
+ if (length && typeof array[0] == 'string' && hasOwnProperty$8.call(array, 'index')) {
3216
3242
  result.index = array.index;
3217
3243
  result.input = array.input;
3218
3244
  }
@@ -6592,13 +6618,13 @@ var objectTag$1 = '[object Object]';
6592
6618
 
6593
6619
  /** Used for built-in method references. */
6594
6620
  var funcProto = Function.prototype,
6595
- objectProto$7 = Object.prototype;
6621
+ objectProto$8 = Object.prototype;
6596
6622
 
6597
6623
  /** Used to resolve the decompiled source of functions. */
6598
6624
  var funcToString = funcProto.toString;
6599
6625
 
6600
6626
  /** Used to check objects for own properties. */
6601
- var hasOwnProperty$6 = objectProto$7.hasOwnProperty;
6627
+ var hasOwnProperty$7 = objectProto$8.hasOwnProperty;
6602
6628
 
6603
6629
  /** Used to infer the `Object` constructor. */
6604
6630
  var objectCtorString = funcToString.call(Object);
@@ -6639,7 +6665,7 @@ function isPlainObject(value) {
6639
6665
  if (proto === null) {
6640
6666
  return true;
6641
6667
  }
6642
- var Ctor = hasOwnProperty$6.call(proto, 'constructor') && proto.constructor;
6668
+ var Ctor = hasOwnProperty$7.call(proto, 'constructor') && proto.constructor;
6643
6669
  return typeof Ctor == 'function' && Ctor instanceof Ctor &&
6644
6670
  funcToString.call(Ctor) == objectCtorString;
6645
6671
  }
@@ -7371,310 +7397,43 @@ function mergebounce(func, wait, options={}) {
7371
7397
  return debounced;
7372
7398
  }
7373
7399
 
7374
- function executeCallback$1(promise, callback) {
7400
+ function chainCallback(promise, callback) {
7375
7401
  if (callback) {
7376
- promise.then(
7377
- function(result) {
7378
- callback(null, result);
7379
- },
7380
- function(error) {
7381
- callback(error);
7382
- }
7383
- );
7402
+ promise.then((result) => callback(null, result), (err) => callback(err));
7384
7403
  }
7385
7404
  }
7386
-
7387
- function getCallback() {
7388
- if (
7389
- arguments.length &&
7390
- typeof arguments[arguments.length - 1] === 'function'
7391
- ) {
7392
- return arguments[arguments.length - 1];
7405
+ function getCallback(...args) {
7406
+ if (args.length && typeof args[args.length - 1] === 'function') {
7407
+ return args[args.length - 1];
7393
7408
  }
7394
7409
  }
7395
-
7396
7410
  function normalizeKey(key) {
7397
- // Cast the key to a string, as that's all we can set as a key.
7398
7411
  if (typeof key !== 'string') {
7399
7412
  console.warn(`${key} used as a key, but it is not a string.`);
7400
7413
  key = String(key);
7401
7414
  }
7402
-
7403
7415
  return key;
7404
7416
  }
7405
-
7406
- // Abstracts constructing a Blob object, so it also works in older
7407
- // browsers that don't support the native Blob constructor. (i.e.
7408
- // old QtWebKit versions, at least).
7409
- // Abstracts constructing a Blob object, so it also works in older
7410
- // browsers that don't support the native Blob constructor. (i.e.
7411
- // old QtWebKit versions, at least).
7412
- function createBlob(parts, properties) {
7413
- /* global BlobBuilder,MSBlobBuilder,MozBlobBuilder,WebKitBlobBuilder */
7414
- parts = parts || [];
7415
- properties = properties || {};
7416
- try {
7417
- return new Blob(parts, properties);
7418
- } catch (e) {
7419
- if (e.name !== 'TypeError') {
7420
- throw e;
7421
- }
7422
- var Builder =
7423
- typeof BlobBuilder !== 'undefined'
7424
- ? BlobBuilder
7425
- : typeof MSBlobBuilder !== 'undefined'
7426
- ? MSBlobBuilder
7427
- : typeof MozBlobBuilder !== 'undefined'
7428
- ? MozBlobBuilder
7429
- : WebKitBlobBuilder;
7430
- var builder = new Builder();
7431
- for (var i = 0; i < parts.length; i += 1) {
7432
- builder.append(parts[i]);
7417
+ function serializeSync(value) {
7418
+ return JSON.stringify(value, (_key, val) => {
7419
+ if (val instanceof Date) {
7420
+ return val.toISOString();
7433
7421
  }
7434
- return builder.getBlob(properties.type);
7435
- }
7436
- }
7437
-
7438
- /* eslint-disable no-bitwise */
7439
-
7440
- // Sadly, the best way to save binary data in WebSQL/localStorage is serializing
7441
- // it to Base64, so this is how we store it to prevent very strange errors with less
7442
- // verbose ways of binary <-> string data storage.
7443
- var BASE_CHARS =
7444
- 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
7445
-
7446
- var BLOB_TYPE_PREFIX = '~~local_forage_type~';
7447
- var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;
7448
-
7449
- var SERIALIZED_MARKER = '__lfsc__:';
7450
- var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;
7451
-
7452
- // OMG the serializations!
7453
- var TYPE_ARRAYBUFFER = 'arbf';
7454
- var TYPE_BLOB = 'blob';
7455
- var TYPE_INT8ARRAY = 'si08';
7456
- var TYPE_UINT8ARRAY = 'ui08';
7457
- var TYPE_UINT8CLAMPEDARRAY = 'uic8';
7458
- var TYPE_INT16ARRAY = 'si16';
7459
- var TYPE_INT32ARRAY = 'si32';
7460
- var TYPE_UINT16ARRAY = 'ur16';
7461
- var TYPE_UINT32ARRAY = 'ui32';
7462
- var TYPE_FLOAT32ARRAY = 'fl32';
7463
- var TYPE_FLOAT64ARRAY = 'fl64';
7464
- var TYPE_SERIALIZED_MARKER_LENGTH =
7465
- SERIALIZED_MARKER_LENGTH + TYPE_ARRAYBUFFER.length;
7466
-
7467
- var toString = Object.prototype.toString;
7468
-
7469
- function stringToBuffer(serializedString) {
7470
- // Fill the string into a ArrayBuffer.
7471
- var bufferLength = serializedString.length * 0.75;
7472
- var len = serializedString.length;
7473
- var i;
7474
- var p = 0;
7475
- var encoded1, encoded2, encoded3, encoded4;
7476
-
7477
- if (serializedString[serializedString.length - 1] === '=') {
7478
- bufferLength--;
7479
- if (serializedString[serializedString.length - 2] === '=') {
7480
- bufferLength--;
7481
- }
7482
- }
7483
-
7484
- var buffer = new ArrayBuffer(bufferLength);
7485
- var bytes = new Uint8Array(buffer);
7486
-
7487
- for (i = 0; i < len; i += 4) {
7488
- encoded1 = BASE_CHARS.indexOf(serializedString[i]);
7489
- encoded2 = BASE_CHARS.indexOf(serializedString[i + 1]);
7490
- encoded3 = BASE_CHARS.indexOf(serializedString[i + 2]);
7491
- encoded4 = BASE_CHARS.indexOf(serializedString[i + 3]);
7492
-
7493
- /*jslint bitwise: true */
7494
- bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
7495
- bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
7496
- bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
7497
- }
7498
- return buffer;
7499
- }
7500
-
7501
- // Converts a buffer to a string to store, serialized, in the backend
7502
- // storage library.
7503
- function bufferToString(buffer) {
7504
- // base64-arraybuffer
7505
- var bytes = new Uint8Array(buffer);
7506
- var base64String = '';
7507
- var i;
7508
-
7509
- for (i = 0; i < bytes.length; i += 3) {
7510
- /*jslint bitwise: true */
7511
- base64String += BASE_CHARS[bytes[i] >> 2];
7512
- base64String += BASE_CHARS[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
7513
- base64String +=
7514
- BASE_CHARS[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
7515
- base64String += BASE_CHARS[bytes[i + 2] & 63];
7516
- }
7517
-
7518
- if (bytes.length % 3 === 2) {
7519
- base64String = base64String.substring(0, base64String.length - 1) + '=';
7520
- } else if (bytes.length % 3 === 1) {
7521
- base64String =
7522
- base64String.substring(0, base64String.length - 2) + '==';
7523
- }
7524
-
7525
- return base64String;
7422
+ return val;
7423
+ });
7526
7424
  }
7527
-
7528
- // Serialize a value, afterwards executing a callback (which usually
7529
- // instructs the `setItem()` callback/promise to be executed). This is how
7530
- // we store binary data with localStorage.
7531
- function serialize$1(value, callback) {
7532
- var valueType = '';
7533
- if (value) {
7534
- valueType = toString.call(value);
7425
+ function serialize(value, callback) {
7426
+ try {
7427
+ callback(serializeSync(value), null);
7535
7428
  }
7536
-
7537
- // Cannot use `value instanceof ArrayBuffer` or such here, as these
7538
- // checks fail when running the tests using casper.js...
7539
- //
7540
- // TODO: See why those tests fail and use a better solution.
7541
- if (
7542
- value &&
7543
- (valueType === '[object ArrayBuffer]' ||
7544
- (value.buffer &&
7545
- toString.call(value.buffer) === '[object ArrayBuffer]'))
7546
- ) {
7547
- // Convert binary arrays to a string and prefix the string with
7548
- // a special marker.
7549
- var buffer;
7550
- var marker = SERIALIZED_MARKER;
7551
-
7552
- if (value instanceof ArrayBuffer) {
7553
- buffer = value;
7554
- marker += TYPE_ARRAYBUFFER;
7555
- } else {
7556
- buffer = value.buffer;
7557
-
7558
- if (valueType === '[object Int8Array]') {
7559
- marker += TYPE_INT8ARRAY;
7560
- } else if (valueType === '[object Uint8Array]') {
7561
- marker += TYPE_UINT8ARRAY;
7562
- } else if (valueType === '[object Uint8ClampedArray]') {
7563
- marker += TYPE_UINT8CLAMPEDARRAY;
7564
- } else if (valueType === '[object Int16Array]') {
7565
- marker += TYPE_INT16ARRAY;
7566
- } else if (valueType === '[object Uint16Array]') {
7567
- marker += TYPE_UINT16ARRAY;
7568
- } else if (valueType === '[object Int32Array]') {
7569
- marker += TYPE_INT32ARRAY;
7570
- } else if (valueType === '[object Uint32Array]') {
7571
- marker += TYPE_UINT32ARRAY;
7572
- } else if (valueType === '[object Float32Array]') {
7573
- marker += TYPE_FLOAT32ARRAY;
7574
- } else if (valueType === '[object Float64Array]') {
7575
- marker += TYPE_FLOAT64ARRAY;
7576
- } else {
7577
- callback(new Error('Failed to get type for BinaryArray'));
7578
- }
7579
- }
7580
-
7581
- callback(marker + bufferToString(buffer));
7582
- } else if (valueType === '[object Blob]') {
7583
- // Conver the blob to a binaryArray and then to a string.
7584
- var fileReader = new FileReader();
7585
-
7586
- fileReader.onload = function() {
7587
- // Backwards-compatible prefix for the blob type.
7588
- var str =
7589
- BLOB_TYPE_PREFIX +
7590
- value.type +
7591
- '~' +
7592
- bufferToString(this.result);
7593
-
7594
- callback(SERIALIZED_MARKER + TYPE_BLOB + str);
7595
- };
7596
-
7597
- fileReader.readAsArrayBuffer(value);
7598
- } else {
7599
- try {
7600
- callback(JSON.stringify(value));
7601
- } catch (e) {
7602
- console.error("Couldn't convert value into a JSON string: ", value);
7603
-
7604
- callback(null, e);
7605
- }
7429
+ catch (e) {
7430
+ callback('', e);
7606
7431
  }
7607
7432
  }
7608
-
7609
- // Deserialize data we've inserted into a value column/field. We place
7610
- // special markers into our strings to mark them as encoded; this isn't
7611
- // as nice as a meta field, but it's the only sane thing we can do whilst
7612
- // keeping localStorage support intact.
7613
- //
7614
- // Oftentimes this will just deserialize JSON content, but if we have a
7615
- // special marker (SERIALIZED_MARKER, defined above), we will extract
7616
- // some kind of arraybuffer/binary data/typed array out of the string.
7617
- function deserialize$1(value) {
7618
- // If we haven't marked this string as being specially serialized (i.e.
7619
- // something other than serialized JSON), we can just return it and be
7620
- // done with it.
7621
- if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) {
7622
- return JSON.parse(value);
7623
- }
7624
-
7625
- // The following code deals with deserializing some kind of Blob or
7626
- // TypedArray. First we separate out the type of data we're dealing
7627
- // with from the data itself.
7628
- var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
7629
- var type = value.substring(
7630
- SERIALIZED_MARKER_LENGTH,
7631
- TYPE_SERIALIZED_MARKER_LENGTH
7632
- );
7633
-
7634
- var blobType;
7635
- // Backwards-compatible blob type serialization strategy.
7636
- // DBs created with older versions of localForage will simply not have the blob type.
7637
- if (type === TYPE_BLOB && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {
7638
- var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);
7639
- blobType = matcher[1];
7640
- serializedString = serializedString.substring(matcher[0].length);
7641
- }
7642
- var buffer = stringToBuffer(serializedString);
7643
-
7644
- // Return the right type based on the code/type set during
7645
- // serialization.
7646
- switch (type) {
7647
- case TYPE_ARRAYBUFFER:
7648
- return buffer;
7649
- case TYPE_BLOB:
7650
- return createBlob([buffer], { type: blobType });
7651
- case TYPE_INT8ARRAY:
7652
- return new Int8Array(buffer);
7653
- case TYPE_UINT8ARRAY:
7654
- return new Uint8Array(buffer);
7655
- case TYPE_UINT8CLAMPEDARRAY:
7656
- return new Uint8ClampedArray(buffer);
7657
- case TYPE_INT16ARRAY:
7658
- return new Int16Array(buffer);
7659
- case TYPE_UINT16ARRAY:
7660
- return new Uint16Array(buffer);
7661
- case TYPE_INT32ARRAY:
7662
- return new Int32Array(buffer);
7663
- case TYPE_UINT32ARRAY:
7664
- return new Uint32Array(buffer);
7665
- case TYPE_FLOAT32ARRAY:
7666
- return new Float32Array(buffer);
7667
- case TYPE_FLOAT64ARRAY:
7668
- return new Float64Array(buffer);
7669
- default:
7670
- throw new Error('Unkown type: ' + type);
7671
- }
7433
+ function deserialize(value) {
7434
+ return JSON.parse(value);
7672
7435
  }
7673
7436
 
7674
- var localforageSerializer = {
7675
- serialize: serialize$1,
7676
- deserialize: deserialize$1};
7677
-
7678
7437
  // Copyright 2014 Mozilla
7679
7438
  // Copyright 2015 Thodoris Greasidis
7680
7439
  // Copyright 2018-2025 JC Brand
@@ -7690,8 +7449,6 @@ var localforageSerializer = {
7690
7449
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7691
7450
  // See the License for the specific language governing permissions and
7692
7451
  // limitations under the License.
7693
- const serialize = localforageSerializer['serialize'];
7694
- const deserialize = localforageSerializer['deserialize'];
7695
7452
  function isSessionStorageValid() {
7696
7453
  try {
7697
7454
  if (sessionStorage && 'setItem' in sessionStorage) {
@@ -7737,7 +7494,7 @@ function clear(callback) {
7737
7494
  }
7738
7495
  }
7739
7496
  });
7740
- executeCallback$1(promise, callback);
7497
+ chainCallback(promise, callback);
7741
7498
  return promise;
7742
7499
  }
7743
7500
  function getItem(key, callback) {
@@ -7753,7 +7510,7 @@ function getItem(key, callback) {
7753
7510
  }
7754
7511
  return null;
7755
7512
  });
7756
- executeCallback$1(promise, callback);
7513
+ chainCallback(promise, callback);
7757
7514
  return promise;
7758
7515
  }
7759
7516
  function iterate(iterator, callback) {
@@ -7781,7 +7538,7 @@ function iterate(iterator, callback) {
7781
7538
  }
7782
7539
  return;
7783
7540
  });
7784
- executeCallback$1(promise, callback);
7541
+ chainCallback(promise, callback);
7785
7542
  return promise;
7786
7543
  }
7787
7544
  // Same as sessionStorage's key() method, except takes a callback.
@@ -7801,7 +7558,7 @@ function key(n, callback) {
7801
7558
  }
7802
7559
  return result;
7803
7560
  });
7804
- executeCallback$1(promise, callback);
7561
+ chainCallback(promise, callback);
7805
7562
  return promise;
7806
7563
  }
7807
7564
  function keys(callback) {
@@ -7817,7 +7574,7 @@ function keys(callback) {
7817
7574
  }
7818
7575
  return keys;
7819
7576
  });
7820
- executeCallback$1(promise, callback);
7577
+ chainCallback(promise, callback);
7821
7578
  return promise;
7822
7579
  }
7823
7580
  // Supply the number of keys in the datastore to the callback function.
@@ -7826,7 +7583,7 @@ function length(callback) {
7826
7583
  const promise = self.keys().then(function (keys) {
7827
7584
  return keys.length;
7828
7585
  });
7829
- executeCallback$1(promise, callback);
7586
+ chainCallback(promise, callback);
7830
7587
  return promise;
7831
7588
  }
7832
7589
  function removeItem(key, callback) {
@@ -7834,7 +7591,7 @@ function removeItem(key, callback) {
7834
7591
  const promise = this.ready().then(function () {
7835
7592
  sessionStorage.removeItem(dbInfo.keyPrefix + key);
7836
7593
  });
7837
- executeCallback$1(promise, callback);
7594
+ chainCallback(promise, callback);
7838
7595
  return promise;
7839
7596
  }
7840
7597
  async function setItem(key, value, callback) {
@@ -7846,27 +7603,27 @@ async function setItem(key, value, callback) {
7846
7603
  dbInfo.serializer.serialize(value, (serializedValue, error) => {
7847
7604
  if (error) {
7848
7605
  reject(error);
7849
- executeCallback$1(Promise.reject(error), callback);
7606
+ chainCallback(Promise.reject(error), callback);
7850
7607
  return;
7851
7608
  }
7852
7609
  try {
7853
7610
  sessionStorage.setItem(dbInfo.keyPrefix + key, serializedValue);
7854
7611
  resolve(originalValue);
7855
- executeCallback$1(Promise.resolve(originalValue), callback);
7612
+ chainCallback(Promise.resolve(originalValue), callback);
7856
7613
  }
7857
7614
  catch (e) {
7858
7615
  if (e.name === 'QuotaExceededError' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
7859
7616
  console.error('Your sessionStorage capacity is used up.');
7860
7617
  }
7861
7618
  reject(e);
7862
- executeCallback$1(Promise.reject(e), callback);
7619
+ chainCallback(Promise.reject(e), callback);
7863
7620
  }
7864
7621
  });
7865
7622
  });
7866
7623
  }
7867
- function dropInstance(options, callback) {
7868
- callback = getCallback.apply(this, arguments);
7869
- options = (typeof options !== 'function' && options) || {};
7624
+ function dropInstance(...args) {
7625
+ const callback = getCallback(...args);
7626
+ let options = (typeof args[0] !== 'function' && args[0]) || {};
7870
7627
  if (!options.name) {
7871
7628
  const currentConfig = this.config();
7872
7629
  options.name = options.name || currentConfig.name;
@@ -7894,7 +7651,7 @@ function dropInstance(options, callback) {
7894
7651
  }
7895
7652
  });
7896
7653
  }
7897
- executeCallback$1(promise, callback);
7654
+ chainCallback(promise, callback);
7898
7655
  return promise;
7899
7656
  }
7900
7657
  const sessionStorageWrapper = {
@@ -8373,10 +8130,10 @@ function extendPrototype(localforage$$1) {
8373
8130
  extendPrototype(localForage);
8374
8131
 
8375
8132
  /** Used for built-in method references. */
8376
- var objectProto$6 = Object.prototype;
8133
+ var objectProto$7 = Object.prototype;
8377
8134
 
8378
8135
  /** Used to check objects for own properties. */
8379
- var hasOwnProperty$5 = objectProto$6.hasOwnProperty;
8136
+ var hasOwnProperty$6 = objectProto$7.hasOwnProperty;
8380
8137
 
8381
8138
  /**
8382
8139
  * The base implementation of `_.has` without support for deep paths.
@@ -8387,7 +8144,7 @@ var hasOwnProperty$5 = objectProto$6.hasOwnProperty;
8387
8144
  * @returns {boolean} Returns `true` if `key` exists, else `false`.
8388
8145
  */
8389
8146
  function baseHas(object, key) {
8390
- return object != null && hasOwnProperty$5.call(object, key);
8147
+ return object != null && hasOwnProperty$6.call(object, key);
8391
8148
  }
8392
8149
 
8393
8150
  /** Used to match property names within property paths. */
@@ -8544,7 +8301,7 @@ function castPath(value, object) {
8544
8301
  if (isArray(value)) {
8545
8302
  return value;
8546
8303
  }
8547
- return isKey(value, object) ? [value] : stringToPath(toString$2(value));
8304
+ return isKey(value, object) ? [value] : stringToPath(toString$1(value));
8548
8305
  }
8549
8306
 
8550
8307
  /**
@@ -8698,16 +8455,18 @@ function getResolveablePromise() {
8698
8455
  wrapper.reject = reject;
8699
8456
  });
8700
8457
  Object.assign(promise, wrapper);
8701
- promise.then(function (v) {
8458
+ // This `then` only mirrors settlement into the state flags. It must NOT
8459
+ // rethrow on rejection: the derived promise is discarded, so rethrowing would
8460
+ // surface as an unhandled rejection whenever the promise is rejected. The real
8461
+ // consumer still awaits `promise` itself, which rejects normally.
8462
+ promise.then(function () {
8702
8463
  promise.isResolved = true;
8703
8464
  promise.isPending = false;
8704
8465
  promise.isRejected = false;
8705
- return v;
8706
- }, function (e) {
8466
+ }, function () {
8707
8467
  promise.isResolved = false;
8708
8468
  promise.isPending = false;
8709
8469
  promise.isRejected = true;
8710
- throw e;
8711
8470
  });
8712
8471
  return promise;
8713
8472
  }
@@ -8715,13 +8474,16 @@ function getResolveablePromise() {
8715
8474
  function urlError() {
8716
8475
  throw new Error('A "url" property or function must be specified');
8717
8476
  }
8718
- // Wrap an optional error callback with a fallback error event.
8719
- function wrapError(model, options) {
8477
+ // Wrap an optional error callback with a fallback error event. When a
8478
+ // `promise` is supplied (the `{ promise: true }` fetch/save path), the error is
8479
+ // also forwarded to `promise.reject` so the returned promise settles on failure.
8480
+ function wrapError(model, options, promise) {
8720
8481
  const error = options.error;
8721
8482
  options.error = function (resp) {
8722
8483
  if (error)
8723
8484
  error.call(options.context, model, resp, options);
8724
8485
  model.trigger('error', model, resp, options);
8486
+ promise && promise.reject && promise.reject(resp);
8725
8487
  };
8726
8488
  }
8727
8489
  // Map from CRUD to HTTP for our default `sync` implementation.
@@ -8732,8 +8494,44 @@ const methodMap = {
8732
8494
  delete: 'DELETE',
8733
8495
  read: 'GET',
8734
8496
  };
8497
+ // Tracks the classes we've already warned about, so the `browserStorage`
8498
+ // deprecation notice is logged at most once per class rather than once per
8499
+ // instance (a collection can resolve storage once per contained model).
8500
+ const warnedBrowserStorage = new WeakSet();
8501
+ /**
8502
+ * Emit a one-time-per-class deprecation warning nudging downstream code from
8503
+ * the `browserStorage` alias to the canonical `storage` accessor.
8504
+ */
8505
+ function warnBrowserStorageDeprecation(obj) {
8506
+ const ctor = obj?.constructor;
8507
+ if (!ctor || warnedBrowserStorage.has(ctor))
8508
+ return;
8509
+ warnedBrowserStorage.add(ctor);
8510
+ const name = ctor.name;
8511
+ console.warn(`Skeletor: \`browserStorage\` is deprecated and will be removed in a future major version; ` +
8512
+ `use \`storage\` instead${name ? ` (on \`${name}\`)` : ''}.`);
8513
+ }
8514
+ /**
8515
+ * Return the PersistentStorage instance configured on `obj`, checking both
8516
+ * the canonical `storage` accessor and the deprecated `browserStorage` alias
8517
+ * so that subclasses that still override `get browserStorage()` continue to work.
8518
+ * @public
8519
+ */
8520
+ function getStorage(obj) {
8521
+ if (!obj)
8522
+ return undefined;
8523
+ const storage = result(obj, 'storage');
8524
+ if (storage != null)
8525
+ return storage;
8526
+ // Fall back to the deprecated alias; warn only when it actually supplies the
8527
+ // store, so storage-less models/collections don't trip the notice.
8528
+ const legacy = result(obj, 'browserStorage');
8529
+ if (legacy != null)
8530
+ warnBrowserStorageDeprecation(obj);
8531
+ return legacy;
8532
+ }
8735
8533
  function getSyncMethod(model) {
8736
- const store = result(model, 'browserStorage') || result(model.collection, 'browserStorage');
8534
+ const store = getStorage(model) || getStorage(model.collection);
8737
8535
  return store ? store.sync() : sync;
8738
8536
  }
8739
8537
  /**
@@ -8783,15 +8581,56 @@ const IN_MEMORY = _driver;
8783
8581
  localForage.defineDriver(memoryDriver);
8784
8582
  localforageSetitemsExports.extendPrototype(localForage);
8785
8583
  extendPrototype(localForage);
8584
+ // Every storage instance is registered with a WeakRef so that flushAll() can
8585
+ // reach pending writes without keeping instances alive. There's no leak and no
8586
+ // lifecycle hook to maintain: an instance is collected once its owning model or
8587
+ // collection is gone, at which point nothing is writing through it anyway.
8588
+ // Models with a pending debounced save stay reachable via the autosync `pending`
8589
+ // map until the timer fires, so flushAll() always reaches in-flight writes.
8590
+ const weakInstances = new Set();
8591
+ // Tracks which instances already have a WeakRef in `weakInstances`, so repeated
8592
+ // `storage =` assignments (or a store shared across models) don't register the
8593
+ // same instance twice and make flushAll() flush it more than once.
8594
+ const registered = new WeakSet();
8786
8595
  /**
8787
8596
  * @public
8788
8597
  */
8789
- class BrowserStorage {
8598
+ class PersistentStorage {
8599
+ /** Register a storage instance with a weak reference. @public */
8600
+ static register(instance) {
8601
+ if (registered.has(instance))
8602
+ return;
8603
+ registered.add(instance);
8604
+ weakInstances.add(new WeakRef(instance));
8605
+ }
8606
+ /**
8607
+ * Flush the debounced write buffer of every registered PersistentStorage
8608
+ * instance. Called automatically on pagehide/visibilitychange when autoSync
8609
+ * is in use; can also be called manually.
8610
+ * @public
8611
+ */
8612
+ static flushAll() {
8613
+ for (const ref of weakInstances) {
8614
+ const instance = ref.deref();
8615
+ if (!instance) {
8616
+ weakInstances.delete(ref);
8617
+ }
8618
+ else {
8619
+ instance.flush();
8620
+ }
8621
+ }
8622
+ }
8790
8623
  constructor(id, type, batchedWrites = false) {
8791
- if (type === 'local' && !window.localStorage) {
8624
+ // Set once `storeInitialized` resolves. Lets `sync()` skip awaiting it on the
8625
+ // hot path so a save buffers/issues its write *synchronously*, which is what
8626
+ // makes the synchronous unload flush (`flushPending` -> `flushAll`) able to
8627
+ // push a pending write out before the page is torn down.
8628
+ this.storeReady = false;
8629
+ this.name = id;
8630
+ if (type === 'local' && typeof window !== 'undefined' && !window.localStorage) {
8792
8631
  throw new Error('Skeletor.storage: Environment does not support localStorage.');
8793
8632
  }
8794
- else if (type === 'session' && !window.sessionStorage) {
8633
+ else if (type === 'session' && typeof window !== 'undefined' && !window.sessionStorage) {
8795
8634
  throw new Error('Skeletor.storage: Environment does not support sessionStorage.');
8796
8635
  }
8797
8636
  if (isString(type)) {
@@ -8806,10 +8645,13 @@ class BrowserStorage {
8806
8645
  }
8807
8646
  this.storeInitialized = Promise.resolve();
8808
8647
  }
8809
- this.name = id;
8648
+ // Flip the synchronous-readiness flag once init settles. Callers that await
8649
+ // `storeInitialized` directly still see any rejection; this branch only
8650
+ // exists to set the flag and must not raise an unhandled rejection.
8651
+ this.storeInitialized.then(() => (this.storeReady = true)).catch(() => { });
8810
8652
  }
8811
8653
  /**
8812
- * @param type - The storage type: 'local', 'session', 'indexed', or 'in_memory'
8654
+ * @param type - The storage type: 'local', 'session', 'indexed', 'node', or 'in_memory'
8813
8655
  * @param batchedWrites - Whether to enable batched writes
8814
8656
  */
8815
8657
  async initStore(type, batchedWrites) {
@@ -8822,6 +8664,20 @@ class BrowserStorage {
8822
8664
  else if (type === 'in_memory') {
8823
8665
  await localForage.config({ 'driver': IN_MEMORY });
8824
8666
  }
8667
+ else if (type === 'node') {
8668
+ const NodeSQLiteStorage = PersistentStorage.nodeStorage;
8669
+ if (!NodeSQLiteStorage) {
8670
+ throw new Error("Skeletor.storage: the 'node' storage type is only available in Node.js builds. " +
8671
+ "Import from '@converse/skeletor/node' instead of '@converse/skeletor'.");
8672
+ }
8673
+ this.store = new NodeSQLiteStorage(this.name);
8674
+ if (batchedWrites) {
8675
+ this.store.debouncedSetItems = mergebounce((items) => this.store.setItems(items), 50, {
8676
+ 'promise': true,
8677
+ });
8678
+ }
8679
+ return;
8680
+ }
8825
8681
  else if (type !== 'indexed') {
8826
8682
  throw new Error('Skeletor.storage: No storage type was specified');
8827
8683
  }
@@ -8838,6 +8694,7 @@ class BrowserStorage {
8838
8694
  }
8839
8695
  }
8840
8696
  async clear() {
8697
+ await this.storeInitialized;
8841
8698
  await this.store.removeItem(this.name).catch((e) => console.error(e));
8842
8699
  const re = new RegExp(`^${this.name}-`);
8843
8700
  const keys = await this.store.keys();
@@ -8852,12 +8709,16 @@ class BrowserStorage {
8852
8709
  // We get the collection (and if necessary the model attribute.
8853
8710
  // Waiting for storeInitialized will cause another iteration of
8854
8711
  // the event loop, after which the collection reference will
8855
- // be removed from the model.
8856
- const collection = model.collection;
8712
+ // be removed from the model. `options.collection` lets a deferred
8713
+ // delete (sequenced behind an in-flight auto-save by Model.destroy)
8714
+ // supply the collection captured before its optimistic removal.
8715
+ const collection = options.collection ?? model.collection;
8857
8716
  if (['patch', 'update'].includes(method)) {
8858
8717
  new_attributes = cloneDeep(model.attributes);
8859
8718
  }
8860
- await that.storeInitialized;
8719
+ // Skip `await` if not necessary to allow for sync flushing
8720
+ if (!that.storeReady)
8721
+ await that.storeInitialized;
8861
8722
  try {
8862
8723
  const original_attributes = model.attributes;
8863
8724
  switch (method) {
@@ -9012,8 +8873,12 @@ class BrowserStorage {
9012
8873
  return this.name + '-' + id;
9013
8874
  }
9014
8875
  }
9015
- BrowserStorage.sessionStorageInitialized = localForage.defineDriver(sessionStorageWrapper);
9016
- BrowserStorage.localForage = localForage;
8876
+ // The Node.js SQLite storage driver. Left null in browser builds so the
8877
+ // node-only driver (and its `node:sqlite` import) never enters the browser
8878
+ // bundle; the `@converse/skeletor/node` entry sets it.
8879
+ PersistentStorage.nodeStorage = null;
8880
+ PersistentStorage.sessionStorageInitialized = localForage.defineDriver(sessionStorageWrapper);
8881
+ PersistentStorage.localForage = localForage;
9017
8882
 
9018
8883
  /** Used to compose bitmasks for cloning. */
9019
8884
  var CLONE_SYMBOLS_FLAG$1 = 4;
@@ -9163,7 +9028,7 @@ function setCacheAdd(value) {
9163
9028
  * @name has
9164
9029
  * @memberOf SetCache
9165
9030
  * @param {*} value The value to search for.
9166
- * @returns {number} Returns `true` if `value` is found, else `false`.
9031
+ * @returns {boolean} Returns `true` if `value` is found, else `false`.
9167
9032
  */
9168
9033
  function setCacheHas(value) {
9169
9034
  return this.__data__.has(value);
@@ -9446,10 +9311,10 @@ function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
9446
9311
  var COMPARE_PARTIAL_FLAG$3 = 1;
9447
9312
 
9448
9313
  /** Used for built-in method references. */
9449
- var objectProto$5 = Object.prototype;
9314
+ var objectProto$6 = Object.prototype;
9450
9315
 
9451
9316
  /** Used to check objects for own properties. */
9452
- var hasOwnProperty$4 = objectProto$5.hasOwnProperty;
9317
+ var hasOwnProperty$5 = objectProto$6.hasOwnProperty;
9453
9318
 
9454
9319
  /**
9455
9320
  * A specialized version of `baseIsEqualDeep` for objects with support for
@@ -9477,7 +9342,7 @@ function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
9477
9342
  var index = objLength;
9478
9343
  while (index--) {
9479
9344
  var key = objProps[index];
9480
- if (!(isPartial ? key in other : hasOwnProperty$4.call(other, key))) {
9345
+ if (!(isPartial ? key in other : hasOwnProperty$5.call(other, key))) {
9481
9346
  return false;
9482
9347
  }
9483
9348
  }
@@ -9538,10 +9403,10 @@ var argsTag = '[object Arguments]',
9538
9403
  objectTag = '[object Object]';
9539
9404
 
9540
9405
  /** Used for built-in method references. */
9541
- var objectProto$4 = Object.prototype;
9406
+ var objectProto$5 = Object.prototype;
9542
9407
 
9543
9408
  /** Used to check objects for own properties. */
9544
- var hasOwnProperty$3 = objectProto$4.hasOwnProperty;
9409
+ var hasOwnProperty$4 = objectProto$5.hasOwnProperty;
9545
9410
 
9546
9411
  /**
9547
9412
  * A specialized version of `baseIsEqual` for arrays and objects which performs
@@ -9584,8 +9449,8 @@ function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
9584
9449
  : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
9585
9450
  }
9586
9451
  if (!(bitmask & COMPARE_PARTIAL_FLAG$2)) {
9587
- var objIsWrapped = objIsObj && hasOwnProperty$3.call(object, '__wrapped__'),
9588
- othIsWrapped = othIsObj && hasOwnProperty$3.call(other, '__wrapped__');
9452
+ var objIsWrapped = objIsObj && hasOwnProperty$4.call(object, '__wrapped__'),
9453
+ othIsWrapped = othIsObj && hasOwnProperty$4.call(other, '__wrapped__');
9589
9454
 
9590
9455
  if (objIsWrapped || othIsWrapped) {
9591
9456
  var objUnwrapped = objIsWrapped ? object.value() : object,
@@ -9959,10 +9824,10 @@ function createAggregator(setter, initializer) {
9959
9824
  }
9960
9825
 
9961
9826
  /** Used for built-in method references. */
9962
- var objectProto$3 = Object.prototype;
9827
+ var objectProto$4 = Object.prototype;
9963
9828
 
9964
9829
  /** Used to check objects for own properties. */
9965
- var hasOwnProperty$2 = objectProto$3.hasOwnProperty;
9830
+ var hasOwnProperty$3 = objectProto$4.hasOwnProperty;
9966
9831
 
9967
9832
  /**
9968
9833
  * Creates an object composed of keys generated from the results of running
@@ -9987,7 +9852,7 @@ var hasOwnProperty$2 = objectProto$3.hasOwnProperty;
9987
9852
  * // => { '3': 2, '5': 1 }
9988
9853
  */
9989
9854
  var countBy = createAggregator(function(result, value, key) {
9990
- if (hasOwnProperty$2.call(result, key)) {
9855
+ if (hasOwnProperty$3.call(result, key)) {
9991
9856
  ++result[key];
9992
9857
  } else {
9993
9858
  baseAssignValue(result, key, 1);
@@ -9995,10 +9860,10 @@ var countBy = createAggregator(function(result, value, key) {
9995
9860
  });
9996
9861
 
9997
9862
  /** Used for built-in method references. */
9998
- var objectProto$2 = Object.prototype;
9863
+ var objectProto$3 = Object.prototype;
9999
9864
 
10000
9865
  /** Used to check objects for own properties. */
10001
- var hasOwnProperty$1 = objectProto$2.hasOwnProperty;
9866
+ var hasOwnProperty$2 = objectProto$3.hasOwnProperty;
10002
9867
 
10003
9868
  /**
10004
9869
  * Creates an object composed of keys generated from the results of running
@@ -10024,7 +9889,7 @@ var hasOwnProperty$1 = objectProto$2.hasOwnProperty;
10024
9889
  * // => { '3': ['one', 'two'], '5': ['three'] }
10025
9890
  */
10026
9891
  var groupBy = createAggregator(function(result, value, key) {
10027
- if (hasOwnProperty$1.call(result, key)) {
9892
+ if (hasOwnProperty$2.call(result, key)) {
10028
9893
  result[key].push(value);
10029
9894
  } else {
10030
9895
  baseAssignValue(result, key, [value]);
@@ -10241,7 +10106,7 @@ function baseOrderBy(collection, iteratees, orders) {
10241
10106
  if (isArray(iteratee)) {
10242
10107
  return function(value) {
10243
10108
  return baseGet(value, iteratee.length === 1 ? iteratee[0] : iteratee);
10244
- }
10109
+ };
10245
10110
  }
10246
10111
  return iteratee;
10247
10112
  });
@@ -10306,11 +10171,130 @@ var sortBy = baseRest(function(collection, iteratees) {
10306
10171
  return baseOrderBy(collection, baseFlatten(iteratees), []);
10307
10172
  });
10308
10173
 
10174
+ const pending = new Map();
10175
+ const inFlight = new Set();
10176
+ // Per-object view of `inFlight`, so a caller (notably `Model.destroy`) can
10177
+ // await the saves for a single object without blocking on unrelated writes.
10178
+ const inFlightByObj = new Map();
10179
+ let unloadListenerAttached = false;
10180
+ /**
10181
+ * Execute a save `run` now and track the resulting promise as in-flight until
10182
+ * it settles, both globally (`inFlight`) and per object (`inFlightByObj`), so
10183
+ * `flushPending({ wait: true })` can await every save and `Model.destroy` can
10184
+ * await just its own.
10185
+ *
10186
+ * @internal
10187
+ * @param obj - The owning model/collection (or `null` when the save isn't tied to one).
10188
+ * A rejection is logged and re-surfaced on `obj`'s `error` event.
10189
+ * Called when a debounce timer fires or a flush forces it.
10190
+ */
10191
+ function fireRun(obj, run) {
10192
+ const p = Promise.resolve(run()).catch((e) => {
10193
+ console.error('Skeletor autoSync save error:', e);
10194
+ // Surface failures that bypassed `options.error` on the model's `error` event,
10195
+ // the same channel storage-layer failures already use. Storage saves route
10196
+ // errors through `options.error` and then resolve, so they never reach this
10197
+ // catch and won't double-emit.
10198
+ obj?.trigger?.('error', obj, e);
10199
+ });
10200
+ inFlight.add(p);
10201
+ let perObj;
10202
+ if (obj) {
10203
+ perObj = inFlightByObj.get(obj);
10204
+ if (!perObj) {
10205
+ perObj = new Set();
10206
+ inFlightByObj.set(obj, perObj);
10207
+ }
10208
+ perObj.add(p);
10209
+ }
10210
+ p.finally(() => {
10211
+ inFlight.delete(p);
10212
+ if (perObj) {
10213
+ perObj.delete(p);
10214
+ if (perObj.size === 0)
10215
+ inFlightByObj.delete(obj);
10216
+ }
10217
+ });
10218
+ }
10219
+ /**
10220
+ * Schedule a debounced auto-save for `obj`. Replaces any pending schedule
10221
+ * for the same object.
10222
+ * @internal
10223
+ */
10224
+ function scheduleAutoSave(obj, run, delay) {
10225
+ const existing = pending.get(obj);
10226
+ if (existing)
10227
+ clearTimeout(existing.timerId);
10228
+ const timerId = setTimeout(() => {
10229
+ pending.delete(obj);
10230
+ fireRun(obj, run);
10231
+ }, delay);
10232
+ pending.set(obj, { timerId, run });
10233
+ }
10234
+ /**
10235
+ * Cancel any pending auto-save for `obj`.
10236
+ *
10237
+ * This only stops a *pending* (not-yet-fired) debounce timer. A save whose
10238
+ * timer has already fired is in flight and beyond cancellation — sequence
10239
+ * against it with {@link awaitInFlightSaves} instead.
10240
+ * @internal
10241
+ */
10242
+ function cancelAutoSave(obj) {
10243
+ const existing = pending.get(obj);
10244
+ if (existing) {
10245
+ clearTimeout(existing.timerId);
10246
+ pending.delete(obj);
10247
+ }
10248
+ }
10249
+ /**
10250
+ * Return a promise that settles once every in-flight auto-save for `obj` has
10251
+ * completed, or `null` when none are in flight. `Model.destroy` uses this to
10252
+ * sequence its delete after a save that has already fired, so a late write
10253
+ * cannot land after the delete and resurrect the record.
10254
+ * @internal
10255
+ */
10256
+ function awaitInFlightSaves(obj) {
10257
+ const set = inFlightByObj.get(obj);
10258
+ if (!set || set.size === 0)
10259
+ return null;
10260
+ return Promise.all([...set]).then(() => undefined);
10261
+ }
10262
+ function flushPending({ storage, wait = false, } = {}) {
10263
+ for (const [obj, { timerId, run }] of pending.entries()) {
10264
+ clearTimeout(timerId);
10265
+ fireRun(obj, run);
10266
+ }
10267
+ pending.clear();
10268
+ if (storage)
10269
+ storage.flushAll();
10270
+ if (wait)
10271
+ return Promise.all([...inFlight]).then(() => undefined);
10272
+ }
10273
+ /**
10274
+ * Lazily attach pagehide/visibilitychange listeners in browser environments
10275
+ * to flush pending writes when the page is hidden/unloading. This is a
10276
+ * best-effort durability measure: the flush initiates writes synchronously but
10277
+ * cannot guarantee an asynchronous backend finishes persisting them before the
10278
+ * page goes away. Called at most once.
10279
+ * @internal
10280
+ */
10281
+ function ensureUnloadListener(storage) {
10282
+ if (unloadListenerAttached || typeof window === 'undefined')
10283
+ return;
10284
+ unloadListenerAttached = true;
10285
+ const flush = () => flushPending({ storage });
10286
+ window.addEventListener('pagehide', flush);
10287
+ window.addEventListener('visibilitychange', () => {
10288
+ if (document.visibilityState === 'hidden')
10289
+ flush();
10290
+ });
10291
+ }
10292
+
10309
10293
  /** Used for built-in method references. */
10310
- var objectProto$1 = Object.prototype;
10294
+ var objectProto$2 = Object.prototype;
10311
10295
 
10312
10296
  /** Used to check objects for own properties. */
10313
- var hasOwnProperty = objectProto$1.hasOwnProperty;
10297
+ var hasOwnProperty$1 = objectProto$2.hasOwnProperty;
10314
10298
 
10315
10299
  /**
10316
10300
  * Assigns own and inherited enumerable string keyed properties of source
@@ -10355,7 +10339,7 @@ var defaults = baseRest(function(object, sources) {
10355
10339
  var value = object[key];
10356
10340
 
10357
10341
  if (value === undefined ||
10358
- (eq(value, objectProto$1[key]) && !hasOwnProperty.call(object, key))) {
10342
+ (eq(value, objectProto$2[key]) && !hasOwnProperty$1.call(object, key))) {
10359
10343
  object[key] = source[key];
10360
10344
  }
10361
10345
  }
@@ -10439,14 +10423,14 @@ function createInverter(setter, toIteratee) {
10439
10423
  }
10440
10424
 
10441
10425
  /** Used for built-in method references. */
10442
- var objectProto = Object.prototype;
10426
+ var objectProto$1 = Object.prototype;
10443
10427
 
10444
10428
  /**
10445
10429
  * Used to resolve the
10446
10430
  * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
10447
10431
  * of values.
10448
10432
  */
10449
- var nativeObjectToString = objectProto.toString;
10433
+ var nativeObjectToString = objectProto$1.toString;
10450
10434
 
10451
10435
  /**
10452
10436
  * Creates an object composed of the inverted keys and values of `object`.
@@ -10617,6 +10601,12 @@ function parent(object, path) {
10617
10601
  return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
10618
10602
  }
10619
10603
 
10604
+ /** Used for built-in method references. */
10605
+ var objectProto = Object.prototype;
10606
+
10607
+ /** Used to check objects for own properties. */
10608
+ var hasOwnProperty = objectProto.hasOwnProperty;
10609
+
10620
10610
  /**
10621
10611
  * The base implementation of `_.unset`.
10622
10612
  *
@@ -10627,8 +10617,34 @@ function parent(object, path) {
10627
10617
  */
10628
10618
  function baseUnset(object, path) {
10629
10619
  path = castPath(path, object);
10630
- object = parent(object, path);
10631
- return object == null || delete object[toKey(last(path))];
10620
+
10621
+ // Prevent prototype pollution:
10622
+ // https://github.com/lodash/lodash/security/advisories/GHSA-xxjr-mmjv-4gpg
10623
+ // https://github.com/lodash/lodash/security/advisories/GHSA-f23m-r3pf-42rh
10624
+ var index = -1,
10625
+ length = path.length;
10626
+
10627
+ if (!length) {
10628
+ return true;
10629
+ }
10630
+
10631
+ while (++index < length) {
10632
+ var key = toKey(path[index]);
10633
+
10634
+ // Always block "__proto__" anywhere in the path if it's not expected
10635
+ if (key === '__proto__' && !hasOwnProperty.call(object, '__proto__')) {
10636
+ return false;
10637
+ }
10638
+
10639
+ // Block constructor/prototype as non-terminal traversal keys to prevent
10640
+ // escaping the object graph into built-in constructors and prototypes.
10641
+ if ((key === 'constructor' || key === 'prototype') && index < length - 1) {
10642
+ return false;
10643
+ }
10644
+ }
10645
+
10646
+ var obj = parent(object, path);
10647
+ return obj == null || delete obj[toKey(last(path))];
10632
10648
  }
10633
10649
 
10634
10650
  /**
@@ -10826,6 +10842,7 @@ var pick = flatRest(function(object, paths) {
10826
10842
  return object == null ? {} : basePick(object, paths);
10827
10843
  });
10828
10844
 
10845
+ var _Model_instances, _Model_computedCache, _Model_computedDefs, _Model_state, _Model_hydrate, _Model_doAutoSave, _Model_updateComputed, _Model_initComputed;
10829
10846
  /**
10830
10847
  * @public
10831
10848
  * **Models** are the basic data object in the framework --
@@ -10840,6 +10857,10 @@ class Model extends EventEmitterObject {
10840
10857
  */
10841
10858
  constructor(attributes, options) {
10842
10859
  super();
10860
+ _Model_instances.add(this);
10861
+ _Model_computedCache.set(this, void 0);
10862
+ _Model_computedDefs.set(this, void 0);
10863
+ _Model_state.set(this, 'constructing');
10843
10864
  this._changing = false;
10844
10865
  this._pending = false;
10845
10866
  this._url = '';
@@ -10857,15 +10878,74 @@ class Model extends EventEmitterObject {
10857
10878
  const default_attrs = result(this, 'defaults');
10858
10879
  attrs = defaults(Object.assign({}, default_attrs, attrs), default_attrs);
10859
10880
  this.set(attrs, options);
10881
+ __classPrivateFieldGet(this, _Model_instances, "m", _Model_initComputed).call(this);
10882
+ this.attrs = new Proxy(this.attributes, {
10883
+ get: (_target, key) => {
10884
+ if (typeof key !== 'symbol' && __classPrivateFieldGet(this, _Model_computedCache, "f") && key in __classPrivateFieldGet(this, _Model_computedCache, "f")) {
10885
+ return __classPrivateFieldGet(this, _Model_computedCache, "f")[key];
10886
+ }
10887
+ return this.attributes[key];
10888
+ },
10889
+ set: (_target, key, value) => {
10890
+ this.set(key, value);
10891
+ return true;
10892
+ },
10893
+ });
10860
10894
  this.initialize.apply(this, arguments);
10861
10895
  // Reset changed after initial set
10862
10896
  this.changed = {};
10897
+ // When autoSync is on, `initialized` is always a Promise so callers can
10898
+ // uniformly `await model.initialized`. It only hydrates from storage when
10899
+ // there's something to load (storage configured and the model isn't new);
10900
+ // otherwise it's already ready and resolves immediately.
10901
+ if (this.autoSync) {
10902
+ if (getStorage(this) && !this.isNew()) {
10903
+ __classPrivateFieldSet(this, _Model_state, 'hydrating', "f");
10904
+ this.initialized = __classPrivateFieldGet(this, _Model_instances, "m", _Model_hydrate).call(this);
10905
+ }
10906
+ else {
10907
+ __classPrivateFieldSet(this, _Model_state, 'ready', "f");
10908
+ this.initialized = Promise.resolve();
10909
+ }
10910
+ }
10911
+ else {
10912
+ __classPrivateFieldSet(this, _Model_state, 'ready', "f");
10913
+ }
10914
+ }
10915
+ /**
10916
+ * The canonical storage accessor. Set to a `PersistentStorage` instance
10917
+ * to enable local persistence for this model.
10918
+ */
10919
+ get storage() {
10920
+ return this._storage;
10863
10921
  }
10864
- set browserStorage(storage) {
10865
- this._browserStorage = storage;
10922
+ set storage(s) {
10923
+ this._storage = s;
10924
+ PersistentStorage.register(s);
10866
10925
  }
10926
+ /**
10927
+ * @deprecated Use `storage` instead.
10928
+ */
10867
10929
  get browserStorage() {
10868
- return this._browserStorage;
10930
+ return this._storage;
10931
+ }
10932
+ set browserStorage(s) {
10933
+ warnBrowserStorageDeprecation(this);
10934
+ this.storage = s;
10935
+ }
10936
+ /**
10937
+ * Override to enable automatic persistence. When true, any `set()` call
10938
+ * that changes attributes will schedule a debounced save to `storage`, and
10939
+ * the model will auto-hydrate from storage on construction.
10940
+ */
10941
+ get autoSync() {
10942
+ return false;
10943
+ }
10944
+ /**
10945
+ * Debounce delay (ms) for auto-save writes. Override to tune.
10946
+ */
10947
+ get autoSyncDelay() {
10948
+ return 100;
10869
10949
  }
10870
10950
  /**
10871
10951
  * The default name for the JSON `id` attribute is `"id"`. MongoDB and
@@ -10901,6 +10981,17 @@ class Model extends EventEmitterObject {
10901
10981
  defaults() {
10902
10982
  return {};
10903
10983
  }
10984
+ /**
10985
+ * Declare computed properties. Override in subclasses to define properties
10986
+ * that derive their value from other attributes. Each entry specifies the
10987
+ * attribute keys it depends on (`deps`) and a function (`fn`) that receives
10988
+ * the model and returns the computed value. The value is cached and
10989
+ * recalculated automatically when any dep changes, firing a `change:key`
10990
+ * event.
10991
+ */
10992
+ get computed() {
10993
+ return {};
10994
+ }
10904
10995
  /**
10905
10996
  * Return a copy of the model's `attributes` object.
10906
10997
  */
@@ -10914,9 +11005,12 @@ class Model extends EventEmitterObject {
10914
11005
  return getSyncMethod(model)(method, model, options);
10915
11006
  }
10916
11007
  /**
10917
- * Get the value of an attribute.
11008
+ * Get the value of an attribute, or a computed property.
10918
11009
  */
10919
11010
  get(attr) {
11011
+ if (__classPrivateFieldGet(this, _Model_computedCache, "f") && attr in __classPrivateFieldGet(this, _Model_computedCache, "f")) {
11012
+ return __classPrivateFieldGet(this, _Model_computedCache, "f")[attr];
11013
+ }
10920
11014
  return this.attributes[attr];
10921
11015
  }
10922
11016
  keys() {
@@ -10981,6 +11075,11 @@ class Model extends EventEmitterObject {
10981
11075
  attrs[key] = val;
10982
11076
  }
10983
11077
  options = options || {};
11078
+ // Guard must come after arg normalization: when called as set(obj, opts),
11079
+ // fromStorage lives in `val` (second arg), not `options` (third arg).
11080
+ if (this.autoSync && __classPrivateFieldGet(this, _Model_state, "f") === 'hydrating' && !options.fromStorage) {
11081
+ throw new Error(`Skeletor: set() called on an autoSync model before initialized resolved. Await model.initialized first.`);
11082
+ }
10984
11083
  // Run validation.
10985
11084
  if (!this._validate(attrs, options))
10986
11085
  return null;
@@ -11021,6 +11120,14 @@ class Model extends EventEmitterObject {
11021
11120
  this.trigger('change:' + changes[i], this, current[changes[i]], options);
11022
11121
  }
11023
11122
  }
11123
+ // Recalculate computed properties whose deps changed.
11124
+ if (changes.length && __classPrivateFieldGet(this, _Model_computedDefs, "f")) {
11125
+ for (const [key, def] of Object.entries(__classPrivateFieldGet(this, _Model_computedDefs, "f"))) {
11126
+ if (def.deps.some((dep) => changes.includes(dep))) {
11127
+ __classPrivateFieldGet(this, _Model_instances, "m", _Model_updateComputed).call(this, key, def, silent, options);
11128
+ }
11129
+ }
11130
+ }
11024
11131
  if (changing)
11025
11132
  return this;
11026
11133
  if (!silent) {
@@ -11034,6 +11141,17 @@ class Model extends EventEmitterObject {
11034
11141
  }
11035
11142
  this._pending = false;
11036
11143
  this._changing = false;
11144
+ // Auto-save: schedule a debounced write when autoSync is on and there
11145
+ // were actual changes that originated from application code (not a
11146
+ // storage read or an explicit noAutoSave call).
11147
+ if (__classPrivateFieldGet(this, _Model_state, "f") === 'ready' &&
11148
+ this.autoSync &&
11149
+ getStorage(this) &&
11150
+ changes.length &&
11151
+ !options.fromStorage &&
11152
+ !options.noAutoSave) {
11153
+ scheduleAutoSave(this, () => __classPrivateFieldGet(this, _Model_instances, "m", _Model_doAutoSave).call(this), this.autoSyncDelay);
11154
+ }
11037
11155
  return this;
11038
11156
  }
11039
11157
  /**
@@ -11108,16 +11226,48 @@ class Model extends EventEmitterObject {
11108
11226
  fetch(options = {}) {
11109
11227
  options = Object.assign({ parse: true }, options);
11110
11228
  const success = options.success;
11229
+ const promise = options.promise ? getResolveablePromise() : undefined;
11230
+ // Tracks whether sync invoked one of the callbacks. A sync may instead
11231
+ // settle its returned promise; the `.then`/`.catch` below bridges that to
11232
+ // the callbacks so the fetch promise never hangs. The flag is set
11233
+ // synchronously inside each callback (before sync's promise resolves), so
11234
+ // it's reliable by the time those handlers run.
11235
+ let settled = false;
11111
11236
  options.success = (resp) => {
11237
+ settled = true;
11112
11238
  const serverAttrs = options.parse ? this.parse(resp, options) : resp;
11113
- if (!this.set(serverAttrs, options))
11239
+ // fromStorage prevents the set() from triggering auto-save on reads
11240
+ if (!this.set(serverAttrs, Object.assign({}, options, { fromStorage: true })))
11114
11241
  return false;
11115
11242
  if (success)
11116
11243
  success.call(options.context, this, resp, options);
11117
11244
  this.trigger('sync', this, resp, options);
11245
+ promise && promise.resolve(resp);
11118
11246
  };
11119
- wrapError(this, options);
11120
- return this.sync('read', this, options);
11247
+ wrapError(this, options, promise);
11248
+ if (promise) {
11249
+ const onError = options.error;
11250
+ options.error = (resp) => {
11251
+ settled = true;
11252
+ onError(resp);
11253
+ };
11254
+ }
11255
+ const result = this.sync('read', this, options);
11256
+ if (promise) {
11257
+ Promise.resolve(result).then(
11258
+ // A sync that resolves its promise without invoking options.success:
11259
+ // treat the resolved value as the response, so the model is still
11260
+ // merged and the promise settles instead of hanging.
11261
+ (value) => {
11262
+ if (!settled)
11263
+ options.success(value);
11264
+ },
11265
+ // A sync that rejects instead of invoking options.error; settling
11266
+ // twice is a harmless no-op.
11267
+ (e) => promise.reject(e));
11268
+ return promise;
11269
+ }
11270
+ return result;
11121
11271
  }
11122
11272
  /**
11123
11273
  * Set a hash of model attributes, and sync the model to the server.
@@ -11194,6 +11344,7 @@ class Model extends EventEmitterObject {
11194
11344
  * If `wait: true` is passed, waits for the server to respond before removal.
11195
11345
  */
11196
11346
  destroy(options) {
11347
+ cancelAutoSave(this);
11197
11348
  options = options ? clone(options) : {};
11198
11349
  const success = options.success;
11199
11350
  const wait = options.wait;
@@ -11209,13 +11360,25 @@ class Model extends EventEmitterObject {
11209
11360
  if (!this.isNew())
11210
11361
  this.trigger('sync', this, resp, options);
11211
11362
  };
11363
+ // A debounced auto-save may already have fired and be in flight.
11364
+ // cancelAutoSave() above only stops a *pending* timer, so sequence the
11365
+ // delete after any in-flight save; otherwise the late write could land
11366
+ // after the delete and resurrect the record. Capture the collection now,
11367
+ // the optimistic in-memory removal below nulls `model.collection` before
11368
+ // the deferred sync runs, but the storage layer still needs it to drop
11369
+ // this id from the collection's persisted index.
11370
+ const inFlightSave = awaitInFlightSaves(this);
11371
+ if (inFlightSave && this.collection)
11372
+ options.collection = this.collection;
11212
11373
  let xhr = false;
11213
11374
  if (this.isNew()) {
11214
11375
  defer(options.success);
11215
11376
  }
11216
11377
  else {
11217
11378
  wrapError(this, options);
11218
- xhr = this.sync('delete', this, options);
11379
+ xhr = inFlightSave
11380
+ ? inFlightSave.then(() => this.sync('delete', this, options))
11381
+ : this.sync('delete', this, options);
11219
11382
  }
11220
11383
  if (!wait)
11221
11384
  destroy();
@@ -11263,6 +11426,14 @@ class Model extends EventEmitterObject {
11263
11426
  isValid(options) {
11264
11427
  return this._validate({}, Object.assign({}, options, { validate: true }));
11265
11428
  }
11429
+ subscribe(eventOrCallback, callback, context) {
11430
+ if (typeof eventOrCallback === 'function') {
11431
+ const cb = (model) => eventOrCallback(model, this.changed);
11432
+ this.on('change', cb);
11433
+ return () => this.off('change', cb);
11434
+ }
11435
+ return super.subscribe(eventOrCallback, callback, context);
11436
+ }
11266
11437
  /**
11267
11438
  * Run validation against the next complete set of model attributes,
11268
11439
  * returning `true` if all is well. Otherwise, fire an `"invalid"` event.
@@ -11278,8 +11449,43 @@ class Model extends EventEmitterObject {
11278
11449
  return false;
11279
11450
  }
11280
11451
  }
11452
+ _Model_computedCache = new WeakMap(), _Model_computedDefs = new WeakMap(), _Model_state = new WeakMap(), _Model_instances = new WeakSet(), _Model_hydrate = async function _Model_hydrate() {
11453
+ ensureUnloadListener(PersistentStorage);
11454
+ try {
11455
+ await this.fetch({ fromStorage: true, promise: true });
11456
+ }
11457
+ catch (e) {
11458
+ // 'Record Not Found' is a normal first-run state (nothing stored yet);
11459
+ // keep the initial attributes and resolve. Re-throw anything else.
11460
+ if (e !== 'Record Not Found')
11461
+ throw e;
11462
+ }
11463
+ finally {
11464
+ __classPrivateFieldSet(this, _Model_state, 'ready', "f");
11465
+ }
11466
+ }, _Model_doAutoSave = function _Model_doAutoSave() {
11467
+ return this.save(null, { noAutoSave: true });
11468
+ }, _Model_updateComputed = function _Model_updateComputed(key, def, silent, options) {
11469
+ const newVal = def.fn(this);
11470
+ if (!isEqual(__classPrivateFieldGet(this, _Model_computedCache, "f")[key], newVal)) {
11471
+ __classPrivateFieldGet(this, _Model_computedCache, "f")[key] = newVal;
11472
+ if (!silent) {
11473
+ this.changed[key] = newVal;
11474
+ this.trigger('change:' + key, this, newVal, options);
11475
+ }
11476
+ }
11477
+ }, _Model_initComputed = function _Model_initComputed() {
11478
+ const defs = result(this, 'computed');
11479
+ if (!defs || isEmpty(defs))
11480
+ return;
11481
+ __classPrivateFieldSet(this, _Model_computedDefs, defs, "f");
11482
+ __classPrivateFieldSet(this, _Model_computedCache, {}, "f");
11483
+ for (const [key, def] of Object.entries(defs)) {
11484
+ __classPrivateFieldGet(this, _Model_computedCache, "f")[key] = def.fn(this);
11485
+ }
11486
+ };
11281
11487
 
11282
- var _a;
11488
+ var _Collection_instances, _Collection_hydrate, _a;
11283
11489
  // Default options for `Collection#set`.
11284
11490
  const setOptions = { add: true, remove: true, merge: true };
11285
11491
  const addOptions = { add: true, remove: false };
@@ -11300,6 +11506,7 @@ class Collection extends EventEmitterObject {
11300
11506
  */
11301
11507
  constructor(models, options) {
11302
11508
  super();
11509
+ _Collection_instances.add(this);
11303
11510
  this._url = '';
11304
11511
  /**
11305
11512
  * @public
@@ -11317,6 +11524,12 @@ class Collection extends EventEmitterObject {
11317
11524
  if (models)
11318
11525
  this.reset(models, Object.assign({ silent: true }, options));
11319
11526
  this[Symbol.iterator] = this.values;
11527
+ // When autoSync is on, `initialized` is always a Promise so callers can
11528
+ // uniformly `await collection.initialized`; it resolves immediately when
11529
+ // there's no storage to hydrate from.
11530
+ if (this.autoSync) {
11531
+ this.initialized = getStorage(this) ? __classPrivateFieldGet(this, _Collection_instances, "m", _Collection_hydrate).call(this) : Promise.resolve();
11532
+ }
11320
11533
  }
11321
11534
  get comparator() {
11322
11535
  return this._comparator;
@@ -11324,11 +11537,40 @@ class Collection extends EventEmitterObject {
11324
11537
  set comparator(c) {
11325
11538
  this._comparator = c;
11326
11539
  }
11327
- set browserStorage(storage) {
11328
- this._browserStorage = storage;
11540
+ /**
11541
+ * The canonical storage accessor. Set to a `PersistentStorage` instance
11542
+ * to enable local persistence for this collection.
11543
+ */
11544
+ get storage() {
11545
+ return this._storage;
11546
+ }
11547
+ set storage(s) {
11548
+ this._storage = s;
11549
+ PersistentStorage.register(s);
11329
11550
  }
11551
+ /**
11552
+ * @deprecated Use `storage` instead.
11553
+ */
11330
11554
  get browserStorage() {
11331
- return this._browserStorage;
11555
+ return this._storage;
11556
+ }
11557
+ set browserStorage(s) {
11558
+ warnBrowserStorageDeprecation(this);
11559
+ this.storage = s;
11560
+ }
11561
+ /**
11562
+ * Override to return `true` to automatically load the collection from
11563
+ * storage on construction. Await `initialized` to know when hydration
11564
+ * is complete.
11565
+ *
11566
+ * Note: collection `autoSync` is hydrate-only. Unlike `Model`, it does
11567
+ * **not** schedule auto-saves when the collection changes (`add`/`remove`/
11568
+ * `reset`). Persisting members is each model's responsibility — enable
11569
+ * `autoSync` on the contained model class and every model writes its own
11570
+ * record. A collection-level write would be redundant with that.
11571
+ */
11572
+ get autoSync() {
11573
+ return false;
11332
11574
  }
11333
11575
  /**
11334
11576
  * The default model for a collection is just a **Model**.
@@ -11523,7 +11765,7 @@ class Collection extends EventEmitterObject {
11523
11765
  }));
11524
11766
  });
11525
11767
  }));
11526
- await this.browserStorage?.clear();
11768
+ await getStorage(this)?.clear();
11527
11769
  this.reset();
11528
11770
  }
11529
11771
  /**
@@ -11761,17 +12003,47 @@ class Collection extends EventEmitterObject {
11761
12003
  const success = options.success;
11762
12004
  // eslint-disable-next-line @typescript-eslint/no-this-alias
11763
12005
  const collection = this;
11764
- const promise = options.promise && getResolveablePromise();
12006
+ const promise = options.promise ? getResolveablePromise() : undefined;
12007
+ // Tracks whether sync invoked one of the callbacks. A sync may instead
12008
+ // settle its returned promise; the `.then`/`.catch` below bridges that to
12009
+ // the callbacks so the fetch promise never hangs. The flag is set
12010
+ // synchronously inside each callback (before sync's promise resolves), so
12011
+ // it's reliable by the time those handlers run.
12012
+ let settled = false;
11765
12013
  options.success = function (resp) {
12014
+ settled = true;
11766
12015
  const method = options.reset ? 'reset' : 'set';
11767
- collection[method](resp, options);
12016
+ // fromStorage prevents individual model set() calls from triggering auto-save on reads
12017
+ collection[method](resp, Object.assign({}, options, { fromStorage: true }));
11768
12018
  if (success)
11769
12019
  success.call(options.context, collection, resp, options);
11770
12020
  promise && promise.resolve();
11771
12021
  collection.trigger('sync', collection, resp, options);
11772
12022
  };
11773
- wrapError(this, options);
11774
- return promise ? promise : this.sync('read', this, options);
12023
+ wrapError(this, options, promise);
12024
+ if (promise) {
12025
+ const onError = options.error;
12026
+ options.error = (resp) => {
12027
+ settled = true;
12028
+ onError(resp);
12029
+ };
12030
+ }
12031
+ const result = this.sync('read', this, options);
12032
+ if (promise) {
12033
+ Promise.resolve(result).then(
12034
+ // A sync that resolves its promise without invoking options.success:
12035
+ // treat the resolved value as the response, so the collection is still
12036
+ // populated and the promise settles instead of hanging.
12037
+ (value) => {
12038
+ if (!settled)
12039
+ options.success(value);
12040
+ },
12041
+ // A sync that rejects instead of invoking options.error; settling
12042
+ // twice is a harmless no-op.
12043
+ (e) => promise.reject(e));
12044
+ return promise;
12045
+ }
12046
+ return result;
11775
12047
  }
11776
12048
  /**
11777
12049
  * Create a new instance of a model in this collection. Add the model to the
@@ -11815,6 +12087,14 @@ class Collection extends EventEmitterObject {
11815
12087
  return preparedModel;
11816
12088
  }
11817
12089
  }
12090
+ subscribe(eventOrCallback, callback, context) {
12091
+ if (typeof eventOrCallback === 'function') {
12092
+ const cb = () => eventOrCallback(this);
12093
+ this.on('update reset sort', cb);
12094
+ return () => this.off('update reset sort', cb);
12095
+ }
12096
+ return super.subscribe(eventOrCallback, callback, context);
12097
+ }
11818
12098
  /**
11819
12099
  * **parse** converts a response into a list of models to be added to the
11820
12100
  * collection. The default implementation is just to pass it through.
@@ -11952,7 +12232,12 @@ class Collection extends EventEmitterObject {
11952
12232
  this.trigger.apply(this, arguments);
11953
12233
  }
11954
12234
  }
11955
- _a = Symbol.iterator;
12235
+ _Collection_instances = new WeakSet(), _Collection_hydrate = async function _Collection_hydrate() {
12236
+ ensureUnloadListener(PersistentStorage);
12237
+ // findAll() returns [] for an empty store, so a first-run collection
12238
+ // resolves rather than erroring the way a model fetch-by-id would.
12239
+ await this.fetch({ fromStorage: true, promise: true });
12240
+ }, _a = Symbol.iterator;
11956
12241
  // This "enum" defines the three possible kinds of values which can be emitted
11957
12242
  // by a CollectionIterator that correspond to the values(), keys() and entries()
11958
12243
  // methods on Collection, respectively.
@@ -12041,6 +12326,11 @@ function noConflict() {
12041
12326
  }
12042
12327
  skeletor.noConflict = noConflict;
12043
12328
  root.Skeletor = skeletor;
12329
+ /**
12330
+ * @deprecated Use `PersistentStorage` instead.
12331
+ * @public
12332
+ */
12333
+ const BrowserStorage = PersistentStorage;
12044
12334
 
12045
- export { BrowserStorage, Collection, EventEmitter, Model, skeletor as default, noConflict, sync };
12335
+ export { BrowserStorage, Collection, EventEmitter, Model, PersistentStorage, skeletor as default, getStorage, noConflict, sync };
12046
12336
  //# sourceMappingURL=skeletor.esm.js.map