msgpackr 1.5.2 → 1.5.5

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
@@ -7,8 +7,9 @@
7
7
  [![module](https://img.shields.io/badge/module-ESM%2FCJS-blue)](README.md)
8
8
  [![license](https://img.shields.io/badge/license-MIT-brightgreen)](LICENSE)
9
9
 
10
+ <img align="right" src="./assets/performance.png" width="380"/>
10
11
 
11
- The msgpackr package is an extremely fast MessagePack NodeJS/JavaScript implementation. Currently, it is significantly faster than any other known implementations, faster than Avro (for JS), and generally faster than native V8 JSON.stringify/parse, on NodeJS. It also includes an optional record extension (the `r` in msgpackr), for defining record structures that makes MessagePack even faster and more compact, often over twice as fast as even native JSON functions, several times faster than other JS implementations, and 15-50% more compact. See the performance section for more details. Structured cloning (with support for cyclical references) is also supported through optional extensions.<img align="right" src="./assets/performance.png" width="380"/>
12
+ The msgpackr package is an extremely fast MessagePack NodeJS/JavaScript implementation. Currently, it is significantly faster than any other known implementations, faster than Avro (for JS), and generally faster than native V8 JSON.stringify/parse, on NodeJS. It also includes an optional record extension (the `r` in msgpackr), for defining record structures that makes MessagePack even faster and more compact, often over twice as fast as even native JSON functions, several times faster than other JS implementations, and 15-50% more compact. See the performance section for more details. Structured cloning (with support for cyclical references) is also supported through optional extensions.
12
13
 
13
14
  ## Basic Usage
14
15
 
@@ -158,7 +159,8 @@ The following options properties can be provided to the Packr or Unpackr constru
158
159
 
159
160
  * `useRecords` - Setting this to `false` disables the record extension and stores JavaScript objects as MessagePack maps, and unpacks maps as JavaScript `Object`s, which ensures compatibilty with other decoders.
160
161
  * `structures` - Provides the array of structures that is to be used for record extension, if you want the structures saved and used again. This array will be modified in place with new record structures that are serialized (if less than 32 structures are in the array).
161
- * `structuredClone` - This enables the structured cloning extensions that will encode object/cyclic references and additional built-in types/classes.
162
+ * `moreTypes` - Enable serialization of additional built-in types/classes including typed arrays, `Set`s, `Map`s, and `Error`s.
163
+ * `structuredClone` - This enables the structured cloning extensions that will encode object/cyclic references. `moreTypes` is enabled by default when this is enabled.
162
164
  * `mapsAsObjects` - If `true`, this will decode MessagePack maps and JS `Object`s with the map entries decoded to object properties. If `false`, maps are decoded as JavaScript `Map`s. This is disabled by default if `useRecords` is enabled (which allows `Map`s to be preserved), and is enabled by default if `useRecords` is disabled.
163
165
  * `useFloat32` - This will enable msgpackr to encode non-integer numbers as `float32`. See next section for possible values.
164
166
  * `variableMapSize` - This will use varying map size definition (fixmap, map16, map32) based on the number of keys when encoding objects, which yields slightly more compact encodings (for small objects), but is typically 5-10% slower during encoding. This is necessary if you need to use objects with more than 65535 keys. This is only relevant when record extension is disabled.
package/dist/index.js CHANGED
@@ -28,6 +28,13 @@
28
28
  const C1 = new C1Type();
29
29
  C1.name = 'MessagePack 0xC1';
30
30
  var sequentialMode = false;
31
+ var inlineObjectReadThreshold = 2;
32
+ try {
33
+ new Function('');
34
+ } catch(error) {
35
+ // if eval variants are not supported, do not create inline object readers ever
36
+ inlineObjectReadThreshold = Infinity;
37
+ }
31
38
 
32
39
  class Unpackr {
33
40
  constructor(options) {
@@ -152,6 +159,9 @@
152
159
  currentStructures.length = sharedLength;
153
160
  }
154
161
  let result = read();
162
+ if (bundledStrings) // bundled strings to skip past
163
+ position = bundledStrings.postBundlePosition;
164
+
155
165
  if (position == srcEnd) {
156
166
  // finished reading this source, cleanup references
157
167
  if (currentStructures.restoreStructures)
@@ -433,7 +443,7 @@
433
443
  function createStructureReader(structure, firstId) {
434
444
  function readObject() {
435
445
  // This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
436
- if (readObject.count++ > 2) {
446
+ if (readObject.count++ > inlineObjectReadThreshold) {
437
447
  let readObject = structure.read = (new Function('r', 'return function(){return {' + structure.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}}'))(read);
438
448
  if (structure.highByte === 0)
439
449
  structure.read = createSecondByteReader(firstId, structure.read);
@@ -715,6 +725,36 @@
715
725
  }
716
726
  }
717
727
 
728
+ function readOnlyJSString() {
729
+ let token = src[position++];
730
+ let length;
731
+ if (token < 0xc0) {
732
+ // fixstr
733
+ length = token - 0xa0;
734
+ } else {
735
+ switch(token) {
736
+ case 0xd9:
737
+ // str 8
738
+ length = src[position++];
739
+ break
740
+ case 0xda:
741
+ // str 16
742
+ length = dataView.getUint16(position);
743
+ position += 2;
744
+ break
745
+ case 0xdb:
746
+ // str 32
747
+ length = dataView.getUint32(position);
748
+ position += 4;
749
+ break
750
+ default:
751
+ throw new Error('Expected string')
752
+ }
753
+ }
754
+ return readStringJS(length)
755
+ }
756
+
757
+
718
758
  function readBin(length) {
719
759
  return currentUnpackr.copyBuffers ?
720
760
  // specifically use the copying slice (not the node one)
@@ -866,21 +906,18 @@
866
906
  let data = read();
867
907
  return new RegExp(data[0], data[1])
868
908
  };
869
-
909
+ const TEMP_BUNDLE = [];
870
910
  currentExtensions[0x62] = (data) => {
871
911
  let dataSize = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
872
912
  let dataPosition = position;
873
- position += dataSize - 4;
874
- bundledStrings = [read(), read()];
913
+ position += dataSize - data.length;
914
+ bundledStrings = TEMP_BUNDLE;
915
+ bundledStrings = [readOnlyJSString(), readOnlyJSString()];
875
916
  bundledStrings.position0 = 0;
876
917
  bundledStrings.position1 = 0;
877
- let postBundlePosition = position;
918
+ bundledStrings.postBundlePosition = position;
878
919
  position = dataPosition;
879
- try {
880
- return read()
881
- } finally {
882
- position = postBundlePosition;
883
- }
920
+ return read()
884
921
  };
885
922
 
886
923
  currentExtensions[0xff] = (data) => {
@@ -977,11 +1014,12 @@
977
1014
  const ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array;
978
1015
  const ByteArray = hasNodeBuffer ? Buffer : Uint8Array;
979
1016
  const MAX_BUFFER_SIZE = hasNodeBuffer ? 0x100000000 : 0x7fd00000;
980
- let target;
1017
+ let target, keysTarget;
981
1018
  let targetView;
982
1019
  let position$1 = 0;
983
1020
  let safeEnd;
984
1021
  let bundledStrings$1 = null;
1022
+ const MAX_BUNDLE_SIZE = 0xf000;
985
1023
  const hasNonLatin = /[\u0080-\uFFFF]/;
986
1024
  const RECORD_SYMBOL = Symbol('record-id');
987
1025
  class Packr extends Unpackr {
@@ -989,7 +1027,6 @@
989
1027
  super(options);
990
1028
  this.offset = 0;
991
1029
  let start;
992
- let sharedStructures;
993
1030
  let hasSharedUpdate;
994
1031
  let structures;
995
1032
  let referenceMap;
@@ -1011,10 +1048,13 @@
1011
1048
  maxSharedStructures = hasSharedStructures ? 32 : 0;
1012
1049
  if (maxSharedStructures > 8160)
1013
1050
  throw new Error('Maximum maxSharedStructure is 8160')
1051
+ if (options.structuredClone && options.moreTypes == undefined) {
1052
+ options.moreTypes = true;
1053
+ }
1014
1054
  let maxOwnStructures = options.maxOwnStructures;
1015
1055
  if (maxOwnStructures == null)
1016
1056
  maxOwnStructures = hasSharedStructures ? 32 : 64;
1017
- if (isSequential && !options.saveStructures)
1057
+ if (!this.structures && options.useRecords != false)
1018
1058
  this.structures = [];
1019
1059
  // two byte record ids for shared structures
1020
1060
  let useTwoByteRecords = maxSharedStructures > 32 || (maxOwnStructures + maxSharedStructures > 64);
@@ -1044,31 +1084,28 @@
1044
1084
  position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
1045
1085
  start = position$1;
1046
1086
  referenceMap = packr.structuredClone ? new Map() : null;
1047
- if (packr.bundleStrings) {
1048
- bundledStrings$1 = ['', ''];
1049
- target[position$1++] = 0xd6;
1050
- target[position$1++] = 0x62; // 'b'
1051
- bundledStrings$1.position = position$1 - start;
1052
- position$1 += 4;
1087
+ if (packr.bundleStrings && typeof value !== 'string') {
1088
+ bundledStrings$1 = [];
1089
+ bundledStrings$1.size = Infinity; // force a new bundle start on first string
1053
1090
  } else
1054
1091
  bundledStrings$1 = null;
1055
- sharedStructures = packr.structures;
1056
- if (sharedStructures) {
1057
- if (sharedStructures.uninitialized)
1058
- sharedStructures = packr._mergeStructures(packr.getStructures());
1059
- let sharedLength = sharedStructures.sharedLength || 0;
1092
+ structures = packr.structures;
1093
+ if (structures) {
1094
+ if (structures.uninitialized)
1095
+ structures = packr._mergeStructures(packr.getStructures());
1096
+ let sharedLength = structures.sharedLength || 0;
1060
1097
  if (sharedLength > maxSharedStructures) {
1061
- //if (maxSharedStructures <= 32 && sharedStructures.sharedLength > 32) // TODO: could support this, but would need to update the limit ids
1062
- throw new Error('Shared structures is larger than maximum shared structures, try increasing maxSharedStructures to ' + sharedStructures.sharedLength)
1098
+ //if (maxSharedStructures <= 32 && structures.sharedLength > 32) // TODO: could support this, but would need to update the limit ids
1099
+ throw new Error('Shared structures is larger than maximum shared structures, try increasing maxSharedStructures to ' + structures.sharedLength)
1063
1100
  }
1064
- if (!sharedStructures.transitions) {
1101
+ if (!structures.transitions) {
1065
1102
  // rebuild our structure transitions
1066
- sharedStructures.transitions = Object.create(null);
1103
+ structures.transitions = Object.create(null);
1067
1104
  for (let i = 0; i < sharedLength; i++) {
1068
- let keys = sharedStructures[i];
1105
+ let keys = structures[i];
1069
1106
  if (!keys)
1070
1107
  continue
1071
- let nextTransition, transition = sharedStructures.transitions;
1108
+ let nextTransition, transition = structures.transitions;
1072
1109
  for (let j = 0, l = keys.length; j < l; j++) {
1073
1110
  let key = keys[j];
1074
1111
  nextTransition = transition[key];
@@ -1082,20 +1119,15 @@
1082
1119
  lastSharedStructuresLength = sharedLength;
1083
1120
  }
1084
1121
  if (!isSequential) {
1085
- sharedStructures.nextId = sharedLength + 0x40;
1122
+ structures.nextId = sharedLength + 0x40;
1086
1123
  }
1087
1124
  }
1088
1125
  if (hasSharedUpdate)
1089
1126
  hasSharedUpdate = false;
1090
- structures = sharedStructures || [];
1091
1127
  try {
1092
1128
  pack(value);
1093
1129
  if (bundledStrings$1) {
1094
- targetView.setUint32(bundledStrings$1.position + start, position$1 - bundledStrings$1.position - start);
1095
- let writeStrings = bundledStrings$1;
1096
- bundledStrings$1 = null;
1097
- pack(writeStrings[0]);
1098
- pack(writeStrings[1]);
1130
+ writeBundles(start, pack);
1099
1131
  }
1100
1132
  packr.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
1101
1133
  if (referenceMap && referenceMap.idsToInsert) {
@@ -1114,12 +1146,15 @@
1114
1146
  }
1115
1147
  return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
1116
1148
  } finally {
1117
- if (sharedStructures) {
1149
+ if (structures) {
1118
1150
  if (serializationsSinceTransitionRebuild < 10)
1119
1151
  serializationsSinceTransitionRebuild++;
1152
+ let sharedLength = structures.sharedLength || maxSharedStructures;
1153
+ if (structures.length > sharedLength)
1154
+ structures.length = sharedLength;
1120
1155
  if (transitionsCount > 10000) {
1121
1156
  // force a rebuild occasionally after a lot of transitions so it can get cleaned up
1122
- sharedStructures.transitions = null;
1157
+ structures.transitions = null;
1123
1158
  serializationsSinceTransitionRebuild = 0;
1124
1159
  transitionsCount = 0;
1125
1160
  if (recordIdsToRemove.length > 0)
@@ -1131,13 +1166,9 @@
1131
1166
  recordIdsToRemove = [];
1132
1167
  }
1133
1168
  if (hasSharedUpdate && packr.saveStructures) {
1134
- let sharedLength = sharedStructures.sharedLength || maxSharedStructures;
1135
- if (sharedStructures.length > sharedLength) {
1136
- sharedStructures = sharedStructures.slice(0, sharedLength);
1137
- }
1138
1169
  // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
1139
1170
  let returnBuffer = target.subarray(start, position$1);
1140
- if (packr.saveStructures(sharedStructures, lastSharedStructuresLength) === false) {
1171
+ if (packr.saveStructures(structures, lastSharedStructuresLength) === false) {
1141
1172
  // get updated structures and try again if the update failed
1142
1173
  packr._mergeStructures(packr.getStructures());
1143
1174
  return packr.pack(value)
@@ -1158,7 +1189,30 @@
1158
1189
  var length;
1159
1190
  if (type === 'string') {
1160
1191
  let strLength = value.length;
1161
- if (bundledStrings$1 && strLength >= 8 && strLength < 0x1000) {
1192
+ if (bundledStrings$1 && strLength >= 4 && strLength < 0x1000) {
1193
+ if ((bundledStrings$1.size += strLength) > MAX_BUNDLE_SIZE) {
1194
+ let extStart;
1195
+ let maxBytes = (bundledStrings$1[0] ? bundledStrings$1[0].length * 3 + bundledStrings$1[1].length : 0) + 10;
1196
+ if (position$1 + maxBytes > safeEnd)
1197
+ target = makeRoom(position$1 + maxBytes);
1198
+ if (bundledStrings$1.position) { // here we use the 0x62 extension to write the last bundle and reserve sapce for the reference pointer to the next/current bundle
1199
+ target[position$1] = 0xc8; // ext 16
1200
+ position$1 += 3; // reserve for the writing bundle size
1201
+ target[position$1++] = 0x62; // 'b'
1202
+ extStart = position$1 - start;
1203
+ position$1 += 4; // reserve for writing bundle reference
1204
+ writeBundles(start, pack); // write the last bundles
1205
+ targetView.setUint16(extStart + start - 3, position$1 - start - extStart);
1206
+ } else { // here we use the 0x62 extension just to reserve the space for the reference pointer to the bundle (will be updated once the bundle is written)
1207
+ target[position$1++] = 0xd6; // fixext 4
1208
+ target[position$1++] = 0x62; // 'b'
1209
+ extStart = position$1 - start;
1210
+ position$1 += 4; // reserve for writing bundle reference
1211
+ }
1212
+ bundledStrings$1 = ['', '']; // create new ones
1213
+ bundledStrings$1.size = 0;
1214
+ bundledStrings$1.position = extStart;
1215
+ }
1162
1216
  let twoByte = hasNonLatin.test(value);
1163
1217
  bundledStrings$1[twoByte ? 0 : 1] += value;
1164
1218
  target[position$1++] = 0xc1;
@@ -1463,53 +1517,55 @@
1463
1517
  target[objectOffset++ + start] = size >> 8;
1464
1518
  target[objectOffset + start] = size & 0xff;
1465
1519
  } :
1466
-
1467
- /* sharedStructures ? // For highly stable structures, using for-in can a little bit faster
1520
+ (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)
1468
1521
  (object, safePrototype) => {
1469
- let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
1470
- let objectOffset = position++ - start
1471
- let wroteKeys
1522
+ let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1523
+ let objectOffset = position$1++ - start;
1524
+ let wroteKeys;
1472
1525
  for (let key in object) {
1473
1526
  if (safePrototype || object.hasOwnProperty(key)) {
1474
- nextTransition = transition[key]
1475
- if (!nextTransition) {
1476
- nextTransition = transition[key] = Object.create(null)
1477
- nextTransition.__keys__ = (transition.__keys__ || []).concat([key])
1478
- /*let keys = Object.keys(object)
1479
- if
1480
- let size = 0
1481
- let startBranch = transition.__keys__ ? transition.__keys__.length : 0
1482
- for (let i = 0, l = keys.length; i++) {
1483
- let key = keys[i]
1484
- size += key.length << 2
1485
- if (i >= startBranch) {
1486
- nextTransition = nextTransition[key] = Object.create(null)
1487
- nextTransition.__keys__ = keys.slice(0, i + 1)
1527
+ nextTransition = transition[key];
1528
+ if (nextTransition)
1529
+ transition = nextTransition;
1530
+ else {
1531
+ // record doesn't exist, create full new record and insert it
1532
+ let keys = Object.keys(object);
1533
+ let lastTransition = transition;
1534
+ transition = structures.transitions;
1535
+ let newTransitions = 0;
1536
+ for (let i = 0, l = keys.length; i < l; i++) {
1537
+ let key = keys[i];
1538
+ nextTransition = transition[key];
1539
+ if (!nextTransition) {
1540
+ nextTransition = transition[key] = Object.create(null);
1541
+ newTransitions++;
1488
1542
  }
1543
+ transition = nextTransition;
1489
1544
  }
1490
- makeRoom(position + size)
1491
- nextTransition = transition[key]
1492
- target.copy(target, )
1493
- objectOffset
1545
+ if (objectOffset + start + 1 == position$1) {
1546
+ // first key, so we don't need to insert, we can just write record directly
1547
+ position$1--;
1548
+ newRecord(transition, keys, newTransitions);
1549
+ } else // otherwise we need to insert the record, moving existing data after the record
1550
+ insertNewRecord(transition, keys, objectOffset, newTransitions);
1551
+ wroteKeys = true;
1552
+ transition = lastTransition[key];
1494
1553
  }
1495
- transition = nextTransition
1496
- pack(object[key])
1554
+ pack(object[key]);
1497
1555
  }
1498
1556
  }
1499
- let id = transition.id
1500
- if (!id) {
1501
- id = transition.id = structures.push(transition.__keys__) + 63
1502
- if (sharedStructures.onUpdate)
1503
- sharedStructures.onUpdate(id, transition.__keys__)
1557
+ if (!wroteKeys) {
1558
+ let recordId = transition[RECORD_SYMBOL];
1559
+ if (recordId)
1560
+ target[objectOffset + start] = recordId;
1561
+ else
1562
+ insertNewRecord(transition, Object.keys(object), objectOffset, 0);
1504
1563
  }
1505
- target[objectOffset + start] = id
1506
- }*/
1507
- (object) => {
1508
- let keys = Object.keys(object);
1564
+ } :
1565
+ (object, safePrototype) => {
1509
1566
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1510
1567
  let newTransitions = 0;
1511
- for (let i = 0, l = keys.length; i < l; i++) {
1512
- let key = keys[i];
1568
+ for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1513
1569
  nextTransition = transition[key];
1514
1570
  if (!nextTransition) {
1515
1571
  nextTransition = transition[key] = Object.create(null);
@@ -1525,57 +1581,12 @@
1525
1581
  } else
1526
1582
  target[position$1++] = recordId;
1527
1583
  } else {
1528
- recordId = structures.nextId;
1529
- if (!recordId)
1530
- recordId = 0x40;
1531
- if (recordId < sharedLimitId && this.shouldShareStructure && !this.shouldShareStructure(keys)) {
1532
- recordId = structures.nextOwnId;
1533
- if (!(recordId < maxStructureId))
1534
- recordId = sharedLimitId;
1535
- structures.nextOwnId = recordId + 1;
1536
- } else {
1537
- if (recordId >= maxStructureId)// cycle back around
1538
- recordId = sharedLimitId;
1539
- structures.nextId = recordId + 1;
1540
- }
1541
- let highByte = keys.highByte = recordId >= 0x60 && useTwoByteRecords ? (recordId - 0x60) >> 5 : -1;
1542
- transition[RECORD_SYMBOL] = recordId;
1543
- structures[recordId - 0x40] = keys;
1544
-
1545
- if (recordId < sharedLimitId) {
1546
- keys.isShared = true;
1547
- structures.sharedLength = recordId - 0x3f;
1548
- hasSharedUpdate = true;
1549
- if (highByte >= 0) {
1550
- target[position$1++] = (recordId & 0x1f) + 0x60;
1551
- target[position$1++] = highByte;
1552
- } else {
1553
- target[position$1++] = recordId;
1554
- }
1555
- } else {
1556
- if (highByte >= 0) {
1557
- target[position$1++] = 0xd5; // fixext 2
1558
- target[position$1++] = 0x72; // "r" record defintion extension type
1559
- target[position$1++] = (recordId & 0x1f) + 0x60;
1560
- target[position$1++] = highByte;
1561
- } else {
1562
- target[position$1++] = 0xd4; // fixext 1
1563
- target[position$1++] = 0x72; // "r" record defintion extension type
1564
- target[position$1++] = recordId;
1565
- }
1566
-
1567
- if (newTransitions)
1568
- transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
1569
- // record the removal of the id, we can maintain our shared structure
1570
- if (recordIdsToRemove.length >= maxOwnStructures)
1571
- recordIdsToRemove.shift()[RECORD_SYMBOL] = 0; // we are cycling back through, and have to remove old ones
1572
- recordIdsToRemove.push(transition);
1573
- pack(keys);
1574
- }
1584
+ newRecord(transition, transition.__keys__ || Object.keys(object), newTransitions);
1575
1585
  }
1576
1586
  // now write the values
1577
- for (let i = 0, l = keys.length; i < l; i++)
1578
- pack(object[keys[i]]);
1587
+ for (let key in object)
1588
+ if (safePrototype || object.hasOwnProperty(key))
1589
+ pack(object[key]);
1579
1590
  };
1580
1591
  const makeRoom = (end) => {
1581
1592
  let newSize;
@@ -1598,6 +1609,86 @@
1598
1609
  safeEnd = newBuffer.length - 10;
1599
1610
  return target = newBuffer
1600
1611
  };
1612
+ const newRecord = (transition, keys, newTransitions) => {
1613
+ let recordId = structures.nextId;
1614
+ if (!recordId)
1615
+ recordId = 0x40;
1616
+ if (recordId < sharedLimitId && this.shouldShareStructure && !this.shouldShareStructure(keys)) {
1617
+ recordId = structures.nextOwnId;
1618
+ if (!(recordId < maxStructureId))
1619
+ recordId = sharedLimitId;
1620
+ structures.nextOwnId = recordId + 1;
1621
+ } else {
1622
+ if (recordId >= maxStructureId)// cycle back around
1623
+ recordId = sharedLimitId;
1624
+ structures.nextId = recordId + 1;
1625
+ }
1626
+ let highByte = keys.highByte = recordId >= 0x60 && useTwoByteRecords ? (recordId - 0x60) >> 5 : -1;
1627
+ transition[RECORD_SYMBOL] = recordId;
1628
+ transition.__keys__ = keys;
1629
+ structures[recordId - 0x40] = keys;
1630
+
1631
+ if (recordId < sharedLimitId) {
1632
+ keys.isShared = true;
1633
+ structures.sharedLength = recordId - 0x3f;
1634
+ hasSharedUpdate = true;
1635
+ if (highByte >= 0) {
1636
+ target[position$1++] = (recordId & 0x1f) + 0x60;
1637
+ target[position$1++] = highByte;
1638
+ } else {
1639
+ target[position$1++] = recordId;
1640
+ }
1641
+ } else {
1642
+ if (highByte >= 0) {
1643
+ target[position$1++] = 0xd5; // fixext 2
1644
+ target[position$1++] = 0x72; // "r" record defintion extension type
1645
+ target[position$1++] = (recordId & 0x1f) + 0x60;
1646
+ target[position$1++] = highByte;
1647
+ } else {
1648
+ target[position$1++] = 0xd4; // fixext 1
1649
+ target[position$1++] = 0x72; // "r" record defintion extension type
1650
+ target[position$1++] = recordId;
1651
+ }
1652
+
1653
+ if (newTransitions)
1654
+ transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
1655
+ // record the removal of the id, we can maintain our shared structure
1656
+ if (recordIdsToRemove.length >= maxOwnStructures)
1657
+ recordIdsToRemove.shift()[RECORD_SYMBOL] = 0; // we are cycling back through, and have to remove old ones
1658
+ recordIdsToRemove.push(transition);
1659
+ pack(keys);
1660
+ }
1661
+ };
1662
+ const insertNewRecord = (transition, keys, insertionOffset, newTransitions) => {
1663
+ let mainTarget = target;
1664
+ let mainPosition = position$1;
1665
+ let mainSafeEnd = safeEnd;
1666
+ let mainStart = start;
1667
+ target = keysTarget;
1668
+ position$1 = 0;
1669
+ start = 0;
1670
+ if (!target)
1671
+ keysTarget = target = new ByteArrayAllocate(8192);
1672
+ safeEnd = target.length - 10;
1673
+ newRecord(transition, keys, newTransitions);
1674
+ keysTarget = target;
1675
+ let keysPosition = position$1;
1676
+ target = mainTarget;
1677
+ position$1 = mainPosition;
1678
+ safeEnd = mainSafeEnd;
1679
+ start = mainStart;
1680
+ if (keysPosition > 1) {
1681
+ let newEnd = position$1 + keysPosition - 1;
1682
+ if (newEnd > safeEnd)
1683
+ makeRoom(newEnd);
1684
+ let insertionPosition = insertionOffset + start;
1685
+ target.copyWithin(insertionPosition + keysPosition, insertionPosition + 1, position$1);
1686
+ target.set(keysTarget.slice(0, keysPosition), insertionPosition);
1687
+ position$1 = newEnd;
1688
+ } else {
1689
+ target[insertionOffset + start] = keysTarget[0];
1690
+ }
1691
+ };
1601
1692
  }
1602
1693
  useBuffer(buffer) {
1603
1694
  // this means we are finished using our own buffer and we can write over it safely
@@ -1605,6 +1696,10 @@
1605
1696
  targetView = new DataView(target.buffer, target.byteOffset, target.byteLength);
1606
1697
  position$1 = 0;
1607
1698
  }
1699
+ clearSharedData() {
1700
+ if (this.structures)
1701
+ this.structures = [];
1702
+ }
1608
1703
  }
1609
1704
 
1610
1705
  extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ];
@@ -1647,8 +1742,8 @@
1647
1742
  }, {
1648
1743
  pack(set, allocateForWrite, pack) {
1649
1744
  let array = Array.from(set);
1650
- let { target, position} = allocateForWrite(this.structuredClone ? 3 : 0);
1651
- if (this.structuredClone) {
1745
+ let { target, position} = allocateForWrite(this.moreTypes ? 3 : 0);
1746
+ if (this.moreTypes) {
1652
1747
  target[position++] = 0xd4;
1653
1748
  target[position++] = 0x73; // 's' for Set
1654
1749
  target[position++] = 0;
@@ -1657,8 +1752,8 @@
1657
1752
  }
1658
1753
  }, {
1659
1754
  pack(error, allocateForWrite, pack) {
1660
- let { target, position} = allocateForWrite(this.structuredClone ? 3 : 0);
1661
- if (this.structuredClone) {
1755
+ let { target, position} = allocateForWrite(this.moreTypes ? 3 : 0);
1756
+ if (this.moreTypes) {
1662
1757
  target[position++] = 0xd4;
1663
1758
  target[position++] = 0x65; // 'e' for error
1664
1759
  target[position++] = 0;
@@ -1667,8 +1762,8 @@
1667
1762
  }
1668
1763
  }, {
1669
1764
  pack(regex, allocateForWrite, pack) {
1670
- let { target, position} = allocateForWrite(this.structuredClone ? 3 : 0);
1671
- if (this.structuredClone) {
1765
+ let { target, position} = allocateForWrite(this.moreTypes ? 3 : 0);
1766
+ if (this.moreTypes) {
1672
1767
  target[position++] = 0xd4;
1673
1768
  target[position++] = 0x78; // 'x' for regeXp
1674
1769
  target[position++] = 0;
@@ -1677,7 +1772,7 @@
1677
1772
  }
1678
1773
  }, {
1679
1774
  pack(arrayBuffer, allocateForWrite) {
1680
- if (this.structuredClone)
1775
+ if (this.moreTypes)
1681
1776
  writeExtBuffer(arrayBuffer, 0x10, allocateForWrite);
1682
1777
  else
1683
1778
  writeBuffer(hasNodeBuffer ? Buffer.from(arrayBuffer) : new Uint8Array(arrayBuffer), allocateForWrite);
@@ -1685,7 +1780,7 @@
1685
1780
  }, {
1686
1781
  pack(typedArray, allocateForWrite) {
1687
1782
  let constructor = typedArray.constructor;
1688
- if (constructor !== ByteArray && this.structuredClone)
1783
+ if (constructor !== ByteArray && this.moreTypes)
1689
1784
  writeExtBuffer(typedArray, typedArrays.indexOf(constructor.name), allocateForWrite);
1690
1785
  else
1691
1786
  writeBuffer(typedArray, allocateForWrite);
@@ -1802,6 +1897,14 @@
1802
1897
  return serialized
1803
1898
  }
1804
1899
 
1900
+ function writeBundles(start, pack) {
1901
+ targetView.setUint32(bundledStrings$1.position + start, position$1 - bundledStrings$1.position - start);
1902
+ let writeStrings = bundledStrings$1;
1903
+ bundledStrings$1 = null;
1904
+ pack(writeStrings[0]);
1905
+ pack(writeStrings[1]);
1906
+ }
1907
+
1805
1908
  function addExtension$1(extension) {
1806
1909
  if (extension.Class) {
1807
1910
  if (!extension.pack && !extension.write)