@colyseus/schema 4.0.20 → 5.0.0
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/README.md +2 -0
- package/build/Metadata.d.ts +55 -2
- package/build/Reflection.d.ts +24 -30
- package/build/Schema.d.ts +70 -9
- package/build/annotations.d.ts +56 -13
- package/build/codegen/cli.cjs +84 -67
- package/build/codegen/cli.cjs.map +1 -1
- package/build/decoder/DecodeOperation.d.ts +48 -5
- package/build/decoder/Decoder.d.ts +2 -2
- package/build/decoder/strategy/Callbacks.d.ts +1 -1
- package/build/encoder/ChangeRecorder.d.ts +107 -0
- package/build/encoder/ChangeTree.d.ts +218 -69
- package/build/encoder/EncodeDescriptor.d.ts +63 -0
- package/build/encoder/EncodeOperation.d.ts +25 -2
- package/build/encoder/Encoder.d.ts +59 -3
- package/build/encoder/MapJournal.d.ts +62 -0
- package/build/encoder/RefIdAllocator.d.ts +35 -0
- package/build/encoder/Root.d.ts +94 -13
- package/build/encoder/StateView.d.ts +116 -8
- package/build/encoder/changeTree/inheritedFlags.d.ts +34 -0
- package/build/encoder/changeTree/liveIteration.d.ts +3 -0
- package/build/encoder/changeTree/parentChain.d.ts +24 -0
- package/build/encoder/changeTree/treeAttachment.d.ts +13 -0
- package/build/encoder/streaming.d.ts +73 -0
- package/build/encoder/subscriptions.d.ts +25 -0
- package/build/index.cjs +5202 -1552
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +7 -3
- package/build/index.js +5202 -1552
- package/build/index.mjs +5193 -1552
- package/build/index.mjs.map +1 -1
- package/build/input/InputDecoder.d.ts +32 -0
- package/build/input/InputEncoder.d.ts +117 -0
- package/build/input/index.cjs +7429 -0
- package/build/input/index.cjs.map +1 -0
- package/build/input/index.d.ts +3 -0
- package/build/input/index.mjs +7426 -0
- package/build/input/index.mjs.map +1 -0
- package/build/types/HelperTypes.d.ts +22 -8
- package/build/types/TypeContext.d.ts +9 -0
- package/build/types/builder.d.ts +162 -0
- package/build/types/custom/ArraySchema.d.ts +25 -4
- package/build/types/custom/CollectionSchema.d.ts +30 -2
- package/build/types/custom/MapSchema.d.ts +52 -3
- package/build/types/custom/SetSchema.d.ts +32 -2
- package/build/types/custom/StreamSchema.d.ts +114 -0
- package/build/types/symbols.d.ts +48 -5
- package/package.json +9 -3
- package/src/Metadata.ts +258 -31
- package/src/Reflection.ts +15 -13
- package/src/Schema.ts +176 -134
- package/src/annotations.ts +308 -236
- package/src/bench_bloat.ts +173 -0
- package/src/bench_decode.ts +221 -0
- package/src/bench_decode_mem.ts +165 -0
- package/src/bench_encode.ts +108 -0
- package/src/bench_init.ts +150 -0
- package/src/bench_static.ts +109 -0
- package/src/bench_stream.ts +295 -0
- package/src/bench_view_cmp.ts +142 -0
- package/src/codegen/languages/csharp.ts +0 -24
- package/src/codegen/parser.ts +83 -61
- package/src/decoder/DecodeOperation.ts +168 -63
- package/src/decoder/Decoder.ts +20 -10
- package/src/decoder/ReferenceTracker.ts +4 -0
- package/src/decoder/strategy/Callbacks.ts +30 -26
- package/src/decoder/strategy/getDecoderStateCallbacks.ts +16 -13
- package/src/encoder/ChangeRecorder.ts +276 -0
- package/src/encoder/ChangeTree.ts +674 -519
- package/src/encoder/EncodeDescriptor.ts +213 -0
- package/src/encoder/EncodeOperation.ts +107 -65
- package/src/encoder/Encoder.ts +630 -119
- package/src/encoder/MapJournal.ts +124 -0
- package/src/encoder/RefIdAllocator.ts +68 -0
- package/src/encoder/Root.ts +247 -120
- package/src/encoder/StateView.ts +592 -121
- package/src/encoder/changeTree/inheritedFlags.ts +217 -0
- package/src/encoder/changeTree/liveIteration.ts +74 -0
- package/src/encoder/changeTree/parentChain.ts +131 -0
- package/src/encoder/changeTree/treeAttachment.ts +171 -0
- package/src/encoder/streaming.ts +232 -0
- package/src/encoder/subscriptions.ts +71 -0
- package/src/index.ts +15 -3
- package/src/input/InputDecoder.ts +57 -0
- package/src/input/InputEncoder.ts +303 -0
- package/src/input/index.ts +3 -0
- package/src/types/HelperTypes.ts +21 -9
- package/src/types/TypeContext.ts +14 -2
- package/src/types/builder.ts +285 -0
- package/src/types/custom/ArraySchema.ts +210 -197
- package/src/types/custom/CollectionSchema.ts +115 -35
- package/src/types/custom/MapSchema.ts +162 -58
- package/src/types/custom/SetSchema.ts +128 -39
- package/src/types/custom/StreamSchema.ts +310 -0
- package/src/types/symbols.ts +54 -6
- package/src/utils.ts +4 -6
package/build/types/symbols.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const $refId
|
|
1
|
+
export declare const $refId: unique symbol;
|
|
2
2
|
export declare const $track = "~track";
|
|
3
3
|
export declare const $encoder = "~encoder";
|
|
4
4
|
export declare const $decoder = "~decoder";
|
|
@@ -6,14 +6,24 @@ export declare const $filter = "~filter";
|
|
|
6
6
|
export declare const $getByIndex = "~getByIndex";
|
|
7
7
|
export declare const $deleteByIndex = "~deleteByIndex";
|
|
8
8
|
/**
|
|
9
|
-
* Used to hold ChangeTree instances whitin the structures
|
|
9
|
+
* Used to hold ChangeTree instances whitin the structures.
|
|
10
|
+
*
|
|
11
|
+
* Real JS Symbol — see the `$values` comment for rationale.
|
|
10
12
|
*/
|
|
11
|
-
export declare const $changes
|
|
13
|
+
export declare const $changes: unique symbol;
|
|
12
14
|
/**
|
|
13
15
|
* Used to keep track of the type of the child elements of a collection
|
|
14
|
-
* (MapSchema, ArraySchema, etc.)
|
|
16
|
+
* (MapSchema, ArraySchema, etc.). Real Symbol — same rationale as $values.
|
|
15
17
|
*/
|
|
16
|
-
export declare const $childType
|
|
18
|
+
export declare const $childType: unique symbol;
|
|
19
|
+
/**
|
|
20
|
+
* Self-reference an instance sets on `this` so its own methods can recover
|
|
21
|
+
* the underlying object even when `this` is a Proxy wrapper. Used by
|
|
22
|
+
* ArraySchema (whose public API is a Proxy) to grab the underlying instance
|
|
23
|
+
* once at the top of hot methods and then access fields directly without
|
|
24
|
+
* paying the Proxy.get cost on every read.
|
|
25
|
+
*/
|
|
26
|
+
export declare const $proxyTarget: unique symbol;
|
|
17
27
|
/**
|
|
18
28
|
* Optional "discard" method for custom types (ArraySchema)
|
|
19
29
|
* (Discards changes for next serialization)
|
|
@@ -23,11 +33,44 @@ export declare const $onEncodeEnd = "~onEncodeEnd";
|
|
|
23
33
|
* When decoding, this method is called after the instance is fully decoded
|
|
24
34
|
*/
|
|
25
35
|
export declare const $onDecodeEnd = "~onDecodeEnd";
|
|
36
|
+
/**
|
|
37
|
+
* Per-instance dense array holding field values by index.
|
|
38
|
+
* Replaces per-field _fieldName shadow properties.
|
|
39
|
+
*
|
|
40
|
+
* Real JS Symbol (not "~"-prefixed string) so plain assignment is safe —
|
|
41
|
+
* symbols are non-enumerable to Object.keys / JSON.stringify / for-in,
|
|
42
|
+
* which means we can drop Object.defineProperty(...{ enumerable: false })
|
|
43
|
+
* and avoid the slow-path / dictionary-mode hazards that come with it.
|
|
44
|
+
*/
|
|
45
|
+
export declare const $values: unique symbol;
|
|
46
|
+
/**
|
|
47
|
+
* Brand for FieldBuilder instances so schema() can detect them.
|
|
48
|
+
*/
|
|
49
|
+
export declare const $builder = "~builder";
|
|
26
50
|
/**
|
|
27
51
|
* Metadata
|
|
28
52
|
*/
|
|
29
53
|
export declare const $descriptors = "~descriptors";
|
|
54
|
+
/**
|
|
55
|
+
* Per-class bitmask: bit i set iff field i carries a @view tag.
|
|
56
|
+
* Lazily computed from $viewFieldIndexes on first encode pass.
|
|
57
|
+
* Skips the per-field metadata[i].tag property chase in the hot encode loop.
|
|
58
|
+
*/
|
|
59
|
+
export declare const $filterBitmask = "~__filterBitmask";
|
|
60
|
+
/**
|
|
61
|
+
* Cached per-class encode descriptor: bundles encoder fn, filter fn,
|
|
62
|
+
* metadata, isSchema flag, and filterBitmask into one object stashed on
|
|
63
|
+
* the constructor. Replaces 5 separate per-tree property chases /
|
|
64
|
+
* function calls in the encode loop with a single property load.
|
|
65
|
+
*/
|
|
66
|
+
export declare const $encodeDescriptor = "~__encodeDescriptor";
|
|
67
|
+
export declare const $encoders = "~encoders";
|
|
30
68
|
export declare const $numFields = "~__numFields";
|
|
31
69
|
export declare const $refTypeFieldIndexes = "~__refTypeFieldIndexes";
|
|
32
70
|
export declare const $viewFieldIndexes = "~__viewFieldIndexes";
|
|
33
71
|
export declare const $fieldIndexesByViewTag = "$__fieldIndexesByViewTag";
|
|
72
|
+
export declare const $unreliableFieldIndexes = "~__unreliableFieldIndexes";
|
|
73
|
+
export declare const $transientFieldIndexes = "~__transientFieldIndexes";
|
|
74
|
+
export declare const $staticFieldIndexes = "~__staticFieldIndexes";
|
|
75
|
+
export declare const $streamFieldIndexes = "~__streamFieldIndexes";
|
|
76
|
+
export declare const $streamPriorities = "~__streamPriorities";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colyseus/schema",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Binary state serializer with delta encoding for games",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc -p tsconfig.build.json && rollup -c rollup.config.mjs",
|
|
12
12
|
"watch": "tsc -p tsconfig.build.json -w",
|
|
13
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
13
14
|
"test": "tsx --tsconfig tsconfig.test.json ./node_modules/.bin/mocha test/*.test.ts test/**/*.test.ts",
|
|
14
|
-
"typecheck": "tsc -p tsconfig.test.json",
|
|
15
15
|
"coverage": "c8 npm run test",
|
|
16
16
|
"generate-test-1": "bin/schema-codegen test-external/PrimitiveTypes.ts --namespace SchemaTest.PrimitiveTypes --output ../colyseus-unity-sdk/Assets/Colyseus/Tests/Editor/ColyseusTests/Schema/PrimitiveTypes",
|
|
17
17
|
"generate-test-2": "bin/schema-codegen test-external/ChildSchemaTypes.ts --namespace SchemaTest.ChildSchemaTypes --output ../colyseus-unity-sdk/Assets/Colyseus/Tests/Editor/ColyseusTests/Schema/ChildSchemaTypes",
|
|
@@ -42,6 +42,12 @@
|
|
|
42
42
|
"import": "./build/index.mjs",
|
|
43
43
|
"require": "./build/index.cjs",
|
|
44
44
|
"types": "./build/index.d.ts"
|
|
45
|
+
},
|
|
46
|
+
"./input": {
|
|
47
|
+
"browser": "./build/input/index.mjs",
|
|
48
|
+
"import": "./build/input/index.mjs",
|
|
49
|
+
"require": "./build/input/index.cjs",
|
|
50
|
+
"types": "./build/input/index.d.ts"
|
|
45
51
|
}
|
|
46
52
|
},
|
|
47
53
|
"repository": {
|
|
@@ -82,7 +88,7 @@
|
|
|
82
88
|
"typescript": "^5.9.3"
|
|
83
89
|
},
|
|
84
90
|
"peerDependencies": {
|
|
85
|
-
"typescript": "^5.
|
|
91
|
+
"typescript": "^5.9.3"
|
|
86
92
|
},
|
|
87
93
|
"c8": {
|
|
88
94
|
"include": [
|
package/src/Metadata.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { DefinitionType, getPropertyDescriptor } from "./annotations.js";
|
|
2
2
|
import { Schema } from "./Schema.js";
|
|
3
|
-
import { getType, registeredTypes } from "./types/registry.js";
|
|
4
|
-
import { $decoder, $descriptors, $encoder, $fieldIndexesByViewTag, $numFields, $refTypeFieldIndexes, $track, $viewFieldIndexes } from "./types/symbols.js";
|
|
3
|
+
import { getType, registeredTypes, TypeDefinition } from "./types/registry.js";
|
|
4
|
+
import { $decoder, $descriptors, $encoder, $encoders, $fieldIndexesByViewTag, $numFields, $refTypeFieldIndexes, $staticFieldIndexes, $streamFieldIndexes, $streamPriorities, $track, $transientFieldIndexes, $unreliableFieldIndexes, $viewFieldIndexes } from "./types/symbols.js";
|
|
5
|
+
import { ARRAY_STREAM_NOT_SUPPORTED } from "./encoder/streaming.js";
|
|
6
|
+
import { encode } from "./encoding/encode.js";
|
|
5
7
|
import { TypeContext } from "./types/TypeContext.js";
|
|
6
8
|
|
|
7
9
|
export type MetadataField = {
|
|
@@ -10,7 +12,11 @@ export type MetadataField = {
|
|
|
10
12
|
index: number,
|
|
11
13
|
tag?: number,
|
|
12
14
|
unreliable?: boolean,
|
|
15
|
+
transient?: boolean,
|
|
13
16
|
deprecated?: boolean,
|
|
17
|
+
owned?: boolean,
|
|
18
|
+
static?: boolean,
|
|
19
|
+
stream?: boolean,
|
|
14
20
|
};
|
|
15
21
|
|
|
16
22
|
export type Metadata =
|
|
@@ -18,10 +24,31 @@ export type Metadata =
|
|
|
18
24
|
{ [$viewFieldIndexes]: number[]; } & // all field indexes with "view" tag
|
|
19
25
|
{ [$fieldIndexesByViewTag]: {[tag: number]: number[]}; } & // field indexes by "view" tag
|
|
20
26
|
{ [$refTypeFieldIndexes]: number[]; } & // all field indexes containing Ref types (Schema, ArraySchema, MapSchema, etc)
|
|
27
|
+
{ [$unreliableFieldIndexes]: number[]; } & // all field indexes tagged with @unreliable
|
|
28
|
+
{ [$transientFieldIndexes]: number[]; } & // all field indexes tagged with @transient (not persisted to snapshots)
|
|
29
|
+
{ [$staticFieldIndexes]: number[]; } & // all field indexes tagged with @static (not tracked after assignment)
|
|
30
|
+
{ [$streamFieldIndexes]: number[]; } & // all field indexes holding a t.stream(...) collection
|
|
31
|
+
{ [$streamPriorities]: { [field: number]: (view: any, element: any) => number }; } & // per-stream-field priority callback declared at schema definition time
|
|
32
|
+
{ [$encoders]: Array<(bytes: Uint8Array, value: any, it: any) => void>; } & // pre-computed encoder fn per primitive field
|
|
21
33
|
{ [field: number]: MetadataField; } & // index => field name
|
|
22
34
|
{ [field: string]: number; } & // field name => field metadata
|
|
23
35
|
{ [$descriptors]: { [field: string]: PropertyDescriptor } } // property descriptors
|
|
24
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Given a normalized field type (`"number"`, `{ map: Foo }`, `Player`,
|
|
39
|
+
* etc.), split into the collection-type descriptor (`{ constructor:
|
|
40
|
+
* MapSchema, ... }`) if applicable and the inner child type. Shared by
|
|
41
|
+
* `@type()` decoration and `Metadata.setFields` — both need to build a
|
|
42
|
+
* property accessor that knows whether the slot holds a collection.
|
|
43
|
+
*/
|
|
44
|
+
export function resolveFieldType(type: any): { complexTypeKlass: TypeDefinition | false, childType: any } {
|
|
45
|
+
const complexTypeKlass = typeof (Object.keys(type)[0]) === "string" && getType(Object.keys(type)[0]);
|
|
46
|
+
return {
|
|
47
|
+
complexTypeKlass,
|
|
48
|
+
childType: complexTypeKlass ? Object.values(type)[0] : type,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
25
52
|
export function getNormalizedType(type: any): DefinitionType {
|
|
26
53
|
if (Array.isArray(type)) {
|
|
27
54
|
return { array: getNormalizedType(type[0]) };
|
|
@@ -91,16 +118,11 @@ export const Metadata = {
|
|
|
91
118
|
});
|
|
92
119
|
|
|
93
120
|
if (descriptor) {
|
|
94
|
-
// for
|
|
121
|
+
// Accessor descriptor for the public field name.
|
|
122
|
+
// Installed on the prototype at class-definition time.
|
|
95
123
|
metadata[$descriptors][name] = descriptor;
|
|
96
|
-
metadata[$descriptors][`_${name}`] = {
|
|
97
|
-
value: undefined,
|
|
98
|
-
writable: true,
|
|
99
|
-
enumerable: false,
|
|
100
|
-
configurable: true,
|
|
101
|
-
};
|
|
102
124
|
} else {
|
|
103
|
-
//
|
|
125
|
+
// For decoder: simple writable slot, also on prototype.
|
|
104
126
|
metadata[$descriptors][name] = {
|
|
105
127
|
value: undefined,
|
|
106
128
|
writable: true,
|
|
@@ -134,6 +156,38 @@ export const Metadata = {
|
|
|
134
156
|
}
|
|
135
157
|
metadata[$refTypeFieldIndexes].push(index);
|
|
136
158
|
}
|
|
159
|
+
|
|
160
|
+
// `{ stream: ... }` collections are always view-scoped (priority-
|
|
161
|
+
// batched emit). Auto-flag here so both `@type({stream: ...})` and
|
|
162
|
+
// the `t.stream(...)` builder route into the same filter / encoder
|
|
163
|
+
// dispatch without the caller needing an extra setStream() call.
|
|
164
|
+
const t = metadata[index].type;
|
|
165
|
+
if (t && typeof t === "object" && (t as any)["stream"] !== undefined) {
|
|
166
|
+
// Reject the combined shorthand `@type({ array: X, stream:
|
|
167
|
+
// true })` at decoration time — same diagnostic as the
|
|
168
|
+
// builder chainable throws for `t.array(X).stream()`.
|
|
169
|
+
if ((t as any).array !== undefined) {
|
|
170
|
+
throw new Error(ARRAY_STREAM_NOT_SUPPORTED);
|
|
171
|
+
}
|
|
172
|
+
metadata[index].stream = true;
|
|
173
|
+
if (!metadata[$streamFieldIndexes]) {
|
|
174
|
+
Object.defineProperty(metadata, $streamFieldIndexes, {
|
|
175
|
+
value: [],
|
|
176
|
+
enumerable: false,
|
|
177
|
+
configurable: true,
|
|
178
|
+
writable: true,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
if (!metadata[$streamFieldIndexes].includes(index)) {
|
|
182
|
+
metadata[$streamFieldIndexes].push(index);
|
|
183
|
+
}
|
|
184
|
+
// Pick up the declaration-scope priority callback if present in
|
|
185
|
+
// the `@type({ stream: X, priority: fn })` shorthand.
|
|
186
|
+
const priorityFn = (type as any)?.priority;
|
|
187
|
+
if (typeof priorityFn === "function") {
|
|
188
|
+
Metadata.setStreamPriority(metadata as any, name, priorityFn);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
137
191
|
},
|
|
138
192
|
|
|
139
193
|
setTag(metadata: Metadata, fieldName: string, tag: number) {
|
|
@@ -168,6 +222,112 @@ export const Metadata = {
|
|
|
168
222
|
metadata[$fieldIndexesByViewTag][tag].push(index);
|
|
169
223
|
},
|
|
170
224
|
|
|
225
|
+
setUnreliable(metadata: Metadata, fieldName: string) {
|
|
226
|
+
const index = metadata[fieldName];
|
|
227
|
+
const fieldType = metadata[index].type;
|
|
228
|
+
// `@unreliable` is only valid on primitive fields. Ref-type fields
|
|
229
|
+
// (Schema sub-classes, MapSchema, ArraySchema, SetSchema,
|
|
230
|
+
// CollectionSchema) carry refIds whose ADD/DELETE must arrive
|
|
231
|
+
// on the reliable channel — otherwise a dropped unreliable packet
|
|
232
|
+
// would leave the decoder unable to interpret subsequent packets
|
|
233
|
+
// referencing the orphan refId. Primitive types are encoded as
|
|
234
|
+
// strings ("number", "string", "int32", ...); anything else is a
|
|
235
|
+
// ref. Reject at decoration time so the bug surfaces in dev, not
|
|
236
|
+
// under packet loss in prod.
|
|
237
|
+
if (typeof fieldType !== "string") {
|
|
238
|
+
throw new Error(
|
|
239
|
+
`@unreliable cannot be applied to ref-type field "${fieldName}". ` +
|
|
240
|
+
`For ref-type fields, mark each primitive sub-field with @unreliable instead. ` +
|
|
241
|
+
`See README "Limitations and best practices".`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
metadata[index].unreliable = true;
|
|
245
|
+
|
|
246
|
+
if (!metadata[$unreliableFieldIndexes]) {
|
|
247
|
+
Object.defineProperty(metadata, $unreliableFieldIndexes, {
|
|
248
|
+
value: [],
|
|
249
|
+
enumerable: false,
|
|
250
|
+
configurable: true,
|
|
251
|
+
writable: true,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
metadata[$unreliableFieldIndexes].push(index);
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
setTransient(metadata: Metadata, fieldName: string) {
|
|
258
|
+
const index = metadata[fieldName];
|
|
259
|
+
metadata[index].transient = true;
|
|
260
|
+
|
|
261
|
+
if (!metadata[$transientFieldIndexes]) {
|
|
262
|
+
Object.defineProperty(metadata, $transientFieldIndexes, {
|
|
263
|
+
value: [],
|
|
264
|
+
enumerable: false,
|
|
265
|
+
configurable: true,
|
|
266
|
+
writable: true,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
metadata[$transientFieldIndexes].push(index);
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
setStatic(metadata: Metadata, fieldName: string) {
|
|
273
|
+
const index = metadata[fieldName];
|
|
274
|
+
metadata[index].static = true;
|
|
275
|
+
|
|
276
|
+
if (!metadata[$staticFieldIndexes]) {
|
|
277
|
+
Object.defineProperty(metadata, $staticFieldIndexes, {
|
|
278
|
+
value: [],
|
|
279
|
+
enumerable: false,
|
|
280
|
+
configurable: true,
|
|
281
|
+
writable: true,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
metadata[$staticFieldIndexes].push(index);
|
|
285
|
+
},
|
|
286
|
+
|
|
287
|
+
setStream(metadata: Metadata, fieldName: string) {
|
|
288
|
+
const index = metadata[fieldName];
|
|
289
|
+
metadata[index].stream = true;
|
|
290
|
+
|
|
291
|
+
if (!metadata[$streamFieldIndexes]) {
|
|
292
|
+
Object.defineProperty(metadata, $streamFieldIndexes, {
|
|
293
|
+
value: [],
|
|
294
|
+
enumerable: false,
|
|
295
|
+
configurable: true,
|
|
296
|
+
writable: true,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
metadata[$streamFieldIndexes].push(index);
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Attach a declaration-scope priority callback to a stream field.
|
|
304
|
+
* Called at schema definition time (via `t.stream(X).priority(fn)` or
|
|
305
|
+
* `@type({ stream: X, priority: fn })`), looked up at stream-attach
|
|
306
|
+
* time to seed the instance's `_stream.priority` slot. The callback
|
|
307
|
+
* signature is `(view: StateView, element: V) => number` — only fires
|
|
308
|
+
* during `encodeView`, broadcast mode emits FIFO regardless.
|
|
309
|
+
*/
|
|
310
|
+
setStreamPriority(
|
|
311
|
+
metadata: Metadata,
|
|
312
|
+
fieldName: string,
|
|
313
|
+
fn: (view: any, element: any) => number,
|
|
314
|
+
) {
|
|
315
|
+
const index = metadata[fieldName];
|
|
316
|
+
if (!metadata[$streamPriorities]) {
|
|
317
|
+
Object.defineProperty(metadata, $streamPriorities, {
|
|
318
|
+
value: {},
|
|
319
|
+
enumerable: false,
|
|
320
|
+
configurable: true,
|
|
321
|
+
writable: true,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
metadata[$streamPriorities][index] = fn;
|
|
325
|
+
},
|
|
326
|
+
|
|
327
|
+
getStreamPriority(metadata: Metadata | undefined, index: number) {
|
|
328
|
+
return metadata?.[$streamPriorities]?.[index];
|
|
329
|
+
},
|
|
330
|
+
|
|
171
331
|
setFields<T extends { new (...args: any[]): InstanceType<T> } = any>(target: T, fields: { [field in keyof InstanceType<T>]?: DefinitionType }) {
|
|
172
332
|
// for inheritance support
|
|
173
333
|
const constructor = target.prototype.constructor;
|
|
@@ -192,24 +352,39 @@ export const Metadata = {
|
|
|
192
352
|
|
|
193
353
|
fieldIndex++;
|
|
194
354
|
|
|
355
|
+
// Pre-computed encoder function table: metadata[$encoders][fieldIndex] = encode.uint8 etc.
|
|
356
|
+
if (!metadata[$encoders]) {
|
|
357
|
+
Object.defineProperty(metadata, $encoders, {
|
|
358
|
+
value: parentMetadata?.[$encoders] ? [...parentMetadata[$encoders]] : [],
|
|
359
|
+
enumerable: false,
|
|
360
|
+
configurable: true,
|
|
361
|
+
writable: true,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
195
365
|
for (const field in fields) {
|
|
196
366
|
const type = getNormalizedType(fields[field]);
|
|
197
367
|
|
|
198
|
-
|
|
199
|
-
const complexTypeKlass = typeof(Object.keys(type)[0]) === "string" && getType(Object.keys(type)[0]);
|
|
200
|
-
|
|
201
|
-
const childType = (complexTypeKlass)
|
|
202
|
-
? Object.values(type)[0]
|
|
203
|
-
: type;
|
|
368
|
+
const { complexTypeKlass, childType } = resolveFieldType(type);
|
|
204
369
|
|
|
205
370
|
Metadata.addField(
|
|
206
371
|
metadata,
|
|
207
372
|
fieldIndex,
|
|
208
373
|
field,
|
|
209
374
|
type,
|
|
210
|
-
getPropertyDescriptor(
|
|
375
|
+
getPropertyDescriptor(field, fieldIndex, childType, complexTypeKlass)
|
|
211
376
|
);
|
|
212
377
|
|
|
378
|
+
// Install accessor descriptor on the prototype (once per class field).
|
|
379
|
+
if (metadata[$descriptors][field]) {
|
|
380
|
+
Object.defineProperty(target.prototype, field, metadata[$descriptors][field]);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Pre-compute encoder function for primitive types.
|
|
384
|
+
if (typeof type === "string") {
|
|
385
|
+
metadata[$encoders][fieldIndex] = (encode as any)[type];
|
|
386
|
+
}
|
|
387
|
+
|
|
213
388
|
fieldIndex++;
|
|
214
389
|
}
|
|
215
390
|
|
|
@@ -220,20 +395,6 @@ export const Metadata = {
|
|
|
220
395
|
return metadata[field].deprecated === true;
|
|
221
396
|
},
|
|
222
397
|
|
|
223
|
-
init(klass: any) {
|
|
224
|
-
//
|
|
225
|
-
// Used only to initialize an empty Schema (Encoder#constructor)
|
|
226
|
-
// TODO: remove/refactor this...
|
|
227
|
-
//
|
|
228
|
-
const metadata = {};
|
|
229
|
-
klass[Symbol.metadata] = metadata;
|
|
230
|
-
Object.defineProperty(metadata, $numFields, {
|
|
231
|
-
value: 0,
|
|
232
|
-
enumerable: false,
|
|
233
|
-
configurable: true,
|
|
234
|
-
});
|
|
235
|
-
},
|
|
236
|
-
|
|
237
398
|
initialize(constructor: any) {
|
|
238
399
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
239
400
|
const parentMetadata: Metadata = parentClass[Symbol.metadata];
|
|
@@ -284,6 +445,46 @@ export const Metadata = {
|
|
|
284
445
|
});
|
|
285
446
|
}
|
|
286
447
|
|
|
448
|
+
// $unreliableFieldIndexes
|
|
449
|
+
if (parentMetadata[$unreliableFieldIndexes] !== undefined) {
|
|
450
|
+
Object.defineProperty(metadata, $unreliableFieldIndexes, {
|
|
451
|
+
value: [...parentMetadata[$unreliableFieldIndexes]],
|
|
452
|
+
enumerable: false,
|
|
453
|
+
configurable: true,
|
|
454
|
+
writable: true,
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// $transientFieldIndexes
|
|
459
|
+
if (parentMetadata[$transientFieldIndexes] !== undefined) {
|
|
460
|
+
Object.defineProperty(metadata, $transientFieldIndexes, {
|
|
461
|
+
value: [...parentMetadata[$transientFieldIndexes]],
|
|
462
|
+
enumerable: false,
|
|
463
|
+
configurable: true,
|
|
464
|
+
writable: true,
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// $staticFieldIndexes
|
|
469
|
+
if (parentMetadata[$staticFieldIndexes] !== undefined) {
|
|
470
|
+
Object.defineProperty(metadata, $staticFieldIndexes, {
|
|
471
|
+
value: [...parentMetadata[$staticFieldIndexes]],
|
|
472
|
+
enumerable: false,
|
|
473
|
+
configurable: true,
|
|
474
|
+
writable: true,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// $streamFieldIndexes
|
|
479
|
+
if (parentMetadata[$streamFieldIndexes] !== undefined) {
|
|
480
|
+
Object.defineProperty(metadata, $streamFieldIndexes, {
|
|
481
|
+
value: [...parentMetadata[$streamFieldIndexes]],
|
|
482
|
+
enumerable: false,
|
|
483
|
+
configurable: true,
|
|
484
|
+
writable: true,
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
|
|
287
488
|
// $descriptors
|
|
288
489
|
Object.defineProperty(metadata, $descriptors, {
|
|
289
490
|
value: { ...parentMetadata[$descriptors] },
|
|
@@ -291,6 +492,16 @@ export const Metadata = {
|
|
|
291
492
|
configurable: true,
|
|
292
493
|
writable: true,
|
|
293
494
|
});
|
|
495
|
+
|
|
496
|
+
// $encoders
|
|
497
|
+
if (parentMetadata[$encoders] !== undefined) {
|
|
498
|
+
Object.defineProperty(metadata, $encoders, {
|
|
499
|
+
value: [...parentMetadata[$encoders]],
|
|
500
|
+
enumerable: false,
|
|
501
|
+
configurable: true,
|
|
502
|
+
writable: true,
|
|
503
|
+
});
|
|
504
|
+
}
|
|
294
505
|
}
|
|
295
506
|
}
|
|
296
507
|
|
|
@@ -321,5 +532,21 @@ export const Metadata = {
|
|
|
321
532
|
|
|
322
533
|
hasViewTagAtIndex(metadata: Metadata, index: number) {
|
|
323
534
|
return metadata?.[$viewFieldIndexes]?.includes(index);
|
|
535
|
+
},
|
|
536
|
+
|
|
537
|
+
hasUnreliableAtIndex(metadata: Metadata, index: number) {
|
|
538
|
+
return metadata?.[$unreliableFieldIndexes]?.includes(index);
|
|
539
|
+
},
|
|
540
|
+
|
|
541
|
+
hasTransientAtIndex(metadata: Metadata, index: number) {
|
|
542
|
+
return metadata?.[$transientFieldIndexes]?.includes(index);
|
|
543
|
+
},
|
|
544
|
+
|
|
545
|
+
hasStaticAtIndex(metadata: Metadata, index: number) {
|
|
546
|
+
return metadata?.[$staticFieldIndexes]?.includes(index);
|
|
547
|
+
},
|
|
548
|
+
|
|
549
|
+
hasStreamAtIndex(metadata: Metadata, index: number) {
|
|
550
|
+
return metadata?.[$streamFieldIndexes]?.includes(index);
|
|
324
551
|
}
|
|
325
552
|
}
|
package/src/Reflection.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { Iterator } from "./encoding/decode.js";
|
|
|
5
5
|
import { Encoder } from "./encoder/Encoder.js";
|
|
6
6
|
import { Decoder } from "./decoder/Decoder.js";
|
|
7
7
|
import { Schema } from "./Schema.js";
|
|
8
|
+
import { t, FieldBuilder } from "./types/builder.js";
|
|
9
|
+
import { ArraySchema } from "./types/custom/ArraySchema.js";
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Static methods available on Reflection
|
|
@@ -33,25 +35,25 @@ interface ReflectionStatic {
|
|
|
33
35
|
* Reflection
|
|
34
36
|
*/
|
|
35
37
|
export const ReflectionField = schema({
|
|
36
|
-
name:
|
|
37
|
-
type:
|
|
38
|
-
referencedType:
|
|
39
|
-
})
|
|
38
|
+
name: t.string(),
|
|
39
|
+
type: t.string(),
|
|
40
|
+
referencedType: t.number(),
|
|
41
|
+
}, "ReflectionField");
|
|
40
42
|
export type ReflectionField = SchemaType<typeof ReflectionField>;
|
|
41
43
|
|
|
42
44
|
export const ReflectionType = schema({
|
|
43
|
-
id:
|
|
44
|
-
extendsId:
|
|
45
|
-
fields:
|
|
46
|
-
})
|
|
45
|
+
id: t.number(),
|
|
46
|
+
extendsId: t.number(),
|
|
47
|
+
fields: t.array(ReflectionField),
|
|
48
|
+
}, "ReflectionType");
|
|
47
49
|
export type ReflectionType = SchemaType<typeof ReflectionType>;
|
|
48
50
|
|
|
49
51
|
export const Reflection = schema({
|
|
50
|
-
types:
|
|
51
|
-
rootType:
|
|
52
|
-
}) as ReturnType<typeof schema<{
|
|
53
|
-
types:
|
|
54
|
-
rootType:
|
|
52
|
+
types: t.array(ReflectionType),
|
|
53
|
+
rootType: t.number(),
|
|
54
|
+
}, "Reflection") as ReturnType<typeof schema<{
|
|
55
|
+
types: FieldBuilder<ArraySchema<ReflectionType>>;
|
|
56
|
+
rootType: FieldBuilder<number>;
|
|
55
57
|
}>> & ReflectionStatic;
|
|
56
58
|
|
|
57
59
|
export type Reflection = SchemaType<typeof Reflection>;
|