@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/Schema.d.ts +7 -0
- package/build/decoder/DecodeOperation.d.ts +3 -3
- package/build/decoder/Decoder.d.ts +3 -3
- package/build/decoder/ReferenceTracker.d.ts +3 -3
- package/build/decoder/strategy/Callbacks.d.ts +5 -5
- package/build/index.cjs +51 -9
- package/build/index.cjs.map +1 -1
- package/build/index.js +51 -9
- package/build/index.mjs +51 -9
- package/build/index.mjs.map +1 -1
- package/build/types/HelperTypes.d.ts +5 -1
- package/package.json +1 -1
- package/src/Metadata.ts +5 -1
- package/src/Schema.ts +10 -0
- package/src/annotations.ts +34 -5
- package/src/decoder/DecodeOperation.ts +3 -5
- package/src/decoder/Decoder.ts +3 -3
- package/src/decoder/ReferenceTracker.ts +4 -4
- package/src/decoder/strategy/Callbacks.ts +7 -7
- package/src/decoder/strategy/getDecoderStateCallbacks.ts +2 -2
- package/src/types/HelperTypes.ts +2 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Definition, DefinitionType, PrimitiveType } from "../annotations.js";
|
|
1
|
+
import type { Definition, DefinitionType, PrimitiveType, RawPrimitiveType } from "../annotations.js";
|
|
2
2
|
import type { Schema } from "../Schema.js";
|
|
3
3
|
import type { ArraySchema } from "./custom/ArraySchema.js";
|
|
4
4
|
import type { CollectionSchema } from "./custom/CollectionSchema.js";
|
|
@@ -42,10 +42,14 @@ export type InferValueType<T extends DefinitionType> = T extends "string" ? stri
|
|
|
42
42
|
} ? (ChildType extends Record<string | number, string | number> ? MapSchema<ChildType[keyof ChildType]> : MapSchema<PrimitiveStringToType<ChildType>>) : T extends {
|
|
43
43
|
set: infer ChildType extends Constructor;
|
|
44
44
|
} ? SetSchema<InstanceType<ChildType>> : T extends {
|
|
45
|
+
set: infer ChildType extends RawPrimitiveType;
|
|
46
|
+
} ? SetSchema<InferValueType<ChildType>> : T extends {
|
|
45
47
|
set: infer ChildType;
|
|
46
48
|
} ? (ChildType extends Record<string | number, string | number> ? SetSchema<ChildType[keyof ChildType]> : SetSchema<ChildType>) : T extends {
|
|
47
49
|
collection: infer ChildType extends Constructor;
|
|
48
50
|
} ? CollectionSchema<InstanceType<ChildType>> : T extends {
|
|
51
|
+
collection: infer ChildType extends RawPrimitiveType;
|
|
52
|
+
} ? CollectionSchema<InferValueType<ChildType>> : T extends {
|
|
49
53
|
collection: infer ChildType;
|
|
50
54
|
} ? (ChildType extends Record<string | number, string | number> ? CollectionSchema<ChildType[keyof ChildType]> : CollectionSchema<ChildType>) : T extends Constructor ? InstanceType<T> : T extends Record<string | number, string | number> ? T[keyof T] : T extends PrimitiveType ? T : never;
|
|
51
55
|
export type InferSchemaInstanceType<T extends Definition> = {
|
package/package.json
CHANGED
package/src/Metadata.ts
CHANGED
|
@@ -294,7 +294,11 @@ export const Metadata = {
|
|
|
294
294
|
}
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
-
constructor
|
|
297
|
+
Object.defineProperty(constructor, Symbol.metadata, {
|
|
298
|
+
value: metadata,
|
|
299
|
+
writable: false,
|
|
300
|
+
configurable: true
|
|
301
|
+
});
|
|
298
302
|
|
|
299
303
|
return metadata;
|
|
300
304
|
},
|
package/src/Schema.ts
CHANGED
|
@@ -42,6 +42,16 @@ export class Schema<C = any> implements IRef {
|
|
|
42
42
|
return typeof((type as typeof Schema)[Symbol.metadata]) === "object";
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Check if a value is an instance of Schema.
|
|
47
|
+
* This method uses duck-typing to avoid issues with multiple @colyseus/schema versions.
|
|
48
|
+
* @param obj Value to check
|
|
49
|
+
* @returns true if the value is a Schema instance
|
|
50
|
+
*/
|
|
51
|
+
static isSchema(obj: any): obj is Schema {
|
|
52
|
+
return typeof obj?.assign === "function";
|
|
53
|
+
}
|
|
54
|
+
|
|
45
55
|
/**
|
|
46
56
|
* Track property changes
|
|
47
57
|
*/
|
package/src/annotations.ts
CHANGED
|
@@ -600,7 +600,12 @@ export function schema<
|
|
|
600
600
|
|
|
601
601
|
} else if (value['type'] !== undefined && Schema.is(value['type'])) {
|
|
602
602
|
// Direct Schema type: Type → new Type()
|
|
603
|
-
|
|
603
|
+
if (!value['type'].prototype.initialize || value['type'].prototype.initialize.length === 0) {
|
|
604
|
+
// only auto-initialize Schema instances if:
|
|
605
|
+
// - they don't have an initialize method
|
|
606
|
+
// - or initialize method doesn't accept any parameters
|
|
607
|
+
defaultValues[fieldName] = new value['type']();
|
|
608
|
+
}
|
|
604
609
|
}
|
|
605
610
|
} else {
|
|
606
611
|
defaultValues[fieldName] = value['default'];
|
|
@@ -610,7 +615,12 @@ export function schema<
|
|
|
610
615
|
} else if (typeof (value) === "function") {
|
|
611
616
|
if (Schema.is(value)) {
|
|
612
617
|
// Direct Schema type: Type → new Type()
|
|
613
|
-
|
|
618
|
+
if (!value.prototype.initialize || value.prototype.initialize.length === 0) {
|
|
619
|
+
// only auto-initialize Schema instances if:
|
|
620
|
+
// - they don't have an initialize method
|
|
621
|
+
// - or initialize method doesn't accept any parameters
|
|
622
|
+
defaultValues[fieldName] = new value();
|
|
623
|
+
}
|
|
614
624
|
fields[fieldName] = getNormalizedType(value);
|
|
615
625
|
} else {
|
|
616
626
|
methods[fieldName] = value;
|
|
@@ -638,14 +648,33 @@ export function schema<
|
|
|
638
648
|
return defaults;
|
|
639
649
|
};
|
|
640
650
|
|
|
651
|
+
const getParentProps = (props: any) => {
|
|
652
|
+
const fieldNames = Object.keys(fields);
|
|
653
|
+
const parentProps: any = {};
|
|
654
|
+
for (const key in props) {
|
|
655
|
+
if (!fieldNames.includes(key)) {
|
|
656
|
+
parentProps[key] = props[key];
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return parentProps;
|
|
660
|
+
}
|
|
661
|
+
|
|
641
662
|
/** @codegen-ignore */
|
|
642
663
|
const klass = Metadata.setFields<any>(class extends (inherits as any) {
|
|
643
664
|
constructor(...args: any[]) {
|
|
644
|
-
super(Object.assign({}, getDefaultValues(), args[0] || {}));
|
|
645
|
-
|
|
646
665
|
// call initialize method
|
|
647
666
|
if (methods.initialize && typeof methods.initialize === 'function') {
|
|
648
|
-
|
|
667
|
+
super(Object.assign({}, getDefaultValues(), getParentProps(args[0] || {})));
|
|
668
|
+
/**
|
|
669
|
+
* only call initialize() in the current class, not the parent ones.
|
|
670
|
+
* see "should not call initialize automatically when creating an instance of inherited Schema"
|
|
671
|
+
*/
|
|
672
|
+
if (new.target === klass) {
|
|
673
|
+
methods.initialize.apply(this, args);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
} else {
|
|
677
|
+
super(Object.assign({}, getDefaultValues(), args[0] || {}));
|
|
649
678
|
}
|
|
650
679
|
}
|
|
651
680
|
}, fields) as SchemaWithExtendsConstructor<T, ExtractInitProps<T>, P>;
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import { OPERATION } from "../encoding/spec.js";
|
|
2
2
|
import { Metadata } from "../Metadata.js";
|
|
3
3
|
import { Schema } from "../Schema.js";
|
|
4
|
-
import type { Ref } from "../encoder/ChangeTree.js";
|
|
4
|
+
import type { IRef, Ref } from "../encoder/ChangeTree.js";
|
|
5
5
|
import type { Decoder } from "./Decoder.js";
|
|
6
6
|
import { Iterator, decode } from "../encoding/decode.js";
|
|
7
7
|
import { $childType, $deleteByIndex, $getByIndex, $refId } from "../types/symbols.js";
|
|
8
8
|
|
|
9
|
-
import type { MapSchema } from "../types/custom/MapSchema.js";
|
|
10
9
|
import type { ArraySchema } from "../types/custom/ArraySchema.js";
|
|
11
|
-
import type { CollectionSchema } from "../types/custom/CollectionSchema.js";
|
|
12
10
|
|
|
13
11
|
import { getType } from "../types/registry.js";
|
|
14
12
|
import { Collection } from "../types/HelperTypes.js";
|
|
15
13
|
|
|
16
14
|
export interface DataChange<T = any, F = string> {
|
|
17
|
-
ref:
|
|
15
|
+
ref: IRef,
|
|
18
16
|
refId: number,
|
|
19
17
|
op: OPERATION,
|
|
20
18
|
field: F;
|
|
@@ -29,7 +27,7 @@ export type DecodeOperation<T extends Schema = any> = (
|
|
|
29
27
|
decoder: Decoder<T>,
|
|
30
28
|
bytes: Uint8Array,
|
|
31
29
|
it: Iterator,
|
|
32
|
-
ref:
|
|
30
|
+
ref: IRef,
|
|
33
31
|
allChanges: DataChange[],
|
|
34
32
|
) => number | void;
|
|
35
33
|
|
package/src/decoder/Decoder.ts
CHANGED
|
@@ -4,13 +4,13 @@ import { Schema } from "../Schema.js";
|
|
|
4
4
|
|
|
5
5
|
import { decode } from "../encoding/decode.js";
|
|
6
6
|
import { OPERATION, SWITCH_TO_STRUCTURE, TYPE_ID } from '../encoding/spec.js';
|
|
7
|
-
import type { Ref } from "../encoder/ChangeTree.js";
|
|
7
|
+
import type { IRef, Ref } from "../encoder/ChangeTree.js";
|
|
8
8
|
import type { Iterator } from "../encoding/decode.js";
|
|
9
9
|
import { ReferenceTracker } from "./ReferenceTracker.js";
|
|
10
10
|
import { DEFINITION_MISMATCH, type DataChange, type DecodeOperation } from "./DecodeOperation.js";
|
|
11
11
|
import { Collection } from "../types/HelperTypes.js";
|
|
12
12
|
|
|
13
|
-
export class Decoder<T extends
|
|
13
|
+
export class Decoder<T extends IRef = any> {
|
|
14
14
|
context: TypeContext;
|
|
15
15
|
|
|
16
16
|
state: T;
|
|
@@ -40,7 +40,7 @@ export class Decoder<T extends Schema = any> {
|
|
|
40
40
|
decode(
|
|
41
41
|
bytes: Uint8Array,
|
|
42
42
|
it: Iterator = { offset: 0 },
|
|
43
|
-
ref:
|
|
43
|
+
ref: IRef = this.state,
|
|
44
44
|
) {
|
|
45
45
|
const allChanges: DataChange[] = [];
|
|
46
46
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Metadata } from "../Metadata.js";
|
|
2
2
|
import { $childType, $refId } from "../types/symbols.js";
|
|
3
|
-
import {
|
|
3
|
+
import type { IRef } from "../encoder/ChangeTree.js";
|
|
4
4
|
import { spliceOne } from "../types/utils.js";
|
|
5
5
|
import { OPERATION } from "../encoding/spec.js";
|
|
6
6
|
|
|
@@ -25,7 +25,7 @@ export class ReferenceTracker {
|
|
|
25
25
|
// Relation of refId => Schema structure
|
|
26
26
|
// For direct access of structures during decoding time.
|
|
27
27
|
//
|
|
28
|
-
public refs = new Map<number,
|
|
28
|
+
public refs = new Map<number, IRef>();
|
|
29
29
|
|
|
30
30
|
public refCount: { [refId: number]: number; } = {};
|
|
31
31
|
public deletedRefs = new Set<number>();
|
|
@@ -38,7 +38,7 @@ export class ReferenceTracker {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// for decoding
|
|
41
|
-
addRef(refId: number, ref:
|
|
41
|
+
addRef(refId: number, ref: IRef, incrementCount: boolean = true) {
|
|
42
42
|
this.refs.set(refId, ref);
|
|
43
43
|
ref[$refId] = refId;
|
|
44
44
|
|
|
@@ -103,7 +103,7 @@ export class ReferenceTracker {
|
|
|
103
103
|
const metadata: Metadata = (ref.constructor as typeof Schema)[Symbol.metadata];
|
|
104
104
|
for (const index in metadata) {
|
|
105
105
|
const field = metadata[index as any as number].name;
|
|
106
|
-
const child = ref[field as keyof
|
|
106
|
+
const child = ref[field as keyof IRef];
|
|
107
107
|
if (typeof(child) === "object" && child) {
|
|
108
108
|
const childRefId = (child as any)[$refId];
|
|
109
109
|
if (childRefId !== undefined && !this.deletedRefs.has(childRefId)) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Metadata } from "../../Metadata.js";
|
|
2
2
|
import { Collection, NonFunctionPropNames } from "../../types/HelperTypes.js";
|
|
3
|
-
import { Ref } from "../../encoder/ChangeTree.js";
|
|
3
|
+
import type { IRef, Ref } from "../../encoder/ChangeTree.js";
|
|
4
4
|
import { Decoder } from "../Decoder.js";
|
|
5
5
|
import { DataChange } from "../DecodeOperation.js";
|
|
6
6
|
import { OPERATION } from "../../encoding/spec.js";
|
|
@@ -45,7 +45,7 @@ type CollectionKeyType<T, K extends keyof T> =
|
|
|
45
45
|
T[K] extends ArraySchema<any> ? number :
|
|
46
46
|
T[K] extends Collection<infer Key, any, any> ? Key : never;
|
|
47
47
|
|
|
48
|
-
export class StateCallbackStrategy<TState extends
|
|
48
|
+
export class StateCallbackStrategy<TState extends IRef> {
|
|
49
49
|
protected decoder: Decoder<TState>;
|
|
50
50
|
protected uniqueRefIds: Set<number> = new Set();
|
|
51
51
|
protected isTriggering: boolean = false;
|
|
@@ -72,7 +72,7 @@ export class StateCallbackStrategy<TState extends Schema> {
|
|
|
72
72
|
return $root.addCallback(refId, operationOrProperty, handler);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
protected addCallbackOrWaitCollectionAvailable<TInstance extends
|
|
75
|
+
protected addCallbackOrWaitCollectionAvailable<TInstance extends IRef, TReturn extends Ref>(
|
|
76
76
|
instance: TInstance,
|
|
77
77
|
propertyName: string,
|
|
78
78
|
operation: OPERATION,
|
|
@@ -142,7 +142,7 @@ export class StateCallbackStrategy<TState extends Schema> {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
protected listenInstance<TInstance extends
|
|
145
|
+
protected listenInstance<TInstance extends IRef>(
|
|
146
146
|
instance: TInstance,
|
|
147
147
|
propertyName: string,
|
|
148
148
|
handler: PropertyChangeCallback<any>,
|
|
@@ -344,7 +344,7 @@ export class StateCallbackStrategy<TState extends Schema> {
|
|
|
344
344
|
//
|
|
345
345
|
if (
|
|
346
346
|
(change.op & OPERATION.DELETE) === OPERATION.DELETE &&
|
|
347
|
-
change.previousValue
|
|
347
|
+
Schema.isSchema(change.previousValue)
|
|
348
348
|
) {
|
|
349
349
|
const childRefId = (change.previousValue as Ref)[$refId];
|
|
350
350
|
const deleteCallbacks = this.callbacks[childRefId]?.[OPERATION.DELETE];
|
|
@@ -355,7 +355,7 @@ export class StateCallbackStrategy<TState extends Schema> {
|
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
357
|
|
|
358
|
-
if (ref
|
|
358
|
+
if (Schema.isSchema(ref)) {
|
|
359
359
|
//
|
|
360
360
|
// Handle Schema instance
|
|
361
361
|
//
|
|
@@ -485,7 +485,7 @@ export const Callbacks = {
|
|
|
485
485
|
* @param roomOrDecoder - Room or Decoder instance to get the callbacks for.
|
|
486
486
|
* @returns the new callbacks standard API.
|
|
487
487
|
*/
|
|
488
|
-
get<T extends
|
|
488
|
+
get<T extends IRef>(roomOrDecoder: Decoder<T> | { serializer: { decoder: Decoder<T> } }): StateCallbackStrategy<T> {
|
|
489
489
|
if (roomOrDecoder instanceof Decoder) {
|
|
490
490
|
return new StateCallbackStrategy<T>(roomOrDecoder);
|
|
491
491
|
|
|
@@ -137,7 +137,7 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
137
137
|
//
|
|
138
138
|
if (
|
|
139
139
|
(change.op & OPERATION.DELETE) === OPERATION.DELETE &&
|
|
140
|
-
change.previousValue
|
|
140
|
+
Schema.isSchema(change.previousValue)
|
|
141
141
|
) {
|
|
142
142
|
const deleteCallbacks = callbacks[(change.previousValue as Ref)[$refId]]?.[OPERATION.DELETE];
|
|
143
143
|
for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {
|
|
@@ -145,7 +145,7 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
if (ref
|
|
148
|
+
if (Schema.isSchema(ref)) {
|
|
149
149
|
//
|
|
150
150
|
// Handle schema instance
|
|
151
151
|
//
|
package/src/types/HelperTypes.ts
CHANGED
|
@@ -56,9 +56,11 @@ export type InferValueType<T extends DefinitionType> =
|
|
|
56
56
|
: T extends { map: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? MapSchema<ChildType[keyof ChildType]> : MapSchema<PrimitiveStringToType<ChildType>>) // TS ENUM
|
|
57
57
|
|
|
58
58
|
: T extends { set: infer ChildType extends Constructor } ? SetSchema<InstanceType<ChildType>>
|
|
59
|
+
: T extends { set: infer ChildType extends RawPrimitiveType } ? SetSchema<InferValueType<ChildType>> // primitive types
|
|
59
60
|
: T extends { set: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? SetSchema<ChildType[keyof ChildType]> : SetSchema<ChildType>) // TS ENUM
|
|
60
61
|
|
|
61
62
|
: T extends { collection: infer ChildType extends Constructor } ? CollectionSchema<InstanceType<ChildType>>
|
|
63
|
+
: T extends { collection: infer ChildType extends RawPrimitiveType } ? CollectionSchema<InferValueType<ChildType>> // primitive types
|
|
62
64
|
: T extends { collection: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? CollectionSchema<ChildType[keyof ChildType]> : CollectionSchema<ChildType>) // TS ENUM
|
|
63
65
|
|
|
64
66
|
// Handle direct types
|