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/pack.js CHANGED
@@ -53,7 +53,7 @@ export class Packr extends Unpackr {
53
53
  if (!this.structures && options.useRecords != false)
54
54
  this.structures = []
55
55
  // two byte record ids for shared structures
56
- let useTwoByteRecords = maxSharedStructures > 32 || (maxOwnStructures + maxSharedStructures > 64)
56
+ let useTwoByteRecords = maxSharedStructures > 32 || (maxOwnStructures + maxSharedStructures > 64)
57
57
  let sharedLimitId = maxSharedStructures + 0x40
58
58
  let maxStructureId = maxSharedStructures + maxOwnStructures + 0x40
59
59
  if (maxStructureId > 8256) {
@@ -71,7 +71,7 @@ export class Packr extends Unpackr {
71
71
  }
72
72
  safeEnd = target.length - 10
73
73
  if (safeEnd - position < 0x800) {
74
- // don't start too close to the end,
74
+ // don't start too close to the end,
75
75
  target = new ByteArrayAllocate(target.length)
76
76
  targetView = target.dataView || (target.dataView = new DataView(target.buffer, 0, target.length))
77
77
  safeEnd = target.length - 10
@@ -189,10 +189,14 @@ export class Packr extends Unpackr {
189
189
  return packr.pack(value, encodeOptions)
190
190
  }
191
191
  packr.lastNamedStructuresLength = sharedLength
192
+ // don't keep large buffers around
193
+ if (target.length > 0x40000000) target = null
192
194
  return returnBuffer
193
195
  }
194
196
  }
195
197
  }
198
+ // don't keep large buffers around, they take too much memory and cause problems (limit at 1GB)
199
+ if (target.length > 0x40000000) target = null
196
200
  if (encodeOptions & RESET_BUFFER_MODE)
197
201
  position = start
198
202
  }
@@ -410,12 +414,12 @@ export class Packr extends Unpackr {
410
414
  targetView.setUint32(position, referee.id)
411
415
  position += 4
412
416
  return
413
- } else
417
+ } else
414
418
  referenceMap.set(value, { offset: position - start })
415
419
  }
416
420
  let constructor = value.constructor
417
421
  if (constructor === Object) {
418
- writeObject(value, true)
422
+ writeObject(value)
419
423
  } else if (constructor === Array) {
420
424
  packArray(value)
421
425
  } else if (constructor === Map) {
@@ -438,7 +442,7 @@ export class Packr extends Unpackr {
438
442
  pack(entryValue)
439
443
  }
440
444
  }
441
- } else {
445
+ } else {
442
446
  for (let i = 0, l = extensions.length; i < l; i++) {
443
447
  let extensionClass = extensionClasses[i]
444
448
  if (value instanceof extensionClass) {
@@ -506,13 +510,13 @@ export class Packr extends Unpackr {
506
510
  if (json !== value)
507
511
  return pack(json)
508
512
  }
509
-
513
+
510
514
  // if there is a writeFunction, use it, otherwise just encode as undefined
511
515
  if (type === 'function')
512
516
  return pack(this.writeFunction && this.writeFunction(value));
513
-
514
- // no extension found, write as object
515
- writeObject(value, !value.hasOwnProperty) // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
517
+
518
+ // no extension found, write as plain object
519
+ writeObject(value)
516
520
  }
517
521
  }
518
522
  }
@@ -568,9 +572,19 @@ export class Packr extends Unpackr {
568
572
  }
569
573
  }
570
574
 
571
- const writePlainObject = (this.variableMapSize || this.coercibleKeyAsNumber) ? (object) => {
575
+ const writePlainObject = (this.variableMapSize || this.coercibleKeyAsNumber || this.skipValues) ? (object) => {
572
576
  // this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects)
573
- let keys = Object.keys(object)
577
+ let keys;
578
+ if (this.skipValues) {
579
+ keys = [];
580
+ for (let key in object) {
581
+ if ((typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) &&
582
+ !this.skipValues.includes(object[key]))
583
+ keys.push(key);
584
+ }
585
+ } else {
586
+ keys = Object.keys(object)
587
+ }
574
588
  let length = keys.length
575
589
  if (length < 0x10) {
576
590
  target[position++] = 0x80 | length
@@ -599,13 +613,13 @@ export class Packr extends Unpackr {
599
613
  }
600
614
  }
601
615
  } :
602
- (object, safePrototype) => {
616
+ (object) => {
603
617
  target[position++] = 0xde // always using map 16, so we can preallocate and set the length afterwards
604
618
  let objectOffset = position - start
605
619
  position += 2
606
620
  let size = 0
607
621
  for (let key in object) {
608
- if (safePrototype || object.hasOwnProperty(key)) {
622
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
609
623
  pack(key)
610
624
  pack(object[key])
611
625
  size++
@@ -617,12 +631,12 @@ export class Packr extends Unpackr {
617
631
 
618
632
  const writeRecord = this.useRecords === false ? writePlainObject :
619
633
  (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)
620
- (object, safePrototype) => {
634
+ (object) => {
621
635
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
622
636
  let objectOffset = position++ - start
623
637
  let wroteKeys
624
638
  for (let key in object) {
625
- if (safePrototype || object.hasOwnProperty(key)) {
639
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
626
640
  nextTransition = transition[key]
627
641
  if (nextTransition)
628
642
  transition = nextTransition
@@ -661,10 +675,10 @@ export class Packr extends Unpackr {
661
675
  insertNewRecord(transition, Object.keys(object), objectOffset, 0)
662
676
  }
663
677
  } :
664
- (object, safePrototype) => {
678
+ (object) => {
665
679
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
666
680
  let newTransitions = 0
667
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
681
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
668
682
  nextTransition = transition[key]
669
683
  if (!nextTransition) {
670
684
  nextTransition = transition[key] = Object.create(null)
@@ -684,16 +698,16 @@ export class Packr extends Unpackr {
684
698
  }
685
699
  // now write the values
686
700
  for (let key in object)
687
- if (safePrototype || object.hasOwnProperty(key)) {
701
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
688
702
  pack(object[key])
689
703
  }
690
704
  }
691
705
 
692
- // craete reference to useRecords if useRecords is a function
706
+ // create reference to useRecords if useRecords is a function
693
707
  const checkUseRecords = typeof this.useRecords == 'function' && this.useRecords;
694
-
695
- const writeObject = checkUseRecords ? (object, safePrototype) => {
696
- checkUseRecords(object) ? writeRecord(object,safePrototype) : writePlainObject(object,safePrototype)
708
+
709
+ const writeObject = checkUseRecords ? (object) => {
710
+ checkUseRecords(object) ? writeRecord(object) : writePlainObject(object)
697
711
  } : writeRecord
698
712
 
699
713
  const makeRoom = (end) => {
@@ -798,7 +812,7 @@ export class Packr extends Unpackr {
798
812
  target[insertionOffset + start] = keysTarget[0]
799
813
  }
800
814
  }
801
- const writeStruct = (object, safePrototype) => {
815
+ const writeStruct = (object) => {
802
816
  let newPosition = writeStructSlots(object, target, start, position, structures, makeRoom, (value, newPosition, notifySharedUpdate) => {
803
817
  if (notifySharedUpdate)
804
818
  return hasSharedUpdate = true;
@@ -812,16 +826,22 @@ export class Packr extends Unpackr {
812
826
  return position;
813
827
  }, this);
814
828
  if (newPosition === 0) // bail and go to a msgpack object
815
- return writeObject(object, true);
829
+ return writeObject(object);
816
830
  position = newPosition;
817
831
  }
818
832
  }
819
833
  useBuffer(buffer) {
820
834
  // this means we are finished using our own buffer and we can write over it safely
821
835
  target = buffer
822
- targetView = new DataView(target.buffer, target.byteOffset, target.byteLength)
836
+ target.dataView || (target.dataView = new DataView(target.buffer, target.byteOffset, target.byteLength))
823
837
  position = 0
824
838
  }
839
+ set position (value) {
840
+ position = value;
841
+ }
842
+ get position() {
843
+ return position;
844
+ }
825
845
  clearSharedData() {
826
846
  if (this.structures)
827
847
  this.structures = []
@@ -830,12 +850,6 @@ export class Packr extends Unpackr {
830
850
  }
831
851
  }
832
852
 
833
- function copyBinary(source, target, targetOffset, offset, endOffset) {
834
- while (offset < endOffset) {
835
- target[targetOffset++] = source[offset++]
836
- }
837
- }
838
-
839
853
  extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ]
840
854
  extensions = [{
841
855
  pack(date, allocateForWrite, pack) {
@@ -896,7 +910,7 @@ extensions = [{
896
910
  target[position++] = 0x65 // 'e' for error
897
911
  target[position++] = 0
898
912
  }
899
- pack([ error.name, error.message ])
913
+ pack([ error.name, error.message, error.cause ])
900
914
  }
901
915
  }, {
902
916
  pack(regex, allocateForWrite, pack) {
@@ -949,6 +963,7 @@ function writeExtBuffer(typedArray, type, allocateForWrite, encode) {
949
963
  }
950
964
  target[position++] = 0x74 // "t" for typed array
951
965
  target[position++] = type
966
+ if (!typedArray.buffer) typedArray = new Uint8Array(typedArray)
952
967
  target.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength), position)
953
968
  }
954
969
  function writeBuffer(buffer, allocateForWrite) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "msgpackr",
3
3
  "author": "Kris Zyp",
4
- "version": "1.10.1",
4
+ "version": "1.11.0",
5
5
  "description": "Ultra-fast MessagePack implementation with extensions for records and structured cloning",
6
6
  "license": "MIT",
7
7
  "types": "./index.d.ts",
package/struct.js CHANGED
@@ -504,6 +504,8 @@ function readStruct(src, position, srcEnd, unpackr) {
504
504
  src = Uint8Array.prototype.slice.call(src, position, srcEnd);
505
505
  srcEnd -= position;
506
506
  position = 0;
507
+ if (!unpackr.getStructures)
508
+ throw new Error(`Reference to shared structure ${recordId} without getStructures method`);
507
509
  unpackr._mergeStructures(unpackr.getStructures());
508
510
  if (!unpackr.typedStructs)
509
511
  throw new Error('Could not find any shared typed structures');
package/unpack.js 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
  }