@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.
Files changed (96) hide show
  1. package/README.md +2 -0
  2. package/build/Metadata.d.ts +55 -2
  3. package/build/Reflection.d.ts +24 -30
  4. package/build/Schema.d.ts +70 -9
  5. package/build/annotations.d.ts +56 -13
  6. package/build/codegen/cli.cjs +84 -67
  7. package/build/codegen/cli.cjs.map +1 -1
  8. package/build/decoder/DecodeOperation.d.ts +48 -5
  9. package/build/decoder/Decoder.d.ts +2 -2
  10. package/build/decoder/strategy/Callbacks.d.ts +1 -1
  11. package/build/encoder/ChangeRecorder.d.ts +107 -0
  12. package/build/encoder/ChangeTree.d.ts +218 -69
  13. package/build/encoder/EncodeDescriptor.d.ts +63 -0
  14. package/build/encoder/EncodeOperation.d.ts +25 -2
  15. package/build/encoder/Encoder.d.ts +59 -3
  16. package/build/encoder/MapJournal.d.ts +62 -0
  17. package/build/encoder/RefIdAllocator.d.ts +35 -0
  18. package/build/encoder/Root.d.ts +94 -13
  19. package/build/encoder/StateView.d.ts +116 -8
  20. package/build/encoder/changeTree/inheritedFlags.d.ts +34 -0
  21. package/build/encoder/changeTree/liveIteration.d.ts +3 -0
  22. package/build/encoder/changeTree/parentChain.d.ts +24 -0
  23. package/build/encoder/changeTree/treeAttachment.d.ts +13 -0
  24. package/build/encoder/streaming.d.ts +73 -0
  25. package/build/encoder/subscriptions.d.ts +25 -0
  26. package/build/index.cjs +5202 -1552
  27. package/build/index.cjs.map +1 -1
  28. package/build/index.d.ts +7 -3
  29. package/build/index.js +5202 -1552
  30. package/build/index.mjs +5193 -1552
  31. package/build/index.mjs.map +1 -1
  32. package/build/input/InputDecoder.d.ts +32 -0
  33. package/build/input/InputEncoder.d.ts +117 -0
  34. package/build/input/index.cjs +7429 -0
  35. package/build/input/index.cjs.map +1 -0
  36. package/build/input/index.d.ts +3 -0
  37. package/build/input/index.mjs +7426 -0
  38. package/build/input/index.mjs.map +1 -0
  39. package/build/types/HelperTypes.d.ts +22 -8
  40. package/build/types/TypeContext.d.ts +9 -0
  41. package/build/types/builder.d.ts +162 -0
  42. package/build/types/custom/ArraySchema.d.ts +25 -4
  43. package/build/types/custom/CollectionSchema.d.ts +30 -2
  44. package/build/types/custom/MapSchema.d.ts +52 -3
  45. package/build/types/custom/SetSchema.d.ts +32 -2
  46. package/build/types/custom/StreamSchema.d.ts +114 -0
  47. package/build/types/symbols.d.ts +48 -5
  48. package/package.json +9 -3
  49. package/src/Metadata.ts +258 -31
  50. package/src/Reflection.ts +15 -13
  51. package/src/Schema.ts +176 -134
  52. package/src/annotations.ts +308 -236
  53. package/src/bench_bloat.ts +173 -0
  54. package/src/bench_decode.ts +221 -0
  55. package/src/bench_decode_mem.ts +165 -0
  56. package/src/bench_encode.ts +108 -0
  57. package/src/bench_init.ts +150 -0
  58. package/src/bench_static.ts +109 -0
  59. package/src/bench_stream.ts +295 -0
  60. package/src/bench_view_cmp.ts +142 -0
  61. package/src/codegen/languages/csharp.ts +0 -24
  62. package/src/codegen/parser.ts +83 -61
  63. package/src/decoder/DecodeOperation.ts +168 -63
  64. package/src/decoder/Decoder.ts +20 -10
  65. package/src/decoder/ReferenceTracker.ts +4 -0
  66. package/src/decoder/strategy/Callbacks.ts +30 -26
  67. package/src/decoder/strategy/getDecoderStateCallbacks.ts +16 -13
  68. package/src/encoder/ChangeRecorder.ts +276 -0
  69. package/src/encoder/ChangeTree.ts +674 -519
  70. package/src/encoder/EncodeDescriptor.ts +213 -0
  71. package/src/encoder/EncodeOperation.ts +107 -65
  72. package/src/encoder/Encoder.ts +630 -119
  73. package/src/encoder/MapJournal.ts +124 -0
  74. package/src/encoder/RefIdAllocator.ts +68 -0
  75. package/src/encoder/Root.ts +247 -120
  76. package/src/encoder/StateView.ts +592 -121
  77. package/src/encoder/changeTree/inheritedFlags.ts +217 -0
  78. package/src/encoder/changeTree/liveIteration.ts +74 -0
  79. package/src/encoder/changeTree/parentChain.ts +131 -0
  80. package/src/encoder/changeTree/treeAttachment.ts +171 -0
  81. package/src/encoder/streaming.ts +232 -0
  82. package/src/encoder/subscriptions.ts +71 -0
  83. package/src/index.ts +15 -3
  84. package/src/input/InputDecoder.ts +57 -0
  85. package/src/input/InputEncoder.ts +303 -0
  86. package/src/input/index.ts +3 -0
  87. package/src/types/HelperTypes.ts +21 -9
  88. package/src/types/TypeContext.ts +14 -2
  89. package/src/types/builder.ts +285 -0
  90. package/src/types/custom/ArraySchema.ts +210 -197
  91. package/src/types/custom/CollectionSchema.ts +115 -35
  92. package/src/types/custom/MapSchema.ts +162 -58
  93. package/src/types/custom/SetSchema.ts +128 -39
  94. package/src/types/custom/StreamSchema.ts +310 -0
  95. package/src/types/symbols.ts +54 -6
  96. package/src/utils.ts +4 -6
@@ -1,9 +1,11 @@
1
- import type { Definition, DefinitionType, PrimitiveType, RawPrimitiveType } from "../annotations.js";
1
+ import type { 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";
5
5
  import type { MapSchema } from "./custom/MapSchema.js";
6
6
  import type { SetSchema } from "./custom/SetSchema.js";
7
+ import type { StreamSchema } from "./custom/StreamSchema.js";
8
+ import type { FieldBuilder } from "./builder.js";
7
9
  export type Constructor<T = {}> = new (...args: any[]) => T;
8
10
  type PrimitiveStringToType<T> = T extends "string" ? string : T extends "number" | "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32" | "int64" | "uint64" | "float32" | "float64" ? number : T extends "boolean" ? boolean : T;
9
11
  export interface Collection<K = any, V = any, IT = V> {
@@ -11,7 +13,7 @@ export interface Collection<K = any, V = any, IT = V> {
11
13
  forEach(callback: Function): void;
12
14
  entries(): IterableIterator<[K, V]>;
13
15
  }
14
- export type InferValueType<T extends DefinitionType> = T extends "string" ? string : T extends "number" ? number : T extends "int8" ? number : T extends "uint8" ? number : T extends "int16" ? number : T extends "uint16" ? number : T extends "int32" ? number : T extends "uint32" ? number : T extends "int64" ? number : T extends "uint64" ? number : T extends "float32" ? number : T extends "float64" ? number : T extends "boolean" ? boolean : T extends {
16
+ export type InferValueType<T> = T extends FieldBuilder<infer V> ? V : T extends "string" ? string : T extends "number" ? number : T extends "int8" ? number : T extends "uint8" ? number : T extends "int16" ? number : T extends "uint16" ? number : T extends "int32" ? number : T extends "uint32" ? number : T extends "int64" ? number : T extends "uint64" ? number : T extends "float32" ? number : T extends "float64" ? number : T extends "boolean" ? boolean : T extends {
15
17
  type: infer ChildType extends PrimitiveType;
16
18
  } ? InferValueType<ChildType> : T extends {
17
19
  type: infer ChildType extends Constructor;
@@ -30,6 +32,14 @@ export type InferValueType<T extends DefinitionType> = T extends "string" ? stri
30
32
  collection: infer ChildType;
31
33
  };
32
34
  } ? (ChildType extends Record<string | number, string | number> ? CollectionSchema<ChildType[keyof ChildType]> : CollectionSchema<ChildType>) : T extends {
35
+ type: {
36
+ stream: infer ChildType extends Constructor;
37
+ };
38
+ } ? StreamSchema<InstanceType<ChildType>> : T extends {
39
+ type: {
40
+ stream: infer ChildType;
41
+ };
42
+ } ? StreamSchema<ChildType> : T extends {
33
43
  type: infer ChildType;
34
44
  } ? (ChildType extends Record<string | number, string | number> ? ChildType[keyof ChildType] : ChildType) : T extends Array<infer ChildType extends Constructor> ? ArraySchema<InstanceType<ChildType>> : T extends Array<infer ChildType> ? (ChildType extends Record<string | number, string | number> ? ArraySchema<ChildType[keyof ChildType]> : ArraySchema<PrimitiveStringToType<ChildType>>) : T extends {
35
45
  array: infer ChildType extends Constructor;
@@ -51,9 +61,13 @@ export type InferValueType<T extends DefinitionType> = T extends "string" ? stri
51
61
  collection: infer ChildType extends RawPrimitiveType;
52
62
  } ? CollectionSchema<InferValueType<ChildType>> : T extends {
53
63
  collection: infer ChildType;
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;
55
- export type InferSchemaInstanceType<T extends Definition> = {
56
- [K in keyof T]: T[K] extends (...args: any[]) => any ? (T[K] extends new (...args: any[]) => any ? InferValueType<T[K]> : T[K]) : InferValueType<T[K]>;
64
+ } ? (ChildType extends Record<string | number, string | number> ? CollectionSchema<ChildType[keyof ChildType]> : CollectionSchema<ChildType>) : T extends {
65
+ stream: infer ChildType extends Constructor;
66
+ } ? StreamSchema<InstanceType<ChildType>> : T extends {
67
+ stream: infer ChildType;
68
+ } ? StreamSchema<ChildType> : T extends Constructor ? InstanceType<T> : T extends Record<string | number, string | number> ? T[keyof T] : T extends PrimitiveType ? T : never;
69
+ export type InferSchemaInstanceType<T> = {
70
+ [K in keyof T]: T[K] extends FieldBuilder<any> ? InferValueType<T[K]> : T[K] extends (...args: any[]) => any ? (T[K] extends new (...args: any[]) => any ? InferValueType<T[K]> : T[K]) : InferValueType<T[K]>;
57
71
  } & Schema;
58
72
  export type NonFunctionProps<T> = Omit<T, {
59
73
  [K in keyof T]: T[K] extends Function ? K : never;
@@ -65,9 +79,9 @@ export type NonFunctionNonPrimitivePropNames<T> = {
65
79
  [K in keyof T]: T[K] extends Function ? never : T[K] extends number | string | boolean ? never : K;
66
80
  }[keyof T];
67
81
  type ToJSONValue<U> = U extends Schema ? ToJSON<U> : PrimitiveStringToType<U>;
68
- export type ToJSON<T> = {
69
- [K in keyof T as T[K] extends Function ? never : K]: T[K] extends MapSchema<infer U> ? Record<string, ToJSONValue<U>> : T[K] extends Map<string, infer U> ? Record<string, ToJSONValue<U>> : T[K] extends ArraySchema<infer U> ? ToJSONValue<U>[] : T[K] extends SetSchema<infer U> ? ToJSONValue<U>[] : T[K] extends CollectionSchema<infer U> ? ToJSONValue<U>[] : T[K] extends Schema ? ToJSON<T[K]> : T[K];
70
- };
82
+ export type ToJSON<T> = NonFunctionProps<{
83
+ [K in keyof T]: T[K] extends MapSchema<infer U> ? Record<string, ToJSONValue<U>> : T[K] extends Map<string, infer U> ? Record<string, ToJSONValue<U>> : T[K] extends ArraySchema<infer U> ? ToJSONValue<U>[] : T[K] extends SetSchema<infer U> ? ToJSONValue<U>[] : T[K] extends CollectionSchema<infer U> ? ToJSONValue<U>[] : T[K] extends Schema ? ToJSON<T[K]> : T[K];
84
+ }>;
71
85
  export type IsNever<T> = [T] extends [never] ? true : false;
72
86
  /**
73
87
  * Type helper for .assign() method - allows assigning values in a flexible way
@@ -8,6 +8,15 @@ export declare class TypeContext {
8
8
  parentFiltered: {
9
9
  [typeIdAndParentIndex: string]: boolean;
10
10
  };
11
+ /**
12
+ * True iff `parentFiltered` has at least one entry. Flipped on by
13
+ * `registerFilteredByParent` and read in `checkInheritedFlags` as a
14
+ * cheap gate to skip the string-keyed `parentFiltered[key]` lookup
15
+ * when no class has registered filter inheritance via ancestry — the
16
+ * common case when @view tags exist only on sibling fields, not
17
+ * along any attachment chain.
18
+ */
19
+ hasParentFilteredEntries: boolean;
11
20
  /**
12
21
  * For inheritance support
13
22
  * Keeps track of which classes extends which. (parent -> children)
@@ -0,0 +1,162 @@
1
+ import type { ArraySchema } from "./custom/ArraySchema.js";
2
+ import type { MapSchema } from "./custom/MapSchema.js";
3
+ import type { SetSchema } from "./custom/SetSchema.js";
4
+ import type { CollectionSchema } from "./custom/CollectionSchema.js";
5
+ import type { StreamSchema } from "./custom/StreamSchema.js";
6
+ import type { Schema } from "../Schema.js";
7
+ import type { DefinitionType, RawPrimitiveType } from "../annotations.js";
8
+ import type { InferValueType, Constructor } from "./HelperTypes.js";
9
+ import { $builder } from "./symbols.js";
10
+ /**
11
+ * Internal record produced by FieldBuilder#toDefinition() and consumed by schema().
12
+ */
13
+ export interface BuilderDefinition {
14
+ type: DefinitionType;
15
+ default?: any;
16
+ hasDefault: boolean;
17
+ view?: number;
18
+ owned?: boolean;
19
+ unreliable?: boolean;
20
+ transient?: boolean;
21
+ deprecated?: boolean;
22
+ deprecatedThrows?: boolean;
23
+ static?: boolean;
24
+ stream?: boolean;
25
+ /** Declaration-scope priority callback for `.stream()` fields. */
26
+ streamPriority?: (view: any, element: any) => number;
27
+ }
28
+ /**
29
+ * Type-function that infers the instance value for a builder.
30
+ */
31
+ export type BuilderOf<T> = FieldBuilder<T>;
32
+ /**
33
+ * Chainable field builder. Instances are produced by `t.*()` factories.
34
+ *
35
+ * The generic parameter T is the runtime/JS type of the field (e.g. `number`,
36
+ * `string`, `ArraySchema<Item>`). schema() reads the internal configuration
37
+ * via `toDefinition()` and wires up metadata through the existing pipeline.
38
+ */
39
+ export declare class FieldBuilder<T = unknown> {
40
+ readonly [$builder]: true;
41
+ _type: DefinitionType;
42
+ _default: any;
43
+ _hasDefault: boolean;
44
+ _view: number | undefined;
45
+ _owned: boolean;
46
+ _unreliable: boolean;
47
+ _transient: boolean;
48
+ _deprecated: boolean;
49
+ _deprecatedThrows: boolean;
50
+ _static: boolean;
51
+ _stream: boolean;
52
+ _streamPriority: ((view: any, element: any) => number) | undefined;
53
+ constructor(type: DefinitionType);
54
+ /** Provide a default value for this field. */
55
+ default(value: T): this;
56
+ /** Tag this field with a view tag (DEFAULT_VIEW_TAG when called without arg). */
57
+ view(tag?: number): this;
58
+ /** Mark this field as owned (encoder-side ownership filtering). */
59
+ owned(): this;
60
+ /**
61
+ * Mark this field as unreliable — tick patches emit it on the unreliable
62
+ * transport channel. Still persisted to full-sync snapshots unless also
63
+ * tagged with `.transient()`.
64
+ */
65
+ unreliable(): this;
66
+ /**
67
+ * Mark this field as transient — NOT persisted to full-sync snapshots
68
+ * (`encodeAll` / `encodeAllView`). Late-joining clients see the field
69
+ * only after its next mutation is emitted on a tick patch. Orthogonal
70
+ * to `.unreliable()`.
71
+ */
72
+ transient(): this;
73
+ /**
74
+ * Mark this field as static.
75
+ * - Primitive / Schema fields: synchronized once, skips change tracking.
76
+ * - Stream fields (`t.stream(X).static()`): child elements are frozen
77
+ * after add — post-add field mutations on elements become no-ops.
78
+ */
79
+ static(): this;
80
+ /**
81
+ * Opt a collection field into priority-batched streaming delivery —
82
+ * ADDs drain at most `maxPerTick` per tick per view (or per broadcast
83
+ * tick without a view). Applies to `t.map(X)` / `t.set(X)` /
84
+ * `t.collection(X)`. Redundant on `t.stream(X)` (the factory already
85
+ * sets this flag).
86
+ *
87
+ * **Not supported on `t.array(X)`.** Array positional operations
88
+ * (`splice`, `unshift`, `reverse`) shift every subsequent index —
89
+ * holding some ADDs back for a later tick while indexes mutate
90
+ * underneath would produce a decoder-side state that doesn't match
91
+ * the server. Use `t.stream(X)` (stable monotonic positions) or
92
+ * `t.map(X).stream()` (keys never shift) instead.
93
+ */
94
+ stream(): this;
95
+ /**
96
+ * Attach a priority callback for per-view `encodeView` delivery. The
97
+ * callback receives the client's StateView and the candidate element;
98
+ * higher return values emit first. Does nothing in broadcast mode
99
+ * (shared `encode()` drains FIFO). Only meaningful on stream fields.
100
+ *
101
+ * ```ts
102
+ * t.stream(Enemy).priority((view, enemy) =>
103
+ * -dist2(view.anchor, enemy)
104
+ * )
105
+ * ```
106
+ */
107
+ priority<V = any>(fn: (view: any, element: V) => number): this;
108
+ /** Mark this field as deprecated. Pass `false` to silence the access error. */
109
+ deprecated(throws?: boolean): this;
110
+ toDefinition(): BuilderDefinition;
111
+ }
112
+ export declare function isBuilder(value: any): value is FieldBuilder<any>;
113
+ export type ChildType = RawPrimitiveType | Constructor<Schema> | FieldBuilder<any>;
114
+ interface ArrayFactory {
115
+ <C extends Constructor<Schema>>(child: C): FieldBuilder<ArraySchema<InstanceType<C>>>;
116
+ <P extends RawPrimitiveType>(child: P): FieldBuilder<ArraySchema<InferValueType<P>>>;
117
+ <V>(child: FieldBuilder<V>): FieldBuilder<ArraySchema<V>>;
118
+ }
119
+ interface MapFactory {
120
+ <C extends Constructor<Schema>>(child: C): FieldBuilder<MapSchema<InstanceType<C>>>;
121
+ <P extends RawPrimitiveType>(child: P): FieldBuilder<MapSchema<InferValueType<P>>>;
122
+ <V>(child: FieldBuilder<V>): FieldBuilder<MapSchema<V>>;
123
+ }
124
+ interface SetFactory {
125
+ <C extends Constructor<Schema>>(child: C): FieldBuilder<SetSchema<InstanceType<C>>>;
126
+ <P extends RawPrimitiveType>(child: P): FieldBuilder<SetSchema<InferValueType<P>>>;
127
+ <V>(child: FieldBuilder<V>): FieldBuilder<SetSchema<V>>;
128
+ }
129
+ interface CollectionFactory {
130
+ <C extends Constructor<Schema>>(child: C): FieldBuilder<CollectionSchema<InstanceType<C>>>;
131
+ <P extends RawPrimitiveType>(child: P): FieldBuilder<CollectionSchema<InferValueType<P>>>;
132
+ <V>(child: FieldBuilder<V>): FieldBuilder<CollectionSchema<V>>;
133
+ }
134
+ interface StreamFactory {
135
+ <C extends Constructor<Schema>>(child: C): FieldBuilder<StreamSchema<InstanceType<C>>>;
136
+ }
137
+ declare function refFactory<C extends Constructor<Schema>>(ctor: C): FieldBuilder<InstanceType<C>>;
138
+ export declare const t: Readonly<{
139
+ string: () => FieldBuilder<string>;
140
+ number: () => FieldBuilder<number>;
141
+ boolean: () => FieldBuilder<boolean>;
142
+ int8: () => FieldBuilder<number>;
143
+ uint8: () => FieldBuilder<number>;
144
+ int16: () => FieldBuilder<number>;
145
+ uint16: () => FieldBuilder<number>;
146
+ int32: () => FieldBuilder<number>;
147
+ uint32: () => FieldBuilder<number>;
148
+ int64: () => FieldBuilder<number>;
149
+ uint64: () => FieldBuilder<number>;
150
+ float32: () => FieldBuilder<number>;
151
+ float64: () => FieldBuilder<number>;
152
+ bigint64: () => FieldBuilder<bigint>;
153
+ biguint64: () => FieldBuilder<bigint>;
154
+ /** Reference to a Schema subtype. `t.array(Item)` usually reads better, but this is available when a plain ref is needed. */
155
+ ref: typeof refFactory;
156
+ array: ArrayFactory;
157
+ map: MapFactory;
158
+ set: SetFactory;
159
+ collection: CollectionFactory;
160
+ stream: StreamFactory;
161
+ }>;
162
+ export {};
@@ -1,4 +1,4 @@
1
- import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $onDecodeEnd, $refId } from "../symbols.js";
1
+ import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $onDecodeEnd, $proxyTarget, $refId } from "../symbols.js";
2
2
  import type { Schema } from "../../Schema.js";
3
3
  import { type IRef, ChangeTree } from "../../encoder/ChangeTree.js";
4
4
  import { OPERATION } from "../../encoding/spec.js";
@@ -8,15 +8,16 @@ export declare class ArraySchema<V = any> implements Array<V>, Collection<number
8
8
  [n: number]: V;
9
9
  [$changes]: ChangeTree;
10
10
  [$refId]?: number;
11
+ [$proxyTarget]: this;
11
12
  protected [$childType]: string | typeof Schema;
12
13
  protected items: V[];
13
14
  protected tmpItems: V[];
14
- protected deletedIndexes: {
15
- [index: number]: boolean;
16
- };
15
+ protected deletedIndexes: boolean[];
17
16
  protected isMovingItems: boolean;
18
17
  static [$encoder]: import("../../encoder/EncodeOperation.js").EncodeOperation<any>;
19
18
  static [$decoder]: import("../../decoder/DecodeOperation.js").DecodeOperation<any>;
19
+ /** Integer tag read by `decodeKeyValueOperation` — see `CollectionKind`. */
20
+ static readonly COLLECTION_KIND: 2;
20
21
  /**
21
22
  * Determine if a property must be filtered.
22
23
  * - If returns false, the property is NOT going to be encoded.
@@ -30,8 +31,22 @@ export declare class ArraySchema<V = any> implements Array<V>, Collection<number
30
31
  static is(type: any): boolean;
31
32
  static from<T>(iterable: Iterable<T> | ArrayLike<T>): ArraySchema<T>;
32
33
  constructor(...items: V[]);
34
+ /**
35
+ * Decoder-side factory. Skips the `ChangeTree` allocation and
36
+ * replicates the class-field initializers by hand (since `Object.create`
37
+ * bypasses them). Must stay in sync with the class-field declarations
38
+ * and the constructor body above.
39
+ *
40
+ * Pass the Proxy to `installUntrackedChangeTree` as the public identity
41
+ * so children set their parent to the Proxy, not the raw target.
42
+ */
43
+ static initializeForDecoder<V = any>(): ArraySchema<V>;
33
44
  set length(newLength: number);
34
45
  get length(): number;
46
+ pauseTracking(): void;
47
+ resumeTracking(): void;
48
+ untracked<T>(fn: () => T): T;
49
+ get isTrackingPaused(): boolean;
35
50
  push(...values: V[]): number;
36
51
  /**
37
52
  * Removes the last element from an array and returns it.
@@ -260,6 +275,12 @@ export declare class ArraySchema<V = any> implements Array<V>, Collection<number
260
275
  * @returns
261
276
  */
262
277
  move(cb: (arr: this) => void): this;
278
+ /**
279
+ * Encoder-only. Reads the staged-snapshot (`tmpItems`) so the encoder can
280
+ * resolve a wire-index even after the user has mutated `items` mid-tick.
281
+ * The decoder reads `items[index]` directly — see `decodeArray` and
282
+ * `$deleteByIndex` below.
283
+ */
263
284
  [$getByIndex](index: number, isEncodeAll?: boolean): any;
264
285
  [$deleteByIndex](index: number): void;
265
286
  protected [$onEncodeEnd](): void;
@@ -1,6 +1,7 @@
1
1
  import { $changes, $childType, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $onEncodeEnd, $refId } from "../symbols.js";
2
2
  import { ChangeTree, type IRef } from "../../encoder/ChangeTree.js";
3
3
  import { Collection } from "../HelperTypes.js";
4
+ import { type StreamableState } from "../../encoder/streaming.js";
4
5
  import type { StateView } from "../../encoder/StateView.js";
5
6
  import type { Schema } from "../../Schema.js";
6
7
  type K = number;
@@ -8,14 +9,28 @@ export declare class CollectionSchema<V = any> implements Collection<K, V>, IRef
8
9
  [$changes]: ChangeTree;
9
10
  [$refId]?: number;
10
11
  protected [$childType]: string | typeof Schema;
12
+ /** The user-visible data, keyed directly by the wire-protocol index. */
11
13
  protected $items: Map<number, V>;
12
- protected $indexes: Map<number, number>;
14
+ /** Snapshots of values that were deleted this tick (for filter visibility). */
13
15
  protected deletedItems: {
14
16
  [field: string]: V;
15
17
  };
18
+ /** Monotonic counter for assigning indexes to newly-added items. */
16
19
  protected $refId: number;
20
+ /**
21
+ * Streamable state — lazily allocated when the field is opted into
22
+ * streaming via `t.collection(X).stream()`. See MapSchema for the
23
+ * same pattern / rationale.
24
+ */
25
+ _stream?: StreamableState;
26
+ get maxPerTick(): number;
27
+ set maxPerTick(n: number);
28
+ get priority(): ((view: any, element: V) => number) | undefined;
29
+ set priority(fn: ((view: any, element: V) => number) | undefined);
17
30
  static [$encoder]: import("../../encoder/EncodeOperation.js").EncodeOperation<any>;
18
31
  static [$decoder]: import("../../decoder/DecodeOperation.js").DecodeOperation<any>;
32
+ /** Integer tag read by `decodeKeyValueOperation` — see `CollectionKind`. */
33
+ static readonly COLLECTION_KIND: 4;
19
34
  /**
20
35
  * Determine if a property must be filtered.
21
36
  * - If returns false, the property is NOT going to be encoded.
@@ -28,6 +43,13 @@ export declare class CollectionSchema<V = any> implements Collection<K, V>, IRef
28
43
  static [$filter](ref: CollectionSchema, index: number, view: StateView): boolean;
29
44
  static is(type: any): boolean;
30
45
  constructor(initialValues?: Array<V>);
46
+ /**
47
+ * Decoder-side factory. Skips the tracking `ChangeTree` allocation;
48
+ * `Object.create` also bypasses the class-field initializers, so we
49
+ * replicate the minimum slot init here. Must stay in sync with the
50
+ * class-field declarations above.
51
+ */
52
+ static initializeForDecoder<V = any>(): CollectionSchema<V>;
31
53
  add(value: V): number;
32
54
  at(index: number): V | undefined;
33
55
  entries(): MapIterator<[number, V]>;
@@ -37,13 +59,19 @@ export declare class CollectionSchema<V = any> implements Collection<K, V>, IRef
37
59
  forEach(callbackfn: (value: V, key: K, collection: CollectionSchema<V>) => void): void;
38
60
  values(): MapIterator<V>;
39
61
  get size(): number;
62
+ pauseTracking(): void;
63
+ resumeTracking(): void;
64
+ untracked<T>(fn: () => T): T;
65
+ get isTrackingPaused(): boolean;
40
66
  /** Iterator */
41
67
  [Symbol.iterator](): IterableIterator<V>;
42
- protected setIndex(index: number, key: number): void;
68
+ protected setIndex(_index: number, _key: number): void;
43
69
  protected getIndex(index: number): number;
44
70
  [$getByIndex](index: number): any;
45
71
  [$deleteByIndex](index: number): void;
46
72
  protected [$onEncodeEnd](): void;
73
+ _dropView(viewId: number): void;
74
+ _unregister(): void;
47
75
  toArray(): V[];
48
76
  toJSON(): V[];
49
77
  clone(isDecoding?: boolean): CollectionSchema<V>;
@@ -1,6 +1,8 @@
1
1
  import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $refId } from "../symbols.js";
2
2
  import { ChangeTree, IRef } from "../../encoder/ChangeTree.js";
3
3
  import { Collection } from "../HelperTypes.js";
4
+ import { MapJournal } from "../../encoder/MapJournal.js";
5
+ import { type StreamableState } from "../../encoder/streaming.js";
4
6
  import type { StateView } from "../../encoder/StateView.js";
5
7
  import type { Schema } from "../../Schema.js";
6
8
  export declare class MapSchema<V = any, K extends string = string> implements Map<K, V>, Collection<K, V, [K, V]>, IRef {
@@ -9,12 +11,46 @@ export declare class MapSchema<V = any, K extends string = string> implements Ma
9
11
  protected childType: new () => V;
10
12
  protected [$childType]: string | typeof Schema;
11
13
  protected $items: Map<K, V>;
12
- protected $indexes: Map<number, K>;
13
- protected deletedItems: {
14
- [index: string]: V;
14
+ /**
15
+ * Wire-protocol identity + change-tracking metadata for this map.
16
+ *
17
+ * Owns: index↔key mapping, monotonic index counter, snapshots of removed
18
+ * values for filter visibility checks. Replaces what used to live as three
19
+ * separate fields on this class ($indexes, _collectionIndexes, deletedItems).
20
+ */
21
+ protected journal: MapJournal<K>;
22
+ /**
23
+ * Streamable state — lazily allocated by `inheritedFlags` (or the
24
+ * `maxPerTick` setter) when streaming actually activates. `undefined`
25
+ * on every non-streaming MapSchema so the common case pays zero
26
+ * Map/Set allocation. Single slot → hidden-class shape stays stable
27
+ * across streaming and non-streaming instances.
28
+ */
29
+ _stream?: StreamableState;
30
+ /** Max ADD ops emitted per tick per view. Ignored outside streaming mode. */
31
+ get maxPerTick(): number;
32
+ set maxPerTick(n: number);
33
+ /**
34
+ * Per-view priority callback for `.stream()` maps. Initialized from the
35
+ * schema declaration (`t.map(X).stream().priority(fn)` or `@type({ map,
36
+ * priority })`); assigning here overrides for this instance. Only fires
37
+ * during `encodeView` — broadcast mode drains FIFO.
38
+ */
39
+ get priority(): ((view: any, element: V) => number) | undefined;
40
+ set priority(fn: ((view: any, element: V) => number) | undefined);
41
+ /** Backwards-compat alias for `journal.keyByIndex`. */
42
+ get $indexes(): Map<number, K>;
43
+ /**
44
+ * Backwards-compat alias for `journal.indexByKey`. Plain object so
45
+ * polymorphic call sites like `ref._collectionIndexes?.[key]` keep working.
46
+ */
47
+ get _collectionIndexes(): {
48
+ [key: string]: number;
15
49
  };
16
50
  static [$encoder]: import("../../encoder/EncodeOperation.js").EncodeOperation<any>;
17
51
  static [$decoder]: import("../../decoder/DecodeOperation.js").DecodeOperation<any>;
52
+ /** Integer tag read by `decodeKeyValueOperation` — see `CollectionKind`. */
53
+ static readonly COLLECTION_KIND: 1;
18
54
  /**
19
55
  * Determine if a property must be filtered.
20
56
  * - If returns false, the property is NOT going to be encoded.
@@ -27,6 +63,13 @@ export declare class MapSchema<V = any, K extends string = string> implements Ma
27
63
  static [$filter](ref: MapSchema, index: number, view: StateView): boolean;
28
64
  static is(type: any): boolean;
29
65
  constructor(initialValues?: Map<K, V> | Record<K, V>);
66
+ /**
67
+ * Decoder-side factory. Skips the tracking `ChangeTree` allocation;
68
+ * `Object.create` also bypasses the class-field initializers, so we
69
+ * replicate the minimum slot init here. Must stay in sync with the
70
+ * class-field declarations above and with the constructor body.
71
+ */
72
+ static initializeForDecoder<V = any, K extends string = string>(): MapSchema<V, K>;
30
73
  /** Iterator */
31
74
  [Symbol.iterator](): IterableIterator<[K, V]>;
32
75
  get [Symbol.toStringTag](): string;
@@ -41,11 +84,17 @@ export declare class MapSchema<V = any, K extends string = string> implements Ma
41
84
  keys(): MapIterator<K>;
42
85
  values(): MapIterator<V>;
43
86
  get size(): number;
87
+ pauseTracking(): void;
88
+ resumeTracking(): void;
89
+ untracked<T>(fn: () => T): T;
90
+ get isTrackingPaused(): boolean;
44
91
  protected setIndex(index: number, key: K): void;
45
92
  protected getIndex(index: number): K;
46
93
  [$getByIndex](index: number): V | undefined;
47
94
  [$deleteByIndex](index: number): void;
48
95
  protected [$onEncodeEnd](): void;
96
+ _dropView(viewId: number): void;
97
+ _unregister(): void;
49
98
  toJSON(): any;
50
99
  clone(isDecoding?: boolean): MapSchema<V>;
51
100
  }
@@ -1,20 +1,37 @@
1
1
  import { $changes, $childType, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $onEncodeEnd, $refId } from "../symbols.js";
2
2
  import { Collection } from "../HelperTypes.js";
3
3
  import { ChangeTree, type IRef } from "../../encoder/ChangeTree.js";
4
+ import { type StreamableState } from "../../encoder/streaming.js";
4
5
  import type { StateView } from "../../encoder/StateView.js";
5
6
  import type { Schema } from "../../Schema.js";
6
7
  export declare class SetSchema<V = any> implements Collection<number, V>, IRef {
7
8
  [$changes]: ChangeTree;
8
9
  [$refId]?: number;
9
10
  protected [$childType]: string | typeof Schema;
11
+ /** The user-visible data, keyed directly by the wire-protocol index. */
10
12
  protected $items: Map<number, V>;
11
- protected $indexes: Map<number, number>;
13
+ /** Snapshots of values that were deleted this tick (for filter visibility). */
12
14
  protected deletedItems: {
13
15
  [field: string]: V;
14
16
  };
17
+ /** Monotonic counter for assigning indexes to newly-added items. */
15
18
  protected $refId: number;
19
+ /**
20
+ * Streamable state — lazily allocated when the field is opted into
21
+ * streaming via `t.set(X).stream()`. See MapSchema for the same
22
+ * pattern / rationale.
23
+ */
24
+ _stream?: StreamableState;
25
+ /** Max ADD ops emitted per tick per view. Ignored outside streaming mode. */
26
+ get maxPerTick(): number;
27
+ set maxPerTick(n: number);
28
+ /** Per-view priority callback — see StreamSchema / MapSchema. */
29
+ get priority(): ((view: any, element: V) => number) | undefined;
30
+ set priority(fn: ((view: any, element: V) => number) | undefined);
16
31
  static [$encoder]: import("../../encoder/EncodeOperation.js").EncodeOperation<any>;
17
32
  static [$decoder]: import("../../decoder/DecodeOperation.js").DecodeOperation<any>;
33
+ /** Integer tag read by `decodeKeyValueOperation` — see `CollectionKind`. */
34
+ static readonly COLLECTION_KIND: 3;
18
35
  /**
19
36
  * Determine if a property must be filtered.
20
37
  * - If returns false, the property is NOT going to be encoded.
@@ -27,6 +44,13 @@ export declare class SetSchema<V = any> implements Collection<number, V>, IRef {
27
44
  static [$filter](ref: SetSchema, index: number, view: StateView): boolean;
28
45
  static is(type: any): boolean;
29
46
  constructor(initialValues?: Array<V>);
47
+ /**
48
+ * Decoder-side factory. Skips the tracking `ChangeTree` allocation;
49
+ * `Object.create` also bypasses the class-field initializers, so we
50
+ * replicate the minimum slot init here. Must stay in sync with the
51
+ * class-field declarations above.
52
+ */
53
+ static initializeForDecoder<V = any>(): SetSchema<V>;
30
54
  add(value: V): number | false;
31
55
  entries(): MapIterator<[number, V]>;
32
56
  delete(item: V): boolean;
@@ -35,13 +59,19 @@ export declare class SetSchema<V = any> implements Collection<number, V>, IRef {
35
59
  forEach(callbackfn: (value: V, key: number, collection: SetSchema<V>) => void): void;
36
60
  values(): MapIterator<V>;
37
61
  get size(): number;
62
+ pauseTracking(): void;
63
+ resumeTracking(): void;
64
+ untracked<T>(fn: () => T): T;
65
+ get isTrackingPaused(): boolean;
38
66
  /** Iterator */
39
67
  [Symbol.iterator](): IterableIterator<V>;
40
- protected setIndex(index: number, key: number): void;
68
+ protected setIndex(_index: number, _key: number): void;
41
69
  protected getIndex(index: number): number;
42
70
  [$getByIndex](index: number): any;
43
71
  [$deleteByIndex](index: number): void;
44
72
  protected [$onEncodeEnd](): void;
73
+ _dropView(viewId: number): void;
74
+ _unregister(): void;
45
75
  toArray(): V[];
46
76
  toJSON(): V[];
47
77
  clone(isDecoding?: boolean): SetSchema<V>;
@@ -0,0 +1,114 @@
1
+ import { $changes, $childType, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $onEncodeEnd, $refId } from "../symbols.js";
2
+ import { ChangeTree, type IRef } from "../../encoder/ChangeTree.js";
3
+ import { type StreamableState } from "../../encoder/streaming.js";
4
+ import type { StateView } from "../../encoder/StateView.js";
5
+ import type { Schema } from "../../Schema.js";
6
+ /**
7
+ * `t.stream(Entity)` — priority-batched collection of Schema instances.
8
+ *
9
+ * Designed for ECS-style use cases where many entities spawn/despawn each
10
+ * tick and the full set won't fit in one encode budget. Adds are queued
11
+ * per-client and drained in priority order (callback on StateView) up to
12
+ * `maxPerTick` per encode pass. Field mutations on already-sent elements
13
+ * propagate through the normal reliable channel without consuming the
14
+ * per-tick budget. Chain `.static()` on the field builder to suppress
15
+ * post-add mutation tracking entirely.
16
+ */
17
+ export declare class StreamSchema<V = any> implements IRef {
18
+ [$changes]: ChangeTree;
19
+ [$refId]?: number;
20
+ protected [$childType]: string | typeof Schema;
21
+ /**
22
+ * Wire-keyed storage: `position → element`. Position is a monotonic
23
+ * counter assigned by `add()` — stable identity even when elements
24
+ * are removed, so pending/sent view state can keep using the same
25
+ * keys across ticks. Map (not Array) so `$items.keys()` / `.values()`
26
+ * skip removed positions without a sparse-slot check.
27
+ */
28
+ protected $items: Map<number, V>;
29
+ /** Monotonic position counter. Incremented on every `add()`. */
30
+ protected $nextPosition: number;
31
+ /** Reverse lookup for O(1) `remove(el)`. */
32
+ protected _itemIndex: Map<V, number>;
33
+ /**
34
+ * Streamable state — holds per-view and broadcast bookkeeping. Lazily
35
+ * allocated when the stream is attached to a Root (or when the user
36
+ * touches `maxPerTick`). `undefined` on detached streams so
37
+ * construction is cheap.
38
+ */
39
+ _stream?: StreamableState;
40
+ /** Max element ADDs emitted per encode tick (per view, or broadcast). */
41
+ get maxPerTick(): number;
42
+ set maxPerTick(n: number);
43
+ /**
44
+ * Per-view priority callback. Initialized from the schema declaration
45
+ * (`.priority(fn)` or `@type({ stream, priority })`); assigning here
46
+ * overrides the class-level default for this instance. Only fires
47
+ * during `encodeView` — broadcast mode drains FIFO.
48
+ */
49
+ get priority(): ((view: any, element: V) => number) | undefined;
50
+ set priority(fn: ((view: any, element: V) => number) | undefined);
51
+ /**
52
+ * Brand used by Root / StateView to detect stream trees without
53
+ * importing this class (avoids circular deps). The `isStreamCollection`
54
+ * ChangeTree flag (set via `inheritedFlags`) is the preferred runtime
55
+ * check — this brand is kept for back-compat.
56
+ */
57
+ static readonly $isStream: true;
58
+ static [$encoder]: import("../../encoder/EncodeOperation.js").EncodeOperation<any>;
59
+ static [$decoder]: import("../../decoder/DecodeOperation.js").DecodeOperation<any>;
60
+ /** Integer tag read by `decodeKeyValueOperation` — see `CollectionKind`. */
61
+ static readonly COLLECTION_KIND: 5;
62
+ /**
63
+ * Element-level visibility. Identical to SetSchema's filter: stream
64
+ * elements are always per-view, the filter just defers to the view's
65
+ * per-tree visibility bitmap.
66
+ */
67
+ static [$filter](ref: StreamSchema, index: number, view: StateView): boolean;
68
+ static is(type: any): boolean;
69
+ constructor();
70
+ /**
71
+ * Decoder-side factory. Skips the tracking `ChangeTree` allocation;
72
+ * `Object.create` also bypasses the class-field initializers, so we
73
+ * replicate the minimum slot init here. Must stay in sync with the
74
+ * class-field declarations above.
75
+ */
76
+ static initializeForDecoder<V = any>(): StreamSchema<V>;
77
+ /**
78
+ * Append an element to the stream. Returns the assigned position,
79
+ * or -1 if the element was already in the stream.
80
+ */
81
+ add(value: V): number;
82
+ /**
83
+ * Remove an element by reference. If the element was pending (never sent
84
+ * to a view), the pending entry is dropped silently. If already sent,
85
+ * a DELETE op is forced on next `encodeView` for that view.
86
+ */
87
+ remove(value: V): boolean;
88
+ has(value: V): boolean;
89
+ /** Remove every element; queue DELETE wire ops for already-sent items. */
90
+ clear(): void;
91
+ forEach(callback: (value: V, index: number, collection: StreamSchema<V>) => void): void;
92
+ values(): IterableIterator<V>;
93
+ /**
94
+ * Iterate `[position, value]` pairs in insertion order. Used by
95
+ * `setParent` recursion when the stream is reassigned to a new parent.
96
+ */
97
+ entries(): IterableIterator<[number, V]>;
98
+ [Symbol.iterator](): IterableIterator<V>;
99
+ /** Live element count. */
100
+ get size(): number;
101
+ /** Alias for `size`. */
102
+ get length(): number;
103
+ protected setIndex(_index: number, _key: number): void;
104
+ protected getIndex(index: number): number;
105
+ [$getByIndex](index: number): V;
106
+ [$deleteByIndex](index: number): void;
107
+ protected [$onEncodeEnd](): void;
108
+ toArray(): V[];
109
+ toJSON(): any[];
110
+ clone(isDecoding?: boolean): StreamSchema<V>;
111
+ _dropView(viewId: number): void;
112
+ /** Called by Root.remove when the stream's refcount hits zero. */
113
+ _unregister(): void;
114
+ }