@colyseus/schema 3.0.0-alpha.3 → 3.0.0-alpha.30

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.
Files changed (116) hide show
  1. package/README.md +131 -61
  2. package/build/cjs/index.js +644 -283
  3. package/build/cjs/index.js.map +1 -1
  4. package/build/esm/index.mjs +643 -282
  5. package/build/esm/index.mjs.map +1 -1
  6. package/build/umd/index.js +644 -283
  7. package/lib/Metadata.d.ts +2 -0
  8. package/lib/Metadata.js +39 -0
  9. package/lib/Metadata.js.map +1 -1
  10. package/lib/Reflection.d.ts +2 -3
  11. package/lib/Reflection.js +31 -26
  12. package/lib/Reflection.js.map +1 -1
  13. package/lib/Schema.d.ts +2 -2
  14. package/lib/Schema.js +2 -2
  15. package/lib/Schema.js.map +1 -1
  16. package/lib/annotations.d.ts +0 -19
  17. package/lib/annotations.js +15 -101
  18. package/lib/annotations.js.map +1 -1
  19. package/lib/bench_encode.d.ts +1 -0
  20. package/lib/bench_encode.js +120 -0
  21. package/lib/bench_encode.js.map +1 -0
  22. package/lib/codegen/api.js +1 -2
  23. package/lib/codegen/api.js.map +1 -1
  24. package/lib/codegen/languages/cpp.js +1 -2
  25. package/lib/codegen/languages/cpp.js.map +1 -1
  26. package/lib/codegen/languages/csharp.js +1 -2
  27. package/lib/codegen/languages/csharp.js.map +1 -1
  28. package/lib/codegen/languages/haxe.js +1 -2
  29. package/lib/codegen/languages/haxe.js.map +1 -1
  30. package/lib/codegen/languages/java.js +1 -2
  31. package/lib/codegen/languages/java.js.map +1 -1
  32. package/lib/codegen/languages/js.js +1 -2
  33. package/lib/codegen/languages/js.js.map +1 -1
  34. package/lib/codegen/languages/lua.js +1 -2
  35. package/lib/codegen/languages/lua.js.map +1 -1
  36. package/lib/codegen/languages/ts.js +1 -2
  37. package/lib/codegen/languages/ts.js.map +1 -1
  38. package/lib/codegen/parser.js +2 -3
  39. package/lib/codegen/parser.js.map +1 -1
  40. package/lib/codegen/types.js +3 -3
  41. package/lib/codegen/types.js.map +1 -1
  42. package/lib/debug.d.ts +1 -0
  43. package/lib/debug.js +52 -0
  44. package/lib/debug.js.map +1 -0
  45. package/lib/decoder/DecodeOperation.d.ts +0 -1
  46. package/lib/decoder/DecodeOperation.js +23 -7
  47. package/lib/decoder/DecodeOperation.js.map +1 -1
  48. package/lib/decoder/Decoder.d.ts +6 -7
  49. package/lib/decoder/Decoder.js +8 -8
  50. package/lib/decoder/Decoder.js.map +1 -1
  51. package/lib/decoder/strategy/RawChanges.js +1 -2
  52. package/lib/decoder/strategy/RawChanges.js.map +1 -1
  53. package/lib/decoder/strategy/StateCallbacks.d.ts +44 -11
  54. package/lib/decoder/strategy/StateCallbacks.js +72 -63
  55. package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
  56. package/lib/encoder/ChangeTree.d.ts +1 -12
  57. package/lib/encoder/ChangeTree.js +29 -58
  58. package/lib/encoder/ChangeTree.js.map +1 -1
  59. package/lib/encoder/EncodeOperation.d.ts +0 -1
  60. package/lib/encoder/EncodeOperation.js +29 -13
  61. package/lib/encoder/EncodeOperation.js.map +1 -1
  62. package/lib/encoder/Encoder.d.ts +10 -8
  63. package/lib/encoder/Encoder.js +78 -53
  64. package/lib/encoder/Encoder.js.map +1 -1
  65. package/lib/encoder/Root.d.ts +17 -0
  66. package/lib/encoder/Root.js +44 -0
  67. package/lib/encoder/Root.js.map +1 -0
  68. package/lib/encoder/StateView.d.ts +2 -2
  69. package/lib/encoder/StateView.js +48 -58
  70. package/lib/encoder/StateView.js.map +1 -1
  71. package/lib/encoding/assert.js +3 -3
  72. package/lib/encoding/assert.js.map +1 -1
  73. package/lib/encoding/decode.js +21 -22
  74. package/lib/encoding/decode.js.map +1 -1
  75. package/lib/encoding/encode.d.ts +2 -2
  76. package/lib/encoding/encode.js +40 -39
  77. package/lib/encoding/encode.js.map +1 -1
  78. package/lib/encoding/spec.d.ts +2 -1
  79. package/lib/encoding/spec.js +1 -0
  80. package/lib/encoding/spec.js.map +1 -1
  81. package/lib/index.d.ts +5 -1
  82. package/lib/index.js +8 -4
  83. package/lib/index.js.map +1 -1
  84. package/lib/types/TypeContext.d.ts +23 -0
  85. package/lib/types/TypeContext.js +109 -0
  86. package/lib/types/TypeContext.js.map +1 -0
  87. package/lib/types/custom/ArraySchema.d.ts +2 -2
  88. package/lib/types/custom/ArraySchema.js +0 -9
  89. package/lib/types/custom/ArraySchema.js.map +1 -1
  90. package/lib/types/registry.js +3 -4
  91. package/lib/types/registry.js.map +1 -1
  92. package/lib/types/utils.js +1 -2
  93. package/lib/types/utils.js.map +1 -1
  94. package/lib/utils.js +3 -4
  95. package/lib/utils.js.map +1 -1
  96. package/package.json +5 -5
  97. package/src/Metadata.ts +47 -0
  98. package/src/Reflection.ts +34 -26
  99. package/src/Schema.ts +2 -2
  100. package/src/annotations.ts +7 -109
  101. package/src/bench_encode.ts +97 -0
  102. package/src/debug.ts +56 -0
  103. package/src/decoder/DecodeOperation.ts +30 -7
  104. package/src/decoder/Decoder.ts +13 -11
  105. package/src/decoder/strategy/StateCallbacks.ts +149 -79
  106. package/src/encoder/ChangeTree.ts +36 -66
  107. package/src/encoder/EncodeOperation.ts +29 -12
  108. package/src/encoder/Encoder.ts +95 -61
  109. package/src/encoder/Root.ts +51 -0
  110. package/src/encoder/StateView.ts +51 -67
  111. package/src/encoding/decode.ts +1 -2
  112. package/src/encoding/encode.ts +25 -22
  113. package/src/encoding/spec.ts +1 -0
  114. package/src/index.ts +8 -11
  115. package/src/types/TypeContext.ts +127 -0
  116. package/src/types/custom/ArraySchema.ts +2 -2
@@ -23,6 +23,7 @@ var OPERATION;
23
23
  OPERATION[OPERATION["REVERSE"] = 15] = "REVERSE";
24
24
  OPERATION[OPERATION["MOVE"] = 32] = "MOVE";
25
25
  OPERATION[OPERATION["DELETE_BY_REFID"] = 33] = "DELETE_BY_REFID";
26
+ OPERATION[OPERATION["ADD_BY_REFID"] = 129] = "ADD_BY_REFID";
26
27
  })(OPERATION || (OPERATION = {}));
27
28
 
28
29
  Symbol.metadata ??= Symbol.for("Symbol.metadata");
@@ -139,6 +140,45 @@ const Metadata = {
139
140
  isDeprecated(metadata, field) {
140
141
  return metadata[field].deprecated === true;
141
142
  },
143
+ init(klass) {
144
+ //
145
+ // Used only to initialize an empty Schema (Encoder#constructor)
146
+ // TODO: remove/refactor this...
147
+ //
148
+ const metadata = {};
149
+ klass[Symbol.metadata] = metadata;
150
+ Object.defineProperty(metadata, -1, {
151
+ value: 0,
152
+ enumerable: false,
153
+ configurable: true,
154
+ });
155
+ },
156
+ initialize(constructor, parentMetadata) {
157
+ let metadata = constructor[Symbol.metadata] ?? Object.create(null);
158
+ // make sure inherited classes have their own metadata object.
159
+ if (constructor[Symbol.metadata] === parentMetadata) {
160
+ metadata = Object.create(null);
161
+ if (parentMetadata) {
162
+ // assign parent metadata to current
163
+ Object.assign(metadata, parentMetadata);
164
+ for (let i = 0; i <= parentMetadata[-1]; i++) {
165
+ Object.defineProperty(metadata, i, {
166
+ value: parentMetadata[i],
167
+ enumerable: false,
168
+ configurable: true,
169
+ });
170
+ }
171
+ Object.defineProperty(metadata, -1, {
172
+ value: parentMetadata[-1],
173
+ enumerable: false,
174
+ configurable: true,
175
+ writable: true,
176
+ });
177
+ }
178
+ }
179
+ constructor[Symbol.metadata] = metadata;
180
+ return metadata;
181
+ },
142
182
  isValidInstance(klass) {
143
183
  return (klass.constructor[Symbol.metadata] &&
144
184
  Object.prototype.hasOwnProperty.call(klass.constructor[Symbol.metadata], -1));
@@ -154,44 +194,6 @@ const Metadata = {
154
194
  };
155
195
 
156
196
  var _a$5;
157
- class Root {
158
- constructor() {
159
- this.nextUniqueId = 0;
160
- this.refCount = new WeakMap();
161
- // all changes
162
- this.allChanges = new Map();
163
- this.allFilteredChanges = new Map();
164
- // pending changes to be encoded
165
- this.changes = new Map();
166
- this.filteredChanges = new Map();
167
- }
168
- getNextUniqueId() {
169
- return this.nextUniqueId++;
170
- }
171
- add(changeTree) {
172
- const refCount = this.refCount.get(changeTree) || 0;
173
- this.refCount.set(changeTree, refCount + 1);
174
- }
175
- remove(changeTree) {
176
- const refCount = this.refCount.get(changeTree);
177
- if (refCount <= 1) {
178
- this.allChanges.delete(changeTree);
179
- this.changes.delete(changeTree);
180
- if (changeTree.isFiltered || changeTree.isPartiallyFiltered) {
181
- this.allFilteredChanges.delete(changeTree);
182
- this.filteredChanges.delete(changeTree);
183
- }
184
- this.refCount.delete(changeTree);
185
- }
186
- else {
187
- this.refCount.set(changeTree, refCount - 1);
188
- }
189
- changeTree.forEachChild((child, _) => this.remove(child));
190
- }
191
- clear() {
192
- this.changes.clear();
193
- }
194
- }
195
197
  class ChangeTree {
196
198
  static { _a$5 = $isNew; }
197
199
  ;
@@ -223,8 +225,6 @@ class ChangeTree {
223
225
  if (this.isFiltered || this.isPartiallyFiltered) {
224
226
  this.root.allFilteredChanges.set(this, this.allFilteredChanges);
225
227
  this.root.filteredChanges.set(this, this.filteredChanges);
226
- // } else {
227
- // this.root.allChanges.set(this, this.allChanges);
228
228
  }
229
229
  if (!this.isFiltered) {
230
230
  this.root.allChanges.set(this, this.allChanges);
@@ -258,14 +258,12 @@ class ChangeTree {
258
258
  this.checkIsFiltered(parent, parentIndex);
259
259
  if (!this.isFiltered) {
260
260
  this.root.changes.set(this, this.changes);
261
+ this.root.allChanges.set(this, this.allChanges);
261
262
  }
262
263
  if (this.isFiltered || this.isPartiallyFiltered) {
263
264
  this.root.filteredChanges.set(this, this.filteredChanges);
264
265
  this.root.allFilteredChanges.set(this, this.filteredChanges);
265
266
  }
266
- else {
267
- this.root.allChanges.set(this, this.allChanges);
268
- }
269
267
  this.ensureRefId();
270
268
  this.forEachChild((changeTree, atIndex) => {
271
269
  changeTree.setParent(this.ref, root, atIndex);
@@ -289,7 +287,7 @@ class ChangeTree {
289
287
  // MapSchema / ArraySchema, etc.
290
288
  this.ref.forEach((value, key) => {
291
289
  if (Metadata.isValidInstance(value)) {
292
- callback(value[$changes], this.ref[$changes].indexes[key]);
290
+ callback(value[$changes], this.ref[$changes].indexes[key] ?? key);
293
291
  }
294
292
  });
295
293
  }
@@ -317,8 +315,9 @@ class ChangeTree {
317
315
  // TODO: are DELETE operations being encoded as ADD here ??
318
316
  //
319
317
  if (isFiltered) {
320
- this.allFilteredChanges.set(index, OPERATION.ADD);
321
318
  this.root?.filteredChanges.set(this, this.filteredChanges);
319
+ this.allFilteredChanges.set(index, OPERATION.ADD);
320
+ this.root?.allFilteredChanges.set(this, this.allFilteredChanges);
322
321
  }
323
322
  else {
324
323
  this.allChanges.set(index, OPERATION.ADD);
@@ -357,7 +356,6 @@ class ChangeTree {
357
356
  }
358
357
  _shiftAllChangeIndexes(shiftIndex, startIndex = 0, allChangeSet) {
359
358
  Array.from(allChangeSet.entries()).forEach(([index, op]) => {
360
- // console.log('shiftAllChangeIndexes', index >= startIndex, { index, op, shiftIndex, startIndex })
361
359
  if (index >= startIndex) {
362
360
  allChangeSet.delete(index);
363
361
  allChangeSet.set(index + shiftIndex, op);
@@ -498,16 +496,31 @@ class ChangeTree {
498
496
  }
499
497
  checkIsFiltered(parent, parentIndex) {
500
498
  // Detect if current structure has "filters" declared
501
- this.isPartiallyFiltered = this.ref['constructor']?.[Symbol.metadata]?.[-2];
502
- // TODO: support "partially filtered", where the instance is visible, but only a field is not.
503
- // Detect if parent has "filters" declared
504
- while (parent && !this.isFiltered) {
505
- const metadata = parent['constructor'][Symbol.metadata];
506
- const fieldName = metadata?.[parentIndex];
507
- const isParentOwned = metadata?.[fieldName]?.tag !== undefined;
508
- this.isFiltered = isParentOwned || parent[$changes].isFiltered; // metadata?.[-2]
509
- parent = parent[$changes].parent;
510
- }
499
+ this.isPartiallyFiltered = (this.ref['constructor']?.[Symbol.metadata]?.[-2] !== undefined);
500
+ if (parent && !Metadata.isValidInstance(parent)) {
501
+ const parentChangeTree = parent[$changes];
502
+ parent = parentChangeTree.parent;
503
+ parentIndex = parentChangeTree.parentIndex;
504
+ }
505
+ const parentMetadata = parent?.['constructor']?.[Symbol.metadata];
506
+ this.isFiltered = (parent &&
507
+ parentMetadata?.[-2]?.includes(parentIndex));
508
+ // this.isFiltered = this.ref['constructor']?.[Symbol.metadata]?.[-4];
509
+ // // Detect if parent has "filters" declared
510
+ // while (parent && !this.isFiltered) {
511
+ // const metadata: Metadata = parent['constructor'][Symbol.metadata];
512
+ // // this.isFiltered = metadata?.[-4];
513
+ // const fieldName = metadata?.[parentIndex];
514
+ // const isParentOwned = metadata?.[fieldName]?.tag !== undefined;
515
+ // this.isFiltered = isParentOwned || parent[$changes].isFiltered; // metadata?.[-2]
516
+ // parent = parent[$changes].parent;
517
+ // };
518
+ // console.log("ChangeTree.checkIsFiltered", {
519
+ // parent: parent?.constructor.name,
520
+ // ref: this.ref.constructor.name,
521
+ // isFiltered: this.isFiltered,
522
+ // isPartiallyFiltered: this.isPartiallyFiltered,
523
+ // });
511
524
  //
512
525
  // TODO: refactor this!
513
526
  //
@@ -559,26 +572,29 @@ try {
559
572
  textEncoder = new TextEncoder();
560
573
  }
561
574
  catch (e) { }
562
- function utf8Length(str) {
563
- var c = 0, length = 0;
564
- for (var i = 0, l = str.length; i < l; i++) {
565
- c = str.charCodeAt(i);
566
- if (c < 0x80) {
567
- length += 1;
568
- }
569
- else if (c < 0x800) {
570
- length += 2;
571
- }
572
- else if (c < 0xd800 || c >= 0xe000) {
573
- length += 3;
574
- }
575
- else {
576
- i++;
577
- length += 4;
575
+ const hasBufferByteLength = (typeof Buffer !== 'undefined' && Buffer.byteLength);
576
+ const utf8Length = (hasBufferByteLength)
577
+ ? Buffer.byteLength // node
578
+ : function (str, _) {
579
+ var c = 0, length = 0;
580
+ for (var i = 0, l = str.length; i < l; i++) {
581
+ c = str.charCodeAt(i);
582
+ if (c < 0x80) {
583
+ length += 1;
584
+ }
585
+ else if (c < 0x800) {
586
+ length += 2;
587
+ }
588
+ else if (c < 0xd800 || c >= 0xe000) {
589
+ length += 3;
590
+ }
591
+ else {
592
+ i++;
593
+ length += 4;
594
+ }
578
595
  }
579
- }
580
- return length;
581
- }
596
+ return length;
597
+ };
582
598
  function utf8Write(view, str, it) {
583
599
  var c = 0;
584
600
  for (var i = 0, l = str.length; i < l; i++) {
@@ -673,8 +689,7 @@ function string$1(bytes, value, it) {
673
689
  if (!value) {
674
690
  value = "";
675
691
  }
676
- // let length = utf8Length(value);
677
- let length = Buffer.byteLength(value, "utf8");
692
+ let length = utf8Length(value, "utf8");
678
693
  let size = 0;
679
694
  // fixstr
680
695
  if (length < 0x20) {
@@ -785,23 +800,23 @@ function number$1(bytes, value, it) {
785
800
 
786
801
  var encode = /*#__PURE__*/Object.freeze({
787
802
  __proto__: null,
788
- utf8Length: utf8Length,
789
- utf8Write: utf8Write,
790
- int8: int8$1,
791
- uint8: uint8$1,
803
+ boolean: boolean$1,
804
+ float32: float32$1,
805
+ float64: float64$1,
792
806
  int16: int16$1,
793
- uint16: uint16$1,
794
807
  int32: int32$1,
795
- uint32: uint32$1,
796
808
  int64: int64$1,
809
+ int8: int8$1,
810
+ number: number$1,
811
+ string: string$1,
812
+ uint16: uint16$1,
813
+ uint32: uint32$1,
797
814
  uint64: uint64$1,
798
- float32: float32$1,
799
- float64: float64$1,
815
+ uint8: uint8$1,
816
+ utf8Length: utf8Length,
817
+ utf8Write: utf8Write,
800
818
  writeFloat32: writeFloat32,
801
- writeFloat64: writeFloat64,
802
- boolean: boolean$1,
803
- string: string$1,
804
- number: number$1
819
+ writeFloat64: writeFloat64
805
820
  });
806
821
 
807
822
  class EncodeSchemaError extends Error {
@@ -943,6 +958,18 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, field, ope
943
958
  }
944
959
  const type = changeTree.getType(field);
945
960
  const value = changeTree.getValue(field);
961
+ // try { throw new Error(); } catch (e) {
962
+ // // only print if not coming from Reflection.ts
963
+ // if (!e.stack.includes("src/Reflection.ts")) {
964
+ // console.log("encodeKeyValueOperation -> ", {
965
+ // ref: changeTree.ref.constructor.name,
966
+ // field,
967
+ // operation: OPERATION[operation],
968
+ // value: value?.toJSON(),
969
+ // items: ref.toJSON(),
970
+ // });
971
+ // }
972
+ // }
946
973
  // TODO: inline this function call small performance gain
947
974
  encodeValue(encoder, bytes, ref, type, value, field, operation, it);
948
975
  };
@@ -952,15 +979,19 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, field, ope
952
979
  */
953
980
  const encodeArray = function (encoder, bytes, changeTree, field, operation, it, isEncodeAll, hasView) {
954
981
  const ref = changeTree.ref;
955
- if (hasView &&
956
- operation === OPERATION.DELETE &&
957
- typeof (changeTree.getType(field)) !== "string") {
958
- // encode delete by refId (array of schemas)
959
- bytes[it.offset++] = OPERATION.DELETE_BY_REFID;
960
- const value = ref['tmpItems'][field];
961
- const refId = value[$changes].refId;
962
- number$1(bytes, refId, it);
963
- return;
982
+ const useOperationByRefId = hasView && changeTree.isFiltered && (typeof (changeTree.getType(field)) !== "string");
983
+ let refOrIndex;
984
+ if (useOperationByRefId) {
985
+ refOrIndex = ref['tmpItems'][field][$changes].refId;
986
+ if (operation === OPERATION.DELETE) {
987
+ operation = OPERATION.DELETE_BY_REFID;
988
+ }
989
+ else if (operation === OPERATION.ADD) {
990
+ operation = OPERATION.ADD_BY_REFID;
991
+ }
992
+ }
993
+ else {
994
+ refOrIndex = field;
964
995
  }
965
996
  // encode operation
966
997
  bytes[it.offset++] = operation & 255;
@@ -969,7 +1000,7 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
969
1000
  return;
970
1001
  }
971
1002
  // encode index
972
- number$1(bytes, field, it);
1003
+ number$1(bytes, refOrIndex, it);
973
1004
  // Do not encode value for DELETE operations
974
1005
  if (operation === OPERATION.DELETE) {
975
1006
  return;
@@ -1010,7 +1041,6 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
1010
1041
  * SOFTWARE
1011
1042
  */
1012
1043
  function utf8Read(bytes, it, length) {
1013
- it.offset += length;
1014
1044
  var string = '', chr = 0;
1015
1045
  for (var i = it.offset, end = it.offset + length; i < end; i++) {
1016
1046
  var byte = bytes[i];
@@ -1047,6 +1077,7 @@ function utf8Read(bytes, it, length) {
1047
1077
  // (do not throw error to avoid server/client from crashing due to hack attemps)
1048
1078
  // throw new Error('Invalid byte ' + byte.toString(16));
1049
1079
  }
1080
+ it.offset += length;
1050
1081
  return string;
1051
1082
  }
1052
1083
  function int8(bytes, it) {
@@ -1218,31 +1249,31 @@ function switchStructureCheck(bytes, it) {
1218
1249
 
1219
1250
  var decode = /*#__PURE__*/Object.freeze({
1220
1251
  __proto__: null,
1221
- utf8Read: utf8Read,
1222
- int8: int8,
1223
- uint8: uint8,
1224
- int16: int16,
1225
- uint16: uint16,
1226
- int32: int32,
1227
- uint32: uint32,
1252
+ arrayCheck: arrayCheck,
1253
+ boolean: boolean,
1228
1254
  float32: float32,
1229
1255
  float64: float64,
1256
+ int16: int16,
1257
+ int32: int32,
1230
1258
  int64: int64,
1231
- uint64: uint64,
1259
+ int8: int8,
1260
+ number: number,
1261
+ numberCheck: numberCheck,
1232
1262
  readFloat32: readFloat32,
1233
1263
  readFloat64: readFloat64,
1234
- boolean: boolean,
1235
1264
  string: string,
1236
1265
  stringCheck: stringCheck,
1237
- number: number,
1238
- numberCheck: numberCheck,
1239
- arrayCheck: arrayCheck,
1240
- switchStructureCheck: switchStructureCheck
1266
+ switchStructureCheck: switchStructureCheck,
1267
+ uint16: uint16,
1268
+ uint32: uint32,
1269
+ uint64: uint64,
1270
+ uint8: uint8,
1271
+ utf8Read: utf8Read
1241
1272
  });
1242
1273
 
1243
1274
  const DEFINITION_MISMATCH = -1;
1244
1275
  function decodeValue(decoder, operation, ref, index, type, bytes, it, allChanges) {
1245
- const $root = decoder.$root;
1276
+ const $root = decoder.root;
1246
1277
  const previousValue = ref[$getByIndex](index);
1247
1278
  let value;
1248
1279
  if ((operation & OPERATION.DELETE) === OPERATION.DELETE) {
@@ -1348,6 +1379,7 @@ const decodeSchemaOperation = function (decoder, bytes, it, ref, allChanges) {
1348
1379
  // skip early if field is not defined
1349
1380
  const field = metadata[index];
1350
1381
  if (field === undefined) {
1382
+ console.warn("@colyseus/schema: field not defined at", { index, ref: ref.constructor.name, metadata });
1351
1383
  return DEFINITION_MISMATCH;
1352
1384
  }
1353
1385
  const { value, previousValue } = decodeValue(decoder, operation, ref, index, metadata[field].type, bytes, it, allChanges);
@@ -1428,7 +1460,8 @@ const decodeKeyValueOperation = function (decoder, bytes, it, ref, allChanges) {
1428
1460
  };
1429
1461
  const decodeArray = function (decoder, bytes, it, ref, allChanges) {
1430
1462
  // "uncompressed" index + operation (array/map items)
1431
- const operation = bytes[it.offset++];
1463
+ let operation = bytes[it.offset++];
1464
+ let index;
1432
1465
  if (operation === OPERATION.CLEAR) {
1433
1466
  //
1434
1467
  // When decoding:
@@ -1442,8 +1475,8 @@ const decodeArray = function (decoder, bytes, it, ref, allChanges) {
1442
1475
  else if (operation === OPERATION.DELETE_BY_REFID) {
1443
1476
  // TODO: refactor here, try to follow same flow as below
1444
1477
  const refId = number(bytes, it);
1445
- const previousValue = decoder.$root.refs.get(refId);
1446
- const index = ref.findIndex((value) => value === previousValue);
1478
+ const previousValue = decoder.root.refs.get(refId);
1479
+ index = ref.findIndex((value) => value === previousValue);
1447
1480
  ref[$deleteByIndex](index);
1448
1481
  allChanges.push({
1449
1482
  ref,
@@ -1456,7 +1489,18 @@ const decodeArray = function (decoder, bytes, it, ref, allChanges) {
1456
1489
  });
1457
1490
  return;
1458
1491
  }
1459
- const index = number(bytes, it);
1492
+ else if (operation === OPERATION.ADD_BY_REFID) {
1493
+ // operation = OPERATION.ADD;
1494
+ const refId = number(bytes, it);
1495
+ const itemByRefId = decoder.root.refs.get(refId);
1496
+ // use existing index, or push new value
1497
+ index = (itemByRefId)
1498
+ ? ref.findIndex((value) => value === itemByRefId)
1499
+ : ref.length;
1500
+ }
1501
+ else {
1502
+ index = number(bytes, it);
1503
+ }
1460
1504
  const type = ref[$childType];
1461
1505
  let dynamicIndex = index;
1462
1506
  const { value, previousValue } = decodeValue(decoder, operation, ref, index, type, bytes, it, allChanges);
@@ -1617,7 +1661,6 @@ class ArraySchema {
1617
1661
  }
1618
1662
  const changeTree = this[$changes];
1619
1663
  changeTree.indexedOperation(length, OPERATION.ADD, this.items.length);
1620
- // changeTree.indexes[length] = length;
1621
1664
  this.items.push(value);
1622
1665
  this.tmpItems.push(value);
1623
1666
  //
@@ -1865,14 +1908,6 @@ class ArraySchema {
1865
1908
  lastIndexOf(searchElement, fromIndex = this.length - 1) {
1866
1909
  return this.items.lastIndexOf(searchElement, fromIndex);
1867
1910
  }
1868
- /**
1869
- * Determines whether all the members of an array satisfy the specified test.
1870
- * @param callbackfn A function that accepts up to three arguments. The every method calls
1871
- * the callbackfn function for each element in the array until the callbackfn returns a value
1872
- * which is coercible to the Boolean value false, or until the end of the array.
1873
- * @param thisArg An object to which the this keyword can refer in the callbackfn function.
1874
- * If thisArg is omitted, undefined is used as the this value.
1875
- */
1876
1911
  every(callbackfn, thisArg) {
1877
1912
  return this.items.every(callbackfn, thisArg);
1878
1913
  }
@@ -2316,7 +2351,6 @@ class MapSchema {
2316
2351
  }
2317
2352
  registerType("map", { constructor: MapSchema });
2318
2353
 
2319
- const DEFAULT_VIEW_TAG = -1;
2320
2354
  class TypeContext {
2321
2355
  /**
2322
2356
  * For inheritance support
@@ -2338,6 +2372,7 @@ class TypeContext {
2338
2372
  this.types = {};
2339
2373
  this.schemas = new Map();
2340
2374
  this.hasFilters = false;
2375
+ this.parentFiltered = {};
2341
2376
  if (rootClass) {
2342
2377
  this.discoverTypes(rootClass);
2343
2378
  }
@@ -2354,32 +2389,46 @@ class TypeContext {
2354
2389
  return false;
2355
2390
  }
2356
2391
  this.types[typeid] = schema;
2392
+ //
2393
+ // Workaround to allow using an empty Schema (with no `@type()` fields)
2394
+ //
2395
+ if (schema[Symbol.metadata] === undefined) {
2396
+ Metadata.init(schema);
2397
+ }
2357
2398
  this.schemas.set(schema, typeid);
2358
2399
  return true;
2359
2400
  }
2360
2401
  getTypeId(klass) {
2361
2402
  return this.schemas.get(klass);
2362
2403
  }
2363
- discoverTypes(klass) {
2404
+ discoverTypes(klass, parentIndex, parentFieldViewTag) {
2364
2405
  if (!this.add(klass)) {
2365
2406
  return;
2366
2407
  }
2367
2408
  // add classes inherited from this base class
2368
2409
  TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
2369
- this.discoverTypes(child);
2410
+ this.discoverTypes(child, parentIndex, parentFieldViewTag);
2370
2411
  });
2371
- // skip if no fields are defined for this class.
2372
- if (klass[Symbol.metadata] === undefined) {
2373
- klass[Symbol.metadata] = {};
2374
- }
2375
- // const metadata = Metadata.getFor(klass);
2376
- const metadata = klass[Symbol.metadata];
2412
+ const metadata = (klass[Symbol.metadata] ??= {});
2377
2413
  // if any schema/field has filters, mark "context" as having filters.
2378
2414
  if (metadata[-2]) {
2379
2415
  this.hasFilters = true;
2380
2416
  }
2417
+ if (parentFieldViewTag !== undefined) {
2418
+ this.parentFiltered[`${this.schemas.get(klass)}-${parentIndex}`] = true;
2419
+ }
2381
2420
  for (const field in metadata) {
2421
+ // //
2422
+ // // Modify the field's metadata to include the parent field's view tag
2423
+ // //
2424
+ // if (
2425
+ // parentFieldViewTag !== undefined &&
2426
+ // metadata[field].tag === undefined
2427
+ // ) {
2428
+ // metadata[field].tag = parentFieldViewTag;
2429
+ // }
2382
2430
  const fieldType = metadata[field].type;
2431
+ const viewTag = metadata[field].tag;
2383
2432
  if (typeof (fieldType) === "string") {
2384
2433
  continue;
2385
2434
  }
@@ -2388,10 +2437,10 @@ class TypeContext {
2388
2437
  if (type === "string") {
2389
2438
  continue;
2390
2439
  }
2391
- this.discoverTypes(type);
2440
+ this.discoverTypes(type, metadata[field].index, viewTag);
2392
2441
  }
2393
2442
  else if (typeof (fieldType) === "function") {
2394
- this.discoverTypes(fieldType);
2443
+ this.discoverTypes(fieldType, viewTag);
2395
2444
  }
2396
2445
  else {
2397
2446
  const type = Object.values(fieldType)[0];
@@ -2399,11 +2448,13 @@ class TypeContext {
2399
2448
  if (typeof (type) === "string") {
2400
2449
  continue;
2401
2450
  }
2402
- this.discoverTypes(type);
2451
+ this.discoverTypes(type, metadata[field].index, viewTag);
2403
2452
  }
2404
2453
  }
2405
2454
  }
2406
2455
  }
2456
+
2457
+ const DEFAULT_VIEW_TAG = -1;
2407
2458
  /**
2408
2459
  * [See documentation](https://docs.colyseus.io/state/schema/)
2409
2460
  *
@@ -2551,6 +2602,7 @@ function view(tag = DEFAULT_VIEW_TAG) {
2551
2602
  const constructor = target.constructor;
2552
2603
  const parentClass = Object.getPrototypeOf(constructor);
2553
2604
  const parentMetadata = parentClass[Symbol.metadata];
2605
+ // TODO: use Metadata.initialize()
2554
2606
  const metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
2555
2607
  if (!metadata[fieldName]) {
2556
2608
  //
@@ -2575,8 +2627,8 @@ function type(type, options) {
2575
2627
  // for inheritance support
2576
2628
  TypeContext.register(constructor);
2577
2629
  const parentClass = Object.getPrototypeOf(constructor);
2578
- const parentMetadata = parentClass[Symbol.metadata];
2579
- const metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
2630
+ const parentMetadata = parentClass && parentClass[Symbol.metadata];
2631
+ const metadata = Metadata.initialize(constructor, parentMetadata);
2580
2632
  let fieldIndex;
2581
2633
  /**
2582
2634
  * skip if descriptor already exists for this field (`@deprecated()`)
@@ -2957,13 +3009,13 @@ class Schema {
2957
3009
  }
2958
3010
  return output;
2959
3011
  }
2960
- static debugChangesDeep(ref) {
3012
+ static debugChangesDeep(ref, changeSetName = "changes") {
2961
3013
  let output = "";
2962
3014
  const rootChangeTree = ref[$changes];
2963
3015
  const changeTrees = new Map();
2964
3016
  let totalInstances = 0;
2965
3017
  let totalOperations = 0;
2966
- for (const [changeTree, changes] of (rootChangeTree.root.changes.entries())) {
3018
+ for (const [changeTree, changes] of (rootChangeTree.root[changeSetName].entries())) {
2967
3019
  let includeChangeTree = false;
2968
3020
  let parentChangeTrees = [];
2969
3021
  let parentChangeTree = changeTree.parent?.[$changes];
@@ -3349,6 +3401,8 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
3349
3401
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
3350
3402
  PERFORMANCE OF THIS SOFTWARE.
3351
3403
  ***************************************************************************** */
3404
+ /* global Reflect, Promise, SuppressedError, Symbol */
3405
+
3352
3406
 
3353
3407
  function __decorate(decorators, target, key, desc) {
3354
3408
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -3362,29 +3416,68 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
3362
3416
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
3363
3417
  };
3364
3418
 
3419
+ class Root {
3420
+ constructor(types) {
3421
+ this.types = types;
3422
+ this.nextUniqueId = 0;
3423
+ this.refCount = new WeakMap();
3424
+ // all changes
3425
+ this.allChanges = new Map();
3426
+ this.allFilteredChanges = new Map();
3427
+ // pending changes to be encoded
3428
+ this.changes = new Map();
3429
+ this.filteredChanges = new Map();
3430
+ }
3431
+ getNextUniqueId() {
3432
+ return this.nextUniqueId++;
3433
+ }
3434
+ add(changeTree) {
3435
+ const refCount = this.refCount.get(changeTree) || 0;
3436
+ this.refCount.set(changeTree, refCount + 1);
3437
+ }
3438
+ remove(changeTree) {
3439
+ const refCount = this.refCount.get(changeTree);
3440
+ if (refCount <= 1) {
3441
+ this.allChanges.delete(changeTree);
3442
+ this.changes.delete(changeTree);
3443
+ if (changeTree.isFiltered || changeTree.isPartiallyFiltered) {
3444
+ this.allFilteredChanges.delete(changeTree);
3445
+ this.filteredChanges.delete(changeTree);
3446
+ }
3447
+ this.refCount.delete(changeTree);
3448
+ }
3449
+ else {
3450
+ this.refCount.set(changeTree, refCount - 1);
3451
+ }
3452
+ changeTree.forEachChild((child, _) => this.remove(child));
3453
+ }
3454
+ clear() {
3455
+ this.changes.clear();
3456
+ }
3457
+ }
3458
+
3365
3459
  class Encoder {
3366
3460
  static { this.BUFFER_SIZE = 8 * 1024; } // 8KB
3367
- constructor(root) {
3461
+ constructor(state) {
3368
3462
  this.sharedBuffer = Buffer.allocUnsafeSlow(Encoder.BUFFER_SIZE);
3369
- this.setRoot(root);
3370
3463
  //
3371
3464
  // TODO: cache and restore "Context" based on root schema
3372
3465
  // (to avoid creating a new context for every new room)
3373
3466
  //
3374
- this.context = new TypeContext(root.constructor);
3467
+ this.context = new TypeContext(state.constructor);
3468
+ this.root = new Root(this.context);
3469
+ this.setState(state);
3375
3470
  // console.log(">>>>>>>>>>>>>>>> Encoder types");
3376
3471
  // this.context.schemas.forEach((id, schema) => {
3377
3472
  // console.log("type:", id, schema.name, Object.keys(schema[Symbol.metadata]));
3378
3473
  // });
3379
3474
  }
3380
- setRoot(state) {
3381
- this.root = new Root();
3475
+ setState(state) {
3382
3476
  this.state = state;
3383
- state[$changes].setRoot(this.root);
3477
+ this.state[$changes].setRoot(this.root);
3384
3478
  }
3385
- encode(it = { offset: 0 }, view, bytes = this.sharedBuffer, changeTrees = this.root.changes) {
3386
- const initialOffset = it.offset; // cache current offset in case we need to resize the buffer
3387
- const isEncodeAll = this.root.allChanges === changeTrees;
3479
+ encode(it = { offset: 0 }, view, buffer = this.sharedBuffer, changeTrees = this.root.changes, isEncodeAll = this.root.allChanges === changeTrees, initialOffset = it.offset // cache current offset in case we need to resize the buffer
3480
+ ) {
3388
3481
  const hasView = (view !== undefined);
3389
3482
  const rootChangeTree = this.state[$changes];
3390
3483
  const changeTreesIterator = changeTrees.entries();
@@ -3393,6 +3486,12 @@ class Encoder {
3393
3486
  const ctor = ref['constructor'];
3394
3487
  const encoder = ctor[$encoder];
3395
3488
  const filter = ctor[$filter];
3489
+ // try { throw new Error(); } catch (e) {
3490
+ // // only print if not coming from Reflection.ts
3491
+ // if (!e.stack.includes("src/Reflection.ts")) {
3492
+ // console.log("ChangeTree:", { ref: ref.constructor.name, });
3493
+ // }
3494
+ // }
3396
3495
  if (hasView) {
3397
3496
  if (!view.items.has(changeTree)) {
3398
3497
  view.invisible.add(changeTree);
@@ -3403,9 +3502,10 @@ class Encoder {
3403
3502
  }
3404
3503
  }
3405
3504
  // skip root `refId` if it's the first change tree
3406
- if (it.offset !== initialOffset || changeTree !== rootChangeTree) {
3407
- bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;
3408
- number$1(bytes, changeTree.refId, it);
3505
+ // (unless it "hasView", which will need to revisit the root)
3506
+ if (hasView || it.offset > initialOffset || changeTree !== rootChangeTree) {
3507
+ buffer[it.offset++] = SWITCH_TO_STRUCTURE & 255;
3508
+ number$1(buffer, changeTree.refId, it);
3409
3509
  }
3410
3510
  const changesIterator = changes.entries();
3411
3511
  for (const [fieldIndex, operation] of changesIterator) {
@@ -3417,27 +3517,39 @@ class Encoder {
3417
3517
  // TODO: avoid checking if no view tags were defined
3418
3518
  //
3419
3519
  if (filter && !filter(ref, fieldIndex, view)) {
3420
- // console.log("SKIP FIELD:", { ref: changeTree.ref.constructor.name, fieldIndex, })
3421
3520
  // console.log("ADD AS INVISIBLE:", fieldIndex, changeTree.ref.constructor.name)
3422
3521
  // view?.invisible.add(changeTree);
3423
3522
  continue;
3424
3523
  }
3425
- // console.log("WILL ENCODE", {
3426
- // ref: changeTree.ref.constructor.name,
3427
- // fieldIndex,
3428
- // operation: OPERATION[operation],
3429
- // });
3430
- encoder(this, bytes, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
3524
+ // try { throw new Error(); } catch (e) {
3525
+ // // only print if not coming from Reflection.ts
3526
+ // if (!e.stack.includes("src/Reflection.ts")) {
3527
+ // console.log("WILL ENCODE", {
3528
+ // ref: changeTree.ref.constructor.name,
3529
+ // fieldIndex,
3530
+ // operation: OPERATION[operation],
3531
+ // });
3532
+ // }
3533
+ // }
3534
+ encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
3431
3535
  }
3432
3536
  }
3433
- if (it.offset > bytes.byteLength) {
3434
- const newSize = getNextPowerOf2(this.sharedBuffer.byteLength * 2);
3435
- console.warn("@colyseus/schema encode buffer overflow. Current buffer size: " + bytes.byteLength + ", encoding offset: " + it.offset + ", new size: " + newSize);
3537
+ if (it.offset > buffer.byteLength) {
3538
+ const newSize = getNextPowerOf2(buffer.byteLength * 2);
3539
+ console.warn(`@colyseus/schema buffer overflow. Encoded state is higher than default BUFFER_SIZE. Use the following to increase default BUFFER_SIZE:
3540
+
3541
+ import { Encoder } from "@colyseus/schema";
3542
+ Encoder.BUFFER_SIZE = ${Math.round(newSize / 1024)} * 1024; // ${Math.round(newSize / 1024)} KB
3543
+ `);
3436
3544
  //
3437
3545
  // resize buffer and re-encode (TODO: can we avoid re-encoding here?)
3438
3546
  //
3439
- this.sharedBuffer = Buffer.allocUnsafeSlow(newSize);
3440
- return this.encode({ offset: initialOffset }, view);
3547
+ buffer = Buffer.allocUnsafeSlow(newSize);
3548
+ // assign resized buffer to local sharedBuffer
3549
+ if (buffer === this.sharedBuffer) {
3550
+ this.sharedBuffer = buffer;
3551
+ }
3552
+ return this.encode({ offset: initialOffset }, view, buffer, changeTrees, isEncodeAll);
3441
3553
  }
3442
3554
  else {
3443
3555
  //
@@ -3449,42 +3561,47 @@ class Encoder {
3449
3561
  //
3450
3562
  this.onEndEncode(changeTrees);
3451
3563
  }
3452
- // return bytes;
3453
- return bytes.slice(0, it.offset);
3564
+ return buffer.subarray(0, it.offset);
3454
3565
  }
3455
3566
  }
3456
- encodeAll(it = { offset: 0 }) {
3457
- // console.log(`encodeAll(), this.$root.allChanges (${this.$root.allChanges.size})`);
3458
- // Array.from(this.$root.allChanges.entries()).map((item) => {
3459
- // console.log("->", item[0].refId, item[0].ref.toJSON());
3460
- // });
3461
- return this.encode(it, undefined, this.sharedBuffer, this.root.allChanges);
3567
+ encodeAll(it = { offset: 0 }, buffer = this.sharedBuffer) {
3568
+ // console.log(`\nencodeAll(), this.root.allChanges (${this.root.allChanges.size})`);
3569
+ // this.debugChanges("allChanges");
3570
+ return this.encode(it, undefined, buffer, this.root.allChanges, true);
3462
3571
  }
3463
3572
  encodeAllView(view, sharedOffset, it, bytes = this.sharedBuffer) {
3464
3573
  const viewOffset = it.offset;
3465
- // console.log(`encodeAllView(), this.$root.allFilteredChanges (${this.$root.allFilteredChanges.size})`);
3466
- // this.debugAllFilteredChanges();
3574
+ // console.log(`\nencodeAllView(), this.root.allFilteredChanges (${this.root.allFilteredChanges.size})`);
3575
+ // this.debugChanges("allFilteredChanges");
3467
3576
  // try to encode "filtered" changes
3468
- this.encode(it, view, bytes, this.root.allFilteredChanges);
3577
+ this.encode(it, view, bytes, this.root.allFilteredChanges, true, viewOffset);
3469
3578
  return Buffer.concat([
3470
- bytes.slice(0, sharedOffset),
3471
- bytes.slice(viewOffset, it.offset)
3579
+ bytes.subarray(0, sharedOffset),
3580
+ bytes.subarray(viewOffset, it.offset)
3472
3581
  ]);
3473
3582
  }
3474
- // debugAllFilteredChanges() {
3475
- // Array.from(this.$root.allFilteredChanges.entries()).map((item) => {
3476
- // console.log("->", { refId: item[0].refId }, item[0].ref.toJSON());
3477
- // if (Array.isArray(item[0].ref.toJSON())) {
3478
- // item[1].forEach((op, key) => {
3479
- // console.log(" ->", { key, op: OPERATION[op] });
3480
- // })
3481
- // }
3482
- // });
3483
- // }
3583
+ debugChanges(field) {
3584
+ const changeSet = (typeof (field) === "string")
3585
+ ? this.root[field]
3586
+ : field;
3587
+ Array.from(changeSet.entries()).map((item) => {
3588
+ const metadata = item[0].ref.constructor[Symbol.metadata];
3589
+ console.log("->", { ref: item[0].ref.constructor.name, refId: item[0].refId, changes: item[1].size });
3590
+ item[1].forEach((op, index) => {
3591
+ console.log(" ->", {
3592
+ index,
3593
+ field: metadata?.[index],
3594
+ op: OPERATION[op],
3595
+ });
3596
+ });
3597
+ });
3598
+ }
3484
3599
  encodeView(view, sharedOffset, it, bytes = this.sharedBuffer) {
3485
3600
  const viewOffset = it.offset;
3486
- // try to encode "filtered" changes
3487
- this.encode(it, view, bytes, this.root.filteredChanges);
3601
+ // console.log(`\nencodeView(), view.changes (${view.changes.size})`);
3602
+ // this.debugChanges(view.changes);
3603
+ // console.log(`\nencodeView(), this.root.filteredChanges (${this.root.filteredChanges.size})`);
3604
+ // this.debugChanges("filteredChanges");
3488
3605
  // encode visibility changes (add/remove for this view)
3489
3606
  const viewChangesIterator = view.changes.entries();
3490
3607
  for (const [changeTree, changes] of viewChangesIterator) {
@@ -3511,9 +3628,11 @@ class Encoder {
3511
3628
  //
3512
3629
  // clear "view" changes after encoding
3513
3630
  view.changes.clear();
3631
+ // try to encode "filtered" changes
3632
+ this.encode(it, view, bytes, this.root.filteredChanges, false, viewOffset);
3514
3633
  return Buffer.concat([
3515
- bytes.slice(0, sharedOffset),
3516
- bytes.slice(viewOffset, it.offset)
3634
+ bytes.subarray(0, sharedOffset),
3635
+ bytes.subarray(viewOffset, it.offset)
3517
3636
  ]);
3518
3637
  }
3519
3638
  onEndEncode(changeTrees = this.root.changes) {
@@ -3683,21 +3802,21 @@ class ReferenceTracker {
3683
3802
  class Decoder {
3684
3803
  constructor(root, context) {
3685
3804
  this.currentRefId = 0;
3686
- this.setRoot(root);
3805
+ this.setState(root);
3687
3806
  this.context = context || new TypeContext(root.constructor);
3688
3807
  // console.log(">>>>>>>>>>>>>>>> Decoder types");
3689
3808
  // this.context.schemas.forEach((id, schema) => {
3690
3809
  // console.log("type:", id, schema.name, Object.keys(schema[Symbol.metadata]));
3691
3810
  // });
3692
3811
  }
3693
- setRoot(root) {
3812
+ setState(root) {
3694
3813
  this.state = root;
3695
- this.$root = new ReferenceTracker();
3696
- this.$root.addRef(0, root);
3814
+ this.root = new ReferenceTracker();
3815
+ this.root.addRef(0, root);
3697
3816
  }
3698
3817
  decode(bytes, it = { offset: 0 }, ref = this.state) {
3699
3818
  const allChanges = [];
3700
- const $root = this.$root;
3819
+ const $root = this.root;
3701
3820
  const totalBytes = bytes.byteLength;
3702
3821
  let decoder = ref['constructor'][$decoder];
3703
3822
  this.currentRefId = 0;
@@ -3778,7 +3897,7 @@ class Decoder {
3778
3897
  previousValue: value
3779
3898
  });
3780
3899
  if (needRemoveRef) {
3781
- this.$root.removeRef(this.$root.refIds.get(value));
3900
+ this.root.removeRef(this.root.refIds.get(value));
3782
3901
  }
3783
3902
  });
3784
3903
  }
@@ -3818,10 +3937,8 @@ class Reflection extends Schema {
3818
3937
  super(...arguments);
3819
3938
  this.types = new ArraySchema();
3820
3939
  }
3821
- static encode(instance, context) {
3822
- if (!context) {
3823
- context = new TypeContext(instance.constructor);
3824
- }
3940
+ static encode(instance, context, it = { offset: 0 }) {
3941
+ context ??= new TypeContext(instance.constructor);
3825
3942
  const reflection = new Reflection();
3826
3943
  const encoder = new Encoder(reflection);
3827
3944
  const buildType = (currentType, metadata) => {
@@ -3875,7 +3992,6 @@ class Reflection extends Schema {
3875
3992
  }
3876
3993
  buildType(type, klass[Symbol.metadata]);
3877
3994
  }
3878
- const it = { offset: 0 };
3879
3995
  const buf = encoder.encodeAll(it);
3880
3996
  return Buffer.from(buf, 0, it.offset);
3881
3997
  }
@@ -3883,59 +3999,314 @@ class Reflection extends Schema {
3883
3999
  const reflection = new Reflection();
3884
4000
  const reflectionDecoder = new Decoder(reflection);
3885
4001
  reflectionDecoder.decode(bytes, it);
3886
- const context = new TypeContext();
3887
- const schemaTypes = reflection.types.reduce((types, reflectionType) => {
3888
- const parentKlass = types[reflectionType.extendsId] || Schema;
3889
- const schema = class _ extends parentKlass {
4002
+ const typeContext = new TypeContext();
4003
+ // 1st pass, initialize metadata + inheritance
4004
+ reflection.types.forEach((reflectionType) => {
4005
+ const parentClass = typeContext.get(reflectionType.extendsId) ?? Schema;
4006
+ const schema = class _ extends parentClass {
3890
4007
  };
3891
- // const _metadata = Object.create(_classSuper[Symbol.metadata] ?? null);
3892
- const _metadata = parentKlass && parentKlass[Symbol.metadata] || Object.create(null);
3893
- Object.defineProperty(schema, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
4008
+ const parentMetadata = parentClass[Symbol.metadata];
3894
4009
  // register for inheritance support
3895
4010
  TypeContext.register(schema);
3896
- const typeid = reflectionType.id;
3897
- types[typeid] = schema;
3898
- context.add(schema, typeid);
3899
- return types;
4011
+ // for inheritance support
4012
+ Metadata.initialize(schema, parentMetadata);
4013
+ typeContext.add(schema, reflectionType.id);
3900
4014
  }, {});
4015
+ // 2nd pass, set fields
3901
4016
  reflection.types.forEach((reflectionType) => {
3902
- const schemaType = schemaTypes[reflectionType.id];
4017
+ const schemaType = typeContext.get(reflectionType.id);
3903
4018
  const metadata = schemaType[Symbol.metadata];
3904
- const parentKlass = reflection.types[reflectionType.extendsId];
3905
- const parentFieldIndex = parentKlass && parentKlass.fields.length || 0;
4019
+ // FIXME: use metadata[-1] to get field count
4020
+ const parentFieldIndex = 0;
4021
+ // console.log("--------------------");
4022
+ // // console.log("reflectionType", reflectionType.toJSON());
4023
+ // console.log("reflectionType.fields", reflectionType.fields.toJSON());
4024
+ // console.log("parentFieldIndex", parentFieldIndex);
4025
+ //
4026
+ // FIXME: set fields using parentKlass as well
4027
+ // currently the fields are duplicated on inherited classes
4028
+ //
4029
+ // // const parentKlass = reflection.types[reflectionType.extendsId];
4030
+ // // parentKlass.fields
3906
4031
  reflectionType.fields.forEach((field, i) => {
3907
4032
  const fieldIndex = parentFieldIndex + i;
3908
4033
  if (field.referencedType !== undefined) {
3909
4034
  let fieldType = field.type;
3910
- let refType = schemaTypes[field.referencedType];
4035
+ let refType = typeContext.get(field.referencedType);
3911
4036
  // map or array of primitive type (-1)
3912
4037
  if (!refType) {
3913
4038
  const typeInfo = field.type.split(":");
3914
4039
  fieldType = typeInfo[0];
3915
- refType = typeInfo[1];
4040
+ refType = typeInfo[1]; // string
3916
4041
  }
3917
4042
  if (fieldType === "ref") {
3918
- // type(refType)(schemaType.prototype, field.name);
3919
4043
  Metadata.addField(metadata, fieldIndex, field.name, refType);
3920
4044
  }
3921
4045
  else {
3922
- // type({ [fieldType]: refType } as DefinitionType)(schemaType.prototype, field.name);
3923
4046
  Metadata.addField(metadata, fieldIndex, field.name, { [fieldType]: refType });
3924
4047
  }
3925
4048
  }
3926
4049
  else {
3927
- // type(field.type as PrimitiveType)(schemaType.prototype, field.name);
3928
4050
  Metadata.addField(metadata, fieldIndex, field.name, field.type);
3929
4051
  }
3930
4052
  });
3931
4053
  });
3932
- return new (schemaTypes[0])();
4054
+ // @ts-ignore
4055
+ return new (typeContext.get(0))();
3933
4056
  }
3934
4057
  }
3935
4058
  __decorate([
3936
4059
  type([ReflectionType])
3937
4060
  ], Reflection.prototype, "types", void 0);
3938
4061
 
4062
+ function getDecoderStateCallbacks(decoder) {
4063
+ const $root = decoder.root;
4064
+ const callbacks = $root.callbacks;
4065
+ const onAddCalls = new WeakMap();
4066
+ let currentOnAddCallback;
4067
+ decoder.triggerChanges = function (allChanges) {
4068
+ const uniqueRefIds = new Set();
4069
+ for (let i = 0, l = allChanges.length; i < l; i++) {
4070
+ const change = allChanges[i];
4071
+ const refId = change.refId;
4072
+ const ref = change.ref;
4073
+ const $callbacks = callbacks[refId];
4074
+ if (!$callbacks) {
4075
+ continue;
4076
+ }
4077
+ //
4078
+ // trigger onRemove on child structure.
4079
+ //
4080
+ if ((change.op & OPERATION.DELETE) === OPERATION.DELETE &&
4081
+ change.previousValue instanceof Schema) {
4082
+ const deleteCallbacks = callbacks[$root.refIds.get(change.previousValue)]?.[OPERATION.DELETE];
4083
+ for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {
4084
+ deleteCallbacks[i]();
4085
+ }
4086
+ }
4087
+ if (ref instanceof Schema) {
4088
+ //
4089
+ // Handle schema instance
4090
+ //
4091
+ if (!uniqueRefIds.has(refId)) {
4092
+ // trigger onChange
4093
+ const replaceCallbacks = $callbacks?.[OPERATION.REPLACE];
4094
+ for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
4095
+ replaceCallbacks[i]();
4096
+ // try {
4097
+ // } catch (e) {
4098
+ // console.error(e);
4099
+ // }
4100
+ }
4101
+ }
4102
+ if ($callbacks.hasOwnProperty(change.field)) {
4103
+ const fieldCallbacks = $callbacks[change.field];
4104
+ for (let i = fieldCallbacks?.length - 1; i >= 0; i--) {
4105
+ fieldCallbacks[i](change.value, change.previousValue);
4106
+ // try {
4107
+ // } catch (e) {
4108
+ // console.error(e);
4109
+ // }
4110
+ }
4111
+ }
4112
+ }
4113
+ else {
4114
+ //
4115
+ // Handle collection of items
4116
+ //
4117
+ if ((change.op & OPERATION.DELETE) === OPERATION.DELETE) {
4118
+ //
4119
+ // FIXME: `previousValue` should always be available.
4120
+ //
4121
+ if (change.previousValue !== undefined) {
4122
+ // triger onRemove
4123
+ const deleteCallbacks = $callbacks[OPERATION.DELETE];
4124
+ for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {
4125
+ deleteCallbacks[i](change.previousValue, change.dynamicIndex ?? change.field);
4126
+ }
4127
+ }
4128
+ // Handle DELETE_AND_ADD operations
4129
+ if ((change.op & OPERATION.ADD) === OPERATION.ADD) {
4130
+ const addCallbacks = $callbacks[OPERATION.ADD];
4131
+ for (let i = addCallbacks?.length - 1; i >= 0; i--) {
4132
+ addCallbacks[i](change.value, change.dynamicIndex ?? change.field);
4133
+ }
4134
+ }
4135
+ }
4136
+ else if ((change.op & OPERATION.ADD) === OPERATION.ADD && change.previousValue === undefined) {
4137
+ // triger onAdd
4138
+ const addCallbacks = $callbacks[OPERATION.ADD];
4139
+ for (let i = addCallbacks?.length - 1; i >= 0; i--) {
4140
+ addCallbacks[i](change.value, change.dynamicIndex ?? change.field);
4141
+ }
4142
+ }
4143
+ // trigger onChange
4144
+ if (change.value !== change.previousValue) {
4145
+ const replaceCallbacks = $callbacks[OPERATION.REPLACE];
4146
+ for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
4147
+ replaceCallbacks[i](change.value, change.dynamicIndex ?? change.field);
4148
+ }
4149
+ }
4150
+ }
4151
+ uniqueRefIds.add(refId);
4152
+ }
4153
+ };
4154
+ function getProxy(metadataOrType, context) {
4155
+ let metadata = context.instance?.constructor[Symbol.metadata] || metadataOrType;
4156
+ let isCollection = ((context.instance && typeof (context.instance['forEach']) === "function") ||
4157
+ (metadataOrType && typeof (metadataOrType[Symbol.metadata]) === "undefined"));
4158
+ if (metadata && !isCollection) {
4159
+ const onAddListen = function (ref, prop, callback, immediate) {
4160
+ // immediate trigger
4161
+ if (immediate &&
4162
+ context.instance[prop] !== undefined &&
4163
+ !onAddCalls.has(currentOnAddCallback) // Workaround for https://github.com/colyseus/schema/issues/147
4164
+ ) {
4165
+ callback(context.instance[prop], undefined);
4166
+ }
4167
+ return $root.addCallback($root.refIds.get(ref), prop, callback);
4168
+ };
4169
+ /**
4170
+ * Schema instances
4171
+ */
4172
+ return new Proxy({
4173
+ listen: function listen(prop, callback, immediate = true) {
4174
+ if (context.instance) {
4175
+ return onAddListen(context.instance, prop, callback, immediate);
4176
+ }
4177
+ else {
4178
+ // collection instance not received yet
4179
+ let detachCallback = () => { };
4180
+ context.onInstanceAvailable((ref, existing) => {
4181
+ detachCallback = onAddListen(ref, prop, callback, immediate && existing && !onAddCalls.has(currentOnAddCallback));
4182
+ });
4183
+ return () => detachCallback();
4184
+ }
4185
+ },
4186
+ onChange: function onChange(callback) {
4187
+ return $root.addCallback($root.refIds.get(context.instance), OPERATION.REPLACE, callback);
4188
+ },
4189
+ //
4190
+ // TODO: refactor `bindTo()` implementation.
4191
+ // There is room for improvement.
4192
+ //
4193
+ bindTo: function bindTo(targetObject, properties) {
4194
+ if (!properties) {
4195
+ properties = Object.keys(metadata);
4196
+ }
4197
+ return $root.addCallback($root.refIds.get(context.instance), OPERATION.REPLACE, () => {
4198
+ properties.forEach((prop) => targetObject[prop] = context.instance[prop]);
4199
+ });
4200
+ }
4201
+ }, {
4202
+ get(target, prop) {
4203
+ if (metadata[prop]) {
4204
+ const instance = context.instance?.[prop];
4205
+ const onInstanceAvailable = ((callback) => {
4206
+ const unbind = $(context.instance).listen(prop, (value, _) => {
4207
+ callback(value, false);
4208
+ // FIXME: by "unbinding" the callback here,
4209
+ // it will not support when the server
4210
+ // re-instantiates the instance.
4211
+ //
4212
+ unbind?.();
4213
+ }, false);
4214
+ // has existing value
4215
+ if ($root.refIds.get(instance) !== undefined) {
4216
+ callback(instance, true);
4217
+ }
4218
+ });
4219
+ return getProxy(metadata[prop].type, {
4220
+ // make sure refId is available, otherwise need to wait for the instance to be available.
4221
+ instance: ($root.refIds.get(instance) && instance),
4222
+ parentInstance: context.instance,
4223
+ onInstanceAvailable,
4224
+ });
4225
+ }
4226
+ else {
4227
+ // accessing the function
4228
+ return target[prop];
4229
+ }
4230
+ },
4231
+ has(target, prop) { return metadata[prop] !== undefined; },
4232
+ set(_, _1, _2) { throw new Error("not allowed"); },
4233
+ deleteProperty(_, _1) { throw new Error("not allowed"); },
4234
+ });
4235
+ }
4236
+ else {
4237
+ /**
4238
+ * Collection instances
4239
+ */
4240
+ const onAdd = function (ref, callback, immediate) {
4241
+ // Trigger callback on existing items
4242
+ if (immediate) {
4243
+ ref.forEach((v, k) => callback(v, k));
4244
+ }
4245
+ return $root.addCallback($root.refIds.get(ref), OPERATION.ADD, (value, key) => {
4246
+ onAddCalls.set(callback, true);
4247
+ currentOnAddCallback = callback;
4248
+ callback(value, key);
4249
+ onAddCalls.delete(callback);
4250
+ currentOnAddCallback = undefined;
4251
+ });
4252
+ };
4253
+ const onRemove = function (ref, callback) {
4254
+ return $root.addCallback($root.refIds.get(ref), OPERATION.DELETE, callback);
4255
+ };
4256
+ return new Proxy({
4257
+ onAdd: function (callback, immediate = true) {
4258
+ //
4259
+ // https://github.com/colyseus/schema/issues/147
4260
+ // If parent instance has "onAdd" registered, avoid triggering immediate callback.
4261
+ //
4262
+ if (context.instance) {
4263
+ return onAdd(context.instance, callback, immediate && !onAddCalls.has(currentOnAddCallback));
4264
+ }
4265
+ else if (context.onInstanceAvailable) {
4266
+ // collection instance not received yet
4267
+ let detachCallback = () => { };
4268
+ context.onInstanceAvailable((ref, existing) => {
4269
+ detachCallback = onAdd(ref, callback, immediate && existing && !onAddCalls.has(currentOnAddCallback));
4270
+ });
4271
+ return () => detachCallback();
4272
+ }
4273
+ },
4274
+ onRemove: function (callback) {
4275
+ if (context.onInstanceAvailable) {
4276
+ // collection instance not received yet
4277
+ let detachCallback = () => { };
4278
+ context.onInstanceAvailable((ref) => {
4279
+ detachCallback = onRemove(ref, callback);
4280
+ });
4281
+ return () => detachCallback();
4282
+ }
4283
+ else if (context.instance) {
4284
+ return onRemove(context.instance, callback);
4285
+ }
4286
+ },
4287
+ }, {
4288
+ get(target, prop) {
4289
+ if (!target[prop]) {
4290
+ throw new Error(`Can't access '${prop}' through callback proxy. access the instance directly.`);
4291
+ }
4292
+ return target[prop];
4293
+ },
4294
+ has(target, prop) { return target[prop] !== undefined; },
4295
+ set(_, _1, _2) { throw new Error("not allowed"); },
4296
+ deleteProperty(_, _1) { throw new Error("not allowed"); },
4297
+ });
4298
+ }
4299
+ }
4300
+ function $(instance) {
4301
+ return getProxy(undefined, { instance });
4302
+ }
4303
+ return $;
4304
+ }
4305
+
4306
+ function getRawChangesCallback(decoder, callback) {
4307
+ decoder.triggerChanges = callback;
4308
+ }
4309
+
3939
4310
  class StateView {
3940
4311
  constructor() {
3941
4312
  /**
@@ -3953,20 +4324,21 @@ class StateView {
3953
4324
  this.changes = new Map();
3954
4325
  }
3955
4326
  // TODO: allow to set multiple tags at once
3956
- add(obj, tag = DEFAULT_VIEW_TAG) {
4327
+ add(obj, tag = DEFAULT_VIEW_TAG, checkIncludeParent = true) {
3957
4328
  if (!obj[$changes]) {
3958
4329
  console.warn("StateView#add(), invalid object:", obj);
3959
4330
  return this;
3960
4331
  }
3961
- let changeTree = obj[$changes];
3962
- this.items.add(changeTree);
3963
- // Add children of this ChangeTree to this view
3964
- changeTree.forEachChild((change, _) => this.add(change.ref, tag));
3965
4332
  // FIXME: ArraySchema/MapSchema does not have metadata
3966
4333
  const metadata = obj.constructor[Symbol.metadata];
3967
- // add parent ChangeTree's, if they are invisible to this view
3968
- // TODO: REFACTOR addParent()
3969
- this.addParent(changeTree, tag);
4334
+ const changeTree = obj[$changes];
4335
+ this.items.add(changeTree);
4336
+ // add parent ChangeTree's
4337
+ // - if it was invisible to this view
4338
+ // - if it were previously filtered out
4339
+ if (checkIncludeParent && changeTree.parent) {
4340
+ this.addParent(changeTree.parent[$changes], changeTree.parentIndex, tag);
4341
+ }
3970
4342
  //
3971
4343
  // TODO: when adding an item of a MapSchema, the changes may not
3972
4344
  // be set (only the parent's changes are set)
@@ -3990,7 +4362,6 @@ class StateView {
3990
4362
  tags = this.tags.get(changeTree);
3991
4363
  }
3992
4364
  tags.add(tag);
3993
- // console.log("BY TAG:", tag);
3994
4365
  // Ref: add tagged properties
3995
4366
  metadata?.[-3]?.[tag]?.forEach((index) => {
3996
4367
  if (changeTree.getChange(index) !== OPERATION.DELETE) {
@@ -3999,73 +4370,63 @@ class StateView {
3999
4370
  });
4000
4371
  }
4001
4372
  else {
4002
- // console.log("DEFAULT TAG", changeTree.allChanges);
4003
- // // add default tag properties
4004
- // metadata?.[-3]?.[DEFAULT_VIEW_TAG]?.forEach((index) => {
4005
- // if (changeTree.getChange(index) !== OPERATION.DELETE) {
4006
- // changes.set(index, OPERATION.ADD);
4007
- // }
4008
- // });
4009
- const allChangesSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)
4373
+ const isInvisible = this.invisible.has(changeTree);
4374
+ const changeSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)
4010
4375
  ? changeTree.allFilteredChanges
4011
4376
  : changeTree.allChanges;
4012
- const it = allChangesSet.keys();
4013
- const isInvisible = this.invisible.has(changeTree);
4014
- for (const index of it) {
4015
- if ((isInvisible || metadata?.[metadata?.[index]].tag === tag) &&
4016
- changeTree.getChange(index) !== OPERATION.DELETE) {
4017
- changes.set(index, OPERATION.ADD);
4377
+ changeSet.forEach((op, index) => {
4378
+ const tagAtIndex = metadata?.[metadata?.[index]].tag;
4379
+ if ((isInvisible || // if "invisible", include all
4380
+ tagAtIndex === undefined || // "all change" with no tag
4381
+ tagAtIndex === tag // tagged property
4382
+ ) &&
4383
+ op !== OPERATION.DELETE) {
4384
+ changes.set(index, op);
4018
4385
  }
4019
- }
4020
- }
4021
- // TODO: avoid unnecessary iteration here
4022
- while (changeTree.parent &&
4023
- (changeTree = changeTree.parent[$changes]) &&
4024
- (changeTree.isFiltered || changeTree.isPartiallyFiltered)) {
4025
- this.items.add(changeTree);
4386
+ });
4026
4387
  }
4388
+ // Add children of this ChangeTree to this view
4389
+ changeTree.forEachChild((change, index) => {
4390
+ // Do not ADD children that don't have the same tag
4391
+ if (metadata && metadata[metadata[index]].tag !== tag) {
4392
+ return;
4393
+ }
4394
+ this.add(change.ref, tag, false);
4395
+ });
4027
4396
  return this;
4028
4397
  }
4029
- addParent(changeTree, tag) {
4030
- const parentRef = changeTree.parent;
4031
- if (!parentRef) {
4032
- return;
4398
+ addParent(changeTree, parentIndex, tag) {
4399
+ // view must have all "changeTree" parent tree
4400
+ this.items.add(changeTree);
4401
+ // add parent's parent
4402
+ const parentChangeTree = changeTree.parent?.[$changes];
4403
+ if (parentChangeTree && (parentChangeTree.isFiltered || parentChangeTree.isPartiallyFiltered)) {
4404
+ this.addParent(parentChangeTree, changeTree.parentIndex, tag);
4033
4405
  }
4034
- const parentChangeTree = parentRef[$changes];
4035
- const parentIndex = changeTree.parentIndex;
4036
- if (!this.invisible.has(parentChangeTree)) {
4037
- // parent is already available, no need to add it!
4406
+ // parent is already available, no need to add it!
4407
+ if (!this.invisible.has(changeTree)) {
4038
4408
  return;
4039
4409
  }
4040
- this.addParent(parentChangeTree, tag);
4041
4410
  // add parent's tag properties
4042
- if (parentChangeTree.getChange(parentIndex) !== OPERATION.DELETE) {
4043
- let parentChanges = this.changes.get(parentChangeTree);
4044
- if (parentChanges === undefined) {
4045
- parentChanges = new Map();
4046
- this.changes.set(parentChangeTree, parentChanges);
4411
+ if (changeTree.getChange(parentIndex) !== OPERATION.DELETE) {
4412
+ let changes = this.changes.get(changeTree);
4413
+ if (changes === undefined) {
4414
+ changes = new Map();
4415
+ this.changes.set(changeTree, changes);
4047
4416
  }
4048
- // console.log("add parent change", {
4049
- // parentIndex,
4050
- // parentChanges,
4051
- // parentChange: (
4052
- // parentChangeTree.getChange(parentIndex) &&
4053
- // OPERATION[parentChangeTree.getChange(parentIndex)]
4054
- // ),
4055
- // })
4056
4417
  if (!this.tags) {
4057
4418
  this.tags = new WeakMap();
4058
4419
  }
4059
4420
  let tags;
4060
- if (!this.tags.has(parentChangeTree)) {
4421
+ if (!this.tags.has(changeTree)) {
4061
4422
  tags = new Set();
4062
- this.tags.set(parentChangeTree, tags);
4423
+ this.tags.set(changeTree, tags);
4063
4424
  }
4064
4425
  else {
4065
- tags = this.tags.get(parentChangeTree);
4426
+ tags = this.tags.get(changeTree);
4066
4427
  }
4067
4428
  tags.add(tag);
4068
- parentChanges.set(parentIndex, OPERATION.ADD);
4429
+ changes.set(parentIndex, OPERATION.ADD);
4069
4430
  }
4070
4431
  }
4071
4432
  remove(obj, tag = DEFAULT_VIEW_TAG) {
@@ -4129,5 +4490,5 @@ registerType("array", { constructor: ArraySchema });
4129
4490
  registerType("set", { constructor: SetSchema });
4130
4491
  registerType("collection", { constructor: CollectionSchema, });
4131
4492
 
4132
- export { $changes, $childType, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $track, ArraySchema, ChangeTree, CollectionSchema, Decoder, Encoder, MapSchema, Metadata, OPERATION, Reflection, ReflectionField, ReflectionType, Schema, SetSchema, StateView, TypeContext, decode, decodeKeyValueOperation, decodeSchemaOperation, defineTypes, deprecated, dumpChanges, encode, encodeArray as encodeKeyValueOperation, encodeSchemaOperation, registerType, type, view };
4493
+ export { $changes, $childType, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $track, ArraySchema, ChangeTree, CollectionSchema, Decoder, Encoder, MapSchema, Metadata, OPERATION, Reflection, ReflectionField, ReflectionType, Schema, SetSchema, StateView, TypeContext, decode, decodeKeyValueOperation, decodeSchemaOperation, defineTypes, deprecated, dumpChanges, encode, encodeArray as encodeKeyValueOperation, encodeSchemaOperation, getDecoderStateCallbacks, getRawChangesCallback, registerType, type, view };
4133
4494
  //# sourceMappingURL=index.mjs.map