msgpackr 1.10.1 → 1.11.0

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.
package/dist/node.cjs CHANGED
@@ -967,8 +967,10 @@ function readKey() {
967
967
  }
968
968
 
969
969
  function asSafeString(property) {
970
+ // protect against expensive (DoS) string conversions
970
971
  if (typeof property === 'string') return property;
971
- if (typeof property === 'number') return property.toString();
972
+ if (typeof property === 'number' || typeof property === 'boolean' || typeof property === 'bigint') return property.toString();
973
+ if (property == null) return property + '';
972
974
  throw new Error('Invalid property type for record', typeof property);
973
975
  }
974
976
  // the registration of the record definition extension (as "r")
@@ -1008,7 +1010,7 @@ currentExtensions[0x42] = (data) => {
1008
1010
  let errors = { Error, TypeError, ReferenceError };
1009
1011
  currentExtensions[0x65] = () => {
1010
1012
  let data = read();
1011
- return (errors[data[0]] || Error)(data[1])
1013
+ return (errors[data[0]] || Error)(data[1], { cause: data[2] })
1012
1014
  };
1013
1015
 
1014
1016
  currentExtensions[0x69] = (data) => {
@@ -1052,8 +1054,15 @@ let glbl = typeof globalThis === 'object' ? globalThis : window;
1052
1054
  currentExtensions[0x74] = (data) => {
1053
1055
  let typeCode = data[0];
1054
1056
  let typedArrayName = typedArrays[typeCode];
1055
- if (!typedArrayName)
1057
+ if (!typedArrayName) {
1058
+ if (typeCode === 16) {
1059
+ let ab = new ArrayBuffer(data.length - 1);
1060
+ let u8 = new Uint8Array(ab);
1061
+ u8.set(data.subarray(1));
1062
+ return ab;
1063
+ }
1056
1064
  throw new Error('Could not find typed array for code ' + typeCode)
1065
+ }
1057
1066
  // we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
1058
1067
  return new glbl[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
1059
1068
  };
@@ -1224,7 +1233,7 @@ class Packr extends Unpackr {
1224
1233
  if (!this.structures && options.useRecords != false)
1225
1234
  this.structures = [];
1226
1235
  // two byte record ids for shared structures
1227
- let useTwoByteRecords = maxSharedStructures > 32 || (maxOwnStructures + maxSharedStructures > 64);
1236
+ let useTwoByteRecords = maxSharedStructures > 32 || (maxOwnStructures + maxSharedStructures > 64);
1228
1237
  let sharedLimitId = maxSharedStructures + 0x40;
1229
1238
  let maxStructureId = maxSharedStructures + maxOwnStructures + 0x40;
1230
1239
  if (maxStructureId > 8256) {
@@ -1242,7 +1251,7 @@ class Packr extends Unpackr {
1242
1251
  }
1243
1252
  safeEnd = target.length - 10;
1244
1253
  if (safeEnd - position < 0x800) {
1245
- // don't start too close to the end,
1254
+ // don't start too close to the end,
1246
1255
  target = new ByteArrayAllocate(target.length);
1247
1256
  targetView = target.dataView || (target.dataView = new DataView(target.buffer, 0, target.length));
1248
1257
  safeEnd = target.length - 10;
@@ -1360,10 +1369,14 @@ class Packr extends Unpackr {
1360
1369
  return packr.pack(value, encodeOptions)
1361
1370
  }
1362
1371
  packr.lastNamedStructuresLength = sharedLength;
1372
+ // don't keep large buffers around
1373
+ if (target.length > 0x40000000) target = null;
1363
1374
  return returnBuffer
1364
1375
  }
1365
1376
  }
1366
1377
  }
1378
+ // don't keep large buffers around, they take too much memory and cause problems (limit at 1GB)
1379
+ if (target.length > 0x40000000) target = null;
1367
1380
  if (encodeOptions & RESET_BUFFER_MODE)
1368
1381
  position = start;
1369
1382
  }
@@ -1581,12 +1594,12 @@ class Packr extends Unpackr {
1581
1594
  targetView.setUint32(position, referee.id);
1582
1595
  position += 4;
1583
1596
  return
1584
- } else
1597
+ } else
1585
1598
  referenceMap.set(value, { offset: position - start });
1586
1599
  }
1587
1600
  let constructor = value.constructor;
1588
1601
  if (constructor === Object) {
1589
- writeObject(value, true);
1602
+ writeObject(value);
1590
1603
  } else if (constructor === Array) {
1591
1604
  packArray(value);
1592
1605
  } else if (constructor === Map) {
@@ -1609,7 +1622,7 @@ class Packr extends Unpackr {
1609
1622
  pack(entryValue);
1610
1623
  }
1611
1624
  }
1612
- } else {
1625
+ } else {
1613
1626
  for (let i = 0, l = extensions.length; i < l; i++) {
1614
1627
  let extensionClass = extensionClasses[i];
1615
1628
  if (value instanceof extensionClass) {
@@ -1677,13 +1690,13 @@ class Packr extends Unpackr {
1677
1690
  if (json !== value)
1678
1691
  return pack(json)
1679
1692
  }
1680
-
1693
+
1681
1694
  // if there is a writeFunction, use it, otherwise just encode as undefined
1682
1695
  if (type === 'function')
1683
1696
  return pack(this.writeFunction && this.writeFunction(value));
1684
-
1685
- // no extension found, write as object
1686
- writeObject(value, !value.hasOwnProperty); // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
1697
+
1698
+ // no extension found, write as plain object
1699
+ writeObject(value);
1687
1700
  }
1688
1701
  }
1689
1702
  }
@@ -1739,9 +1752,19 @@ class Packr extends Unpackr {
1739
1752
  }
1740
1753
  };
1741
1754
 
1742
- const writePlainObject = (this.variableMapSize || this.coercibleKeyAsNumber) ? (object) => {
1755
+ const writePlainObject = (this.variableMapSize || this.coercibleKeyAsNumber || this.skipValues) ? (object) => {
1743
1756
  // this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects)
1744
- let keys = Object.keys(object);
1757
+ let keys;
1758
+ if (this.skipValues) {
1759
+ keys = [];
1760
+ for (let key in object) {
1761
+ if ((typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) &&
1762
+ !this.skipValues.includes(object[key]))
1763
+ keys.push(key);
1764
+ }
1765
+ } else {
1766
+ keys = Object.keys(object);
1767
+ }
1745
1768
  let length = keys.length;
1746
1769
  if (length < 0x10) {
1747
1770
  target[position++] = 0x80 | length;
@@ -1770,13 +1793,13 @@ class Packr extends Unpackr {
1770
1793
  }
1771
1794
  }
1772
1795
  } :
1773
- (object, safePrototype) => {
1796
+ (object) => {
1774
1797
  target[position++] = 0xde; // always using map 16, so we can preallocate and set the length afterwards
1775
1798
  let objectOffset = position - start;
1776
1799
  position += 2;
1777
1800
  let size = 0;
1778
1801
  for (let key in object) {
1779
- if (safePrototype || object.hasOwnProperty(key)) {
1802
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1780
1803
  pack(key);
1781
1804
  pack(object[key]);
1782
1805
  size++;
@@ -1788,12 +1811,12 @@ class Packr extends Unpackr {
1788
1811
 
1789
1812
  const writeRecord = this.useRecords === false ? writePlainObject :
1790
1813
  (options.progressiveRecords && !useTwoByteRecords) ? // this is about 2% faster for highly stable structures, since it only requires one for-in loop (but much more expensive when new structure needs to be written)
1791
- (object, safePrototype) => {
1814
+ (object) => {
1792
1815
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1793
1816
  let objectOffset = position++ - start;
1794
1817
  let wroteKeys;
1795
1818
  for (let key in object) {
1796
- if (safePrototype || object.hasOwnProperty(key)) {
1819
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1797
1820
  nextTransition = transition[key];
1798
1821
  if (nextTransition)
1799
1822
  transition = nextTransition;
@@ -1832,10 +1855,10 @@ class Packr extends Unpackr {
1832
1855
  insertNewRecord(transition, Object.keys(object), objectOffset, 0);
1833
1856
  }
1834
1857
  } :
1835
- (object, safePrototype) => {
1858
+ (object) => {
1836
1859
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1837
1860
  let newTransitions = 0;
1838
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1861
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1839
1862
  nextTransition = transition[key];
1840
1863
  if (!nextTransition) {
1841
1864
  nextTransition = transition[key] = Object.create(null);
@@ -1855,16 +1878,16 @@ class Packr extends Unpackr {
1855
1878
  }
1856
1879
  // now write the values
1857
1880
  for (let key in object)
1858
- if (safePrototype || object.hasOwnProperty(key)) {
1881
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1859
1882
  pack(object[key]);
1860
1883
  }
1861
1884
  };
1862
1885
 
1863
- // craete reference to useRecords if useRecords is a function
1886
+ // create reference to useRecords if useRecords is a function
1864
1887
  const checkUseRecords = typeof this.useRecords == 'function' && this.useRecords;
1865
-
1866
- const writeObject = checkUseRecords ? (object, safePrototype) => {
1867
- checkUseRecords(object) ? writeRecord(object,safePrototype) : writePlainObject(object,safePrototype);
1888
+
1889
+ const writeObject = checkUseRecords ? (object) => {
1890
+ checkUseRecords(object) ? writeRecord(object) : writePlainObject(object);
1868
1891
  } : writeRecord;
1869
1892
 
1870
1893
  const makeRoom = (end) => {
@@ -1969,7 +1992,7 @@ class Packr extends Unpackr {
1969
1992
  target[insertionOffset + start] = keysTarget[0];
1970
1993
  }
1971
1994
  };
1972
- const writeStruct = (object, safePrototype) => {
1995
+ const writeStruct = (object) => {
1973
1996
  let newPosition = writeStructSlots(object, target, start, position, structures, makeRoom, (value, newPosition, notifySharedUpdate) => {
1974
1997
  if (notifySharedUpdate)
1975
1998
  return hasSharedUpdate = true;
@@ -1983,16 +2006,22 @@ class Packr extends Unpackr {
1983
2006
  return position;
1984
2007
  }, this);
1985
2008
  if (newPosition === 0) // bail and go to a msgpack object
1986
- return writeObject(object, true);
2009
+ return writeObject(object);
1987
2010
  position = newPosition;
1988
2011
  };
1989
2012
  }
1990
2013
  useBuffer(buffer) {
1991
2014
  // this means we are finished using our own buffer and we can write over it safely
1992
2015
  target = buffer;
1993
- targetView = new DataView(target.buffer, target.byteOffset, target.byteLength);
2016
+ target.dataView || (target.dataView = new DataView(target.buffer, target.byteOffset, target.byteLength));
1994
2017
  position = 0;
1995
2018
  }
2019
+ set position (value) {
2020
+ position = value;
2021
+ }
2022
+ get position() {
2023
+ return position;
2024
+ }
1996
2025
  clearSharedData() {
1997
2026
  if (this.structures)
1998
2027
  this.structures = [];
@@ -2061,7 +2090,7 @@ extensions = [{
2061
2090
  target[position++] = 0x65; // 'e' for error
2062
2091
  target[position++] = 0;
2063
2092
  }
2064
- pack([ error.name, error.message ]);
2093
+ pack([ error.name, error.message, error.cause ]);
2065
2094
  }
2066
2095
  }, {
2067
2096
  pack(regex, allocateForWrite, pack) {
@@ -2114,6 +2143,7 @@ function writeExtBuffer(typedArray, type, allocateForWrite, encode) {
2114
2143
  }
2115
2144
  target[position++] = 0x74; // "t" for typed array
2116
2145
  target[position++] = type;
2146
+ if (!typedArray.buffer) typedArray = new Uint8Array(typedArray);
2117
2147
  target.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength), position);
2118
2148
  }
2119
2149
  function writeBuffer(buffer, allocateForWrite) {
@@ -2708,6 +2738,8 @@ function readStruct(src, position, srcEnd, unpackr) {
2708
2738
  src = Uint8Array.prototype.slice.call(src, position, srcEnd);
2709
2739
  srcEnd -= position;
2710
2740
  position = 0;
2741
+ if (!unpackr.getStructures)
2742
+ throw new Error(`Reference to shared structure ${recordId} without getStructures method`);
2711
2743
  unpackr._mergeStructures(unpackr.getStructures());
2712
2744
  if (!unpackr.typedStructs)
2713
2745
  throw new Error('Could not find any shared typed structures');