Contents
- ✨ New Features
- Expose whether a container runtime has staged changes (#27648)
- Start sharing local handle payloads before attachment (#27704)
- 🌳 SharedTree DDS Changes
- Add Component utilities for composing open-polymorphic schema (#27628)
- Independent tree views now accept an optional telemetry logger (#27567)
- Retain history option (#27696)
- Add at, pop, shift, unshift, findLast, and findLastIndex methods to TreeArrayNodeAlpha (#27686)
- Shared branch names (#27708)
- 🐛 Bug Fixes
- Other Changes
- Re-export telemetry types from
fluid-framework(#27567)
- Re-export telemetry types from
✨ New Features
Expose whether a container runtime has staged changes (#27648)
IContainerRuntimeBase now exposes hasStagedChanges, a flag indicating whether there are any changes submitted while in Staging Mode (via enterStagingMode) that have not yet been discarded or committed. A new hasStagedChangesChanged event is emitted whenever this value changes.
This is distinct from isDirty: a container runtime can be dirty due to ordinary unacknowledged local changes without having any staged changes.
containerRuntime.on("hasStagedChangesChanged", (hasStagedChanges) => {
// update UI to reflect whether there are staged changes awaiting commit/discard
});
const hasStagedChanges = containerRuntime.hasStagedChanges;Change details
Commit: c12943d
Affected packages:
- @fluidframework/runtime-definitions
- @fluidframework/container-runtime-definitions
⬆️ Table of contents
Start sharing local handle payloads before attachment (#27704)
Locally created Fluid handles can now expose an optional sharePayload() method that starts sharing their payload without attaching the handle to the Fluid object graph. Blob handles implement this method, allowing applications to begin uploading a blob before serializing its handle into a DDS.
const handle = await runtime.uploadBlob(bytes);
if (isLocalFluidHandle(handle) && handle.sharePayload !== undefined) {
handle.sharePayload();
}Change details
Commit: 2c4d5aa
Affected packages:
- @fluidframework/core-interfaces
- @fluidframework/container-runtime
⬆️ Table of contents
🌳 SharedTree DDS Changes
Add Component utilities for composing open-polymorphic schema (#27628)
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" schema patterns where the set of allowed types for a field or collection can be extended by separate libraries.
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.
/** Example application component content type. */
interface MyAppComponentContent {
/**
* Item types contributed by this component.
* We are just typing them as TreeNodeSchema here to keep things simple.
* Real use would often provide some static factory to be able to create instances, as well as some APIs all item nodes should implement.
*/
readonly items: Component.LazyArray<TreeNodeSchema>;
}
type MyAppComponent = Component.Factory<MyAppComponentContent>;
// A simple component, which does not depend on any other context.
const textComponent: MyAppComponent = () => ({
items: () => [() => TextItem],
});
// A component which creates an item type which recursively depends on all item types.
const containerComponent: MyAppComponent = (config) => ({
items: () => [
() => class extends sf.array("Container", config().getComposed("items")) {},
],
});
const appConfig = Component.compose([containerComponent, textComponent]);
// The config's items can now be used to create a TreeViewConfiguration, root schema, or whatever else is needed.
class Root extends sf.object("Root", {
content: appConfig.getComposed("items"),
}) {}See the worked examples in openPolymorphism.integration.ts for end-to-end usage with SharedTree schema.
Change details
Commit: 7a56d09
Affected packages:
- @fluidframework/tree
- fluid-framework
⬆️ Table of contents
Independent tree views now accept an optional telemetry logger (#27567)
The alpha independentView, independentInitializedView, and createIndependentTreeAlpha APIs now accept an optional logger on their options. Previously these standalone (non-SharedTree) views had no way to surface telemetry, so internal events—including those emitted when the tree enters a broken state—were dropped. Passing a logger forwards those events to the caller's telemetry pipeline. 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.
Events emitted by an independent tree view are tagged with the independentView namespace. If no logger is provided, behavior is unchanged and telemetry events continue to be dropped.
The logger option is typed as ITelemetryBaseLogger from @fluidframework/core-interfaces, so any standard Fluid telemetry logger can be passed directly.
// ...
const view = independentView(new TreeViewConfiguration({ schema: MySchema }), {
logger: myTelemetryLogger,
});
// ...Change details
Commit: 5fbbcab
Affected packages:
- @fluidframework/tree
- fluid-framework
⬆️ Table of contents
Retain history option (#27696)
Adds a new retainHistory flag to SharedTreeOptions (defaults to false). Setting retainHistory to true will prevent SharedTree from garbage-collecting historical data about old changes. 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). For these reasons, this option is only intended for debugging and experimentation.
Change details
Commit: 2fa44c6
Affected packages:
- fluid-framework
- @fluidframework/tree
⬆️ Table of contents
Add at, pop, shift, unshift, findLast, and findLastIndex methods to TreeArrayNodeAlpha (#27686)
TreeArrayNodeAlpha now has at, pop, shift, unshift, findLast, and findLastIndex methods, further aligning it with JavaScript's built-in Array API:
at(index)atwas already implemented at runtime, and consumers compiling withlib: ES2022or later could already see it through the inheritedReadonlyArraytypings. This change adds no new runtime behavior, but makesatan explicitly declared, documented part of the API, independent of the consumer's TypeScriptlibconfiguration.unshift(...items)is an alias forinsertAtStart, mirroring howpushaliasesinsertAtEnd: it inserts new item(s) at the start of the array. UnlikeArray.prototype.unshift, it does not return the new length of the array.pop()removes and returns the last item in the array, or returnsundefined(without modifying the array) if it is empty.shift()removes and returns the first item in the array, or returnsundefined(without modifying the array) if it is empty.findLast(predicate, thisArg?)andfindLastIndex(predicate, thisArg?)search the array from the last item to the first, returning the last matching item (orundefined) and its index (or-1) respectively, like theirArray.prototypeequivalents. As withArray.prototype.findLast, passing a type guard as thefindLastpredicate narrows the returned item's type.
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.
Usage
import { SchemaFactory, asAlpha } from "@fluidframework/tree/alpha";
const sf = new SchemaFactory("example");
const Inventory = sf.array("Inventory", sf.string);
const inventory = asAlpha(new Inventory(["Apples", "Bananas", "Pears"]));
// inventory: ["Apples", "Bananas", "Pears"]
inventory.unshift("Oranges", "Grapes");
// inventory: ["Oranges", "Grapes", "Apples", "Bananas", "Pears"]
inventory.at(0); // "Oranges"
inventory.at(-1); // "Pears"
inventory.at(10); // undefined
inventory.findLast((item) => item.startsWith("G")); // "Grapes"
inventory.findLastIndex((item) => item.startsWith("G")); // 1
// inventory: ["Oranges", "Grapes", "Apples", "Bananas", "Pears"]
inventory.pop(); // "Pears"
// inventory ["Oranges", "Grapes", "Apples", "Bananas"]
inventory.shift(); // "Oranges"
// inventory: ["Grapes", "Apples", "Bananas"]Change details
Commit: 5966900
Affected packages:
- fluid-framework
- @fluidframework/tree
⬆️ Table of contents
Shared branch names (#27708)
The existing createSharedBranch alpha API now takes an optional name string parameter that is associated with the shared branch. This name can be retrieved by passing the shared branch ID to getSharedBranchName.
Note that, unlike the shared branch IDs, shared branch names are not guaranteed to be unique.
Compatibility Implications
This change breaks compatibility in the following ways:
- A document written by a client running an earlier FF version cannot be opened by a client running this version.
- A document written by a client running this version cannot be opened by a client running an earlier FF version.
- Clients running earlier FF versions will crash upon receiving ops from clients running this version.
- Clients running this version will crash upon receiving ops from clients running earlier FF versions.
These breaks are only applicable for clients with enableSharedBranches turned on. Other clients are unaffected.
Change details
Commit: 1f08b92
Affected packages:
- @fluidframework/tree
- fluid-framework
⬆️ Table of contents
🐛 Bug Fixes
Other Changes
Re-export telemetry types from fluid-framework (#27567)
The fluid-framework package now re-exports the following telemetry types from @fluidframework/core-interfaces:
ITelemetryBaseEventITelemetryBaseLoggerLogLevelLogLevelConst
Consumers can now import these types directly from fluid-framework without needing a separate dependency on @fluidframework/core-interfaces.
Change details
Commit: 5fbbcab
Affected packages:
- fluid-framework
⬆️ Table of contents
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!