fluid-framework 2.1.1 → 2.2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,248 @@
1
1
  # fluid-framework
2
2
 
3
+ ## 2.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - The PropertyManager class and related functions and properties are deprecated ([#22183](https://github.com/microsoft/FluidFramework/pull/22183)) [cbba69554f](https://github.com/microsoft/FluidFramework/commit/cbba69554fc5026f562f44683a902474fabd6e81)
8
+
9
+ The `PropertyManager` class, along with the `propertyManager` properties and `addProperties` functions on segments and intervals, are not intended for external use.
10
+ These elements will be removed in a future release for the following reasons:
11
+
12
+ - There are no scenarios where they need to be used directly.
13
+ - Using them directly will cause eventual consistency problems.
14
+ - Upcoming features will require modifications to these mechanisms.
15
+
16
+ - Compile-time type narrowing based on a TreeNode's NodeKind ([#22222](https://github.com/microsoft/FluidFramework/pull/22222)) [4d3bc876ae](https://github.com/microsoft/FluidFramework/commit/4d3bc876ae32fa3f2568299e29246f6970e48ee0)
17
+
18
+ `TreeNode`'s schema-aware APIs implement `WithType`, which now has a `NodeKind` parameter that can be used to narrow `TreeNode`s based on `NodeKind`.
19
+
20
+ Example:
21
+
22
+ ```typescript
23
+ function getKeys(node: TreeNode & WithType<string, NodeKind.Array>): number[];
24
+ function getKeys(node: TreeNode & WithType<string, NodeKind.Map | NodeKind.Object>): string[];
25
+ function getKeys(node: TreeNode): string[] | number[];
26
+ function getKeys(node: TreeNode): string[] | number[] {
27
+ const schema = Tree.schema(node);
28
+ switch (schema.kind) {
29
+ case NodeKind.Array: {
30
+ const arrayNode = node as TreeArrayNode;
31
+ const keys: number[] = [];
32
+ for (let index = 0; index < arrayNode.length; index++) {
33
+ keys.push(index);
34
+ }
35
+ return keys;
36
+ }
37
+ case NodeKind.Map:
38
+ return [...(node as TreeMapNode).keys()];
39
+ case NodeKind.Object:
40
+ return Object.keys(node);
41
+ default:
42
+ throw new Error("Unsupported Kind");
43
+ }
44
+ }
45
+ ```
46
+
47
+ - ✨ New! `Record`-typed objects can now be used to construct MapNodes ([#22042](https://github.com/microsoft/FluidFramework/pull/22042)) [25deff344b](https://github.com/microsoft/FluidFramework/commit/25deff344b447380486c1efb64ed69177c32ddc5)
48
+
49
+ You can now construct MapNodes from `Record` typed objects, similar to how maps are expressed in JSON.
50
+
51
+ Before this change, an `Iterable<string, Child>` was required, but now an object like `{key1: Child1, key2: Child2}` is allowed.
52
+
53
+ Full example using this new API:
54
+
55
+ ```typescript
56
+ class Schema extends schemaFactory.map("ExampleMap", schemaFactory.number) {}
57
+ const fromRecord = new Schema({ x: 5 });
58
+ ```
59
+
60
+ This new feature makes it possible for schemas to construct a tree entirely from JSON-compatible objects using their constructors,
61
+ as long as they do not require unhydrated nodes to differentiate ambiguous unions,
62
+ or IFluidHandles (which themselves are not JSON compatible).
63
+
64
+ Due to limitations of TypeScript and recursive types,
65
+ recursive maps do not advertise support for this feature in their typing,
66
+ but it works at runtime.
67
+
68
+ - New SharedTree configuration option: `ITreeConfigurationOptions.preventAmbiguity` ([#22048](https://github.com/microsoft/FluidFramework/pull/22048)) [966906a034](https://github.com/microsoft/FluidFramework/commit/966906a03490daa5a914030b37342abb8267c12d)
69
+
70
+ The new `ITreeConfigurationOptions.preventAmbiguity` flag can be set to true to enable checking of some additional rules when constructing the `TreeViewConfiguration`.
71
+
72
+ This example shows an ambiguous schema:
73
+
74
+ ```typescript
75
+ const schemaFactory = new SchemaFactory("com.example");
76
+ class Feet extends schemaFactory.object("Feet", { length: schemaFactory.number }) {}
77
+ class Meters extends schemaFactory.object("Meters", { length: schemaFactory.number }) {}
78
+ const config = new TreeViewConfiguration({
79
+ // This combination of schema can lead to ambiguous cases, and will error since preventAmbiguity is true.
80
+ schema: [Feet, Meters],
81
+ preventAmbiguity: true,
82
+ });
83
+ const view = tree.viewWith(config);
84
+ // This is invalid since it is ambiguous which type of node is being constructed.
85
+ // The error thrown above when constructing the TreeViewConfiguration is because of this ambiguous case:
86
+ view.initialize({ length: 5 });
87
+ ```
88
+
89
+ See the documentation on `ITreeConfigurationOptions.preventAmbiguity` for a more complete example and more details.
90
+
91
+ - `Tree.schema` now returns `TreeNodeSchema` ([#22185](https://github.com/microsoft/FluidFramework/pull/22185)) [bfe8310a94](https://github.com/microsoft/FluidFramework/commit/bfe8310a9406a8658c2fac8827c7114844c32234)
92
+
93
+ The typing of `Tree.schema` has changed from:
94
+
95
+ ```typescript
96
+ schema<T extends TreeNode | TreeLeafValue>(node: T): TreeNodeSchema<string, NodeKind, unknown, T>;
97
+ ```
98
+
99
+ to:
100
+
101
+ ```typescript
102
+ schema(node: TreeNode | TreeLeafValue): TreeNodeSchema;
103
+ ```
104
+
105
+ The runtime behavior is unaffected: any code which worked and still compiles is fine and does not need changes.
106
+
107
+ `Tree.schema` was changed to mitigate two different issues:
108
+
109
+ 1. It tried to give a more specific type based on the type of the passed in value.
110
+ When the type of the input is not known precisely (for example it is a union of node types like `Foo | Bar`, or `TreeNode` or even `TreeNode | TreeLeafValue`), this was fine since schema are covariant over their node type.
111
+ However when the input was more specific that the schema type, for example the type is simply `0`, this would result in unsound typing, since the create function could actually return values that did not conform with that schema (for example `schema.create(1)` for the number schema typed with `0` would return `1` with type `0`).
112
+ 2. The node type was provided to the incorrect type parameter of TreeNodeSchema.
113
+ The `TNode` parameter is the third one, not the fourth.
114
+ The fourth is `TBuild` which sets the input accepted to its create function or constructor.
115
+ Thus this code accidentally left `TNode` unset (which is good due to the above issue), but invalidly set `TBuild`.
116
+ `TBuild` is contravariant, so it has the opposite issue that setting `TNode` would have: if your input is simply typed as something general like `TreeNode`, then the returned schema would claim to be able to construct an instance given any `TreeNode`.
117
+ This is incorrect, and this typing has been removed.
118
+
119
+ Fortunately it should be rare for code to be impacted by this issue.
120
+ Any code which manually specified a generic type parameter to `Tree.schema()` will break, as well as code which assigned its result to an overly specifically typed variable.
121
+ Code which used `typeof` on the returned schema could also break, though there are few use-cases for this so such code is not expected to exist.
122
+ Currently it's very difficult to invoke the create function or constructor associated with a `TreeNodeSchema` as doing so already requires narrowing to `TreeNodeSchemaClass` or `TreeNodeSchemaNonClass`.
123
+ It is possible some such code exists which will need to have an explicit cast added because it happened to work with the more specific (but incorrect) constructor input type.
124
+
125
+ - Recursive SharedTree schemas using MapNodes no longer produce invalid d.ts files ([#22106](https://github.com/microsoft/FluidFramework/pull/22106)) [554fc5a94e](https://github.com/microsoft/FluidFramework/commit/554fc5a94e57e2d109ea9008b7c64517c58a6b73)
126
+
127
+ Consider a recursive SharedTree schema like the following, which follows all our recommended best practices:
128
+
129
+ ```typescript
130
+ export class RecursiveMap extends schema.mapRecursive("RM", [() => RecursiveMap]) {}
131
+ {
132
+ type _check = ValidateRecursiveSchema<typeof RecursiveMap>;
133
+ }
134
+ ```
135
+
136
+ This schema would work when used from within its compilation unit, but would generate d.ts that fails to compile when exporting it:
137
+
138
+ ```typescript
139
+ declare const RecursiveMap_base: import("@fluidframework/tree").TreeNodeSchemaClass<
140
+ "com.example.RM",
141
+ import("@fluidframework/tree").NodeKind.Map,
142
+ import("@fluidframework/tree").TreeMapNodeUnsafe<readonly [() => typeof RecursiveMap]> &
143
+ import("@fluidframework/tree").WithType<"com.example.RM">,
144
+ {
145
+ [Symbol.iterator](): Iterator<[string, RecursiveMap], any, undefined>;
146
+ },
147
+ false,
148
+ readonly [() => typeof RecursiveMap]
149
+ >;
150
+ export declare class RecursiveMap extends RecursiveMap_base {}
151
+ ```
152
+
153
+ This results in the compile error in TypeScript 5.4.5:
154
+
155
+ > error TS2310: Type 'RecursiveMap' recursively references itself as a base type.
156
+
157
+ With this change, that error is fixed by modifying the `TreeMapNodeUnsafe` type it references to inline the definition of `ReadonlyMap` instead of using the one from the TypeScript standard library.
158
+
159
+ - ✨ New! When unambiguous, ArrayNodes can now be constructed from Maps and MapNodes from arrays ([#22036](https://github.com/microsoft/FluidFramework/pull/22036)) [25e74f9f3b](https://github.com/microsoft/FluidFramework/commit/25e74f9f3bed6e6ff041c088813c4cc1ea276b9c)
160
+
161
+ Since the types for ArrayNodes and MapNodes indicate they can be constructed from iterables,
162
+ it should work, even if those iterables are themselves arrays or maps.
163
+ To avoid this being a breaking change, a priority system was introduced.
164
+ ArrayNodes will only be implicitly constructable from JavaScript Map objects in contexts where no MapNodes are allowed.
165
+ Similarly MapNodes will only be implicitly constructable from JavaScript Array objects in contexts where no ArrayNodes are allowed.
166
+
167
+ In practice, the main case in which this is likely to matter is when implicitly constructing a map node. If you provide an array of key value pairs, this now works instead of erroring, as long as no ArrayNode is valid at that location in the tree.
168
+
169
+ ```typescript
170
+ class MyMapNode extends schemaFactory.map("x", schemaFactory.number) {}
171
+ class Root extends schemaFactory.object("root", { data: MyMapNode }) {}
172
+ // This now works (before it compiled, but error at runtime):
173
+ const fromArray = new Root({ data: [["x", 5]] });
174
+ ```
175
+
176
+ Prior versions used to have to do:
177
+
178
+ ```typescript
179
+ new Root({ data: new MyMapNode([["x", 5]]) });
180
+ ```
181
+
182
+ or:
183
+
184
+ ```typescript
185
+ new Root({ data: new Map([["x", 5]]) });
186
+ ```
187
+
188
+ Both of these options still work: strictly more cases are allowed with this change.
189
+
190
+ - Implicit TreeNode construction improvements ([#21995](https://github.com/microsoft/FluidFramework/pull/21995)) [977f96c1a0](https://github.com/microsoft/FluidFramework/commit/977f96c1a0dd1d5eb0dbcd087d07cb7510d533ea)
191
+
192
+ ArrayNodes and MapNodes could always be explicitly constructed (using `new`) from iterables.
193
+ The types also allowed using of iterables to implicitly construct array nodes and map nodes,
194
+ but this did not work at runtime.
195
+ This has been fixed for all cases except implicitly constructing an ArrayNode form an `Iterable` that is actually a `Map`,
196
+ and implicitly constructing a MapNode from an `Iterable` that is actually an `Array`.
197
+ These cases may be fixed in the future, but require additional work to ensure unions of array nodes and map nodes work correctly.
198
+
199
+ Additionally MapNodes can now be constructed from `Iterator<readonly [string, content]>` where previously the inner arrays had to be mutable.
200
+
201
+ - Enforce use of TreeViewConfiguration's constructor ([#22055](https://github.com/microsoft/FluidFramework/pull/22055)) [e8955579f6](https://github.com/microsoft/FluidFramework/commit/e8955579f6d52a6c7e300642088c60d6ed12d7db)
202
+
203
+ `TreeViewConfiguration` is `@sealed`, meaning creating custom implementations of it such as assigning object literals to a `TreeViewConfiguration` or sub-classing it are not supported.
204
+ This reserved the ability for the Fluid Framework to add members to this class over time, informing users that they must use it in such a way where such changes are non-breaking.
205
+ However, there was no compiler-based enforcement of this expectation.
206
+ It was only indicated via documentation and an implicit assumption that when an API takes in a typed defined as a class, that an instance of that class must be used rather than an arbitrary object of a similar shape.
207
+
208
+ With this change, the TypeScript compiler will now inform users when they invalidly provide an object literal as a `TreeViewConfiguration`.
209
+
210
+ More specifically this causes code like this to produce a compile error:
211
+
212
+ ```typescript
213
+ // Don't do this!
214
+ const view = tree.viewWith({ schema: TestNode, enableSchemaValidation: false });
215
+ ```
216
+
217
+ The above was never intended to work, and is not a supported use of the `viewWith` since it requires a `TreeViewConfiguration` which is sealed.
218
+ Any code using the above pattern will break in Fluid Framework 2.2 and above. Such code will need to be updated to the pattern shown below.
219
+ Any code broken by this change is technically unsupported and only worked due to a gap in the type checking. This is not considered a breaking change.
220
+ The correct way to get a `TreeViewConfiguration` is by using its constructor:
221
+
222
+ ```typescript
223
+ // This pattern correctly initializes default values and validates input.
224
+ const view = tree.viewWith(new TreeViewConfiguration({ schema: TestNode }));
225
+ ```
226
+
227
+ Skipping the constructor causes the following problems:
228
+
229
+ 1. `TreeViewConfiguration` does validation in its constructor, so skipping it also skips the validation which leads to much less friendly error messages for invalid schema.
230
+ 2. Skipping the constructor also discards any default values for options like `enableSchemaValidation`.
231
+ This means that code written in that style would break if more options were added. Since such changes are planned,
232
+ it is not practical to support this pattern.
233
+
234
+ - New `isFluidHandle` type guard to check if an object is an `IFluidHandle` ([#22029](https://github.com/microsoft/FluidFramework/pull/22029)) [7827d1040a](https://github.com/microsoft/FluidFramework/commit/7827d1040a9ebc0bd11388dc31f15370ea9f68d3)
235
+
236
+ The `isFluidHandle` type guard function is now exported and can be used to detect which objects are `IFluidHandle`s.
237
+ Since `IFluidHandle` often needs special handling (for example when serializing since it's not JSON compatible),
238
+ having a dedicated detection function for it is useful.
239
+ Doing this detection was possible previously using the `tree` package's schema system via `Tree.is(value, new SchemaFactory("").handle)`,
240
+ but can now be done with just `isFluidHandle(value)`.
241
+
242
+ - Add a function `isRepoSuperset` to determine if changes to a document schema are backward-compatible ([#22045](https://github.com/microsoft/FluidFramework/pull/22045)) [f6fdc95bb3](https://github.com/microsoft/FluidFramework/commit/f6fdc95bb36a892710bc315aae85fd2c75aec975)
243
+
244
+ Note: These changes are not customer-facing and make progress toward future plans in Tree's schema evolution space.
245
+
3
246
  ## 2.1.0
4
247
 
5
248
  ### Minor Changes
package/README.md CHANGED
@@ -9,7 +9,7 @@ There are some packages there are not included as part of this `fluid-framework`
9
9
  - Fluid Framework [developer tools](https://github.com/microsoft/FluidFramework/tree/main/packages/tools/devtools/devtools).
10
10
  - `@fluidframework/app-insights-logger`: to route Fluid telemetry to Azure App Insights.
11
11
 
12
- <!-- AUTO-GENERATED-CONTENT:START (LIBRARY_PACKAGE_README_HEADER) -->
12
+ <!-- AUTO-GENERATED-CONTENT:START (LIBRARY_README_HEADER) -->
13
13
 
14
14
  <!-- prettier-ignore-start -->
15
15
  <!-- NOTE: This section is automatically generated using @fluid-tools/markdown-magic. Do not update these generated contents directly. -->
@@ -69,7 +69,7 @@ The `fluid-framework` package offers the following data structures:
69
69
 
70
70
  Check out the [Hello World tutorial](https://fluidframework.com/docs/start/tutorial/) using `fluid-framework`.
71
71
 
72
- <!-- AUTO-GENERATED-CONTENT:START (LIBRARY_PACKAGE_README_FOOTER) -->
72
+ <!-- AUTO-GENERATED-CONTENT:START (README_FOOTER) -->
73
73
 
74
74
  <!-- prettier-ignore-start -->
75
75
  <!-- NOTE: This section is automatically generated using @fluid-tools/markdown-magic. Do not update these generated contents directly. -->
@@ -100,7 +100,8 @@ export class FieldSchema<out Kind extends FieldKind = FieldKind, out Types exten
100
100
  get allowedTypeSet(): ReadonlySet<TreeNodeSchema>;
101
101
  readonly kind: Kind;
102
102
  readonly props?: FieldProps | undefined;
103
- protected _typeCheck?: MakeNominal;
103
+ readonly requiresValue: boolean;
104
+ protected _typeCheck: MakeNominal;
104
105
  }
105
106
 
106
107
  // @public
@@ -465,6 +466,7 @@ declare namespace InternalTypes {
465
466
  InsertableTypedNodeUnsafe,
466
467
  NodeBuilderDataUnsafe,
467
468
  NodeFromSchemaUnsafe,
469
+ ReadonlyMapInlined,
468
470
  FlexList,
469
471
  FlexListToUnion,
470
472
  ExtractItemType,
@@ -495,6 +497,9 @@ export interface IServiceAudienceEvents<M extends IMember> extends IEvent {
495
497
  (event: "memberRemoved", listener: MemberChangedListener<M>): void;
496
498
  }
497
499
 
500
+ // @public
501
+ export function isFluidHandle(value: unknown): value is IFluidHandle;
502
+
498
503
  // @public
499
504
  export type IsListener<TListener> = TListener extends (...args: any[]) => void ? true : false;
500
505
 
@@ -516,11 +521,11 @@ export interface ITree extends IFluidLoadable {
516
521
  // @public
517
522
  export interface ITreeConfigurationOptions {
518
523
  enableSchemaValidation?: boolean;
524
+ readonly preventAmbiguity?: boolean;
519
525
  }
520
526
 
521
527
  // @public
522
- export interface ITreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> {
523
- readonly enableSchemaValidation?: boolean;
528
+ export interface ITreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> extends ITreeConfigurationOptions {
524
529
  readonly schema: TSchema;
525
530
  }
526
531
 
@@ -541,6 +546,9 @@ export type Listeners<T extends object> = {
541
546
  export interface MakeNominal {
542
547
  }
543
548
 
549
+ // @public
550
+ export type MapNodeInsertableData<T extends ImplicitAllowedTypes> = Iterable<readonly [string, InsertableTreeNodeFromImplicitAllowedTypes<T>]> | RestrictiveReadonlyRecord<string, InsertableTreeNodeFromImplicitAllowedTypes<T>>;
551
+
544
552
  // @public
545
553
  export type MemberChangedListener<M extends IMember> = (clientId: string, member: M) => void;
546
554
 
@@ -590,6 +598,22 @@ type ObjectFromSchemaRecordUnsafe<T extends Unenforced<RestrictiveReadonlyRecord
590
598
  // @public
591
599
  export type Off = () => void;
592
600
 
601
+ // @public @sealed
602
+ interface ReadonlyMapInlined<K, T extends Unenforced<ImplicitAllowedTypes>> {
603
+ [Symbol.iterator](): IterableIterator<[K, TreeNodeFromImplicitAllowedTypesUnsafe<T>]>;
604
+ entries(): IterableIterator<[K, TreeNodeFromImplicitAllowedTypesUnsafe<T>]>;
605
+ // (undocumented)
606
+ forEach(callbackfn: (value: TreeNodeFromImplicitAllowedTypesUnsafe<T>, key: K, map: ReadonlyMap<K, TreeNodeFromImplicitAllowedTypesUnsafe<T>>) => void, thisArg?: any): void;
607
+ // (undocumented)
608
+ get(key: K): TreeNodeFromImplicitAllowedTypesUnsafe<T> | undefined;
609
+ // (undocumented)
610
+ has(key: K): boolean;
611
+ keys(): IterableIterator<K>;
612
+ // (undocumented)
613
+ readonly size: number;
614
+ values(): IterableIterator<TreeNodeFromImplicitAllowedTypesUnsafe<T>>;
615
+ }
616
+
593
617
  // @public
594
618
  export type ReplaceIEventThisPlaceHolder<L extends any[], TThis> = L extends any[] ? {
595
619
  [K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K];
@@ -648,17 +672,17 @@ export interface SchemaCompatibilityStatus {
648
672
  // @public @sealed
649
673
  export class SchemaFactory<out TScope extends string | undefined = string | undefined, TName extends number | string = string> {
650
674
  constructor(scope: TScope);
651
- array<const T extends TreeNodeSchema | readonly TreeNodeSchema[]>(allowedTypes: T): TreeNodeSchema<ScopedSchemaName<TScope, `Array<${string}>`>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, `Array<${string}>`>>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T>;
652
- array<const Name extends TName, const T extends ImplicitAllowedTypes>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, Name>>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T>;
653
- arrayRecursive<const Name extends TName, const T extends Unenforced<ImplicitAllowedTypes>>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Array, TreeArrayNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>>, {
675
+ array<const T extends TreeNodeSchema | readonly TreeNodeSchema[]>(allowedTypes: T): TreeNodeSchema<ScopedSchemaName<TScope, `Array<${string}>`>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, `Array<${string}>`>, NodeKind.Array>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T>;
676
+ array<const Name extends TName, const T extends ImplicitAllowedTypes>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Array>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T>;
677
+ arrayRecursive<const Name extends TName, const T extends Unenforced<ImplicitAllowedTypes>>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Array, TreeArrayNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Array>, {
654
678
  [Symbol.iterator](): Iterator<InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>>;
655
679
  }, false, T>;
656
680
  readonly boolean: TreeNodeSchema<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean>;
657
681
  readonly handle: TreeNodeSchema<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle<unknown>, IFluidHandle<unknown>>;
658
682
  get identifier(): FieldSchema<FieldKind.Identifier, typeof SchemaFactory.string>;
659
- map<const T extends TreeNodeSchema | readonly TreeNodeSchema[]>(allowedTypes: T): TreeNodeSchema<ScopedSchemaName<TScope, `Map<${string}>`>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, `Map<${string}>`>>, Iterable<[string, InsertableTreeNodeFromImplicitAllowedTypes<T>]>, true, T>;
660
- map<Name extends TName, const T extends ImplicitAllowedTypes>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, Name>>, Iterable<[string, InsertableTreeNodeFromImplicitAllowedTypes<T>]>, true, T>;
661
- mapRecursive<Name extends TName, const T extends Unenforced<ImplicitAllowedTypes>>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>>, {
683
+ map<const T extends TreeNodeSchema | readonly TreeNodeSchema[]>(allowedTypes: T): TreeNodeSchema<ScopedSchemaName<TScope, `Map<${string}>`>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, `Map<${string}>`>, NodeKind.Map>, MapNodeInsertableData<T>, true, T>;
684
+ map<Name extends TName, const T extends ImplicitAllowedTypes>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Map>, MapNodeInsertableData<T>, true, T>;
685
+ mapRecursive<Name extends TName, const T extends Unenforced<ImplicitAllowedTypes>>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Map>, {
662
686
  [Symbol.iterator](): Iterator<[
663
687
  string,
664
688
  InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>
@@ -775,7 +799,7 @@ export interface TreeMapNode<T extends ImplicitAllowedTypes = ImplicitAllowedTyp
775
799
  }
776
800
 
777
801
  // @public @sealed
778
- export interface TreeMapNodeUnsafe<T extends Unenforced<ImplicitAllowedTypes>> extends ReadonlyMap<string, TreeNodeFromImplicitAllowedTypesUnsafe<T>>, TreeNode {
802
+ export interface TreeMapNodeUnsafe<T extends Unenforced<ImplicitAllowedTypes>> extends ReadonlyMapInlined<string, T>, TreeNode {
779
803
  delete(key: string): void;
780
804
  set(key: string, value: InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T> | undefined): void;
781
805
  }
@@ -784,8 +808,10 @@ export interface TreeMapNodeUnsafe<T extends Unenforced<ImplicitAllowedTypes>> e
784
808
  export abstract class TreeNode implements WithType {
785
809
  static [Symbol.hasInstance](value: unknown): value is TreeNode;
786
810
  static [Symbol.hasInstance]<TSchema extends abstract new (...args: any[]) => TreeNode>(this: TSchema, value: unknown): value is InstanceType<TSchema>;
811
+ // @deprecated
787
812
  abstract get [typeNameSymbol](): string;
788
- protected constructor();
813
+ abstract get [typeSchemaSymbol](): TreeNodeSchemaClass;
814
+ protected constructor(token: unknown);
789
815
  }
790
816
 
791
817
  // @public @sealed
@@ -794,7 +820,7 @@ export interface TreeNodeApi {
794
820
  key(node: TreeNode): string | number;
795
821
  on<K extends keyof TreeChangeEvents>(node: TreeNode, eventName: K, listener: TreeChangeEvents[K]): () => void;
796
822
  parent(node: TreeNode): TreeNode | undefined;
797
- schema<T extends TreeNode | TreeLeafValue>(node: T): TreeNodeSchema<string, NodeKind, unknown, T>;
823
+ schema(node: TreeNode | TreeLeafValue): TreeNodeSchema;
798
824
  shortId(node: TreeNode): number | string | undefined;
799
825
  status(node: TreeNode): TreeStatus;
800
826
  }
@@ -816,7 +842,6 @@ export interface TreeNodeSchemaClass<out Name extends string = string, out Kind
816
842
 
817
843
  // @public @sealed
818
844
  export interface TreeNodeSchemaCore<out Name extends string, out Kind extends NodeKind, out ImplicitlyConstructable extends boolean, out Info = unknown> {
819
- // (undocumented)
820
845
  readonly identifier: Name;
821
846
  readonly implicitlyConstructable: ImplicitlyConstructable;
822
847
  readonly info: Info;
@@ -831,10 +856,10 @@ interface TreeNodeSchemaNonClass<out Name extends string = string, out Kind exte
831
856
  }
832
857
 
833
858
  // @public
834
- export type TreeObjectNode<T extends RestrictiveReadonlyRecord<string, ImplicitFieldSchema>, TypeName extends string = string> = TreeNode & ObjectFromSchemaRecord<T> & WithType<TypeName>;
859
+ export type TreeObjectNode<T extends RestrictiveReadonlyRecord<string, ImplicitFieldSchema>, TypeName extends string = string> = TreeNode & ObjectFromSchemaRecord<T> & WithType<TypeName, NodeKind.Object>;
835
860
 
836
861
  // @public
837
- export type TreeObjectNodeUnsafe<T extends Unenforced<RestrictiveReadonlyRecord<string, ImplicitFieldSchema>>, TypeName extends string = string> = TreeNode & ObjectFromSchemaRecordUnsafe<T> & WithType<TypeName>;
862
+ export type TreeObjectNodeUnsafe<T extends Unenforced<RestrictiveReadonlyRecord<string, ImplicitFieldSchema>>, TypeName extends string = string> = TreeNode & ObjectFromSchemaRecordUnsafe<T> & WithType<TypeName, NodeKind.Object>;
838
863
 
839
864
  // @public
840
865
  export enum TreeStatus {
@@ -858,7 +883,10 @@ export interface TreeView<TSchema extends ImplicitFieldSchema> extends IDisposab
858
883
  export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
859
884
  constructor(props: ITreeViewConfiguration<TSchema>);
860
885
  readonly enableSchemaValidation: boolean;
886
+ readonly preventAmbiguity: boolean;
861
887
  readonly schema: TSchema;
888
+ // (undocumented)
889
+ protected _typeCheck: MakeNominal;
862
890
  }
863
891
 
864
892
  // @public @sealed
@@ -868,9 +896,12 @@ export interface TreeViewEvents {
868
896
  schemaChanged(): void;
869
897
  }
870
898
 
871
- // @public
899
+ // @public @deprecated
872
900
  const typeNameSymbol: unique symbol;
873
901
 
902
+ // @public
903
+ export const typeSchemaSymbol: unique symbol;
904
+
874
905
  // @public
875
906
  export type Unenforced<_DesiredExtendsConstraint> = unknown;
876
907
 
@@ -878,7 +909,7 @@ export type Unenforced<_DesiredExtendsConstraint> = unknown;
878
909
  export type Unhydrated<T> = T;
879
910
 
880
911
  // @public
881
- export type ValidateRecursiveSchema<T extends TreeNodeSchemaClass<string, NodeKind.Array | NodeKind.Map | NodeKind.Object, TreeNode & WithType<T["identifier"]>, {
912
+ export type ValidateRecursiveSchema<T extends TreeNodeSchemaClass<string, NodeKind.Array | NodeKind.Map | NodeKind.Object, TreeNode & WithType<T["identifier"], T["kind"]>, {
882
913
  [NodeKind.Object]: T["info"] extends RestrictiveReadonlyRecord<string, ImplicitFieldSchema> ? InsertableObjectFromSchemaRecord<T["info"]> : unknown;
883
914
  [NodeKind.Array]: T["info"] extends ImplicitAllowedTypes ? Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T["info"]>> : unknown;
884
915
  [NodeKind.Map]: T["info"] extends ImplicitAllowedTypes ? Iterable<[string, InsertableTreeNodeFromImplicitAllowedTypes<T["info"]>]> : unknown;
@@ -889,8 +920,10 @@ export type ValidateRecursiveSchema<T extends TreeNodeSchemaClass<string, NodeKi
889
920
  }[T["kind"]]>> = true;
890
921
 
891
922
  // @public @sealed
892
- export interface WithType<TName extends string = string> {
923
+ export interface WithType<out TName extends string = string, out TKind extends NodeKind = NodeKind> {
924
+ // @deprecated
893
925
  get [typeNameSymbol](): TName;
926
+ get [typeSchemaSymbol](): TreeNodeSchemaClass<TName, TKind>;
894
927
  }
895
928
 
896
929
  ```