@colyseus/schema 2.0.32 → 3.0.0-alpha.1

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.
Files changed (160) hide show
  1. package/build/cjs/index.js +3428 -2677
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/esm/index.mjs +3324 -2445
  4. package/build/esm/index.mjs.map +1 -1
  5. package/build/umd/index.js +3428 -2677
  6. package/lib/Decoder.d.ts +16 -0
  7. package/lib/Decoder.js +182 -0
  8. package/lib/Decoder.js.map +1 -0
  9. package/lib/Encoder.d.ts +13 -0
  10. package/lib/Encoder.js +79 -0
  11. package/lib/Encoder.js.map +1 -0
  12. package/lib/Metadata.d.ts +36 -0
  13. package/lib/Metadata.js +91 -0
  14. package/lib/Metadata.js.map +1 -0
  15. package/lib/Reflection.d.ts +7 -5
  16. package/lib/Reflection.js +62 -58
  17. package/lib/Reflection.js.map +1 -1
  18. package/lib/Schema.d.ts +39 -51
  19. package/lib/Schema.js +189 -731
  20. package/lib/Schema.js.map +1 -1
  21. package/lib/annotations.d.ts +26 -45
  22. package/lib/annotations.js +363 -194
  23. package/lib/annotations.js.map +1 -1
  24. package/lib/changes/ChangeSet.d.ts +12 -0
  25. package/lib/changes/ChangeSet.js +35 -0
  26. package/lib/changes/ChangeSet.js.map +1 -0
  27. package/lib/changes/DecodeOperation.d.ts +15 -0
  28. package/lib/changes/DecodeOperation.js +186 -0
  29. package/lib/changes/DecodeOperation.js.map +1 -0
  30. package/lib/changes/EncodeOperation.d.ts +18 -0
  31. package/lib/changes/EncodeOperation.js +130 -0
  32. package/lib/changes/EncodeOperation.js.map +1 -0
  33. package/lib/changes/consts.d.ts +14 -0
  34. package/lib/changes/consts.js +18 -0
  35. package/lib/changes/consts.js.map +1 -0
  36. package/lib/decoder/DecodeOperation.d.ts +24 -0
  37. package/lib/decoder/DecodeOperation.js +256 -0
  38. package/lib/decoder/DecodeOperation.js.map +1 -0
  39. package/lib/decoder/Decoder.d.ts +21 -0
  40. package/lib/decoder/Decoder.js +114 -0
  41. package/lib/decoder/Decoder.js.map +1 -0
  42. package/lib/decoder/ReferenceTracker.d.ts +26 -0
  43. package/lib/decoder/ReferenceTracker.js +131 -0
  44. package/lib/decoder/ReferenceTracker.js.map +1 -0
  45. package/lib/decoder/strategy/RawChanges.d.ts +3 -0
  46. package/lib/decoder/strategy/RawChanges.js +8 -0
  47. package/lib/decoder/strategy/RawChanges.js.map +1 -0
  48. package/lib/decoder/strategy/StateCallbacks.d.ts +20 -0
  49. package/lib/decoder/strategy/StateCallbacks.js +240 -0
  50. package/lib/decoder/strategy/StateCallbacks.js.map +1 -0
  51. package/lib/decoding/decode.d.ts +48 -0
  52. package/lib/decoding/decode.js +267 -0
  53. package/lib/decoding/decode.js.map +1 -0
  54. package/lib/ecs.d.ts +11 -0
  55. package/lib/ecs.js +160 -0
  56. package/lib/ecs.js.map +1 -0
  57. package/lib/encoder/ChangeTree.d.ts +72 -0
  58. package/lib/encoder/ChangeTree.js +384 -0
  59. package/lib/encoder/ChangeTree.js.map +1 -0
  60. package/lib/encoder/EncodeOperation.d.ts +25 -0
  61. package/lib/encoder/EncodeOperation.js +156 -0
  62. package/lib/encoder/EncodeOperation.js.map +1 -0
  63. package/lib/encoder/Encoder.d.ts +23 -0
  64. package/lib/encoder/Encoder.js +192 -0
  65. package/lib/encoder/Encoder.js.map +1 -0
  66. package/lib/encoder/StateView.d.ts +21 -0
  67. package/lib/encoder/StateView.js +196 -0
  68. package/lib/encoder/StateView.js.map +1 -0
  69. package/lib/encoding/assert.d.ts +9 -0
  70. package/lib/encoding/assert.js +47 -0
  71. package/lib/encoding/assert.js.map +1 -0
  72. package/lib/encoding/decode.js +1 -1
  73. package/lib/encoding/decode.js.map +1 -1
  74. package/lib/encoding/encode.d.ts +19 -16
  75. package/lib/encoding/encode.js +88 -81
  76. package/lib/encoding/encode.js.map +1 -1
  77. package/lib/encoding/spec.d.ts +25 -0
  78. package/lib/encoding/spec.js +30 -0
  79. package/lib/encoding/spec.js.map +1 -0
  80. package/lib/index.d.ts +18 -10
  81. package/lib/index.js +39 -17
  82. package/lib/index.js.map +1 -1
  83. package/lib/symbol.shim.d.ts +6 -0
  84. package/lib/symbol.shim.js +4 -0
  85. package/lib/symbol.shim.js.map +1 -0
  86. package/lib/types/ArraySchema.d.ts +1 -1
  87. package/lib/types/ArraySchema.js +0 -7
  88. package/lib/types/ArraySchema.js.map +1 -1
  89. package/lib/types/HelperTypes.d.ts +10 -2
  90. package/lib/types/HelperTypes.js.map +1 -1
  91. package/lib/types/custom/ArraySchema.d.ts +245 -0
  92. package/lib/types/custom/ArraySchema.js +659 -0
  93. package/lib/types/custom/ArraySchema.js.map +1 -0
  94. package/lib/types/custom/CollectionSchema.d.ts +42 -0
  95. package/lib/types/custom/CollectionSchema.js +165 -0
  96. package/lib/types/custom/CollectionSchema.js.map +1 -0
  97. package/lib/types/custom/MapSchema.d.ts +43 -0
  98. package/lib/types/custom/MapSchema.js +200 -0
  99. package/lib/types/custom/MapSchema.js.map +1 -0
  100. package/lib/types/custom/SetSchema.d.ts +39 -0
  101. package/lib/types/custom/SetSchema.js +177 -0
  102. package/lib/types/custom/SetSchema.js.map +1 -0
  103. package/lib/types/registry.d.ts +6 -0
  104. package/lib/types/registry.js +19 -0
  105. package/lib/types/registry.js.map +1 -0
  106. package/lib/types/symbols.d.ts +29 -0
  107. package/lib/types/symbols.js +33 -0
  108. package/lib/types/symbols.js.map +1 -0
  109. package/lib/types/utils.d.ts +0 -8
  110. package/lib/types/utils.js +1 -33
  111. package/lib/types/utils.js.map +1 -1
  112. package/lib/usage.d.ts +1 -0
  113. package/lib/usage.js +22 -0
  114. package/lib/usage.js.map +1 -0
  115. package/lib/utils.d.ts +13 -2
  116. package/lib/utils.js +36 -15
  117. package/lib/utils.js.map +1 -1
  118. package/lib/v3.d.ts +1 -0
  119. package/lib/v3.js +427 -0
  120. package/lib/v3.js.map +1 -0
  121. package/lib/v3_bench.d.ts +1 -0
  122. package/lib/v3_bench.js +130 -0
  123. package/lib/v3_bench.js.map +1 -0
  124. package/lib/v3_experiment.d.ts +1 -0
  125. package/lib/v3_experiment.js +407 -0
  126. package/lib/v3_experiment.js.map +1 -0
  127. package/package.json +5 -5
  128. package/src/Metadata.ts +135 -0
  129. package/src/Reflection.ts +75 -66
  130. package/src/Schema.ts +213 -931
  131. package/src/annotations.ts +430 -243
  132. package/src/decoder/DecodeOperation.ts +372 -0
  133. package/src/decoder/Decoder.ts +155 -0
  134. package/src/decoder/ReferenceTracker.ts +151 -0
  135. package/src/decoder/strategy/RawChanges.ts +9 -0
  136. package/src/decoder/strategy/StateCallbacks.ts +326 -0
  137. package/src/encoder/ChangeTree.ts +492 -0
  138. package/src/encoder/EncodeOperation.ts +237 -0
  139. package/src/encoder/Encoder.ts +246 -0
  140. package/src/encoder/StateView.ts +229 -0
  141. package/src/encoding/assert.ts +58 -0
  142. package/src/encoding/decode.ts +1 -1
  143. package/src/encoding/encode.ts +91 -82
  144. package/src/encoding/spec.ts +29 -0
  145. package/src/index.ts +22 -19
  146. package/src/symbol.shim.ts +12 -0
  147. package/src/types/HelperTypes.ts +16 -2
  148. package/src/types/{ArraySchema.ts → custom/ArraySchema.ts} +342 -248
  149. package/src/types/{CollectionSchema.ts → custom/CollectionSchema.ts} +56 -46
  150. package/src/types/{MapSchema.ts → custom/MapSchema.ts} +88 -115
  151. package/src/types/{SetSchema.ts → custom/SetSchema.ts} +58 -47
  152. package/src/types/{typeRegistry.ts → registry.ts} +6 -6
  153. package/src/types/symbols.ts +36 -0
  154. package/src/types/utils.ts +0 -46
  155. package/src/utils.ts +50 -21
  156. package/src/v3_bench.ts +107 -0
  157. package/src/changes/ChangeTree.ts +0 -295
  158. package/src/changes/ReferenceTracker.ts +0 -91
  159. package/src/filters/index.ts +0 -23
  160. package/src/spec.ts +0 -49
@@ -0,0 +1,326 @@
1
+ import { Metadata } from "../../Metadata";
2
+ import { Collection, NonFunctionNonPrimitivePropNames, NonFunctionPropNames } from "../../types/HelperTypes";
3
+ import { Ref } from "../../encoder/ChangeTree";
4
+ import { Decoder } from "../Decoder";
5
+ import { DataChange } from "../DecodeOperation";
6
+ import { OPERATION } from "../../encoding/spec";
7
+ import { DefinitionType } from "../../annotations";
8
+ import { Schema } from "../../Schema";
9
+ import type { ArraySchema } from "../../types/custom/ArraySchema";
10
+
11
+ //
12
+ // Discussion: https://github.com/colyseus/schema/issues/155
13
+ //
14
+ // Main points:
15
+ // - Decouple structures from their callbacks.
16
+ // - Registering deep callbacks can be confusing.
17
+ // - Avoid closures by allowing to pass a context. (https://github.com/colyseus/schema/issues/155#issuecomment-1804694081)
18
+ //
19
+
20
+ type GetProxyType<T> = unknown extends T // is "any"?
21
+ ? InstanceCallback<T> & CollectionCallback<any, any>
22
+ : T extends Collection<infer K, infer V, infer _>
23
+ ? CollectionCallback<K, V>
24
+ : InstanceCallback<T>
25
+
26
+ type InstanceCallback<T> = {
27
+ listen<K extends NonFunctionPropNames<T>>(
28
+ prop: K,
29
+ callback: (value: T[K], previousValue: T[K]) => void,
30
+ immediate?: boolean,
31
+ )
32
+ onChange(callback: () => void): void;
33
+ bindTo(targetObject: any, properties?: Array<NonFunctionPropNames<T>>): void;
34
+ } & {
35
+ [K in NonFunctionNonPrimitivePropNames<T>]: GetProxyType<T[K]>;
36
+ }
37
+
38
+ type CollectionCallback<K, V> = {
39
+ onAdd(callback: (item: V, index: K) => void, immediate?: boolean): void;
40
+ onRemove(callback: (item: V, index: K) => void): void;
41
+ };
42
+
43
+ type OnInstanceAvailableCallback = (callback: (ref: Ref, existing: boolean) => void) => void;
44
+
45
+ type CallContext = {
46
+ instance?: any,
47
+ parentInstance?: any,
48
+ onInstanceAvailable?: OnInstanceAvailableCallback,
49
+ }
50
+
51
+ export function getStateCallbacks(decoder: Decoder) {
52
+ const $root = decoder.$root;
53
+ const callbacks = $root.callbacks;
54
+
55
+ let isTriggeringOnAdd = false;
56
+
57
+ decoder.triggerChanges = function (allChanges: DataChange[]) {
58
+ const uniqueRefIds = new Set<number>();
59
+
60
+ for (let i = 0, l = allChanges.length; i < l; i++) {
61
+ const change = allChanges[i];
62
+ const refId = change.refId;
63
+ const ref = change.ref;
64
+ const $callbacks = callbacks[refId];
65
+
66
+ if (!$callbacks) { continue; }
67
+
68
+ //
69
+ // trigger onRemove on child structure.
70
+ //
71
+ if (
72
+ (change.op & OPERATION.DELETE) === OPERATION.DELETE &&
73
+ change.previousValue instanceof Schema
74
+ ) {
75
+ const deleteCallbacks = callbacks[$root.refIds.get(change.previousValue)]?.[OPERATION.DELETE];
76
+ for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {
77
+ deleteCallbacks[i]();
78
+ }
79
+ // callbacks[$root.refIds.get(change.previousValue)]?.[OPERATION.DELETE]?.forEach(callback =>
80
+ // callback());
81
+ }
82
+
83
+ if (ref instanceof Schema) {
84
+ //
85
+ // Handle schema instance
86
+ //
87
+
88
+ if (!uniqueRefIds.has(refId)) {
89
+ try {
90
+ // trigger onChange
91
+ const replaceCallbacks = $callbacks?.[OPERATION.REPLACE];
92
+ for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
93
+ replaceCallbacks[i]();
94
+ }
95
+
96
+ } catch (e) {
97
+ console.error(e);
98
+ }
99
+ }
100
+
101
+ try {
102
+ if ($callbacks.hasOwnProperty(change.field)) {
103
+ const fieldCallbacks = $callbacks[change.field];
104
+ for (let i = fieldCallbacks?.length - 1; i >= 0; i--) {
105
+ fieldCallbacks[i](change.value, change.previousValue);
106
+ }
107
+ }
108
+
109
+ } catch (e) {
110
+ //
111
+ console.error(e);
112
+ }
113
+
114
+ } else {
115
+ //
116
+ // Handle collection of items
117
+ //
118
+
119
+ if (change.op === OPERATION.ADD && change.previousValue === undefined) {
120
+ // triger onAdd
121
+
122
+ isTriggeringOnAdd = true;
123
+ const addCallbacks = $callbacks[OPERATION.ADD];
124
+ for (let i = addCallbacks?.length - 1; i >= 0; i--) {
125
+ addCallbacks[i](change.value, change.dynamicIndex ?? change.field);
126
+ }
127
+ isTriggeringOnAdd = false;
128
+
129
+ } else if ((change.op & OPERATION.DELETE) === OPERATION.DELETE) {
130
+ //
131
+ // FIXME: `previousValue` should always be available.
132
+ //
133
+ if (change.previousValue !== undefined) {
134
+ // triger onRemove
135
+ const deleteCallbacks = $callbacks[OPERATION.DELETE];
136
+ for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {
137
+ deleteCallbacks[i](change.previousValue, change.dynamicIndex ?? change.field);
138
+ }
139
+ }
140
+
141
+ // Handle DELETE_AND_ADD operations
142
+ // FIXME: should we set "isTriggeringOnAdd" here?
143
+ if ((change.op & OPERATION.ADD) === OPERATION.ADD) {
144
+ const addCallbacks = $callbacks[OPERATION.ADD];
145
+ for (let i = addCallbacks?.length - 1; i >= 0; i--) {
146
+ addCallbacks[i](change.value, change.dynamicIndex ?? change.field);
147
+ }
148
+ }
149
+ }
150
+
151
+ // trigger onChange
152
+ if (change.value !== change.previousValue) {
153
+ const replaceCallbacks = $callbacks[OPERATION.REPLACE];
154
+ for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
155
+ replaceCallbacks[i](change.value, change.dynamicIndex ?? change.field);
156
+ }
157
+ }
158
+ }
159
+
160
+ uniqueRefIds.add(refId);
161
+ }
162
+ };
163
+
164
+ function getProxy(metadataOrType: Metadata | DefinitionType, context: CallContext) {
165
+ let metadata: Metadata = context.instance?.constructor[Symbol.metadata] || metadataOrType;
166
+ let isCollection = (
167
+ (context.instance && typeof (context.instance['forEach']) === "function") ||
168
+ (metadataOrType && typeof (metadataOrType[Symbol.metadata]) === "undefined")
169
+ );
170
+
171
+ if (metadata && !isCollection) {
172
+
173
+ const onAdd = function (
174
+ ref: Ref,
175
+ prop: string,
176
+ callback: (value: any, previousValue: any) => void, immediate: boolean
177
+ ) {
178
+ // immediate trigger
179
+ if (
180
+ immediate &&
181
+ context.instance[prop] !== undefined &&
182
+ !isTriggeringOnAdd // FIXME: This is a workaround (https://github.com/colyseus/schema/issues/147)
183
+ ) {
184
+ callback(context.instance[prop], undefined);
185
+ }
186
+ return $root.addCallback($root.refIds.get(ref), prop, callback);
187
+ }
188
+
189
+ /**
190
+ * Schema instances
191
+ */
192
+ return new Proxy({
193
+ listen: function listen(prop: string, callback: (value: any, previousValue: any) => void, immediate: boolean = true) {
194
+ if (context.instance) {
195
+ return onAdd(context.instance, prop, callback, immediate);
196
+
197
+ } else {
198
+ // collection instance not received yet
199
+ context.onInstanceAvailable((ref: Ref, existing: boolean) =>
200
+ onAdd(ref, prop, callback, immediate && existing));
201
+ }
202
+ },
203
+ onChange: function onChange(callback: () => void) {
204
+ return $root.addCallback(
205
+ $root.refIds.get(context.instance),
206
+ OPERATION.REPLACE,
207
+ callback
208
+ );
209
+
210
+ },
211
+ bindTo: function bindTo(targetObject: any, properties?: string[]) {
212
+ console.log("bindTo", targetObject, properties);
213
+ }
214
+ }, {
215
+ get(target, prop: string) {
216
+ if (metadata[prop]) {
217
+ const instance = context.instance?.[prop];
218
+ const onInstanceAvailable: OnInstanceAvailableCallback = (
219
+ (callback: (ref: Ref, existing: boolean) => void) => {
220
+ const unbind = $(context.instance).listen(prop, (value, _) => {
221
+ callback(value, false);
222
+
223
+ // FIXME: by "unbinding" the callback here,
224
+ // it will not support when the server
225
+ // re-instantiates the instance.
226
+ //
227
+ unbind?.();
228
+ }, false);
229
+
230
+ // has existing value
231
+ if ($root.refIds.get(instance) !== undefined) {
232
+ callback(instance, true);
233
+ }
234
+ }
235
+ );
236
+ return getProxy(metadata[prop].type, {
237
+ instance,
238
+ parentInstance: context.instance,
239
+ onInstanceAvailable,
240
+ });
241
+
242
+ } else {
243
+ // accessing the function
244
+ return target[prop];
245
+ }
246
+ },
247
+ has(target, prop: string) { return metadata[prop] !== undefined; },
248
+ set(_, _1, _2) { throw new Error("not allowed"); },
249
+ deleteProperty(_, _1) { throw new Error("not allowed"); },
250
+ });
251
+
252
+ } else {
253
+ /**
254
+ * Collection instances
255
+ */
256
+
257
+ const onAdd = function (ref: Ref, callback: (value: any, key: any) => void, immediate: boolean) {
258
+ // Trigger callback on existing items
259
+ if (immediate) {
260
+ (ref as ArraySchema).forEach((v, k) => callback(v, k));
261
+ }
262
+ return $root.addCallback($root.refIds.get(ref), OPERATION.ADD, callback);
263
+ };
264
+
265
+ const onRemove = function (ref: Ref, callback: (value: any, key: any) => void) {
266
+ return $root.addCallback($root.refIds.get(ref), OPERATION.DELETE, callback);
267
+ };
268
+
269
+ return new Proxy({
270
+ onAdd: function(callback: (value, key) => void, immediate: boolean = true) {
271
+ //
272
+ // https://github.com/colyseus/schema/issues/147
273
+ // If parent instance has "onAdd" registered, avoid triggering immediate callback.
274
+ //
275
+ // FIXME: "isTriggeringOnAdd" is a workaround. We should find a better way to handle this.
276
+ //
277
+ if (context.onInstanceAvailable) {
278
+ // collection instance not received yet
279
+ context.onInstanceAvailable((ref: Ref, existing: boolean) =>
280
+ onAdd(ref, callback, immediate && existing && !isTriggeringOnAdd));
281
+
282
+ } else if (context.instance) {
283
+ onAdd(context.instance, callback, immediate && !isTriggeringOnAdd);
284
+ }
285
+ },
286
+ onRemove: function(callback: (value, key) => void) {
287
+ if (context.onInstanceAvailable) {
288
+ // collection instance not received yet
289
+ context.onInstanceAvailable((ref: Ref) =>
290
+ onRemove(ref, callback));
291
+
292
+ } else if (context.instance) {
293
+ onRemove(context.instance, callback);
294
+ }
295
+ },
296
+ }, {
297
+ get(target, prop: string) {
298
+ if (!target[prop]) {
299
+ throw new Error(`Can't access '${prop}' through callback proxy. access the instance directly.`);
300
+ }
301
+ return target[prop];
302
+ },
303
+ has(target, prop) { return target[prop] !== undefined; },
304
+ set(_, _1, _2) { throw new Error("not allowed"); },
305
+ deleteProperty(_, _1) { throw new Error("not allowed"); },
306
+ });
307
+ }
308
+ }
309
+
310
+ function $<T>(instance: T): GetProxyType<T> {
311
+ return getProxy(undefined, { instance }) as GetProxyType<T>;
312
+ }
313
+
314
+ return {
315
+ $,
316
+ trigger: function trigger(changes: DataChange[]) {
317
+ for (let i = 0, l = changes.length; i < l; i++) {
318
+ const change = changes[i];
319
+
320
+ change.op
321
+ change.ref
322
+ }
323
+ }
324
+ }
325
+
326
+ }