@colyseus/schema 5.0.2 → 5.0.4

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.
@@ -27,6 +27,8 @@ export interface BuilderDefinition {
27
27
  static?: boolean;
28
28
  stream?: boolean;
29
29
  optional?: boolean;
30
+ /** Local-only field: typed + initialized, but never registered for sync. */
31
+ noSync?: boolean;
30
32
  /** Declaration-scope priority callback for `.stream()` fields. */
31
33
  streamPriority?: (view: any, element: any) => number;
32
34
  }
@@ -64,21 +66,24 @@ export class FieldBuilder<
64
66
  > {
65
67
  readonly [$builder]: true = true;
66
68
 
67
- // Internal configuration. Public so schema() and tests can read it, but not
68
- // meant to be mutated by users directly.
69
- _type: DefinitionType;
70
- _default: any = undefined;
71
- _hasDefault = false;
72
- _view: number | undefined = undefined;
73
- _owned = false;
74
- _unreliable = false;
75
- _transient = false;
76
- _deprecated = false;
77
- _deprecatedThrows = true;
78
- _static = false;
79
- _stream = false;
80
- _optional = false;
81
- _streamPriority: ((view: any, element: any) => number) | undefined = undefined;
69
+ // Internal configuration. Declared `private` (soft-private): hidden from
70
+ // editor autocomplete and from normal external `.field` access, but still
71
+ // reachable at runtime via element access (e.g. `builder['_noSync']`) for
72
+ // internal tooling/tests. Not meant to be mutated by end users.
73
+ private _type: DefinitionType;
74
+ private _default: any = undefined;
75
+ private _hasDefault = false;
76
+ private _view: number | undefined = undefined;
77
+ private _owned = false;
78
+ private _unreliable = false;
79
+ private _transient = false;
80
+ private _deprecated = false;
81
+ private _deprecatedThrows = true;
82
+ private _static = false;
83
+ private _stream = false;
84
+ private _optional = false;
85
+ private _noSync = false;
86
+ private _streamPriority: ((view: any, element: any) => number) | undefined = undefined;
82
87
 
83
88
  constructor(type: DefinitionType) {
84
89
  this._type = type;
@@ -136,6 +141,31 @@ export class FieldBuilder<
136
141
  return this;
137
142
  }
138
143
 
144
+ /**
145
+ * Mark this field as **local-only** — it is typed and initialized on the
146
+ * instance (so `.default()` and the inferred instance type still apply),
147
+ * but is never registered for synchronization: it never enters change
148
+ * tracking, never goes over the wire, and decoders never receive it.
149
+ *
150
+ * Useful for server-side scratch state, per-peer UI state, or values you
151
+ * want on the class for typing convenience without paying any sync cost.
152
+ *
153
+ * Mutually exclusive with the sync-only modifiers (`.view()`, `.owned()`,
154
+ * `.unreliable()`, `.transient()`, `.static()`, `.stream()`) — combining
155
+ * them throws at `schema()` time.
156
+ *
157
+ * ```ts
158
+ * const Player = schema({
159
+ * hp: t.uint8().default(100), // synchronized
160
+ * lastInputTick: t.number().noSync(), // local-only
161
+ * }, 'Player');
162
+ * ```
163
+ */
164
+ noSync(): this {
165
+ this._noSync = true;
166
+ return this;
167
+ }
168
+
139
169
  /**
140
170
  * Opt a collection field into priority-batched streaming delivery —
141
171
  * ADDs drain at most `maxPerTick` per tick per view (or per broadcast
@@ -194,7 +224,12 @@ export class FieldBuilder<
194
224
  return this as unknown as FieldBuilder<T | undefined, HasDefault, true>;
195
225
  }
196
226
 
197
- toDefinition(): BuilderDefinition {
227
+ /**
228
+ * @internal — snapshot of the builder's configuration consumed by
229
+ * `schema()`. `private` keeps it out of autocomplete; internal callers
230
+ * reach it via element access (`builder['toDefinition']()`).
231
+ */
232
+ private toDefinition(): BuilderDefinition {
198
233
  return {
199
234
  type: this._type,
200
235
  default: this._default,
@@ -208,6 +243,7 @@ export class FieldBuilder<
208
243
  static: this._static,
209
244
  stream: this._stream,
210
245
  optional: this._optional,
246
+ noSync: this._noSync,
211
247
  streamPriority: this._streamPriority,
212
248
  };
213
249
  }
@@ -233,7 +269,8 @@ export type ChildType =
233
269
 
234
270
  function resolveChild(child: ChildType): DefinitionType {
235
271
  if (isBuilder(child)) {
236
- return child._type;
272
+ // `_type` is private; element access bypasses the visibility check.
273
+ return child['_type'];
237
274
  }
238
275
  return child as DefinitionType;
239
276
  }
@@ -283,7 +320,7 @@ const collectionFactory: CollectionFactory = ((child: ChildType) =>
283
320
  new FieldBuilder({ collection: resolveChild(child) } as DefinitionType)) as CollectionFactory;
284
321
  const streamFactory: StreamFactory = ((child: ChildType) => {
285
322
  const b = new FieldBuilder({ stream: resolveChild(child) } as DefinitionType);
286
- b._stream = true;
323
+ b['_stream'] = true; // element access bypasses `private`
287
324
  return b;
288
325
  }) as StreamFactory;
289
326