fluid-framework 2.110.0 → 2.112.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,214 @@
1
1
  # fluid-framework
2
2
 
3
+ ## 2.112.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add Component utilities for composing open-polymorphic schema ([#27628](https://github.com/microsoft/FluidFramework/pull/27628)) [7a56d096bf](https://github.com/microsoft/FluidFramework/commit/7a56d096bffab133ab4e7ab9c8f9c465b7ba9e81)
8
+
9
+ A new `@alpha` `Component` namespace is now exported from `@fluidframework/tree` (and re-exported from `fluid-framework`). It provides utilities for composing independently authored application "components" that contribute to a shared configuration, which is useful for implementing ["open polymorphism"](<https://en.wikipedia.org/wiki/Polymorphism_(computer_science)>) schema patterns where the set of allowed types for a field or collection can be extended by separate libraries.
10
+
11
+ Each component is expressed as a `Component.Factory`: a function which receives a lazy reference to the composed configuration and returns the content that component contributes. Because the configuration is provided lazily, components may reference (including recursively) types contributed by other components. `Component.compose` combines a set of components into a `Component.Composed`, from which the aggregated configuration and per-component content can be read.
12
+
13
+ ```typescript
14
+ /** Example application component content type. */
15
+ interface MyAppComponentContent {
16
+ /**
17
+ * Item types contributed by this component.
18
+ * We are just typing them as TreeNodeSchema here to keep things simple.
19
+ * Real use would often provide some static factory to be able to create instances, as well as some APIs all item nodes should implement.
20
+ */
21
+ readonly items: Component.LazyArray<TreeNodeSchema>;
22
+ }
23
+
24
+ type MyAppComponent = Component.Factory<MyAppComponentContent>;
25
+
26
+ // A simple component, which does not depend on any other context.
27
+ const textComponent: MyAppComponent = () => ({
28
+ items: () => [() => TextItem],
29
+ });
30
+
31
+ // A component which creates an item type which recursively depends on all item types.
32
+ const containerComponent: MyAppComponent = (config) => ({
33
+ items: () => [
34
+ () =>
35
+ class extends sf.array("Container", config().getComposed("items")) {},
36
+ ],
37
+ });
38
+
39
+ const appConfig = Component.compose([containerComponent, textComponent]);
40
+
41
+ // The config's items can now be used to create a TreeViewConfiguration, root schema, or whatever else is needed.
42
+ class Root extends sf.object("Root", {
43
+ content: appConfig.getComposed("items"),
44
+ }) {}
45
+ ```
46
+
47
+ See the worked examples in [openPolymorphism.integration.ts](https://github.com/microsoft/FluidFramework/blob/main/packages/dds/tree/src/test/openPolymorphism.integration.ts) for end-to-end usage with SharedTree schema.
48
+
49
+ - Independent tree views now accept an optional telemetry logger ([#27567](https://github.com/microsoft/FluidFramework/pull/27567)) [5fbbcab0af](https://github.com/microsoft/FluidFramework/commit/5fbbcab0aff87519ae6f112611f0c1e62f30d97e)
50
+
51
+ The alpha `independentView`, `independentInitializedView`, and `createIndependentTreeAlpha` APIs now accept an optional `logger` on their options.
52
+ Previously these standalone (non-`SharedTree`) views had no way to surface telemetry,
53
+ so internal events—including those emitted when the tree enters a broken state—were dropped.
54
+ Passing a logger forwards those events to the caller's telemetry pipeline.
55
+ This makes it possible to diagnose failures in scenarios that use independent tree views, such as snapshot import/export, schema migration, and other out-of-container workflows.
56
+
57
+ Events emitted by an independent tree view are tagged with the `independentView` namespace.
58
+ If no logger is provided, behavior is unchanged and telemetry events continue to be dropped.
59
+
60
+ The `logger` option is typed as `ITelemetryBaseLogger` from `@fluidframework/core-interfaces`,
61
+ so any standard Fluid telemetry logger can be passed directly.
62
+
63
+ ```typescript
64
+ // ...
65
+ const view = independentView(
66
+ new TreeViewConfiguration({ schema: MySchema }),
67
+ {
68
+ logger: myTelemetryLogger,
69
+ },
70
+ );
71
+ // ...
72
+ ```
73
+
74
+ - Shared branch names ([#27708](https://github.com/microsoft/FluidFramework/pull/27708)) [1f08b9210b](https://github.com/microsoft/FluidFramework/commit/1f08b9210bf7ba3adbc98c45b02ab8a6a58929f5)
75
+
76
+ The existing [`createSharedBranch`](https://fluidframework.com/docs/api/tree/itreealpha-interface#createsharedbranch-methodsignature) alpha API now takes an optional `name` string parameter that is associated with the shared branch.
77
+ This name can be retrieved by passing the shared branch ID to `getSharedBranchName`.
78
+
79
+ Note that, unlike the shared branch IDs, shared branch names are not guaranteed to be unique.
80
+
81
+ #### Compatibility Implications
82
+
83
+ This change breaks compatibility in the following ways:
84
+ - A document written by a client running an earlier FF version cannot be opened by a client running this version.
85
+ - A document written by a client running this version cannot be opened by a client running an earlier FF version.
86
+ - Clients running earlier FF versions will crash upon receiving ops from clients running this version.
87
+ - Clients running this version will crash upon receiving ops from clients running earlier FF versions.
88
+
89
+ These breaks are only applicable for clients with `enableSharedBranches` turned on. Other clients are unaffected.
90
+
91
+ - Add at, pop, shift, unshift, findLast, and findLastIndex methods to TreeArrayNodeAlpha ([#27686](https://github.com/microsoft/FluidFramework/pull/27686)) [59669008b9](https://github.com/microsoft/FluidFramework/commit/59669008b9f9f70ccb94030a6382afcdf8f28cd4)
92
+
93
+ `TreeArrayNodeAlpha` now has `at`, `pop`, `shift`, `unshift`, `findLast`, and `findLastIndex` methods, further aligning it with JavaScript's built-in Array API:
94
+ - `at(index)` `at` was already implemented at runtime, and consumers compiling with `lib: ES2022` or later could already see it through the inherited `ReadonlyArray` typings. This change adds no new runtime behavior, but makes `at` an explicitly declared, documented part of the API, independent of the consumer's TypeScript `lib` configuration.
95
+ - `unshift(...items)` is an alias for `insertAtStart`, mirroring how `push` aliases `insertAtEnd`: it inserts new item(s) at the start of the array. Unlike `Array.prototype.unshift`, it does not return the new length of the array.
96
+ - `pop()` removes and returns the last item in the array, or returns `undefined` (without modifying the array) if it is empty.
97
+ - `shift()` removes and returns the first item in the array, or returns `undefined` (without modifying the array) if it is empty.
98
+ - `findLast(predicate, thisArg?)` and `findLastIndex(predicate, thisArg?)` search the array from the last item to the first, returning the last matching item (or `undefined`) and its index (or `-1`) respectively, like their `Array.prototype` equivalents. As with `Array.prototype.findLast`, passing a type guard as the `findLast` predicate narrows the returned item's type.
99
+
100
+ These methods are available on `TreeArrayNodeAlpha`, which can be obtained from an existing `TreeArrayNode` via `asAlpha`, or by declaring the schema with `SchemaFactoryAlpha`'s `arrayAlpha`.
101
+
102
+ #### Usage
103
+
104
+ ```typescript
105
+ import { SchemaFactory, asAlpha } from "@fluidframework/tree/alpha";
106
+
107
+ const sf = new SchemaFactory("example");
108
+ const Inventory = sf.array("Inventory", sf.string);
109
+ const inventory = asAlpha(new Inventory(["Apples", "Bananas", "Pears"]));
110
+
111
+ // inventory: ["Apples", "Bananas", "Pears"]
112
+ inventory.unshift("Oranges", "Grapes");
113
+ // inventory: ["Oranges", "Grapes", "Apples", "Bananas", "Pears"]
114
+
115
+ inventory.at(0); // "Oranges"
116
+ inventory.at(-1); // "Pears"
117
+ inventory.at(10); // undefined
118
+
119
+ inventory.findLast((item) => item.startsWith("G")); // "Grapes"
120
+ inventory.findLastIndex((item) => item.startsWith("G")); // 1
121
+
122
+ // inventory: ["Oranges", "Grapes", "Apples", "Bananas", "Pears"]
123
+ inventory.pop(); // "Pears"
124
+ // inventory ["Oranges", "Grapes", "Apples", "Bananas"]
125
+
126
+ inventory.shift(); // "Oranges"
127
+ // inventory: ["Grapes", "Apples", "Bananas"]
128
+ ```
129
+
130
+ - Re-export telemetry types from `fluid-framework` ([#27567](https://github.com/microsoft/FluidFramework/pull/27567)) [5fbbcab0af](https://github.com/microsoft/FluidFramework/commit/5fbbcab0aff87519ae6f112611f0c1e62f30d97e)
131
+
132
+ The `fluid-framework` package now re-exports the following telemetry types from `@fluidframework/core-interfaces`:
133
+ - `ITelemetryBaseEvent`
134
+ - `ITelemetryBaseLogger`
135
+ - `LogLevel`
136
+ - `LogLevelConst`
137
+
138
+ Consumers can now import these types directly from `fluid-framework` without needing a separate dependency on `@fluidframework/core-interfaces`.
139
+
140
+ - Retain history option ([#27696](https://github.com/microsoft/FluidFramework/pull/27696)) [2fa44c6ed2](https://github.com/microsoft/FluidFramework/commit/2fa44c6ed222a8ed88a632a0bf3cad0c26e72514)
141
+
142
+ Adds a new `retainHistory` flag to [`SharedTreeOptions`](https://fluidframework.com/docs/api/tree/sharedtreeoptions-interface) (defaults to `false`).
143
+ Setting `retainHistory` to `true` will prevent SharedTree from garbage-collecting historical data about old changes.
144
+ Note that this will cause unbounded growth both in memory on the client and in summaries/snapshots (the at-rest data representing a Fluid document).
145
+ For these reasons, this option is only intended for debugging and experimentation.
146
+
147
+ ### Patch Changes
148
+
149
+ - Fix insertable types when using typesRecursive with multiple allowed types ([#27698](https://github.com/microsoft/FluidFramework/pull/27698)) [b72f836d09](https://github.com/microsoft/FluidFramework/commit/b72f836d09437654e0ef5787625073f9da41cf9f)
150
+
151
+ The allowed types produced by `SchemaFactoryBeta.typesRecursive` (and `SchemaFactoryAlpha.typesRecursive`) are now processed correctly when used in a recursive schema that permits more than one type.
152
+
153
+ Previously, passing their output to a recursive schema (for example `factory.arrayRecursive` or `factory.mapRecursive`) computed the node's insertable content type as `never`.
154
+ This caused valid insertions to fail to compile.
155
+ Recursive schemas built from a `typesRecursive` list with two or more types now accept insertable content for each of the allowed types as expected.
156
+ Recursive schemas that use a single type were unaffected.
157
+
158
+ - Throw DataCorruptionError for meaningful duplicate batch detections ([#27668](https://github.com/microsoft/FluidFramework/pull/27668)) [46a69e3d8e](https://github.com/microsoft/FluidFramework/commit/46a69e3d8e68a344bbfc277bd5c9e70699c29542)
159
+
160
+ Previously, all detected duplicate batches were only logged via the `DuplicateBatch` telemetry event, and the corresponding `DataCorruptionError` was never thrown. This was a temporary mitigation for a service-side bug that could redeliver batches.
161
+
162
+ Now, the error is thrown when either the incoming batch or the previously-seen batch has an explicit `batchId` (i.e. the batch was resubmitted, as opposed to a fresh batch whose `batchId` is derived from `clientId` and `batchStartCsn`). This distinguishes genuine duplicate-batch scenarios (e.g. container forking) from the known service-outage artifact, which only ever produces duplicates without explicit batch ids. Duplicates without an explicit `batchId` on either side continue to be log-only.
163
+
164
+ ## 2.111.0
165
+
166
+ ### Minor Changes
167
+
168
+ - Add an opt-in postProcessor option when running a transaction ([#27610](https://github.com/microsoft/FluidFramework/pull/27610)) [ee981100f3f](https://github.com/microsoft/FluidFramework/commit/ee981100f3fa5fb9b5ea26b9ef62efa7e0691b69)
169
+
170
+ `RunTransactionParams` now accepts an optional `postProcessor` (used by `runTransaction` and `runTransactionAsync`). When supplied, the edits made during the transaction are post-processed when the transaction is committed, transforming the resulting squashed change. For example, post-processing could be used to "minimize" the change so that it contains no extraneous information. Such extraneous information includes data for nodes that were both created and removed within the transaction, or changes whose effects cancel out to nothing.
171
+
172
+ `postProcessor` is a type-erased handle (`TransactionPostProcessor`) whose concrete representation is an implementation detail of `@fluidframework/tree`. It is opt-in: when it is omitted the existing behavior is preserved.
173
+
174
+ Note: minimization is the first intended implementation and use of post-processing, but it is not yet available.
175
+
176
+ - TreeView transaction APIs have been promoted to beta ([#27592](https://github.com/microsoft/FluidFramework/pull/27592)) [1ed11dbeddd](https://github.com/microsoft/FluidFramework/commit/1ed11dbeddd98fd0b788aad6f74b6d480249ce28)
177
+
178
+ The [TreeViewBeta](https://fluidframework.com/docs/api/fluid-framework/treeviewbeta-interface) interface exposes `runTransaction` and `runTransactionAsync` methods.
179
+
180
+ The [asBeta](https://fluidframework.com/docs/api/fluid-framework/#asbeta-function) helper function can be used to down-cast a `TreeView` to a `TreeViewBeta`.
181
+
182
+ ```typescript
183
+ import { asBeta } from "fluid-framework/beta";
184
+ // ...
185
+ const view = asBeta(tree.viewWith(config));
186
+ const result = view.runTransaction(() => {
187
+ // ... make edits to the tree ...
188
+ });
189
+ if (result.success === false) {
190
+ // ... handle the failed transaction ...
191
+ }
192
+ ```
193
+
194
+ > [!IMPORTANT]
195
+ > Transaction constraints are not yet available as a part of the beta transaction APIs.
196
+ > These capabilities can still be accessed via the updated alpha APIs.
197
+
198
+ **Type Name Changes**
199
+
200
+ With the introduction of new beta types, existing alpha types have been replaced with new alpha and beta variants.
201
+
202
+ | Old | New Alpha | New Beta |
203
+ | ------------------------------- | ------------------------------------ | ----------------------------------- |
204
+ | `RunTransactionParams` | `RunTransactionParamsAlpha` | `RunTransactionParamsBeta` |
205
+ | `TransactionCallbackStatus` | `TransactionCallbackStatusAlpha` | `TransactionCallbackStatusBeta` |
206
+ | `VoidTransactionCallbackStatus` | `VoidTransactionCallbackStatusAlpha` | `VoidTransactionCallbackStatusBeta` |
207
+
208
+ **Other Renames**
209
+ - `TransactionResult` (alpha) -> `TransactionVoidResult` (beta)
210
+ - `TransactionResultExt` (alpha) -> `TransactionValueResult` (beta)
211
+
3
212
  ## 2.110.0
4
213
 
5
214
  ### Minor Changes
@@ -225,6 +225,31 @@ export interface CommitMetadata {
225
225
  // @alpha
226
226
  export function comparePersistedSchema(persisted: JsonCompatible, view: ImplicitFieldSchema, options: ICodecOptions): Omit<SchemaCompatibilityStatus, "canInitialize">;
227
227
 
228
+ // @alpha
229
+ export namespace Component {
230
+ export function compose<TComponent>(allComponents: readonly Factory<TComponent>[]): Composed<TComponent>;
231
+ export function compose<TComponent, TConfig>(allComponents: readonly Factory<TComponent, TConfig>[], lazyConfiguration: (composed: Composed<TComponent, TConfig>) => TConfig): Composed<TComponent, TConfig>;
232
+ const memoize: <T>(factory: () => T) => (() => T);
233
+ // @sealed
234
+ export interface Composed<TComponent, TConfig = ComposedDefault<TComponent>> {
235
+ readonly components: readonly TComponent[];
236
+ readonly config: TConfig;
237
+ getComponent<TFactory extends Factory<TComponent, TConfig>>(factory: TFactory): ReturnType<TFactory>;
238
+ getComposed<TKey extends keyof {
239
+ [Property in keyof TComponent as TComponent[Property] extends LazyArray<unknown> | undefined ? Property : never]: boolean;
240
+ }>(property: TKey): readonly (Exclude<TComponent[TKey], undefined> extends LazyArray<infer U> ? () => U : never)[];
241
+ getConfigured<TConfigurable extends Configurable<TConfig, unknown, TComponent>>(configurable: TConfigurable): ReturnType<TConfigurable["configure"]>;
242
+ }
243
+ // @sealed
244
+ export type ComposedDefault<TComponent> = Composed<TComponent, ComposedDefault<TComponent>>;
245
+ export interface Configurable<TConfigPartial, out TResult, TComponent> {
246
+ configure(config: TConfigPartial, components: Composed<TComponent, TConfigPartial>): TResult;
247
+ }
248
+ // @input
249
+ export type Factory<TComponent, TConfig = ComposedDefault<TComponent>> = (lazyConfiguration: () => TConfig) => TComponent;
250
+ export type LazyArray<T> = () => readonly (() => T)[];
251
+ }
252
+
228
253
  // @beta
229
254
  export type ConciseTree<THandle = IFluidHandle> = Exclude<TreeLeafValue, IFluidHandle> | THandle | ConciseTree<THandle>[] | {
230
255
  [key: string]: ConciseTree<THandle>;
@@ -284,7 +309,7 @@ export function createIdentifierIndex<TSchema extends ImplicitFieldSchema>(view:
284
309
  export function createIndependentTreeAlpha<const TSchema extends ImplicitFieldSchema>(options?: CreateIndependentTreeAlphaOptions): ViewableTree & Pick<ITreeAlpha, "exportVerbose" | "exportSimpleSchema">;
285
310
 
286
311
  // @alpha
287
- export type CreateIndependentTreeAlphaOptions = ForestOptions & ((IndependentViewOptions & {
312
+ export type CreateIndependentTreeAlphaOptions = ForestOptions & IndependentViewTelemetryOptions & ((IndependentViewOptions & {
288
313
  content?: never;
289
314
  }) | (ICodecOptions & {
290
315
  content: ViewContent;
@@ -894,16 +919,21 @@ export function incrementalEncodingPolicyForAllowedTypes(rootSchema: TreeSchema)
894
919
  export const incrementalSummaryHint: unique symbol;
895
920
 
896
921
  // @alpha
897
- export function independentInitializedView<const TSchema extends ImplicitFieldSchema>(config: TreeViewConfiguration<TSchema>, options: ForestOptions & ICodecOptions, content: ViewContent): TreeViewAlpha<TSchema>;
922
+ export function independentInitializedView<const TSchema extends ImplicitFieldSchema>(config: TreeViewConfiguration<TSchema>, options: ForestOptions & ICodecOptions & IndependentViewTelemetryOptions, content: ViewContent): TreeViewAlpha<TSchema>;
898
923
 
899
924
  // @alpha
900
925
  export function independentView<const TSchema extends ImplicitFieldSchema>(config: TreeViewConfiguration<TSchema>, options?: IndependentViewOptions): TreeViewAlpha<TSchema>;
901
926
 
902
927
  // @alpha @input
903
- export interface IndependentViewOptions extends ForestOptions, Partial<CodecWriteOptions> {
928
+ export interface IndependentViewOptions extends ForestOptions, Partial<CodecWriteOptions>, IndependentViewTelemetryOptions {
904
929
  idCompressor?: IIdCompressor | undefined;
905
930
  }
906
931
 
932
+ // @alpha @input
933
+ export interface IndependentViewTelemetryOptions {
934
+ readonly logger?: ITelemetryBaseLogger | undefined;
935
+ }
936
+
907
937
  // @public
908
938
  export type InitialObjects<T extends ContainerSchema> = {
909
939
  [K in keyof T["initialObjects"]]: T["initialObjects"][K] extends SharedObjectKind<infer TChannel> ? TChannel : never;
@@ -1023,6 +1053,20 @@ export type IsListener<TListener> = TListener extends (...args: any[]) => void ?
1023
1053
  // @public @system
1024
1054
  export type IsUnion<T, T2 = T> = T extends unknown ? [T2] extends [T] ? false : true : "error";
1025
1055
 
1056
+ // @public
1057
+ export interface ITelemetryBaseEvent extends ITelemetryBaseProperties {
1058
+ // (undocumented)
1059
+ category: string;
1060
+ // (undocumented)
1061
+ eventName: string;
1062
+ }
1063
+
1064
+ // @public
1065
+ export interface ITelemetryBaseLogger {
1066
+ minLogLevel?: LogLevel | undefined;
1067
+ send(event: ITelemetryBaseEvent, logLevel?: LogLevel): void;
1068
+ }
1069
+
1026
1070
  // @public
1027
1071
  export interface ITelemetryBaseProperties {
1028
1072
  [index: string]: TelemetryBaseEventPropertyType | Tagged<TelemetryBaseEventPropertyType>;
@@ -1039,10 +1083,11 @@ export interface ITree extends ViewableTree, IFluidLoadable {
1039
1083
 
1040
1084
  // @alpha @sealed
1041
1085
  export interface ITreeAlpha extends ITree {
1042
- createSharedBranch(): string;
1086
+ createSharedBranch(name?: string): string;
1043
1087
  exportSimpleSchema(): SimpleTreeSchema;
1044
1088
  exportVerbose(): VerboseTree | undefined;
1045
1089
  getSharedBranchIds(): string[];
1090
+ getSharedBranchName(branchId: string): string | undefined;
1046
1091
  viewSharedBranchWith<TRoot extends ImplicitFieldSchema>(branchId: string, config: TreeViewConfiguration<TRoot>): TreeView<TRoot>;
1047
1092
  }
1048
1093
 
@@ -1206,6 +1251,23 @@ export interface LocalChangeMetadata extends CommitMetadata {
1206
1251
  readonly labels: TransactionLabels;
1207
1252
  }
1208
1253
 
1254
+ // @public
1255
+ export const LogLevel: LogLevelConst;
1256
+
1257
+ // @public
1258
+ export type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];
1259
+
1260
+ // @public
1261
+ export interface LogLevelConst {
1262
+ // @deprecated
1263
+ readonly default: 20;
1264
+ // @deprecated
1265
+ readonly error: 30;
1266
+ readonly essential: 30;
1267
+ readonly info: 20;
1268
+ readonly verbose: 10;
1269
+ }
1270
+
1209
1271
  // @public @sealed
1210
1272
  export interface MakeNominal {
1211
1273
  }
@@ -1243,6 +1305,9 @@ export const MapNodeSchema: {
1243
1305
  // @public
1244
1306
  export type MemberChangedListener<M extends IMember> = (clientId: string, member: M) => void;
1245
1307
 
1308
+ // @alpha @deprecated
1309
+ export const minimize: TransactionPostProcessor;
1310
+
1246
1311
  // @public
1247
1312
  export type Myself<M extends IMember = IMember> = M & {
1248
1313
  readonly currentConnection: string;
@@ -1486,11 +1551,16 @@ export interface RunTransaction {
1486
1551
  }
1487
1552
 
1488
1553
  // @alpha @input
1489
- export interface RunTransactionParams {
1490
- readonly label?: unknown;
1554
+ export interface RunTransactionParamsAlpha extends RunTransactionParamsBeta {
1555
+ readonly postProcessor?: TransactionPostProcessor;
1491
1556
  readonly preconditions?: readonly TransactionConstraintAlpha[];
1492
1557
  }
1493
1558
 
1559
+ // @beta @input
1560
+ export interface RunTransactionParamsBeta {
1561
+ readonly label?: unknown;
1562
+ }
1563
+
1494
1564
  // @public @sealed
1495
1565
  export interface SchemaCompatibilityStatus {
1496
1566
  readonly canInitialize: boolean;
@@ -1663,6 +1733,7 @@ export interface SharedTreeFormatOptions {
1663
1733
  // @alpha @input
1664
1734
  export interface SharedTreeOptions extends SharedTreeOptionsBeta, Partial<CodecWriteOptions>, Partial<SharedTreeFormatOptions> {
1665
1735
  readonly enableSharedBranches?: boolean;
1736
+ readonly retainHistory?: boolean;
1666
1737
  shouldEncodeIncrementally?: IncrementalEncodingPolicy;
1667
1738
  }
1668
1739
 
@@ -1869,7 +1940,7 @@ export namespace System_Unsafe {
1869
1940
  // @system
1870
1941
  export type InsertableTreeNodeFromAllowedTypesUnsafe<TList extends AllowedTypesUnsafe> = IsUnion<TList> extends true ? never : {
1871
1942
  readonly [Property in keyof TList]: TList[Property] extends LazyItem<infer TSchema extends TreeNodeSchemaUnsafe> ? InsertableTypedNodeUnsafe<TSchema> : never;
1872
- }[number];
1943
+ }[NumberKeys<TList>];
1873
1944
  // @system
1874
1945
  export type InsertableTreeNodeFromImplicitAllowedTypesUnsafe<TSchema extends ImplicitAllowedTypesUnsafe> = [TSchema] extends [TreeNodeSchemaUnsafe] ? InsertableTypedNodeUnsafe<TSchema> : [TSchema] extends [AllowedTypesUnsafe] ? InsertableTreeNodeFromAllowedTypesUnsafe<TSchema> : never;
1875
1946
  // @system
@@ -2063,15 +2134,18 @@ export namespace TextAsTree {
2063
2134
  // @alpha
2064
2135
  export function trackDirtyNodes(view: TreeViewAlpha<ImplicitFieldSchema>, dirty: DirtyTreeMap): () => void;
2065
2136
 
2066
- // @alpha
2067
- export type TransactionCallbackStatus<TSuccessValue, TFailureValue> = ((WithValue<TSuccessValue> & {
2068
- rollback?: false;
2069
- }) | (WithValue<TFailureValue> & {
2070
- rollback: true;
2071
- })) & {
2072
- preconditionsOnRevert?: readonly TransactionConstraintAlpha[];
2137
+ // @alpha @input
2138
+ export type TransactionCallbackStatusAlpha<TSuccessValue, TFailureValue> = TransactionCallbackStatusBeta<TSuccessValue, TFailureValue> & {
2139
+ readonly preconditionsOnRevert?: readonly TransactionConstraintAlpha[];
2073
2140
  };
2074
2141
 
2142
+ // @beta @input
2143
+ export type TransactionCallbackStatusBeta<TSuccessValue, TFailureValue> = (WithValue<TSuccessValue> & {
2144
+ readonly rollback?: false;
2145
+ }) | (WithValue<TFailureValue> & {
2146
+ readonly rollback: true;
2147
+ });
2148
+
2075
2149
  // @public
2076
2150
  export type TransactionConstraint = NodeInDocumentConstraint;
2077
2151
 
@@ -2083,22 +2157,26 @@ export type TransactionLabels = Set<unknown> & {
2083
2157
  tree?: LabelTree;
2084
2158
  };
2085
2159
 
2086
- // @alpha
2087
- export type TransactionResult = Omit<TransactionResultSuccess<unknown>, "value"> | Omit<TransactionResultFailed<unknown>, "value">;
2088
-
2089
- // @alpha
2090
- export type TransactionResultExt<TSuccessValue, TFailureValue> = TransactionResultSuccess<TSuccessValue> | TransactionResultFailed<TFailureValue>;
2160
+ // @alpha @sealed @system
2161
+ export interface TransactionPostProcessor extends ErasedType<"@fluidframework/tree.TransactionPostProcessor"> {
2162
+ }
2091
2163
 
2092
- // @alpha
2164
+ // @beta @sealed
2093
2165
  export interface TransactionResultFailed<TFailureValue> extends WithValue<TFailureValue> {
2094
- success: false;
2166
+ readonly success: false;
2095
2167
  }
2096
2168
 
2097
- // @alpha
2169
+ // @beta @sealed
2098
2170
  export interface TransactionResultSuccess<TSuccessValue> extends WithValue<TSuccessValue> {
2099
- success: true;
2171
+ readonly success: true;
2100
2172
  }
2101
2173
 
2174
+ // @beta @sealed
2175
+ export type TransactionValueResult<TSuccessValue, TFailureValue> = TransactionResultSuccess<TSuccessValue> | TransactionResultFailed<TFailureValue>;
2176
+
2177
+ // @beta @sealed
2178
+ export type TransactionVoidResult = Omit<TransactionResultSuccess<unknown>, "value"> | Omit<TransactionResultFailed<unknown>, "value">;
2179
+
2102
2180
  // @public
2103
2181
  export type TransformedEvent<TThis, E, A extends any[]> = (event: E, listener: (...args: ReplaceIEventThisPlaceHolder<A, TThis>) => void) => TThis;
2104
2182
 
@@ -2171,7 +2249,14 @@ export const TreeArrayNode: {
2171
2249
 
2172
2250
  // @alpha @sealed
2173
2251
  export interface TreeArrayNodeAlpha<TAllowedTypes extends System_Unsafe.ImplicitAllowedTypesUnsafe = ImplicitAllowedTypes, out T = [TAllowedTypes] extends [ImplicitAllowedTypes] ? TreeNodeFromImplicitAllowedTypes<TAllowedTypes> : TreeNodeFromImplicitAllowedTypes<ImplicitAllowedTypes>, in TNew = [TAllowedTypes] extends [ImplicitAllowedTypes] ? InsertableTreeNodeFromImplicitAllowedTypes<TAllowedTypes> : InsertableTreeNodeFromImplicitAllowedTypes<ImplicitAllowedTypes>> extends TreeArrayNode<TAllowedTypes, T, TNew> {
2252
+ at(index: number): T | undefined;
2253
+ findLast<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: unknown): S | undefined;
2254
+ findLast(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: unknown): T | undefined;
2255
+ findLastIndex(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: unknown): number;
2256
+ pop(): T | undefined;
2257
+ shift(): T | undefined;
2174
2258
  splice(start: number, deleteCount?: number, ...items: readonly (TNew | IterableTreeArrayContent<TNew>)[]): T[];
2259
+ unshift(...value: readonly (TNew | IterableTreeArrayContent<TNew>)[]): void;
2175
2260
  }
2176
2261
 
2177
2262
  // @beta @sealed
@@ -2198,15 +2283,16 @@ export interface TreeBranch extends IDisposable {
2198
2283
  // @alpha @sealed
2199
2284
  export interface TreeBranchAlpha extends TreeBranch, TreeContextAlpha {
2200
2285
  applyChange(change: JsonCompatibleReadOnly): void;
2286
+ computeNetChangeIfRebasedOnto(branch: TreeBranch): JsonCompatibleReadOnly | undefined;
2201
2287
  readonly events: Listenable<TreeBranchEvents>;
2202
2288
  // (undocumented)
2203
2289
  fork(): TreeBranchAlpha;
2204
2290
  hasRootSchema<TSchema extends ImplicitFieldSchema>(schema: TSchema): this is TreeViewAlpha<TSchema>;
2205
2291
  isMissingEditsFrom(branch: TreeBranch): boolean;
2206
- runTransaction<TSuccessValue, TFailureValue>(transaction: () => TransactionCallbackStatus<TSuccessValue, TFailureValue>, params?: RunTransactionParams): TransactionResultExt<TSuccessValue, TFailureValue>;
2207
- runTransaction(transaction: () => VoidTransactionCallbackStatus | void, params?: RunTransactionParams): TransactionResult;
2208
- runTransactionAsync<TSuccessValue, TFailureValue>(transaction: () => Promise<TransactionCallbackStatus<TSuccessValue, TFailureValue>>, params?: RunTransactionParams): Promise<TransactionResultExt<TSuccessValue, TFailureValue>>;
2209
- runTransactionAsync(transaction: () => Promise<VoidTransactionCallbackStatus | void>, params?: RunTransactionParams): Promise<TransactionResult>;
2292
+ runTransaction<TSuccessValue, TFailureValue>(transaction: () => TransactionCallbackStatusAlpha<TSuccessValue, TFailureValue>, params?: RunTransactionParamsAlpha): TransactionValueResult<TSuccessValue, TFailureValue>;
2293
+ runTransaction(transaction: () => VoidTransactionCallbackStatusAlpha | void, params?: RunTransactionParamsAlpha): TransactionVoidResult;
2294
+ runTransactionAsync<TSuccessValue, TFailureValue>(transaction: () => Promise<TransactionCallbackStatusAlpha<TSuccessValue, TFailureValue>>, params?: RunTransactionParamsAlpha): Promise<TransactionValueResult<TSuccessValue, TFailureValue>>;
2295
+ runTransactionAsync(transaction: () => Promise<VoidTransactionCallbackStatusAlpha | void>, params?: RunTransactionParamsAlpha): Promise<TransactionVoidResult>;
2210
2296
  }
2211
2297
 
2212
2298
  // @alpha @sealed
@@ -2241,10 +2327,10 @@ export enum TreeCompressionStrategy {
2241
2327
  // @alpha
2242
2328
  export interface TreeContextAlpha {
2243
2329
  isBranch(): this is TreeBranchAlpha;
2244
- runTransaction<TValue>(transaction: () => WithValue<TValue>, params?: RunTransactionParams): TransactionResultExt<TValue, TValue>;
2245
- runTransaction(transaction: () => void, params?: RunTransactionParams): TransactionResult;
2246
- runTransactionAsync<TValue>(transaction: () => Promise<WithValue<TValue>>, params?: RunTransactionParams): Promise<TransactionResultExt<TValue, TValue>>;
2247
- runTransactionAsync(transaction: () => Promise<void>, params?: RunTransactionParams): Promise<TransactionResult>;
2330
+ runTransaction<TValue>(transaction: () => WithValue<TValue>, params?: RunTransactionParamsAlpha): TransactionValueResult<TValue, TValue>;
2331
+ runTransaction(transaction: () => void, params?: RunTransactionParamsAlpha): TransactionVoidResult;
2332
+ runTransactionAsync<TValue>(transaction: () => Promise<WithValue<TValue>>, params?: RunTransactionParamsAlpha): Promise<TransactionValueResult<TValue, TValue>>;
2333
+ runTransactionAsync(transaction: () => Promise<void>, params?: RunTransactionParamsAlpha): Promise<TransactionVoidResult>;
2248
2334
  }
2249
2335
 
2250
2336
  // @beta @input
@@ -2398,7 +2484,7 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
2398
2484
  }
2399
2485
 
2400
2486
  // @alpha @sealed
2401
- export interface TreeViewAlpha<in out TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> extends Omit<TreeViewBeta<ReadSchema<TSchema>>, "root" | "initialize" | "fork">, TreeBranchAlpha {
2487
+ export interface TreeViewAlpha<in out TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> extends Omit<TreeViewBeta<ReadSchema<TSchema>>, "root" | "initialize" | "fork" | "runTransaction" | "runTransactionAsync">, TreeBranchAlpha {
2402
2488
  // (undocumented)
2403
2489
  readonly events: Listenable<TreeViewEvents & TreeBranchEvents>;
2404
2490
  // (undocumented)
@@ -2414,6 +2500,8 @@ export interface TreeViewAlpha<in out TSchema extends ImplicitFieldSchema | Unsa
2414
2500
  export interface TreeViewBeta<in out TSchema extends ImplicitFieldSchema> extends TreeView<TSchema>, TreeBranch {
2415
2501
  // (undocumented)
2416
2502
  fork(): ReturnType<TreeBranch["fork"]> & TreeViewBeta<TSchema>;
2503
+ runTransaction<TOut extends TransactionCallbackStatusBeta<unknown, unknown> | VoidTransactionCallbackStatusBeta | void>(transaction: () => TOut, params?: RunTransactionParamsBeta): TOut extends TransactionCallbackStatusBeta<infer TSuccessValue, infer TFailureValue> ? TransactionValueResult<TSuccessValue, TFailureValue> : TransactionVoidResult;
2504
+ runTransactionAsync<TOut extends TransactionCallbackStatusBeta<unknown, unknown> | VoidTransactionCallbackStatusBeta | void>(transaction: () => Promise<TOut>, params?: RunTransactionParamsBeta): Promise<TOut extends TransactionCallbackStatusBeta<infer TSuccessValue, infer TFailureValue> ? TransactionValueResult<TSuccessValue, TFailureValue> : TransactionVoidResult>;
2417
2505
  }
2418
2506
 
2419
2507
  // @public @sealed
@@ -2538,8 +2626,11 @@ export interface ViewContent {
2538
2626
  readonly tree: JsonCompatible<IFluidHandle>;
2539
2627
  }
2540
2628
 
2541
- // @alpha
2542
- export type VoidTransactionCallbackStatus = Omit<TransactionCallbackStatus<unknown, unknown>, "value">;
2629
+ // @alpha @input
2630
+ export type VoidTransactionCallbackStatusAlpha = Omit<TransactionCallbackStatusAlpha<unknown, unknown>, "value">;
2631
+
2632
+ // @beta @input
2633
+ export type VoidTransactionCallbackStatusBeta = Omit<TransactionCallbackStatusBeta<unknown, unknown>, "value">;
2543
2634
 
2544
2635
  // @public @sealed
2545
2636
  export interface WithType<out TName extends string = string, out TKind extends NodeKind = NodeKind, out TInfo = unknown> {
@@ -2548,9 +2639,9 @@ export interface WithType<out TName extends string = string, out TKind extends N
2548
2639
  get [typeSchemaSymbol](): TreeNodeSchemaClass<TName, TKind, TreeNode, never, boolean, TInfo>;
2549
2640
  }
2550
2641
 
2551
- // @alpha
2642
+ // @beta @input
2552
2643
  export interface WithValue<TValue> {
2553
- value: TValue;
2644
+ readonly value: TValue;
2554
2645
  }
2555
2646
 
2556
2647
  ```