msgpackr 1.10.1 → 1.10.2

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/README.md CHANGED
@@ -188,6 +188,7 @@ The following options properties can be provided to the Packr or Unpackr constru
188
188
  * `encodeUndefinedAsNil` - Encodes a value of `undefined` as a MessagePack `nil`, the same as a `null`.
189
189
  * `int64AsType` - This will decode uint64 and int64 numbers as the specified type. The type can be `bigint` (default), `number`, `string`, or `auto` (where range [-2^53...2^53] is represented by number and everything else by a bigint).
190
190
  * `onInvalidDate` - This can be provided as function that will be called when an invalid date is provided. The function can throw an error, or return a value that will be encoded in place of the invalid date. If not provided, an invalid date will be encoded as an invalid timestamp (which decodes with msgpackr back to an invalid date).
191
+ * `writeFunction` - This can be provided as function that will be called when a function is encountered. The function can throw an error, or return a value that will be encoded in place of the function. If not provided, a function will be encoded as undefined (similar to `JSON.stringify`).
191
192
  * `mapAsEmptyObject` - Encodes JS `Map`s as empty objects (for back-compat with older libraries).
192
193
  * `setAsEmptyObject` - Encodes JS `Set`s as empty objects (for back-compat with older libraries).
193
194
 
@@ -912,8 +912,10 @@
912
912
  }
913
913
 
914
914
  function asSafeString(property) {
915
+ // protect against expensive (DoS) string conversions
915
916
  if (typeof property === 'string') return property;
916
- if (typeof property === 'number') return property.toString();
917
+ if (typeof property === 'number' || typeof property === 'boolean' || typeof property === 'bigint') return property.toString();
918
+ if (property == null) return property + '';
917
919
  throw new Error('Invalid property type for record', typeof property);
918
920
  }
919
921
  // the registration of the record definition extension (as "r")
@@ -953,7 +955,7 @@
953
955
  let errors = { Error, TypeError, ReferenceError };
954
956
  currentExtensions[0x65] = () => {
955
957
  let data = read();
956
- return (errors[data[0]] || Error)(data[1])
958
+ return (errors[data[0]] || Error)(data[1], { cause: data[2] })
957
959
  };
958
960
 
959
961
  currentExtensions[0x69] = (data) => {
@@ -997,8 +999,15 @@
997
999
  currentExtensions[0x74] = (data) => {
998
1000
  let typeCode = data[0];
999
1001
  let typedArrayName = typedArrays[typeCode];
1000
- if (!typedArrayName)
1002
+ if (!typedArrayName) {
1003
+ if (typeCode === 16) {
1004
+ let ab = new ArrayBuffer(data.length - 1);
1005
+ let u8 = new Uint8Array(ab);
1006
+ u8.set(data.subarray(1));
1007
+ return ab;
1008
+ }
1001
1009
  throw new Error('Could not find typed array for code ' + typeCode)
1010
+ }
1002
1011
  // we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
1003
1012
  return new glbl[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
1004
1013
  };
@@ -1294,10 +1303,14 @@
1294
1303
  return packr.pack(value, encodeOptions)
1295
1304
  }
1296
1305
  packr.lastNamedStructuresLength = sharedLength;
1306
+ // don't keep large buffers around
1307
+ if (target.length > 0x40000000) target = null;
1297
1308
  return returnBuffer
1298
1309
  }
1299
1310
  }
1300
1311
  }
1312
+ // don't keep large buffers around, they take too much memory and cause problems (limit at 1GB)
1313
+ if (target.length > 0x40000000) target = null;
1301
1314
  if (encodeOptions & RESET_BUFFER_MODE)
1302
1315
  position = start;
1303
1316
  }
@@ -1520,7 +1533,7 @@
1520
1533
  }
1521
1534
  let constructor = value.constructor;
1522
1535
  if (constructor === Object) {
1523
- writeObject(value, true);
1536
+ writeObject(value);
1524
1537
  } else if (constructor === Array) {
1525
1538
  packArray(value);
1526
1539
  } else if (constructor === Map) {
@@ -1616,8 +1629,8 @@
1616
1629
  if (type === 'function')
1617
1630
  return pack(this.writeFunction && this.writeFunction(value));
1618
1631
 
1619
- // no extension found, write as object
1620
- writeObject(value, !value.hasOwnProperty); // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
1632
+ // no extension found, write as plain object
1633
+ writeObject(value);
1621
1634
  }
1622
1635
  }
1623
1636
  }
@@ -1704,13 +1717,13 @@
1704
1717
  }
1705
1718
  }
1706
1719
  } :
1707
- (object, safePrototype) => {
1720
+ (object) => {
1708
1721
  target[position++] = 0xde; // always using map 16, so we can preallocate and set the length afterwards
1709
1722
  let objectOffset = position - start;
1710
1723
  position += 2;
1711
1724
  let size = 0;
1712
1725
  for (let key in object) {
1713
- if (safePrototype || object.hasOwnProperty(key)) {
1726
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1714
1727
  pack(key);
1715
1728
  pack(object[key]);
1716
1729
  size++;
@@ -1722,12 +1735,12 @@
1722
1735
 
1723
1736
  const writeRecord = this.useRecords === false ? writePlainObject :
1724
1737
  (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)
1725
- (object, safePrototype) => {
1738
+ (object) => {
1726
1739
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1727
1740
  let objectOffset = position++ - start;
1728
1741
  let wroteKeys;
1729
1742
  for (let key in object) {
1730
- if (safePrototype || object.hasOwnProperty(key)) {
1743
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1731
1744
  nextTransition = transition[key];
1732
1745
  if (nextTransition)
1733
1746
  transition = nextTransition;
@@ -1766,10 +1779,10 @@
1766
1779
  insertNewRecord(transition, Object.keys(object), objectOffset, 0);
1767
1780
  }
1768
1781
  } :
1769
- (object, safePrototype) => {
1782
+ (object) => {
1770
1783
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1771
1784
  let newTransitions = 0;
1772
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1785
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1773
1786
  nextTransition = transition[key];
1774
1787
  if (!nextTransition) {
1775
1788
  nextTransition = transition[key] = Object.create(null);
@@ -1789,7 +1802,7 @@
1789
1802
  }
1790
1803
  // now write the values
1791
1804
  for (let key in object)
1792
- if (safePrototype || object.hasOwnProperty(key)) {
1805
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1793
1806
  pack(object[key]);
1794
1807
  }
1795
1808
  };
@@ -1797,8 +1810,8 @@
1797
1810
  // craete reference to useRecords if useRecords is a function
1798
1811
  const checkUseRecords = typeof this.useRecords == 'function' && this.useRecords;
1799
1812
 
1800
- const writeObject = checkUseRecords ? (object, safePrototype) => {
1801
- checkUseRecords(object) ? writeRecord(object,safePrototype) : writePlainObject(object,safePrototype);
1813
+ const writeObject = checkUseRecords ? (object) => {
1814
+ checkUseRecords(object) ? writeRecord(object) : writePlainObject(object);
1802
1815
  } : writeRecord;
1803
1816
 
1804
1817
  const makeRoom = (end) => {
@@ -1903,7 +1916,7 @@
1903
1916
  target[insertionOffset + start] = keysTarget[0];
1904
1917
  }
1905
1918
  };
1906
- const writeStruct = (object, safePrototype) => {
1919
+ const writeStruct = (object) => {
1907
1920
  let newPosition = writeStructSlots(object, target, start, position, structures, makeRoom, (value, newPosition, notifySharedUpdate) => {
1908
1921
  if (notifySharedUpdate)
1909
1922
  return hasSharedUpdate = true;
@@ -1917,7 +1930,7 @@
1917
1930
  return position;
1918
1931
  }, this);
1919
1932
  if (newPosition === 0) // bail and go to a msgpack object
1920
- return writeObject(object, true);
1933
+ return writeObject(object);
1921
1934
  position = newPosition;
1922
1935
  };
1923
1936
  }
@@ -1995,7 +2008,7 @@
1995
2008
  target[position++] = 0x65; // 'e' for error
1996
2009
  target[position++] = 0;
1997
2010
  }
1998
- pack([ error.name, error.message ]);
2011
+ pack([ error.name, error.message, error.cause ]);
1999
2012
  }
2000
2013
  }, {
2001
2014
  pack(regex, allocateForWrite, pack) {
@@ -2048,6 +2061,7 @@
2048
2061
  }
2049
2062
  target[position++] = 0x74; // "t" for typed array
2050
2063
  target[position++] = type;
2064
+ if (!typedArray.buffer) typedArray = new Uint8Array(typedArray);
2051
2065
  target.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength), position);
2052
2066
  }
2053
2067
  function writeBuffer(buffer, allocateForWrite) {