fluid-framework 2.113.1 → 2.114.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/CHANGELOG.md CHANGED
@@ -1,5 +1,115 @@
1
1
  # fluid-framework
2
2
 
3
+ ## 2.114.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add FluidReadonlyArray type independent of TypeScript lib ([#27747](https://github.com/microsoft/FluidFramework/pull/27747)) [040d35bc29](https://github.com/microsoft/FluidFramework/commit/040d35bc29901d58e9e778f5f2e75ba581a80dc0)
8
+
9
+ `FluidReadonlyArray<T>` provides an equivalent of the built-in `ReadonlyArray` type that is independent of TypeScript [`lib`](https://www.typescriptlang.org/tsconfig/#lib), following the same pattern as `FluidReadonlyMap` and `FluidMap`.
10
+ The interface includes stable methods through ES2023 (`at()`, `findLast()`, `findLastIndex()`) but excludes newer copy-on-write methods (`toReversed()`, `toSorted()`, `toSpliced()`, `with()`) that Fluid Framework implementations don't yet support.
11
+ This ensures these types remain safe to implement without `lib` changes breaking them.
12
+
13
+ - Add clear method to TreeMapNodeAlpha ([#27765](https://github.com/microsoft/FluidFramework/pull/27765)) [30c889b99c](https://github.com/microsoft/FluidFramework/commit/30c889b99caca3d6ad1ab276761092d94118eab1)
14
+
15
+ [`TreeMapNodeAlpha`](https://fluidframework.com/docs/api/fluid-framework/treemapnodealpha-interface) now has a `clear` method, further aligning it with JavaScript's built-in Map API. It removes all elements from the map.
16
+
17
+ The merge semantics of `clear` are loosely specified: either of the following may occur:
18
+ - `clear` may remove all elements that were in the map when the edit was authored, even if some of those elements have since been moved elsewhere in the tree (in which case they are removed from their new location).
19
+ - `clear` may remove all elements that are in the map when the edit is sequenced, even if some of those elements were not yet in the map when the edit was authored.
20
+
21
+ This method is available on `TreeMapNodeAlpha`, which can be obtained from an existing `TreeMapNode` via `asAlpha`, or by declaring the schema with `SchemaFactoryAlpha`'s `mapAlpha`.
22
+
23
+ ```typescript
24
+ const schemaFactory = new SchemaFactoryAlpha("example");
25
+ class Inventory extends schemaFactory.mapAlpha(
26
+ "Inventory",
27
+ schemaFactory.number,
28
+ ) {}
29
+
30
+ const inventory = new Inventory(
31
+ new Map([
32
+ ["apples", 5],
33
+ ["pears", 3],
34
+ ]),
35
+ );
36
+
37
+ inventory.size; // 2
38
+ inventory.clear();
39
+ inventory.size; // 0
40
+ ```
41
+
42
+ - Promote Fluid container type interfaces to public ([#27746](https://github.com/microsoft/FluidFramework/pull/27746)) [33e014ac63](https://github.com/microsoft/FluidFramework/commit/33e014ac636d43a5f90b1ce1f64b95e60aaf2bca)
43
+
44
+ `FluidIterable`, `FluidIterableIterator`, `FluidReadonlyMap`, `FluidMap`, and `FluidReadonlyArray` are promoted from `@beta` to `@public`.
45
+ These sealed interfaces provide equivalents of the built-in `Iterable`, `IterableIterator`, `ReadonlyMap`, `Map`, and `ReadonlyArray` types that are independent of TypeScript [`lib`](https://www.typescriptlang.org/tsconfig/#lib).
46
+ They can now be used in public API surfaces.
47
+
48
+ - Add new @alpha ServiceClient API for creating and loading Fluid containers ([#27693](https://github.com/microsoft/FluidFramework/pull/27693)) [ee47192d4a](https://github.com/microsoft/FluidFramework/commit/ee47192d4ae91bc28f9154c4d1ead2acad762f3c)
49
+
50
+ This introduces an experimental (`@alpha`), service-agnostic API for working with Fluid containers whose root is an arbitrary data store, along with an in-memory implementation for testing.
51
+
52
+ The new surface is made up of:
53
+ - `ServiceClient` (`@fluidframework/driver-definitions`): the entry point for creating and loading containers. Along with it come the supporting container types (`FluidContainer`, `FluidContainerWithService`, `FluidContainerAttached`), the data store model (`DataStoreKind`, `DataStoreKey`, `DataStoreRegistry`, `DataStoreCreator`), and the generic registry primitives (`Registry`, `RegistryKey`, `lookupInRegistry`, `createBasicRegistryKey`).
54
+ - `defineDataStore` and `sharedObjectRegistryFromIterable` (`@fluidframework/shared-object-base`): build a `DataStoreKind` from a root shared object and a registry of shared object kinds.
55
+ - `defineTreeDataStore` and `instantiateTreeFirstTime` (`@fluidframework/tree`): a SharedTree-specific convenience wrapper that produces a `DataStoreKind` backed by a `TreeView`.
56
+ - `startEphemeralService` (`@fluidframework/local-driver`): starts an in-memory `EphemeralService` for tests. The service owns the lifetime of the in-memory documents and resources, and produces `ServiceClient`s connected to it (via `EphemeralService.newClient` or `EphemeralService.defaultClient`). The helpers `cleanupEphemeralService` and `getDefaultEphemeralService` manage an optional default service instance.
57
+
58
+ Apart from the `@fluidframework/local-driver` helpers (which come from `@fluidframework/local-driver/alpha`), these APIs are also re-exported from `fluid-framework`. None reference any `@legacy` types.
59
+
60
+ Example:
61
+
62
+ ```typescript
63
+ import { startEphemeralService } from "@fluidframework/local-driver/alpha";
64
+ import {
65
+ ServiceClient,
66
+ defineTreeDataStore,
67
+ TreeViewConfiguration,
68
+ SchemaFactory,
69
+ } from "fluid-framework/alpha";
70
+ import { strict as assert } from "node:assert";
71
+
72
+ // Start an ephemeral in-memory service and get a ServiceClient connected to it.
73
+ const service = startEphemeralService();
74
+ const client: ServiceClient = service.defaultClient;
75
+ // Define a DataStoreKind which uses a SharedTree.
76
+ // In this case the schema is for a single number with an initializer that starts the it at 1.
77
+ // This schema is captures in the type allowing for strongly typed access to the data in the tree,
78
+ // where the type matches the schema based runtime enforcement of the schema.
79
+ const numberStore = defineTreeDataStore({
80
+ type: "my-app-root",
81
+ config: new TreeViewConfiguration({ schema: SchemaFactory.number }),
82
+ initializer: () => 1,
83
+ });
84
+
85
+ // Create a container in the service with the above DataStoreKind.
86
+ // Ideally this creation would use a service independent API, and only the attach call would be service dependent,
87
+ // but that is not supported yet.
88
+ const detachedContainer1 = await client.createContainer(numberStore);
89
+ const container1 = await detachedContainer1.attach();
90
+
91
+ // We now have easy and type safe access to the data in the tree, which will be synced over the service.
92
+ assert.equal(container1.data.root, 1);
93
+
94
+ // A second client can load the same container from the service, and will see the same data.
95
+ const container2 = await client.loadContainer(container1.id, numberStore);
96
+ assert.equal(container2.data.root, 1);
97
+
98
+ // Both clients can modify the data, and the changes will be synced over the service.
99
+ container2.data.root = 2;
100
+ // Since we are using an ephemeral service, we can await the synchronization using service.synchronize.
101
+ await service.synchronize();
102
+
103
+ // And now the changes are visible for all clients.
104
+ assert.equal(container1.data.root, 2);
105
+ assert.equal(container2.data.root, 2);
106
+ ```
107
+
108
+ Note that this example does a couple of things which are difficult to do with the other API surfaces:
109
+ 1. It creates a container, then loads a second copy of it, allowing for collaboration. There is currently no non-legacy API surface which allows this without spawning a server process. This is also cleaner than the exacting legacy API options, and can replace the test specific APIs for this as well.
110
+ 2. It creates a container which has a SharedTree at the root, and nothing else. This avoids depending on legacy DDS implementations, which is great for long-term document support and bundle size. This is currently impossible using `fluid-static`, which forces a special root data store. It is also impossible if using `aqueduct`, which forces a root directory in every data store. It can be done using the low level legacy APIs directly, but this new API for it is much simpler.
111
+ 3. There is a common interface all services implement (`ServiceClient`), making the container creation part of the code work for any service implementation.
112
+
3
113
  ## 2.113.0
4
114
 
5
115
  ### Minor Changes
@@ -302,6 +302,9 @@ export const contentSchemaSymbol: unique symbol;
302
302
  // @alpha
303
303
  export function createArrayInsertionAnchor(node: TreeArrayNode, currentIndex: number): ArrayPlaceAnchor;
304
304
 
305
+ // @alpha
306
+ export function createBasicRegistryKey<T>(type: string): RegistryKey<T, T>;
307
+
305
308
  // @beta
306
309
  export function createIdentifierIndex<TSchema extends ImplicitFieldSchema>(view: TreeView<TSchema>): IdentifierIndex;
307
310
 
@@ -331,6 +334,33 @@ export function createTreeIndex<TFieldSchema extends ImplicitFieldSchema, TKey e
331
334
  // @beta
332
335
  export function createTreeIndex<TFieldSchema extends ImplicitFieldSchema, TKey extends TreeIndexKey, TValue, TSchema extends TreeNodeSchema>(view: TreeView<TFieldSchema>, indexer: Map<TreeNodeSchema, string>, getValue: (nodes: TreeIndexNodes<NodeFromSchema<TSchema>>) => TValue, isKeyValid: (key: TreeIndexKey) => key is TKey, indexableSchema: readonly TSchema[]): TreeIndex<TKey, TValue>;
333
336
 
337
+ // @alpha @sealed
338
+ export interface DataStoreContext extends SharedObjectCreator {
339
+ }
340
+
341
+ // @alpha @sealed
342
+ export interface DataStoreCreator {
343
+ createDataStore<T>(kind: DataStoreKey<T>): Promise<T>;
344
+ }
345
+
346
+ // @alpha @input
347
+ export type DataStoreKey<T, TAll = unknown> = RegistryKey<Promise<DataStoreKind<T>>, Promise<DataStoreKind<TAll>>>;
348
+
349
+ // @alpha @sealed
350
+ export interface DataStoreKind<out T = unknown> extends DataStoreKey<T>, ErasedBaseType<readonly ["DataStoreKind", T]> {
351
+ }
352
+
353
+ // @alpha @input
354
+ export interface DataStoreOptions<in out TRoot extends IFluidLoadable, out TOutput> {
355
+ instantiateFirstTime(rootCreator: SharedObjectCreator<TRoot>, context: DataStoreContext): Promise<TRoot>;
356
+ readonly registry: SharedObjectRegistry;
357
+ readonly type: string;
358
+ view(root: TRoot, context: DataStoreContext): Promise<TOutput>;
359
+ }
360
+
361
+ // @alpha @input
362
+ export type DataStoreRegistry<out T = unknown> = Registry<Promise<DataStoreKind<T>>>;
363
+
334
364
  // @alpha
335
365
  export function decodeSchemaCompatibilitySnapshot(encodedSchema: JsonCompatibleReadOnly, validator?: FormatValidator): SimpleTreeSchema;
336
366
 
@@ -338,6 +368,12 @@ export function decodeSchemaCompatibilitySnapshot(encodedSchema: JsonCompatibleR
338
368
  interface DefaultProvider extends ErasedType<"@fluidframework/tree.FieldProvider"> {
339
369
  }
340
370
 
371
+ // @alpha
372
+ export function defineDataStore<T, TRoot extends IFluidLoadable>(options: DataStoreOptions<TRoot, T>): DataStoreKind<T>;
373
+
374
+ // @alpha
375
+ export function defineTreeDataStore<const TSchema extends ImplicitFieldSchema>(options: TreeDataStoreOptions<TSchema>): DataStoreKind<TreeView<TSchema>>;
376
+
341
377
  // @alpha
342
378
  export interface DirtyTreeMap {
343
379
  // (undocumented)
@@ -523,12 +559,29 @@ export const FluidClientVersion: {
523
559
  readonly v2_80: "2.80.0";
524
560
  };
525
561
 
526
- // @beta @sealed
562
+ // @alpha @sealed
563
+ export interface FluidContainer<TData = unknown> extends DataStoreCreator, ErasedBaseType<readonly ["FluidContainer", TData]> {
564
+ close(): void;
565
+ readonly data: TData;
566
+ readonly id?: string | undefined;
567
+ }
568
+
569
+ // @alpha @sealed
570
+ export interface FluidContainerAttached<TData = unknown> extends FluidContainer<TData> {
571
+ readonly id: string;
572
+ }
573
+
574
+ // @alpha @sealed
575
+ export interface FluidContainerWithService<TData = unknown> extends FluidContainer<TData> {
576
+ attach(): Promise<FluidContainerAttached<TData>>;
577
+ }
578
+
579
+ // @public @sealed
527
580
  export interface FluidIterable<T> {
528
581
  [Symbol.iterator](): FluidIterableIterator<T>;
529
582
  }
530
583
 
531
- // @beta @sealed
584
+ // @public @sealed
532
585
  export interface FluidIterableIterator<T> extends FluidIterable<T> {
533
586
  next(): {
534
587
  value: T;
@@ -539,7 +592,7 @@ export interface FluidIterableIterator<T> extends FluidIterable<T> {
539
592
  };
540
593
  }
541
594
 
542
- // @beta @sealed
595
+ // @public @sealed
543
596
  export interface FluidMap<K, V> extends FluidReadonlyMap<K, V> {
544
597
  delete(key: K): void;
545
598
  forEach(callbackfn: (value: V, key: K, map: FluidMap<K, V>) => void, thisArg?: any): void;
@@ -554,7 +607,50 @@ export type FluidObject<T = unknown> = {
554
607
  // @public
555
608
  export type FluidObjectProviderKeys<T, TProp extends keyof T = keyof T> = string extends TProp ? never : number extends TProp ? never : TProp extends keyof Required<T>[TProp] ? Required<T>[TProp] extends Required<Required<T>[TProp]>[TProp] ? TProp : never : never;
556
609
 
557
- // @beta @sealed
610
+ // @public @sealed
611
+ export interface FluidReadonlyArray<T> {
612
+ [Symbol.iterator](): FluidIterableIterator<T>;
613
+ readonly [Symbol.unscopables]: {
614
+ [K in keyof (readonly any[])]?: boolean;
615
+ };
616
+ readonly [n: number]: T;
617
+ at(index: number): T | undefined;
618
+ concat(...items: ConcatArray<T>[]): T[];
619
+ concat(...items: (T | ConcatArray<T>)[]): T[];
620
+ entries(): FluidIterableIterator<[number, T]>;
621
+ every<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): this is FluidReadonlyArray<S>;
622
+ every(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): boolean;
623
+ filter<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): S[];
624
+ filter(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): T[];
625
+ find<S extends T>(predicate: (value: T, index: number, obj: readonly T[]) => value is S, thisArg?: any): S | undefined;
626
+ find(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): T | undefined;
627
+ findIndex(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): number;
628
+ findLast<S extends T>(predicate: (value: T, index: number, obj: readonly T[]) => value is S, thisArg?: any): S | undefined;
629
+ findLast(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): T | undefined;
630
+ findLastIndex(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): number;
631
+ flat<A, D extends number = 1>(this: A, depth?: D): FlatArray<A, D>[];
632
+ flatMap<U, This = undefined>(callback: (this: This, value: T, index: number, array: T[]) => U | readonly U[], thisArg?: This): U[];
633
+ forEach(callbackfn: (value: T, index: number, array: readonly T[]) => void, thisArg?: any): void;
634
+ includes(searchElement: T, fromIndex?: number): boolean;
635
+ indexOf(searchElement: T, fromIndex?: number): number;
636
+ join(separator?: string): string;
637
+ keys(): FluidIterableIterator<number>;
638
+ lastIndexOf(searchElement: T, fromIndex?: number): number;
639
+ readonly length: number;
640
+ map<U>(callbackfn: (value: T, index: number, array: readonly T[]) => U, thisArg?: any): U[];
641
+ reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T;
642
+ reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U;
643
+ reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T;
644
+ reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U;
645
+ slice(start?: number, end?: number): T[];
646
+ some(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): boolean;
647
+ // (undocumented)
648
+ toLocaleString(): string;
649
+ toString(): string;
650
+ values(): FluidIterableIterator<T>;
651
+ }
652
+
653
+ // @public @sealed
558
654
  export interface FluidReadonlyMap<K, V> {
559
655
  [Symbol.iterator](): FluidIterableIterator<[K, V]>;
560
656
  readonly [Symbol.toStringTag]: string;
@@ -999,6 +1095,9 @@ TSchema
999
1095
  // @public
1000
1096
  export type InsertableTypedNode<TSchema extends TreeNodeSchema, T = UnionToIntersection<TSchema>> = (T extends TreeNodeSchema<string, NodeKind, TreeNode | TreeLeafValue, never, true> ? NodeBuilderData<T> : never) | (T extends TreeNodeSchema ? Unhydrated<TreeNode extends NodeFromSchema<T> ? never : NodeFromSchema<T>> : never);
1001
1097
 
1098
+ // @alpha
1099
+ export function instantiateTreeFirstTime<TSchema extends ImplicitFieldSchema>(rootCreator: SharedObjectCreator, creator: SharedObjectCreator, treeKind: SharedObjectKey<ITree>, options: Pick<TreeDataStoreOptions<TSchema>, "config" | "initializer">): Promise<ITree>;
1100
+
1002
1101
  // @public @sealed
1003
1102
  export interface InternalTreeNode extends ErasedType<"@fluidframework/tree.InternalTreeNode"> {
1004
1103
  }
@@ -1273,6 +1372,9 @@ export interface LogLevelConst {
1273
1372
  readonly verbose: 10;
1274
1373
  }
1275
1374
 
1375
+ // @alpha
1376
+ export function lookupInRegistry<TOut, TIn>(registry: Registry<TIn>, key: RegistryKey<TOut, TIn>): TOut;
1377
+
1276
1378
  // @public @sealed
1277
1379
  export interface MakeNominal {
1278
1380
  }
@@ -1313,6 +1415,9 @@ export type MemberChangedListener<M extends IMember> = (clientId: string, member
1313
1415
  // @alpha @deprecated
1314
1416
  export const minimize: TransactionPostProcessor;
1315
1417
 
1418
+ // @alpha @input
1419
+ export type MinimumVersionForCollaboration = `2.${bigint}.0`;
1420
+
1316
1421
  // @public
1317
1422
  export type Myself<M extends IMember = IMember> = M & {
1318
1423
  readonly currentConnection: string;
@@ -1475,6 +1580,15 @@ export const RecordNodeSchema: {
1475
1580
  readonly [Symbol.hasInstance]: (value: TreeNodeSchema) => value is RecordNodeSchema<string, ImplicitAllowedTypes, true, unknown>;
1476
1581
  };
1477
1582
 
1583
+ // @alpha @input
1584
+ export type Registry<T> = (type: string) => T;
1585
+
1586
+ // @alpha @sealed @input
1587
+ export interface RegistryKey<TOut, TIn = unknown> {
1588
+ adapt(value: TIn): TOut;
1589
+ readonly type: string;
1590
+ }
1591
+
1478
1592
  // @alpha @sealed
1479
1593
  export interface RemoteChangeMetadata extends CommitMetadata {
1480
1594
  readonly getChange?: undefined;
@@ -1722,14 +1836,51 @@ export class SchemaUpgrade {
1722
1836
  // @public @system
1723
1837
  type ScopedSchemaName<TScope extends string | undefined, TName extends number | string> = TScope extends undefined ? `${TName}` : `${TScope}.${TName}`;
1724
1838
 
1839
+ // @alpha @sealed
1840
+ export interface ServiceClient {
1841
+ createContainer<T>(root: DataStoreKind<T>): Promise<FluidContainerWithService<T>>;
1842
+ createContainer<T>(root: DataStoreKey<T>, registry: DataStoreRegistry): Promise<FluidContainerWithService<T>>;
1843
+ loadContainer<T>(id: string, root: DataStoreKind<T> | DataStoreRegistry<T>): Promise<FluidContainerAttached<T>>;
1844
+ }
1845
+
1846
+ // @alpha @input
1847
+ export interface ServiceOptions {
1848
+ // (undocumented)
1849
+ readonly minVersionForCollaboration: MinimumVersionForCollaboration;
1850
+ }
1851
+
1852
+ // @alpha @sealed
1853
+ export interface SharedObjectCreator<TConstraint = IFluidLoadable> {
1854
+ createSharedObject<T extends TConstraint>(kind: SharedObjectKey<T>): Promise<T>;
1855
+ }
1856
+
1857
+ // @alpha @input
1858
+ export type SharedObjectKey<T> = RegistryKey<SharedObjectKindAlpha<T>, SharedObjectKindAlpha>;
1859
+
1725
1860
  // @public @sealed
1726
1861
  export interface SharedObjectKind<out TSharedObject = unknown> extends ErasedType<readonly ["SharedObjectKind", TSharedObject]> {
1727
1862
  is(value: IFluidLoadable): value is IFluidLoadable & TSharedObject;
1728
1863
  }
1729
1864
 
1865
+ // @alpha @sealed
1866
+ export interface SharedObjectKindAlpha<out TSharedObject = unknown> extends SharedObjectKind<TSharedObject>, SharedObjectKey<TSharedObject> {
1867
+ }
1868
+
1869
+ // @alpha @input
1870
+ export type SharedObjectRegistry = () => Promise<Registry<SharedObjectKindAlpha<IFluidLoadable>>>;
1871
+
1872
+ // @alpha
1873
+ export function sharedObjectRegistryFromIterable(entries: Iterable<SharedObjectKindAlpha<IFluidLoadable> | {
1874
+ type: string;
1875
+ kind: () => Promise<SharedObjectKindAlpha<IFluidLoadable>>;
1876
+ }>): SharedObjectRegistry;
1877
+
1730
1878
  // @public
1731
1879
  export const SharedTree: SharedObjectKind<ITree>;
1732
1880
 
1881
+ // @alpha
1882
+ export const SharedTreeAlpha: SharedObjectKindAlpha<ITree>;
1883
+
1733
1884
  // @alpha @input
1734
1885
  export interface SharedTreeFormatOptions {
1735
1886
  treeEncodeType: TreeCompressionStrategy;
@@ -2354,6 +2505,15 @@ export interface TreeContextAlpha {
2354
2505
  runTransactionAsync(transaction: () => Promise<void>, params?: RunTransactionParamsAlpha): Promise<TransactionVoidResult>;
2355
2506
  }
2356
2507
 
2508
+ // @alpha @input
2509
+ export interface TreeDataStoreOptions<TSchema extends ImplicitFieldSchema> extends Pick<DataStoreOptions<never, never>, "type"> {
2510
+ readonly config: TreeViewConfiguration<TSchema>;
2511
+ readonly initializer?: (creator: SharedObjectCreator) => InsertableTreeFieldFromImplicitField<TSchema>;
2512
+ // (undocumented)
2513
+ readonly key?: SharedObjectKey<ITree>;
2514
+ readonly registry?: Iterable<SharedObjectKindAlpha<IFluidLoadable>> | SharedObjectRegistry;
2515
+ }
2516
+
2357
2517
  // @beta @input
2358
2518
  export interface TreeEncodingOptions<TKeyOptions = KeyEncodingOptions> {
2359
2519
  readonly keys?: TKeyOptions;
@@ -2397,6 +2557,7 @@ export interface TreeMapNode<T extends ImplicitAllowedTypes = ImplicitAllowedTyp
2397
2557
 
2398
2558
  // @alpha @sealed
2399
2559
  export interface TreeMapNodeAlpha<T extends ImplicitAllowedTypes = ImplicitAllowedTypes> extends FluidReadonlyMap<string, TreeNodeFromImplicitAllowedTypes<T>>, TreeNode, Pick<TreeMapNode<T>, "set" | "delete"> {
2560
+ clear(): void;
2400
2561
  }
2401
2562
 
2402
2563
  // @public @sealed
@@ -268,12 +268,12 @@ type FlexList<Item = unknown> = readonly LazyItem<Item>[];
268
268
  // @public @system
269
269
  type FlexListToUnion<TList extends FlexList> = ExtractItemType<TList[number]>;
270
270
 
271
- // @beta @sealed
271
+ // @public @sealed
272
272
  export interface FluidIterable<T> {
273
273
  [Symbol.iterator](): FluidIterableIterator<T>;
274
274
  }
275
275
 
276
- // @beta @sealed
276
+ // @public @sealed
277
277
  export interface FluidIterableIterator<T> extends FluidIterable<T> {
278
278
  next(): {
279
279
  value: T;
@@ -284,7 +284,7 @@ export interface FluidIterableIterator<T> extends FluidIterable<T> {
284
284
  };
285
285
  }
286
286
 
287
- // @beta @sealed
287
+ // @public @sealed
288
288
  export interface FluidMap<K, V> extends FluidReadonlyMap<K, V> {
289
289
  delete(key: K): void;
290
290
  forEach(callbackfn: (value: V, key: K, map: FluidMap<K, V>) => void, thisArg?: any): void;
@@ -299,7 +299,50 @@ export type FluidObject<T = unknown> = {
299
299
  // @public
300
300
  export type FluidObjectProviderKeys<T, TProp extends keyof T = keyof T> = string extends TProp ? never : number extends TProp ? never : TProp extends keyof Required<T>[TProp] ? Required<T>[TProp] extends Required<Required<T>[TProp]>[TProp] ? TProp : never : never;
301
301
 
302
- // @beta @sealed
302
+ // @public @sealed
303
+ export interface FluidReadonlyArray<T> {
304
+ [Symbol.iterator](): FluidIterableIterator<T>;
305
+ readonly [Symbol.unscopables]: {
306
+ [K in keyof (readonly any[])]?: boolean;
307
+ };
308
+ readonly [n: number]: T;
309
+ at(index: number): T | undefined;
310
+ concat(...items: ConcatArray<T>[]): T[];
311
+ concat(...items: (T | ConcatArray<T>)[]): T[];
312
+ entries(): FluidIterableIterator<[number, T]>;
313
+ every<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): this is FluidReadonlyArray<S>;
314
+ every(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): boolean;
315
+ filter<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): S[];
316
+ filter(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): T[];
317
+ find<S extends T>(predicate: (value: T, index: number, obj: readonly T[]) => value is S, thisArg?: any): S | undefined;
318
+ find(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): T | undefined;
319
+ findIndex(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): number;
320
+ findLast<S extends T>(predicate: (value: T, index: number, obj: readonly T[]) => value is S, thisArg?: any): S | undefined;
321
+ findLast(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): T | undefined;
322
+ findLastIndex(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): number;
323
+ flat<A, D extends number = 1>(this: A, depth?: D): FlatArray<A, D>[];
324
+ flatMap<U, This = undefined>(callback: (this: This, value: T, index: number, array: T[]) => U | readonly U[], thisArg?: This): U[];
325
+ forEach(callbackfn: (value: T, index: number, array: readonly T[]) => void, thisArg?: any): void;
326
+ includes(searchElement: T, fromIndex?: number): boolean;
327
+ indexOf(searchElement: T, fromIndex?: number): number;
328
+ join(separator?: string): string;
329
+ keys(): FluidIterableIterator<number>;
330
+ lastIndexOf(searchElement: T, fromIndex?: number): number;
331
+ readonly length: number;
332
+ map<U>(callbackfn: (value: T, index: number, array: readonly T[]) => U, thisArg?: any): U[];
333
+ reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T;
334
+ reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U;
335
+ reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T;
336
+ reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U;
337
+ slice(start?: number, end?: number): T[];
338
+ some(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): boolean;
339
+ // (undocumented)
340
+ toLocaleString(): string;
341
+ toString(): string;
342
+ values(): FluidIterableIterator<T>;
343
+ }
344
+
345
+ // @public @sealed
303
346
  export interface FluidReadonlyMap<K, V> {
304
347
  [Symbol.iterator](): FluidIterableIterator<[K, V]>;
305
348
  readonly [Symbol.toStringTag]: string;
@@ -271,12 +271,12 @@ type FlexList<Item = unknown> = readonly LazyItem<Item>[];
271
271
  // @public @system
272
272
  type FlexListToUnion<TList extends FlexList> = ExtractItemType<TList[number]>;
273
273
 
274
- // @beta @sealed
274
+ // @public @sealed
275
275
  export interface FluidIterable<T> {
276
276
  [Symbol.iterator](): FluidIterableIterator<T>;
277
277
  }
278
278
 
279
- // @beta @sealed
279
+ // @public @sealed
280
280
  export interface FluidIterableIterator<T> extends FluidIterable<T> {
281
281
  next(): {
282
282
  value: T;
@@ -287,7 +287,7 @@ export interface FluidIterableIterator<T> extends FluidIterable<T> {
287
287
  };
288
288
  }
289
289
 
290
- // @beta @sealed
290
+ // @public @sealed
291
291
  export interface FluidMap<K, V> extends FluidReadonlyMap<K, V> {
292
292
  delete(key: K): void;
293
293
  forEach(callbackfn: (value: V, key: K, map: FluidMap<K, V>) => void, thisArg?: any): void;
@@ -302,7 +302,50 @@ export type FluidObject<T = unknown> = {
302
302
  // @public
303
303
  export type FluidObjectProviderKeys<T, TProp extends keyof T = keyof T> = string extends TProp ? never : number extends TProp ? never : TProp extends keyof Required<T>[TProp] ? Required<T>[TProp] extends Required<Required<T>[TProp]>[TProp] ? TProp : never : never;
304
304
 
305
- // @beta @sealed
305
+ // @public @sealed
306
+ export interface FluidReadonlyArray<T> {
307
+ [Symbol.iterator](): FluidIterableIterator<T>;
308
+ readonly [Symbol.unscopables]: {
309
+ [K in keyof (readonly any[])]?: boolean;
310
+ };
311
+ readonly [n: number]: T;
312
+ at(index: number): T | undefined;
313
+ concat(...items: ConcatArray<T>[]): T[];
314
+ concat(...items: (T | ConcatArray<T>)[]): T[];
315
+ entries(): FluidIterableIterator<[number, T]>;
316
+ every<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): this is FluidReadonlyArray<S>;
317
+ every(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): boolean;
318
+ filter<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): S[];
319
+ filter(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): T[];
320
+ find<S extends T>(predicate: (value: T, index: number, obj: readonly T[]) => value is S, thisArg?: any): S | undefined;
321
+ find(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): T | undefined;
322
+ findIndex(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): number;
323
+ findLast<S extends T>(predicate: (value: T, index: number, obj: readonly T[]) => value is S, thisArg?: any): S | undefined;
324
+ findLast(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): T | undefined;
325
+ findLastIndex(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): number;
326
+ flat<A, D extends number = 1>(this: A, depth?: D): FlatArray<A, D>[];
327
+ flatMap<U, This = undefined>(callback: (this: This, value: T, index: number, array: T[]) => U | readonly U[], thisArg?: This): U[];
328
+ forEach(callbackfn: (value: T, index: number, array: readonly T[]) => void, thisArg?: any): void;
329
+ includes(searchElement: T, fromIndex?: number): boolean;
330
+ indexOf(searchElement: T, fromIndex?: number): number;
331
+ join(separator?: string): string;
332
+ keys(): FluidIterableIterator<number>;
333
+ lastIndexOf(searchElement: T, fromIndex?: number): number;
334
+ readonly length: number;
335
+ map<U>(callbackfn: (value: T, index: number, array: readonly T[]) => U, thisArg?: any): U[];
336
+ reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T;
337
+ reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U;
338
+ reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T;
339
+ reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U;
340
+ slice(start?: number, end?: number): T[];
341
+ some(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): boolean;
342
+ // (undocumented)
343
+ toLocaleString(): string;
344
+ toString(): string;
345
+ values(): FluidIterableIterator<T>;
346
+ }
347
+
348
+ // @public @sealed
306
349
  export interface FluidReadonlyMap<K, V> {
307
350
  [Symbol.iterator](): FluidIterableIterator<[K, V]>;
308
351
  readonly [Symbol.toStringTag]: string;
@@ -135,6 +135,29 @@ type FlexList<Item = unknown> = readonly LazyItem<Item>[];
135
135
  // @public @system
136
136
  type FlexListToUnion<TList extends FlexList> = ExtractItemType<TList[number]>;
137
137
 
138
+ // @public @sealed
139
+ export interface FluidIterable<T> {
140
+ [Symbol.iterator](): FluidIterableIterator<T>;
141
+ }
142
+
143
+ // @public @sealed
144
+ export interface FluidIterableIterator<T> extends FluidIterable<T> {
145
+ next(): {
146
+ value: T;
147
+ done?: false;
148
+ } | {
149
+ value: any;
150
+ done: true;
151
+ };
152
+ }
153
+
154
+ // @public @sealed
155
+ export interface FluidMap<K, V> extends FluidReadonlyMap<K, V> {
156
+ delete(key: K): void;
157
+ forEach(callbackfn: (value: V, key: K, map: FluidMap<K, V>) => void, thisArg?: any): void;
158
+ set(key: K, value: V): void;
159
+ }
160
+
138
161
  // @public
139
162
  export type FluidObject<T = unknown> = {
140
163
  [P in FluidObjectProviderKeys<T>]?: T[P];
@@ -143,6 +166,62 @@ export type FluidObject<T = unknown> = {
143
166
  // @public
144
167
  export type FluidObjectProviderKeys<T, TProp extends keyof T = keyof T> = string extends TProp ? never : number extends TProp ? never : TProp extends keyof Required<T>[TProp] ? Required<T>[TProp] extends Required<Required<T>[TProp]>[TProp] ? TProp : never : never;
145
168
 
169
+ // @public @sealed
170
+ export interface FluidReadonlyArray<T> {
171
+ [Symbol.iterator](): FluidIterableIterator<T>;
172
+ readonly [Symbol.unscopables]: {
173
+ [K in keyof (readonly any[])]?: boolean;
174
+ };
175
+ readonly [n: number]: T;
176
+ at(index: number): T | undefined;
177
+ concat(...items: ConcatArray<T>[]): T[];
178
+ concat(...items: (T | ConcatArray<T>)[]): T[];
179
+ entries(): FluidIterableIterator<[number, T]>;
180
+ every<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): this is FluidReadonlyArray<S>;
181
+ every(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): boolean;
182
+ filter<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): S[];
183
+ filter(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): T[];
184
+ find<S extends T>(predicate: (value: T, index: number, obj: readonly T[]) => value is S, thisArg?: any): S | undefined;
185
+ find(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): T | undefined;
186
+ findIndex(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): number;
187
+ findLast<S extends T>(predicate: (value: T, index: number, obj: readonly T[]) => value is S, thisArg?: any): S | undefined;
188
+ findLast(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): T | undefined;
189
+ findLastIndex(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): number;
190
+ flat<A, D extends number = 1>(this: A, depth?: D): FlatArray<A, D>[];
191
+ flatMap<U, This = undefined>(callback: (this: This, value: T, index: number, array: T[]) => U | readonly U[], thisArg?: This): U[];
192
+ forEach(callbackfn: (value: T, index: number, array: readonly T[]) => void, thisArg?: any): void;
193
+ includes(searchElement: T, fromIndex?: number): boolean;
194
+ indexOf(searchElement: T, fromIndex?: number): number;
195
+ join(separator?: string): string;
196
+ keys(): FluidIterableIterator<number>;
197
+ lastIndexOf(searchElement: T, fromIndex?: number): number;
198
+ readonly length: number;
199
+ map<U>(callbackfn: (value: T, index: number, array: readonly T[]) => U, thisArg?: any): U[];
200
+ reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T;
201
+ reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U;
202
+ reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T;
203
+ reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U;
204
+ slice(start?: number, end?: number): T[];
205
+ some(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): boolean;
206
+ // (undocumented)
207
+ toLocaleString(): string;
208
+ toString(): string;
209
+ values(): FluidIterableIterator<T>;
210
+ }
211
+
212
+ // @public @sealed
213
+ export interface FluidReadonlyMap<K, V> {
214
+ [Symbol.iterator](): FluidIterableIterator<[K, V]>;
215
+ readonly [Symbol.toStringTag]: string;
216
+ entries(): FluidIterableIterator<[K, V]>;
217
+ forEach(callbackfn: (value: V, key: K, map: FluidReadonlyMap<K, V>) => void, thisArg?: any): void;
218
+ get(key: K): V | undefined;
219
+ has(key: K): boolean;
220
+ keys(): FluidIterableIterator<K>;
221
+ readonly size: number;
222
+ values(): FluidIterableIterator<V>;
223
+ }
224
+
146
225
  // @public
147
226
  export const getPresence: (fluidContainer: IFluidContainer) => Presence;
148
227