@colyseus/schema 4.0.4 → 4.0.6

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/build/index.js CHANGED
@@ -933,7 +933,11 @@
933
933
  });
934
934
  }
935
935
  }
936
- constructor[Symbol.metadata] = metadata;
936
+ Object.defineProperty(constructor, Symbol.metadata, {
937
+ value: metadata,
938
+ writable: false,
939
+ configurable: true
940
+ });
937
941
  return metadata;
938
942
  },
939
943
  isValidInstance(klass) {
@@ -3555,7 +3559,12 @@
3555
3559
  }
3556
3560
  else if (value['type'] !== undefined && Schema.is(value['type'])) {
3557
3561
  // Direct Schema type: Type → new Type()
3558
- defaultValues[fieldName] = new value['type']();
3562
+ if (!value['type'].prototype.initialize || value['type'].prototype.initialize.length === 0) {
3563
+ // only auto-initialize Schema instances if:
3564
+ // - they don't have an initialize method
3565
+ // - or initialize method doesn't accept any parameters
3566
+ defaultValues[fieldName] = new value['type']();
3567
+ }
3559
3568
  }
3560
3569
  }
3561
3570
  else {
@@ -3565,7 +3574,12 @@
3565
3574
  else if (typeof (value) === "function") {
3566
3575
  if (Schema.is(value)) {
3567
3576
  // Direct Schema type: Type → new Type()
3568
- defaultValues[fieldName] = new value();
3577
+ if (!value.prototype.initialize || value.prototype.initialize.length === 0) {
3578
+ // only auto-initialize Schema instances if:
3579
+ // - they don't have an initialize method
3580
+ // - or initialize method doesn't accept any parameters
3581
+ defaultValues[fieldName] = new value();
3582
+ }
3569
3583
  fields[fieldName] = getNormalizedType(value);
3570
3584
  }
3571
3585
  else {
@@ -3592,13 +3606,32 @@
3592
3606
  }
3593
3607
  return defaults;
3594
3608
  };
3609
+ const getParentProps = (props) => {
3610
+ const fieldNames = Object.keys(fields);
3611
+ const parentProps = {};
3612
+ for (const key in props) {
3613
+ if (!fieldNames.includes(key)) {
3614
+ parentProps[key] = props[key];
3615
+ }
3616
+ }
3617
+ return parentProps;
3618
+ };
3595
3619
  /** @codegen-ignore */
3596
3620
  const klass = Metadata.setFields(class extends inherits {
3597
3621
  constructor(...args) {
3598
- super(Object.assign({}, getDefaultValues(), args[0] || {}));
3599
3622
  // call initialize method
3600
3623
  if (methods.initialize && typeof methods.initialize === 'function') {
3601
- methods.initialize.apply(this, args);
3624
+ super(Object.assign({}, getDefaultValues(), getParentProps(args[0] || {})));
3625
+ /**
3626
+ * only call initialize() in the current class, not the parent ones.
3627
+ * see "should not call initialize automatically when creating an instance of inherited Schema"
3628
+ */
3629
+ if (new.target === klass) {
3630
+ methods.initialize.apply(this, args);
3631
+ }
3632
+ }
3633
+ else {
3634
+ super(Object.assign({}, getDefaultValues(), args[0] || {}));
3602
3635
  }
3603
3636
  }
3604
3637
  }, fields);
@@ -3672,6 +3705,15 @@
3672
3705
  static is(type) {
3673
3706
  return typeof (type[Symbol.metadata]) === "object";
3674
3707
  }
3708
+ /**
3709
+ * Check if a value is an instance of Schema.
3710
+ * This method uses duck-typing to avoid issues with multiple @colyseus/schema versions.
3711
+ * @param obj Value to check
3712
+ * @returns true if the value is a Schema instance
3713
+ */
3714
+ static isSchema(obj) {
3715
+ return typeof obj?.assign === "function";
3716
+ }
3675
3717
  /**
3676
3718
  * Track property changes
3677
3719
  */
@@ -4876,13 +4918,13 @@
4876
4918
  // trigger onRemove on child structure.
4877
4919
  //
4878
4920
  if ((change.op & exports.OPERATION.DELETE) === exports.OPERATION.DELETE &&
4879
- change.previousValue instanceof Schema) {
4921
+ Schema.isSchema(change.previousValue)) {
4880
4922
  const deleteCallbacks = callbacks[change.previousValue[$refId]]?.[exports.OPERATION.DELETE];
4881
4923
  for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {
4882
4924
  deleteCallbacks[i]();
4883
4925
  }
4884
4926
  }
4885
- if (ref instanceof Schema) {
4927
+ if (Schema.isSchema(ref)) {
4886
4928
  //
4887
4929
  // Handle schema instance
4888
4930
  //
@@ -5266,7 +5308,7 @@
5266
5308
  // trigger onRemove on child structure.
5267
5309
  //
5268
5310
  if ((change.op & exports.OPERATION.DELETE) === exports.OPERATION.DELETE &&
5269
- change.previousValue instanceof Schema) {
5311
+ Schema.isSchema(change.previousValue)) {
5270
5312
  const childRefId = change.previousValue[$refId];
5271
5313
  const deleteCallbacks = this.callbacks[childRefId]?.[exports.OPERATION.DELETE];
5272
5314
  if (deleteCallbacks) {
@@ -5275,7 +5317,7 @@
5275
5317
  }
5276
5318
  }
5277
5319
  }
5278
- if (ref instanceof Schema) {
5320
+ if (Schema.isSchema(ref)) {
5279
5321
  //
5280
5322
  // Handle Schema instance
5281
5323
  //
package/build/index.mjs CHANGED
@@ -927,7 +927,11 @@ const Metadata = {
927
927
  });
928
928
  }
929
929
  }
930
- constructor[Symbol.metadata] = metadata;
930
+ Object.defineProperty(constructor, Symbol.metadata, {
931
+ value: metadata,
932
+ writable: false,
933
+ configurable: true
934
+ });
931
935
  return metadata;
932
936
  },
933
937
  isValidInstance(klass) {
@@ -3549,7 +3553,12 @@ function schema(fieldsAndMethods, name, inherits = Schema) {
3549
3553
  }
3550
3554
  else if (value['type'] !== undefined && Schema.is(value['type'])) {
3551
3555
  // Direct Schema type: Type → new Type()
3552
- defaultValues[fieldName] = new value['type']();
3556
+ if (!value['type'].prototype.initialize || value['type'].prototype.initialize.length === 0) {
3557
+ // only auto-initialize Schema instances if:
3558
+ // - they don't have an initialize method
3559
+ // - or initialize method doesn't accept any parameters
3560
+ defaultValues[fieldName] = new value['type']();
3561
+ }
3553
3562
  }
3554
3563
  }
3555
3564
  else {
@@ -3559,7 +3568,12 @@ function schema(fieldsAndMethods, name, inherits = Schema) {
3559
3568
  else if (typeof (value) === "function") {
3560
3569
  if (Schema.is(value)) {
3561
3570
  // Direct Schema type: Type → new Type()
3562
- defaultValues[fieldName] = new value();
3571
+ if (!value.prototype.initialize || value.prototype.initialize.length === 0) {
3572
+ // only auto-initialize Schema instances if:
3573
+ // - they don't have an initialize method
3574
+ // - or initialize method doesn't accept any parameters
3575
+ defaultValues[fieldName] = new value();
3576
+ }
3563
3577
  fields[fieldName] = getNormalizedType(value);
3564
3578
  }
3565
3579
  else {
@@ -3586,13 +3600,32 @@ function schema(fieldsAndMethods, name, inherits = Schema) {
3586
3600
  }
3587
3601
  return defaults;
3588
3602
  };
3603
+ const getParentProps = (props) => {
3604
+ const fieldNames = Object.keys(fields);
3605
+ const parentProps = {};
3606
+ for (const key in props) {
3607
+ if (!fieldNames.includes(key)) {
3608
+ parentProps[key] = props[key];
3609
+ }
3610
+ }
3611
+ return parentProps;
3612
+ };
3589
3613
  /** @codegen-ignore */
3590
3614
  const klass = Metadata.setFields(class extends inherits {
3591
3615
  constructor(...args) {
3592
- super(Object.assign({}, getDefaultValues(), args[0] || {}));
3593
3616
  // call initialize method
3594
3617
  if (methods.initialize && typeof methods.initialize === 'function') {
3595
- methods.initialize.apply(this, args);
3618
+ super(Object.assign({}, getDefaultValues(), getParentProps(args[0] || {})));
3619
+ /**
3620
+ * only call initialize() in the current class, not the parent ones.
3621
+ * see "should not call initialize automatically when creating an instance of inherited Schema"
3622
+ */
3623
+ if (new.target === klass) {
3624
+ methods.initialize.apply(this, args);
3625
+ }
3626
+ }
3627
+ else {
3628
+ super(Object.assign({}, getDefaultValues(), args[0] || {}));
3596
3629
  }
3597
3630
  }
3598
3631
  }, fields);
@@ -3666,6 +3699,15 @@ class Schema {
3666
3699
  static is(type) {
3667
3700
  return typeof (type[Symbol.metadata]) === "object";
3668
3701
  }
3702
+ /**
3703
+ * Check if a value is an instance of Schema.
3704
+ * This method uses duck-typing to avoid issues with multiple @colyseus/schema versions.
3705
+ * @param obj Value to check
3706
+ * @returns true if the value is a Schema instance
3707
+ */
3708
+ static isSchema(obj) {
3709
+ return typeof obj?.assign === "function";
3710
+ }
3669
3711
  /**
3670
3712
  * Track property changes
3671
3713
  */
@@ -4870,13 +4912,13 @@ function getDecoderStateCallbacks(decoder) {
4870
4912
  // trigger onRemove on child structure.
4871
4913
  //
4872
4914
  if ((change.op & OPERATION.DELETE) === OPERATION.DELETE &&
4873
- change.previousValue instanceof Schema) {
4915
+ Schema.isSchema(change.previousValue)) {
4874
4916
  const deleteCallbacks = callbacks[change.previousValue[$refId]]?.[OPERATION.DELETE];
4875
4917
  for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {
4876
4918
  deleteCallbacks[i]();
4877
4919
  }
4878
4920
  }
4879
- if (ref instanceof Schema) {
4921
+ if (Schema.isSchema(ref)) {
4880
4922
  //
4881
4923
  // Handle schema instance
4882
4924
  //
@@ -5260,7 +5302,7 @@ class StateCallbackStrategy {
5260
5302
  // trigger onRemove on child structure.
5261
5303
  //
5262
5304
  if ((change.op & OPERATION.DELETE) === OPERATION.DELETE &&
5263
- change.previousValue instanceof Schema) {
5305
+ Schema.isSchema(change.previousValue)) {
5264
5306
  const childRefId = change.previousValue[$refId];
5265
5307
  const deleteCallbacks = this.callbacks[childRefId]?.[OPERATION.DELETE];
5266
5308
  if (deleteCallbacks) {
@@ -5269,7 +5311,7 @@ class StateCallbackStrategy {
5269
5311
  }
5270
5312
  }
5271
5313
  }
5272
- if (ref instanceof Schema) {
5314
+ if (Schema.isSchema(ref)) {
5273
5315
  //
5274
5316
  // Handle Schema instance
5275
5317
  //