msgpackr 1.7.0-beta1 → 1.7.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.
package/index.d.ts CHANGED
@@ -1,17 +1,65 @@
1
- export {
2
- Unpackr,
3
- Decoder,
4
- unpack,
5
- unpackMultiple,
6
- decode,
7
- addExtension,
8
- FLOAT32_OPTIONS,
9
- clearSource,
10
- roundFloat32,
11
- isNativeAccelerationEnabled,
12
- } from './unpack'
13
- import { Options } from './unpack'
14
- export { Packr, Encoder, pack, encode } from './pack'
1
+ export enum FLOAT32_OPTIONS {
2
+ NEVER = 0,
3
+ ALWAYS = 1,
4
+ DECIMAL_ROUND = 3,
5
+ DECIMAL_FIT = 4
6
+ }
7
+
8
+ export interface Options {
9
+ useFloat32?: FLOAT32_OPTIONS
10
+ useRecords?: boolean
11
+ structures?: {}[]
12
+ moreTypes?: boolean
13
+ structuredClone?: boolean
14
+ mapsAsObjects?: boolean
15
+ variableMapSize?: boolean
16
+ copyBuffers?: boolean
17
+ bundleStrings?: boolean
18
+ useTimestamp32?: boolean
19
+ largeBigIntToFloat?: boolean
20
+ encodeUndefinedAsNil?: boolean
21
+ maxSharedStructures?: number
22
+ maxOwnStructures?: number
23
+ int64AsNumber?: boolean
24
+ shouldShareStructure?: (keys: string[]) => boolean
25
+ getStructures?(): {}[]
26
+ saveStructures?(structures: {}[]): boolean | void
27
+ onInvalidDate?: () => any
28
+ }
29
+ interface Extension {
30
+ Class: Function
31
+ type: number
32
+ pack?(value: any): Buffer | Uint8Array
33
+ unpack?(messagePack: Buffer | Uint8Array): any
34
+ read?(datum: any): any
35
+ write?(instance: any): any
36
+ }
37
+ export class Unpackr {
38
+ constructor(options?: Options)
39
+ unpack(messagePack: Buffer | Uint8Array): any
40
+ decode(messagePack: Buffer | Uint8Array): any
41
+ unpackMultiple(messagePack: Buffer | Uint8Array): any[]
42
+ unpackMultiple(messagePack: Buffer | Uint8Array, forEach: (value: any) => any): void
43
+ }
44
+ export class Decoder extends Unpackr {}
45
+ export function unpack(messagePack: Buffer | Uint8Array): any
46
+ export function unpackMultiple(messagePack: Buffer | Uint8Array): any[]
47
+ export function unpackMultiple(messagePack: Buffer | Uint8Array, forEach: (value: any) => any): void
48
+ export function decode(messagePack: Buffer | Uint8Array): any
49
+ export function addExtension(extension: Extension): void
50
+ export function clearSource(): void
51
+ export function roundFloat32(float32Number: number): number
52
+ export const C1: {}
53
+ export let isNativeAccelerationEnabled: boolean
54
+
55
+ export class Packr extends Unpackr {
56
+ pack(value: any): Buffer
57
+ encode(value: any): Buffer
58
+ }
59
+ export class Encoder extends Packr {}
60
+ export function pack(value: any): Buffer
61
+ export function encode(value: any): Buffer
62
+
15
63
  import { Transform, Readable } from 'stream'
16
64
 
17
65
  export as namespace msgpackr;
package/pack.d.ts CHANGED
@@ -1,9 +1 @@
1
- import { Unpackr } from './unpack'
2
- export { addExtension, FLOAT32_OPTIONS } from './unpack'
3
- export class Packr extends Unpackr {
4
- pack(value: any): Buffer
5
- encode(value: any): Buffer
6
- }
7
- export class Encoder extends Packr {}
8
- export function pack(value: any): Buffer
9
- export function encode(value: any): Buffer
1
+ export { Unpackr, Decoder, Packr, Encoder, pack, encode, unpack, decode, addExtension, FLOAT32_OPTIONS } from '.'
package/pack.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict"
2
1
  import { Unpackr, mult10, C1Type, typedArrays, addExtension as unpackAddExtension } from './unpack.js'
3
2
  let textEncoder
4
3
  try {
@@ -126,12 +125,11 @@ export class Packr extends Unpackr {
126
125
  writeStruct(value);
127
126
  else
128
127
  pack(value)
129
- if (bundledStrings) {
130
- writeBundles(start, pack)
131
- }
132
- packr.offset = position // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
133
128
  if (referenceMap && referenceMap.idsToInsert) {
134
- position += referenceMap.idsToInsert.length * 6
129
+ let incrementPosition = referenceMap.idsToInsert.length * 6;
130
+ if (bundledStrings)
131
+ writeBundles(start, pack, incrementPosition)
132
+ position += incrementPosition
135
133
  if (position > safeEnd)
136
134
  makeRoom(position)
137
135
  packr.offset = position
@@ -139,6 +137,9 @@ export class Packr extends Unpackr {
139
137
  referenceMap = null
140
138
  return serialized
141
139
  }
140
+ if (bundledStrings)
141
+ writeBundles(start, pack, 0)
142
+ packr.offset = position // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
142
143
  if (encodeOptions & REUSE_BUFFER_MODE) {
143
144
  target.start = start
144
145
  target.end = position
@@ -923,12 +924,11 @@ function insertIds(serialized, idsToInsert) {
923
924
  return serialized
924
925
  }
925
926
 
926
- function writeBundles(start, pack) {
927
+ function writeBundles(start, pack, incrementPosition) {
927
928
  if (bundledStrings.length > 0) {
928
- targetView.setUint32(bundledStrings.position + start, position - bundledStrings.position - start)
929
+ targetView.setUint32(bundledStrings.position + start, position + incrementPosition - bundledStrings.position - start)
929
930
  let writeStrings = bundledStrings
930
931
  bundledStrings = null
931
- let startPosition = position
932
932
  pack(writeStrings[0])
933
933
  pack(writeStrings[1])
934
934
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "msgpackr",
3
3
  "author": "Kris Zyp",
4
- "version": "1.7.0-beta1",
4
+ "version": "1.7.1",
5
5
  "description": "Ultra-fast MessagePack implementation with extensions for records and structured cloning",
6
6
  "license": "MIT",
7
7
  "types": "./index.d.ts",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "scripts": {
22
22
  "benchmark": "node ./tests/benchmark.cjs",
23
- "build": "rollup -c",
23
+ "build": "rollup -c && cpy index.d.ts . --rename=index.d.cts",
24
24
  "dry-run": "npm publish --dry-run",
25
25
  "prepare": "npm run build",
26
26
  "test": "mocha tests/test**.*js -u tdd --experimental-json-modules"
@@ -36,6 +36,10 @@
36
36
  "require": "./dist/node.cjs",
37
37
  "import": "./node-index.js"
38
38
  },
39
+ "types": {
40
+ "require": "./index.d.cts",
41
+ "import": "./index.d.ts"
42
+ },
39
43
  "default": "./index.js"
40
44
  },
41
45
  "./pack": {
@@ -68,13 +72,14 @@
68
72
  "/*.ts"
69
73
  ],
70
74
  "optionalDependencies": {
71
- "msgpackr-extract": "^2.1.1"
75
+ "msgpackr-extract": "^2.1.2"
72
76
  },
73
77
  "devDependencies": {
74
78
  "@rollup/plugin-json": "^4.1.0",
75
79
  "@types/node": "latest",
76
80
  "async": "^3",
77
81
  "chai": "^4.3.4",
82
+ "cpy-cli": "^4.1.0",
78
83
  "esm": "^3.2.25",
79
84
  "mocha": "^8.1.3",
80
85
  "rollup": "^1.20.3",
package/struct.js CHANGED
@@ -45,6 +45,14 @@ const DATE = 16;
45
45
  const TYPE_NAMES = ['num', 'object', 'string', 'ascii'];
46
46
  TYPE_NAMES[DATE] = 'date';
47
47
  const float32Headers = [false, true, true, false, false, true, true, false];
48
+ let evalSupported;
49
+ try {
50
+ new Function('');
51
+ evalSupported = true;
52
+ } catch(error) {
53
+ // if eval variants are not supported, do not create inline object readers ever
54
+ }
55
+
48
56
  let updatedPosition;
49
57
  const hasNodeBuffer = typeof Buffer !== 'undefined'
50
58
  let textEncoder, currentSource;
@@ -484,7 +492,7 @@ function readStruct(src, position, srcEnd, unpackr) {
484
492
  case 27: recordId = src[position++] + (src[position++] << 8) + (src[position++] << 16) + (src[position++] << 24); break;
485
493
  }
486
494
  }
487
- let structure = unpackr.typedStructs?.[recordId];
495
+ let structure = unpackr.typedStructs && unpackr.typedStructs[recordId];
488
496
  if (!structure) {
489
497
  // copy src buffer because getStructures will override it
490
498
  src = Uint8Array.prototype.slice.call(src, position, srcEnd);
@@ -504,23 +512,13 @@ function readStruct(src, position, srcEnd, unpackr) {
504
512
  }
505
513
  var prototype = construct.prototype;
506
514
  let properties = [];
507
- Object.defineProperty(prototype, 'toJSON', {
508
- value() {
509
- // return an enumerable object with own properties to JSON stringify
510
- let resolved = {};
511
- for (let i = 0, l = properties.length; i < l; i++) {
512
- let key = properties[i].key;
513
- resolved[key] = this[key];
514
- }
515
- return resolved;
516
- },
517
- // not enumerable or anything
518
- });
519
515
  let currentOffset = 0;
520
516
  let lastRefProperty;
521
517
  for (let i = 0, l = structure.length; i < l; i++) {
522
518
  let definition = structure[i];
523
519
  let [ type, size, key, enumerationOffset ] = definition;
520
+ if (key === '__proto__')
521
+ key = '__proto_';
524
522
  let property = {
525
523
  key,
526
524
  offset: currentOffset,
@@ -564,8 +562,7 @@ function readStruct(src, position, srcEnd, unpackr) {
564
562
  lastRefProperty.next = property;
565
563
  lastRefProperty = property;
566
564
  property.multiGetCount = 0;
567
- get = function() {
568
- let source = this[sourceSymbol];
565
+ get = function(source) {
569
566
  let src = source.bytes;
570
567
  let position = source.position;
571
568
  let refStart = currentOffset + position;
@@ -616,8 +613,7 @@ function readStruct(src, position, srcEnd, unpackr) {
616
613
  if (lastRefProperty && !lastRefProperty.next)
617
614
  lastRefProperty.next = property;
618
615
  lastRefProperty = property;
619
- get = function() {
620
- let source = this[sourceSymbol];
616
+ get = function(source) {
621
617
  let position = source.position;
622
618
  let refStart = currentOffset + position;
623
619
  let ref = getRef(source, position);
@@ -649,8 +645,7 @@ function readStruct(src, position, srcEnd, unpackr) {
649
645
  case NUMBER:
650
646
  switch(size) {
651
647
  case 4:
652
- get = function () {
653
- let source = this[sourceSymbol];
648
+ get = function (source) {
654
649
  let src = source.bytes;
655
650
  let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
656
651
  let position = source.position + property.offset;
@@ -668,8 +663,7 @@ function readStruct(src, position, srcEnd, unpackr) {
668
663
  };
669
664
  break;
670
665
  case 8:
671
- get = function () {
672
- let source = this[sourceSymbol];
666
+ get = function (source) {
673
667
  let src = source.bytes;
674
668
  let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
675
669
  let value = dataView.getFloat64(source.position + property.offset, true);
@@ -682,8 +676,7 @@ function readStruct(src, position, srcEnd, unpackr) {
682
676
  };
683
677
  break;
684
678
  case 1:
685
- get = function () {
686
- let source = this[sourceSymbol];
679
+ get = function (source) {
687
680
  let src = source.bytes;
688
681
  let value = src[source.position + property.offset];
689
682
  return value < 0xf6 ? value : toConstant(value);
@@ -692,8 +685,7 @@ function readStruct(src, position, srcEnd, unpackr) {
692
685
  }
693
686
  break;
694
687
  case DATE:
695
- get = function () {
696
- let source = this[sourceSymbol];
688
+ get = function (source) {
697
689
  let src = source.bytes;
698
690
  let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
699
691
  return new Date(dataView.getFloat64(source.position + property.offset, true));
@@ -703,8 +695,38 @@ function readStruct(src, position, srcEnd, unpackr) {
703
695
  }
704
696
  property.get = get;
705
697
  }
706
- for (let property of properties) // assign in enumeration order
707
- Object.defineProperty(prototype, property.key, { get: property.get, enumerable: true });
698
+ // TODO: load the srcString for faster string decoding on toJSON
699
+ if (evalSupported) {
700
+ let objectLiteralProperties = [];
701
+ let args = [];
702
+ let i = 0;
703
+ for (let property of properties) { // assign in enumeration order
704
+ Object.defineProperty(prototype, property.key, { get: withSource(property.get), enumerable: true });
705
+ let valueFunction = 'v' + i++;
706
+ args.push(valueFunction);
707
+ objectLiteralProperties.push('[' + JSON.stringify(property.key) + ']:' + valueFunction + '(s)');
708
+ }
709
+ let toObject = (new Function(...args, 'return function(s){return{' + objectLiteralProperties.join(',') + '}}')).apply(null, properties.map(prop => prop.get));
710
+ Object.defineProperty(prototype, 'toJSON', {
711
+ value() {
712
+ return toObject(this[sourceSymbol]);
713
+ }
714
+ });
715
+ } else {
716
+ Object.defineProperty(prototype, 'toJSON', {
717
+ value() {
718
+ // return an enumerable object with own properties to JSON stringify
719
+ let resolved = {};
720
+ for (let i = 0, l = properties.length; i < l; i++) {
721
+ let key = properties[i].key;
722
+
723
+ resolved[key] = this[key];
724
+ }
725
+ return resolved;
726
+ },
727
+ // not enumerable or anything
728
+ });
729
+ }
708
730
  }
709
731
  var instance = new construct();
710
732
  instance[sourceSymbol] = {
@@ -724,6 +746,11 @@ function toConstant(code) {
724
746
  }
725
747
  throw new Error('Unknown constant');
726
748
  }
749
+ function withSource(get) {
750
+ return function() {
751
+ return get(this[sourceSymbol]);
752
+ }
753
+ }
727
754
 
728
755
  function saveState() {
729
756
  if (currentSource) {
@@ -757,7 +784,7 @@ function prepareStructures(structures, packr) {
757
784
  packr._mergeStructures(existing);
758
785
  return compatible;
759
786
  };
760
- packr.lastTypedStructuresLength = packr.typedStructs?.length;
787
+ packr.lastTypedStructuresLength = packr.typedStructs && packr.typedStructs.length;
761
788
  return structures;
762
789
  }
763
790
 
package/unpack.d.ts CHANGED
@@ -1,53 +1,2 @@
1
- export enum FLOAT32_OPTIONS {
2
- NEVER = 0,
3
- ALWAYS = 1,
4
- DECIMAL_ROUND = 3,
5
- DECIMAL_FIT = 4
6
- }
7
-
8
- export interface Options {
9
- useFloat32?: FLOAT32_OPTIONS
10
- useRecords?: boolean
11
- structures?: {}[]
12
- moreTypes?: boolean
13
- structuredClone?: boolean
14
- mapsAsObjects?: boolean
15
- variableMapSize?: boolean
16
- copyBuffers?: boolean
17
- bundleStrings?: boolean
18
- useTimestamp32?: boolean
19
- largeBigIntToFloat?: boolean
20
- encodeUndefinedAsNil?: boolean
21
- maxSharedStructures?: number
22
- maxOwnStructures?: number
23
- int64AsNumber?: boolean
24
- shouldShareStructure?: (keys: string[]) => boolean
25
- getStructures?(): {}[]
26
- saveStructures?(structures: {}[]): boolean | void
27
- onInvalidDate?: () => any
28
- }
29
- interface Extension {
30
- Class: Function
31
- type: number
32
- pack?(value: any): Buffer | Uint8Array
33
- unpack?(messagePack: Buffer | Uint8Array): any
34
- read?(datum: any): any
35
- write?(instance: any): any
36
- }
37
- export class Unpackr {
38
- constructor(options?: Options)
39
- unpack(messagePack: Buffer | Uint8Array): any
40
- decode(messagePack: Buffer | Uint8Array): any
41
- unpackMultiple(messagePack: Buffer | Uint8Array): any[]
42
- unpackMultiple(messagePack: Buffer | Uint8Array, forEach: (value: any) => any): void
43
- }
44
- export class Decoder extends Unpackr {}
45
- export function unpack(messagePack: Buffer | Uint8Array): any
46
- export function unpackMultiple(messagePack: Buffer | Uint8Array): any[]
47
- export function unpackMultiple(messagePack: Buffer | Uint8Array, forEach: (value: any) => any): void
48
- export function decode(messagePack: Buffer | Uint8Array): any
49
- export function addExtension(extension: Extension): void
50
- export function clearSource(): void
51
- export function roundFloat32(float32Number: number): number
52
- export const C1: {}
53
- export let isNativeAccelerationEnabled: boolean
1
+ export { Unpackr, Decoder, unpack, unpackMultiple, decode,
2
+ addExtension, FLOAT32_OPTIONS, Options, Extension, clearSource, roundFloat32 } from '.'
package/unpack.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict"
2
1
  var decoder
3
2
  try {
4
3
  decoder = new TextDecoder()
@@ -183,6 +182,7 @@ export function checkedRead(options) {
183
182
  let result
184
183
  if (currentUnpackr.randomAccessStructure && src[position] < 0x40 && src[position] >= 0x20 && readStruct) {
185
184
  result = readStruct(src, position, srcEnd, currentUnpackr)
185
+ src = null // dispose of this so that recursive unpack calls don't save state
186
186
  if (!(options && options.lazy) && result)
187
187
  result = result.toJSON()
188
188
  position = srcEnd
@@ -193,7 +193,7 @@ export function checkedRead(options) {
193
193
 
194
194
  if (position == srcEnd) {
195
195
  // finished reading this source, cleanup references
196
- if (currentStructures.restoreStructures)
196
+ if (currentStructures && currentStructures.restoreStructures)
197
197
  restoreStructures()
198
198
  currentStructures = null
199
199
  src = null
@@ -208,7 +208,7 @@ export function checkedRead(options) {
208
208
  // else more to read, but we are reading sequentially, so don't clear source yet
209
209
  return result
210
210
  } catch(error) {
211
- if (currentStructures?.restoreStructures)
211
+ if (currentStructures && currentStructures.restoreStructures)
212
212
  restoreStructures()
213
213
  clearSource()
214
214
  if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer') || position > srcEnd) {
@@ -248,7 +248,10 @@ export function read() {
248
248
  if (currentUnpackr.mapsAsObjects) {
249
249
  let object = {}
250
250
  for (let i = 0; i < token; i++) {
251
- object[readKey()] = read()
251
+ let key = readKey()
252
+ if (key === '__proto__')
253
+ key = '__proto_'
254
+ object[key] = read()
252
255
  }
253
256
  return object
254
257
  } else {
@@ -477,7 +480,7 @@ function createStructureReader(structure, firstId) {
477
480
  // This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
478
481
  if (readObject.count++ > inlineObjectReadThreshold) {
479
482
  let readObject = structure.read = (new Function('r', 'return function(){return ' + (currentUnpackr.freezeData ? 'Object.freeze' : '') +
480
- '({' + structure.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '})}'))(read)
483
+ '({' + structure.map(key => key === '__proto__' ? '__proto_:r()' : validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '})}'))(read)
481
484
  if (structure.highByte === 0)
482
485
  structure.read = createSecondByteReader(firstId, structure.read)
483
486
  return readObject() // second byte is already read, if there is one so immediately read object
@@ -485,6 +488,8 @@ function createStructureReader(structure, firstId) {
485
488
  let object = {}
486
489
  for (let i = 0, l = structure.length; i < l; i++) {
487
490
  let key = structure[i]
491
+ if (key === '__proto__')
492
+ key = '__proto_'
488
493
  object[key] = read()
489
494
  }
490
495
  if (currentUnpackr.freezeData)
@@ -645,7 +650,10 @@ function readMap(length) {
645
650
  if (currentUnpackr.mapsAsObjects) {
646
651
  let object = {}
647
652
  for (let i = 0; i < length; i++) {
648
- object[readKey()] = read()
653
+ let key = readKey()
654
+ if (key === '__proto__')
655
+ key = '__proto_';
656
+ object[key] = read()
649
657
  }
650
658
  return object
651
659
  } else {