@colyseus/schema 4.0.23 → 4.0.25

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.cjs CHANGED
@@ -1231,12 +1231,26 @@ class ChangeTree {
1231
1231
  }
1232
1232
  return;
1233
1233
  }
1234
- const changeSet = (this.filteredChanges !== undefined)
1234
+ // Mirror `change()`: a field's add/delete must target the same
1235
+ // changeset family (filtered vs non-filtered). Otherwise
1236
+ // `deleteOperationAtIndex` falls through to its "find last
1237
+ // operation" branch and evicts an unrelated sibling field —
1238
+ // surfaced as encodeAll() dropping a non-@view field after a
1239
+ // sibling @view field is set to undefined on a Schema with
1240
+ // mixed @view / non-@view fields (filteredChanges defined,
1241
+ // isFiltered false).
1242
+ const isFiltered = this.isFiltered || (this.metadata?.[index]?.tag !== undefined);
1243
+ const changeSet = (isFiltered)
1235
1244
  ? this.filteredChanges
1236
1245
  : this.changes;
1237
1246
  this.indexedOperations[index] = operation ?? exports.OPERATION.DELETE;
1238
1247
  setOperationAtIndex(changeSet, index);
1239
- deleteOperationAtIndex(this.allChanges, allChangesIndex);
1248
+ if (isFiltered) {
1249
+ deleteOperationAtIndex(this.allFilteredChanges, allChangesIndex);
1250
+ }
1251
+ else {
1252
+ deleteOperationAtIndex(this.allChanges, allChangesIndex);
1253
+ }
1240
1254
  const previousValue = this.getValue(index);
1241
1255
  // remove `root` reference
1242
1256
  if (previousValue && previousValue[$changes]) {
@@ -1252,11 +1266,7 @@ class ChangeTree {
1252
1266
  //
1253
1267
  this.root?.remove(previousValue[$changes]);
1254
1268
  }
1255
- //
1256
- // FIXME: this is looking a ugly and repeated
1257
- //
1258
- if (this.filteredChanges !== undefined) {
1259
- deleteOperationAtIndex(this.allFilteredChanges, allChangesIndex);
1269
+ if (isFiltered) {
1260
1270
  this.root?.enqueueChangeTree(this, 'filteredChanges');
1261
1271
  }
1262
1272
  else {
@@ -1361,7 +1371,8 @@ class ChangeTree {
1361
1371
  key += `-${this.root.types.schemas.get(parentConstructor)}`;
1362
1372
  }
1363
1373
  key += `-${parentIndex}`;
1364
- const fieldHasViewTag = Metadata.hasViewTagAtIndex(parentConstructor?.[Symbol.metadata], parentIndex);
1374
+ const parentMetadata = parentConstructor?.[Symbol.metadata];
1375
+ const fieldHasViewTag = Metadata.hasViewTagAtIndex(parentMetadata, parentIndex);
1365
1376
  this.isFiltered = parent[$changes].isFiltered // in case parent is already filtered
1366
1377
  || this.root.types.parentFiltered[key]
1367
1378
  || fieldHasViewTag;
@@ -1370,9 +1381,22 @@ class ChangeTree {
1370
1381
  // when it's available, we need to enqueue the "changes" changeset into the "filteredChanges" changeset.
1371
1382
  //
1372
1383
  if (this.isFiltered) {
1384
+ //
1385
+ // Children of a `@view(N)` collection (non-default tag) inherit
1386
+ // visibility from their parent, so items pushed/set after the
1387
+ // initial `view.add(state, N)` show up automatically.
1388
+ //
1389
+ // Default-tag `@view()` collections deliberately keep per-item
1390
+ // gating — `view.add(item)` is required to opt each one in.
1391
+ //
1392
+ // The `parentMetadata[parentIndex].tag` access is safe inside
1393
+ // this branch: the OR's short-circuit means we only reach it
1394
+ // when `fieldHasViewTag` is true, which guarantees the metadata
1395
+ // entry and its `tag` property exist.
1396
+ //
1373
1397
  this.isVisibilitySharedWithParent = (parentChangeTree.isFiltered &&
1374
1398
  typeof (refType) !== "string" &&
1375
- !fieldHasViewTag);
1399
+ (!fieldHasViewTag || (parentIsCollection && parentMetadata[parentIndex].tag !== DEFAULT_VIEW_TAG)));
1376
1400
  if (!this.filteredChanges) {
1377
1401
  this.filteredChanges = createChangeSet();
1378
1402
  this.allFilteredChanges = createChangeSet();