@colyseus/schema 5.0.4 → 5.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.cjs +1 -4
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -4
- package/build/index.mjs +1 -4
- package/build/index.mjs.map +1 -1
- package/build/types/HelperTypes.d.ts +22 -0
- package/build/types/builder.d.ts +40 -15
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/types/HelperTypes.ts +23 -0
- package/src/types/builder.ts +27 -2
|
@@ -97,6 +97,28 @@ export type ToJSON<T> = NonFunctionProps<{
|
|
|
97
97
|
} & {
|
|
98
98
|
[K in ToJSONOptionalKeys<T>]?: ToJSONField<Exclude<T[K], undefined>>;
|
|
99
99
|
}>;
|
|
100
|
+
/**
|
|
101
|
+
* The plain DATA shape of a Schema instance type `T`: its synchronized fields
|
|
102
|
+
* with all `Schema` machinery stripped (`assign`, `clone`, `toJSON`, the
|
|
103
|
+
* change-tracking state, the internal symbol keys, …), so a plain object literal
|
|
104
|
+
* satisfies it. Field types — including narrowed primitives like
|
|
105
|
+
* `t.int8<-1 | 0 | 1>()` — are preserved exactly.
|
|
106
|
+
*
|
|
107
|
+
* Use it to type code that operates on schema-shaped *plain objects* rather than
|
|
108
|
+
* decoded instances: deterministic simulation / physics steps, synthesized or
|
|
109
|
+
* buffered input commands, plain DTOs, etc.
|
|
110
|
+
*
|
|
111
|
+
* ```ts
|
|
112
|
+
* function applyInput(state: Player, cmd: Data<MoveInput>) { … }
|
|
113
|
+
* applyInput(player, { moveX: 1, jump: false, dt }); // plain literal — OK
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* Unlike {@link ToJSON} (a recursive *serialization* shape), this is a flat
|
|
117
|
+
* structural projection: nested Schema / collection fields keep their instance
|
|
118
|
+
* types, and it does not retain the non-method `Schema` members that `ToJSON`'s
|
|
119
|
+
* `NonFunctionProps` pass leaves behind.
|
|
120
|
+
*/
|
|
121
|
+
export type Data<T> = Omit<T, keyof Schema>;
|
|
100
122
|
export type IsNever<T> = [T] extends [never] ? true : false;
|
|
101
123
|
/**
|
|
102
124
|
* Type helper for .assign() method - allows assigning values in a flexible way
|
package/build/types/builder.d.ts
CHANGED
|
@@ -162,6 +162,31 @@ export declare class FieldBuilder<T = unknown, HasDefault extends boolean = fals
|
|
|
162
162
|
private toDefinition;
|
|
163
163
|
}
|
|
164
164
|
export declare function isBuilder(value: any): value is FieldBuilder<any>;
|
|
165
|
+
/**
|
|
166
|
+
* Primitive field factory. Calling it bare (`t.int8()`) yields the natural type
|
|
167
|
+
* for the wire codec (`number` for the int/float formats, plus `string` /
|
|
168
|
+
* `boolean` / `bigint`). Pass an explicit type argument to refine the inferred
|
|
169
|
+
* value at the TYPE level, while the wire encoding is unchanged:
|
|
170
|
+
*
|
|
171
|
+
* moveX: t.int8<-1 | 0 | 1>(), // typed -1|0|1, still encoded as int8
|
|
172
|
+
* team: t.string<"red" | "blue">(),
|
|
173
|
+
*
|
|
174
|
+
* Two call signatures, NOT a defaulted generic `<T extends TBase = TBase>`: the
|
|
175
|
+
* bare form must return a CONCRETE `FieldBuilder<TBase>` so `schema({ x:
|
|
176
|
+
* t.number() })` still infers `x: number`. A defaulted free type parameter gets
|
|
177
|
+
* captured as `any` during `schema()`'s self-referential field inference (and
|
|
178
|
+
* `undefined extends any` then flips every field optional).
|
|
179
|
+
*
|
|
180
|
+
* NOTE: the refinement is a TYPE-LEVEL assertion, not a runtime guarantee — the
|
|
181
|
+
* wire still carries the codec's full range and the DECODER writes whatever
|
|
182
|
+
* bytes arrive. Sound for server-authored state; for INPUT schemas the value
|
|
183
|
+
* comes from an untrusted client (the type reads `-1|0|1` while a peer can send
|
|
184
|
+
* any int8), so keep validating/clamping on the receiving side.
|
|
185
|
+
*/
|
|
186
|
+
interface PrimitiveFactory<TBase> {
|
|
187
|
+
(): FieldBuilder<TBase>;
|
|
188
|
+
<T extends TBase>(): FieldBuilder<T>;
|
|
189
|
+
}
|
|
165
190
|
export type ChildType = RawPrimitiveType | Constructor<Schema> | FieldBuilder<any>;
|
|
166
191
|
interface ArrayFactory {
|
|
167
192
|
<C extends Constructor<Schema>>(child: C): FieldBuilder<ArraySchema<InstanceType<C>>, true, false>;
|
|
@@ -195,21 +220,21 @@ interface RefFactory {
|
|
|
195
220
|
<C extends Constructor<Schema>>(ctor: C): FieldBuilder<InstanceType<C>, RefHasDefault<C>, false>;
|
|
196
221
|
}
|
|
197
222
|
export declare const t: Readonly<{
|
|
198
|
-
string:
|
|
199
|
-
number:
|
|
200
|
-
boolean:
|
|
201
|
-
int8:
|
|
202
|
-
uint8:
|
|
203
|
-
int16:
|
|
204
|
-
uint16:
|
|
205
|
-
int32:
|
|
206
|
-
uint32:
|
|
207
|
-
int64:
|
|
208
|
-
uint64:
|
|
209
|
-
float32:
|
|
210
|
-
float64:
|
|
211
|
-
bigint64:
|
|
212
|
-
biguint64:
|
|
223
|
+
string: PrimitiveFactory<string>;
|
|
224
|
+
number: PrimitiveFactory<number>;
|
|
225
|
+
boolean: PrimitiveFactory<boolean>;
|
|
226
|
+
int8: PrimitiveFactory<number>;
|
|
227
|
+
uint8: PrimitiveFactory<number>;
|
|
228
|
+
int16: PrimitiveFactory<number>;
|
|
229
|
+
uint16: PrimitiveFactory<number>;
|
|
230
|
+
int32: PrimitiveFactory<number>;
|
|
231
|
+
uint32: PrimitiveFactory<number>;
|
|
232
|
+
int64: PrimitiveFactory<number>;
|
|
233
|
+
uint64: PrimitiveFactory<number>;
|
|
234
|
+
float32: PrimitiveFactory<number>;
|
|
235
|
+
float64: PrimitiveFactory<number>;
|
|
236
|
+
bigint64: PrimitiveFactory<bigint>;
|
|
237
|
+
biguint64: PrimitiveFactory<bigint>;
|
|
213
238
|
/** Reference to a Schema subtype. `t.array(Item)` usually reads better, but this is available when a plain ref is needed. */
|
|
214
239
|
ref: RefFactory;
|
|
215
240
|
array: ArrayFactory;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -71,7 +71,7 @@ export { t, FieldBuilder, isBuilder, type BuilderDefinition, type ChildType } fr
|
|
|
71
71
|
export { TypeContext } from "./types/TypeContext.js";
|
|
72
72
|
|
|
73
73
|
// Helper types for type inference
|
|
74
|
-
export type { InferValueType, InferSchemaInstanceType, AssignableProps, BuilderInitProps } from "./types/HelperTypes.js";
|
|
74
|
+
export type { InferValueType, InferSchemaInstanceType, AssignableProps, BuilderInitProps, Data } from "./types/HelperTypes.js";
|
|
75
75
|
|
|
76
76
|
export { getDecoderStateCallbacks, type CallbackProxy, type SchemaCallback, type CollectionCallback, type SchemaCallbackProxy } from "./decoder/strategy/getDecoderStateCallbacks.js";
|
|
77
77
|
export { Callbacks, StateCallbackStrategy } from "./decoder/strategy/Callbacks.js";
|
package/src/types/HelperTypes.ts
CHANGED
|
@@ -143,6 +143,29 @@ export type ToJSON<T> = NonFunctionProps<
|
|
|
143
143
|
& { [K in ToJSONOptionalKeys<T>]?: ToJSONField<Exclude<T[K], undefined>> }
|
|
144
144
|
>;
|
|
145
145
|
|
|
146
|
+
/**
|
|
147
|
+
* The plain DATA shape of a Schema instance type `T`: its synchronized fields
|
|
148
|
+
* with all `Schema` machinery stripped (`assign`, `clone`, `toJSON`, the
|
|
149
|
+
* change-tracking state, the internal symbol keys, …), so a plain object literal
|
|
150
|
+
* satisfies it. Field types — including narrowed primitives like
|
|
151
|
+
* `t.int8<-1 | 0 | 1>()` — are preserved exactly.
|
|
152
|
+
*
|
|
153
|
+
* Use it to type code that operates on schema-shaped *plain objects* rather than
|
|
154
|
+
* decoded instances: deterministic simulation / physics steps, synthesized or
|
|
155
|
+
* buffered input commands, plain DTOs, etc.
|
|
156
|
+
*
|
|
157
|
+
* ```ts
|
|
158
|
+
* function applyInput(state: Player, cmd: Data<MoveInput>) { … }
|
|
159
|
+
* applyInput(player, { moveX: 1, jump: false, dt }); // plain literal — OK
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* Unlike {@link ToJSON} (a recursive *serialization* shape), this is a flat
|
|
163
|
+
* structural projection: nested Schema / collection fields keep their instance
|
|
164
|
+
* types, and it does not retain the non-method `Schema` members that `ToJSON`'s
|
|
165
|
+
* `NonFunctionProps` pass leaves behind.
|
|
166
|
+
*/
|
|
167
|
+
export type Data<T> = Omit<T, keyof Schema>;
|
|
168
|
+
|
|
146
169
|
// Helper type to check if T is exactly 'never' (meaning no InitProps was provided)
|
|
147
170
|
export type IsNever<T> = [T] extends [never] ? true : false;
|
|
148
171
|
|
package/src/types/builder.ts
CHANGED
|
@@ -257,8 +257,33 @@ export function isBuilder(value: any): value is FieldBuilder<any> {
|
|
|
257
257
|
// Factory helpers
|
|
258
258
|
// ---------------------------------------------------------------------------
|
|
259
259
|
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
/**
|
|
261
|
+
* Primitive field factory. Calling it bare (`t.int8()`) yields the natural type
|
|
262
|
+
* for the wire codec (`number` for the int/float formats, plus `string` /
|
|
263
|
+
* `boolean` / `bigint`). Pass an explicit type argument to refine the inferred
|
|
264
|
+
* value at the TYPE level, while the wire encoding is unchanged:
|
|
265
|
+
*
|
|
266
|
+
* moveX: t.int8<-1 | 0 | 1>(), // typed -1|0|1, still encoded as int8
|
|
267
|
+
* team: t.string<"red" | "blue">(),
|
|
268
|
+
*
|
|
269
|
+
* Two call signatures, NOT a defaulted generic `<T extends TBase = TBase>`: the
|
|
270
|
+
* bare form must return a CONCRETE `FieldBuilder<TBase>` so `schema({ x:
|
|
271
|
+
* t.number() })` still infers `x: number`. A defaulted free type parameter gets
|
|
272
|
+
* captured as `any` during `schema()`'s self-referential field inference (and
|
|
273
|
+
* `undefined extends any` then flips every field optional).
|
|
274
|
+
*
|
|
275
|
+
* NOTE: the refinement is a TYPE-LEVEL assertion, not a runtime guarantee — the
|
|
276
|
+
* wire still carries the codec's full range and the DECODER writes whatever
|
|
277
|
+
* bytes arrive. Sound for server-authored state; for INPUT schemas the value
|
|
278
|
+
* comes from an untrusted client (the type reads `-1|0|1` while a peer can send
|
|
279
|
+
* any int8), so keep validating/clamping on the receiving side.
|
|
280
|
+
*/
|
|
281
|
+
interface PrimitiveFactory<TBase> {
|
|
282
|
+
(): FieldBuilder<TBase>;
|
|
283
|
+
<T extends TBase>(): FieldBuilder<T>;
|
|
284
|
+
}
|
|
285
|
+
function primitive<TBase>(name: RawPrimitiveType): PrimitiveFactory<TBase> {
|
|
286
|
+
return (() => new FieldBuilder<TBase>(name)) as PrimitiveFactory<TBase>;
|
|
262
287
|
}
|
|
263
288
|
|
|
264
289
|
// Accepts a Schema class, a primitive string, or another FieldBuilder as a child type.
|