@colyseus/schema 5.0.23 → 5.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.
@@ -89,16 +89,10 @@ export type CodecFor<T> = {
89
89
  [K in RawPrimitiveType]: [T] extends [InferValueType<K>] ? K : never;
90
90
  }[RawPrimitiveType];
91
91
  type IsOptionalBuilderKey<T, K extends keyof T> = T[K] extends FieldBuilder<unknown, boolean, infer O extends boolean> ? O : false;
92
- type OptionalBuilderKeys<T> = {
93
- [K in keyof T]-?: IsOptionalBuilderKey<T, K> extends true ? K : never;
94
- }[keyof T];
95
- type RequiredBuilderKeys<T> = {
96
- [K in keyof T]-?: IsOptionalBuilderKey<T, K> extends true ? never : K;
97
- }[keyof T];
98
92
  export type InferSchemaInstanceType<T> = {
99
- [K in RequiredBuilderKeys<T>]: T[K] extends FieldBuilder<any> ? InferValueType<T[K]> : T[K] extends (...args: any[]) => any ? (T[K] extends new (...args: any[]) => any ? InferValueType<T[K]> : T[K]) : InferValueType<T[K]>;
93
+ -readonly [K in keyof T as IsOptionalBuilderKey<T, K> extends true ? never : K]-?: T[K] extends FieldBuilder<any> ? InferValueType<T[K]> : T[K] extends (...args: any[]) => any ? (T[K] extends new (...args: any[]) => any ? InferValueType<T[K]> : T[K]) : InferValueType<T[K]>;
100
94
  } & {
101
- [K in OptionalBuilderKeys<T>]?: T[K] extends FieldBuilder<infer V> ? V : never;
95
+ -readonly [K in keyof T as IsOptionalBuilderKey<T, K> extends true ? K : never]?: T[K] extends FieldBuilder<infer V> ? V : never;
102
96
  } & Schema;
103
97
  type DataKey<T, K extends keyof T> = K extends keyof Schema ? never : T[K] extends Function ? never : K;
104
98
  export type NonFunctionPropNames<T> = {
@@ -110,16 +104,10 @@ export type NonFunctionNonPrimitivePropNames<T> = {
110
104
  type ToJSONValue<U> = U extends Schema ? ToJSON<U> : PrimitiveStringToType<U>;
111
105
  type ToJSONField<X> = X extends MapSchema<infer U> ? Record<string, ToJSONValue<U>> : X extends Map<string, infer U> ? Record<string, ToJSONValue<U>> : X extends ArraySchema<infer U> ? ToJSONValue<U>[] : X extends SetSchema<infer U> ? ToJSONValue<U>[] : X extends CollectionSchema<infer U> ? ToJSONValue<U>[] : X extends Schema ? ToJSON<X> : X;
112
106
  type IsOptionalKey<T, K extends keyof T> = undefined extends {} ? ({} extends Pick<T, K> ? true : false) : (undefined extends T[K] ? true : false);
113
- type ToJSONRequiredKeys<T> = {
114
- [K in keyof T]-?: [DataKey<T, K>] extends [never] ? never : IsOptionalKey<T, K> extends true ? never : K;
115
- }[keyof T];
116
- type ToJSONOptionalKeys<T> = {
117
- [K in keyof T]-?: [DataKey<T, K>] extends [never] ? never : IsOptionalKey<T, K> extends true ? K : never;
118
- }[keyof T];
119
107
  export type ToJSON<T> = {
120
- [K in ToJSONRequiredKeys<T>]: ToJSONField<T[K]>;
108
+ -readonly [K in keyof T as IsOptionalKey<T, K> extends true ? never : DataKey<T, K>]-?: ToJSONField<T[K]>;
121
109
  } & {
122
- [K in ToJSONOptionalKeys<T>]?: ToJSONField<Exclude<T[K], undefined>>;
110
+ -readonly [K in keyof T as IsOptionalKey<T, K> extends true ? DataKey<T, K> : never]?: ToJSONField<Exclude<T[K], undefined>>;
123
111
  };
124
112
  /**
125
113
  * The plain DATA shape of a Schema instance type `T`: its synchronized fields
@@ -148,9 +136,11 @@ export type IsNever<T> = [T] extends [never] ? true : false;
148
136
  * - Primitives can be assigned directly
149
137
  * - Schema instances can be assigned from plain objects or Schema instances
150
138
  * - Collections can be assigned from their JSON representations
139
+ *
140
+ * Keys filter through `DataKey` in the `as` clause — see THE RULE above.
151
141
  */
152
142
  export type AssignableProps<T> = {
153
- [K in NonFunctionPropNames<T>]?: AssignableValue<T[K]>;
143
+ -readonly [K in keyof T as DataKey<T, K>]?: AssignableValue<T[K]>;
154
144
  };
155
145
  /**
156
146
  * Value-level assignment shape shared by `AssignableProps` and
@@ -165,20 +155,18 @@ export type RefHasDefault<C> = C extends {
165
155
  } ? (P extends readonly [] ? true : false) : true;
166
156
  type FieldValue<F> = F extends FieldBuilder<infer V, boolean, boolean> ? V : F extends new (...args: any[]) => infer I ? (I extends Schema ? I : never) : never;
167
157
  type KeyClass<T, K extends keyof T> = T[K] extends FieldBuilder<unknown, infer D extends boolean, infer O extends boolean> ? (D extends true ? "optional" : O extends true ? "optional" : "required") : T[K] extends new (...args: any[]) => Schema ? (RefHasDefault<T[K]> extends true ? "optional" : "required") : "none";
168
- export type BuilderRequiredKeys<T> = {
169
- [K in keyof T]-?: KeyClass<T, K> extends "required" ? K : never;
170
- }[keyof T];
171
- export type BuilderOptionalKeys<T> = {
172
- [K in keyof T]-?: KeyClass<T, K> extends "optional" ? K : never;
173
- }[keyof T];
174
158
  /**
175
159
  * Constructor/init-props type for a schema() fields map. Required fields
176
160
  * (primitives without `.default()` or `.optional()`, and Schema refs with
177
161
  * non-zero-arg `initialize()`) are `:`; everything else is `?:`.
162
+ *
163
+ * Split by `KeyClass` in the `as` clause — see THE RULE above. `-?` matters
164
+ * under `strictNullChecks: false`: an optional key in the fields map still
165
+ * classifies as "required" there, and would otherwise inherit the `?`.
178
166
  */
179
167
  export type BuilderInitProps<T> = {
180
- [K in BuilderRequiredKeys<T>]: AssignableValue<FieldValue<T[K]>>;
168
+ -readonly [K in keyof T as KeyClass<T, K> extends "required" ? K : never]-?: AssignableValue<FieldValue<T[K]>>;
181
169
  } & {
182
- [K in BuilderOptionalKeys<T>]?: AssignableValue<Exclude<FieldValue<T[K]>, undefined>>;
170
+ -readonly [K in keyof T as KeyClass<T, K> extends "optional" ? K : never]?: AssignableValue<Exclude<FieldValue<T[K]>, undefined>>;
183
171
  };
184
172
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colyseus/schema",
3
- "version": "5.0.23",
3
+ "version": "5.0.25",
4
4
  "description": "Automatic state replication for multiplayer games. Mutate plain objects, and every client gets a live, typed mirror through delta encoding.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -619,7 +619,18 @@ export class StateView {
619
619
  this.changes.set(changeTree.ref[$refId], changes);
620
620
  }
621
621
 
622
- this.addTag(changeTree, tag);
622
+ // Grant the tag on the parent only when the field pointing at
623
+ // the child carries an overlapping tag — that field is the sole
624
+ // reason the parent needs it. Granting unconditionally handed
625
+ // the view every OTHER same-tag field on the parent, which then
626
+ // rode out on its next mutation (never at add() time, so it read
627
+ // as "the field only shows up after it changes").
628
+ const parentFieldTag = changeTree.encDescriptor.tags[parentIndex];
629
+ if (parentFieldTag !== undefined &&
630
+ parentFieldTag !== DEFAULT_VIEW_TAG &&
631
+ (parentFieldTag & tag) !== 0) {
632
+ this.addTag(changeTree, tag);
633
+ }
623
634
 
624
635
  // ArraySchema parents: key by the child's identity, not the wire
625
636
  // slot it holds right now — a same-tick unshift()/reverse()/move()
@@ -117,19 +117,20 @@ export type CodecFor<T> = {
117
117
  type IsOptionalBuilderKey<T, K extends keyof T> =
118
118
  T[K] extends FieldBuilder<unknown, boolean, infer O extends boolean> ? O : false;
119
119
 
120
- // Per key, like `DataKey` below an `Exclude<keyof T, …>` split defers every
121
- // key once one field is typed by a bare type parameter.
122
- type OptionalBuilderKeys<T> = { [K in keyof T]-?: IsOptionalBuilderKey<T, K> extends true ? K : never }[keyof T];
123
- type RequiredBuilderKeys<T> = { [K in keyof T]-?: IsOptionalBuilderKey<T, K> extends true ? never : K }[keyof T];
124
-
120
+ // THE RULE for every mapped type below that projects a user's declared fields:
121
+ // split in the `as` clause, never over a precomputed key union. Only a
122
+ // homomorphic mapping carries each key back to its declaration, and that link
123
+ // is what go-to-definition and rename resolve through losing it leaves rename
124
+ // silently touching just the cursor (colyseus/colyseus#958). The `-readonly`
125
+ // and `-?` that follow drop the modifiers such a mapping inherits from `T`.
125
126
  export type InferSchemaInstanceType<T> = {
126
- [K in RequiredBuilderKeys<T>]: T[K] extends FieldBuilder<any>
127
+ -readonly [K in keyof T as IsOptionalBuilderKey<T, K> extends true ? never : K]-?: T[K] extends FieldBuilder<any>
127
128
  ? InferValueType<T[K]>
128
129
  : T[K] extends (...args: any[]) => any
129
130
  ? (T[K] extends new (...args: any[]) => any ? InferValueType<T[K]> : T[K])
130
131
  : InferValueType<T[K]>
131
132
  } & {
132
- [K in OptionalBuilderKeys<T>]?: T[K] extends FieldBuilder<infer V>
133
+ -readonly [K in keyof T as IsOptionalBuilderKey<T, K> extends true ? K : never]?: T[K] extends FieldBuilder<infer V>
133
134
  ? V
134
135
  : never
135
136
  } & Schema;
@@ -170,15 +171,14 @@ type IsOptionalKey<T, K extends keyof T> = undefined extends {}
170
171
  ? ({} extends Pick<T, K> ? true : false)
171
172
  : (undefined extends T[K] ? true : false);
172
173
 
173
- // `DataKey` first: machinery and method keys drop before the optionality probe.
174
- type ToJSONRequiredKeys<T> = { [K in keyof T]-?: [DataKey<T, K>] extends [never] ? never : IsOptionalKey<T, K> extends true ? never : K }[keyof T];
175
- type ToJSONOptionalKeys<T> = { [K in keyof T]-?: [DataKey<T, K>] extends [never] ? never : IsOptionalKey<T, K> extends true ? K : never }[keyof T];
176
-
177
- // Keys are filtered before mapping: `ToJSONField` over the `this`-typed methods
178
- // exceeds TypeScript 7's instantiation depth.
174
+ // Beyond THE RULE, the `as` clause is load-bearing here for a second reason: it
175
+ // runs before the value type, so `ToJSONField` never reaches the machinery,
176
+ // where it would recurse through `restore(json: ToJSON<this>)` past TypeScript
177
+ // 7's instantiation limit. Probing `IsOptionalKey` first is deliberate too —
178
+ // `DataKey` then runs in the taken branch only, once per key not once per half.
179
179
  export type ToJSON<T> =
180
- & { [K in ToJSONRequiredKeys<T>]: ToJSONField<T[K]> }
181
- & { [K in ToJSONOptionalKeys<T>]?: ToJSONField<Exclude<T[K], undefined>> };
180
+ & { -readonly [K in keyof T as IsOptionalKey<T, K> extends true ? never : DataKey<T, K>]-?: ToJSONField<T[K]> }
181
+ & { -readonly [K in keyof T as IsOptionalKey<T, K> extends true ? DataKey<T, K> : never]?: ToJSONField<Exclude<T[K], undefined>> };
182
182
 
183
183
  /**
184
184
  * The plain DATA shape of a Schema instance type `T`: its synchronized fields
@@ -210,9 +210,11 @@ export type IsNever<T> = [T] extends [never] ? true : false;
210
210
  * - Primitives can be assigned directly
211
211
  * - Schema instances can be assigned from plain objects or Schema instances
212
212
  * - Collections can be assigned from their JSON representations
213
+ *
214
+ * Keys filter through `DataKey` in the `as` clause — see THE RULE above.
213
215
  */
214
216
  export type AssignableProps<T> = {
215
- [K in NonFunctionPropNames<T>]?: AssignableValue<T[K]>
217
+ -readonly [K in keyof T as DataKey<T, K>]?: AssignableValue<T[K]>
216
218
  };
217
219
 
218
220
  /**
@@ -267,19 +269,15 @@ type KeyClass<T, K extends keyof T> =
267
269
  ? (RefHasDefault<T[K]> extends true ? "optional" : "required")
268
270
  : "none";
269
271
 
270
- export type BuilderRequiredKeys<T> = {
271
- [K in keyof T]-?: KeyClass<T, K> extends "required" ? K : never
272
- }[keyof T];
273
-
274
- export type BuilderOptionalKeys<T> = {
275
- [K in keyof T]-?: KeyClass<T, K> extends "optional" ? K : never
276
- }[keyof T];
277
-
278
272
  /**
279
273
  * Constructor/init-props type for a schema() fields map. Required fields
280
274
  * (primitives without `.default()` or `.optional()`, and Schema refs with
281
275
  * non-zero-arg `initialize()`) are `:`; everything else is `?:`.
276
+ *
277
+ * Split by `KeyClass` in the `as` clause — see THE RULE above. `-?` matters
278
+ * under `strictNullChecks: false`: an optional key in the fields map still
279
+ * classifies as "required" there, and would otherwise inherit the `?`.
282
280
  */
283
281
  export type BuilderInitProps<T> =
284
- & { [K in BuilderRequiredKeys<T>]: AssignableValue<FieldValue<T[K]>> }
285
- & { [K in BuilderOptionalKeys<T>]?: AssignableValue<Exclude<FieldValue<T[K]>, undefined>> };
282
+ & { -readonly [K in keyof T as KeyClass<T, K> extends "required" ? K : never]-?: AssignableValue<FieldValue<T[K]>> }
283
+ & { -readonly [K in keyof T as KeyClass<T, K> extends "optional" ? K : never]?: AssignableValue<Exclude<FieldValue<T[K]>, undefined>> };