Releases: microsoft/FluidFramework
Fluid Framework v2.81.0 (minor)
Contents
🚨 Breaking Changes
directory: Path parameter added to cleared event (#26112)
The clear event for SharedDirectory did not include a path parameter indicating which directory was cleared. Therefore, the clear event is deprecated and will be removed in a future release. Instead use the cleared event.
Before:
sharedDirectory.on("clear", (local, target) => {
// No way to know which subdirectory was cleared
});After:
sharedDirectory.on("cleared", (path, local, target) => {
// path tells you which directory was cleared (e.g., "/", "/subdir1", "/subdir2")
});This change provides better observability by allowing listeners to distinguish between clear operations on different subdirectories within the SharedDirectory hierarchy.
Change details
Commit: 1ded6bf
Affected packages:
- fluid-framework
- @fluidframework/map
🌳 SharedTree DDS Changes
tree-agent: New type factory system for method and property bindings (#26167)
The @fluidframework/tree-agent package now includes a custom type system (Type Factory) as an alternative to Zod for defining method and property types. This new system is available in the /alpha entry point and provides a familiar API for type definitions.
Key features
- Familiar API: Use
tf.string(),tf.object(), etc. - similar to Zod's syntax (wheretfis aliased fromtypeFactory) - Same API surface: The existing
expose,exposeProperty, andbuildFuncmethods work with both Zod and Type Factory types
Usage
Import from the alpha entry point to use Type Factory types:
import {
typeFactory as tf,
buildFunc,
exposeMethodsSymbol,
} from "@fluidframework/tree-agent/alpha";
import { SchemaFactory } from "@fluidframework/tree";
const sf = new SchemaFactory("myApp");
class TodoList extends sf.object("TodoList", {
items: sf.array(sf.string),
}) {
public addItem(item: string): void {
this.items.insertAtEnd(item);
}
public static [exposeMethodsSymbol](methods) {
methods.expose(
TodoList,
"addItem",
buildFunc({ returns: tf.void() }, ["item", tf.string()]),
);
}
}Available types
All common types are supported:
- Primitives:
tf.string(),tf.number(),tf.boolean(),tf.void(),tf.undefined(),tf.null(),tf.unknown() - Collections:
tf.array(elementType),tf.object({ shape }),tf.map(keyType, valueType),tf.record(keyType, valueType),tf.tuple([types]) - Utilities:
tf.union([types]),tf.literal(value),tf.optional(type),tf.readonly(type) - Schema references:
tf.instanceOf(SchemaClass)
Migration from Zod
You can migrate gradually - both Zod and Type Factory types work in the same codebase:
Before (Zod):
import { z } from "zod";
import { buildFunc, exposeMethodsSymbol } from "@fluidframework/tree-agent";
methods.expose(
MyClass,
"myMethod",
buildFunc({ returns: z.string() }, ["param", z.number()]),
);After (Type Factory):
import {
typeFactory as tf,
buildFunc,
exposeMethodsSymbol,
} from "@fluidframework/tree-agent/alpha";
methods.expose(
MyClass,
"myMethod",
buildFunc({ returns: tf.string() }, ["param", tf.number()]),
);Note on type safety
The Type Factory type system does not currently provide compile-time type checking, though this may be added in the future. For applications requiring strict compile-time validation, Zod types remain fully supported.
Change details
Commit: f09aa24
Affected packages:
- @fluidframework/tree-agent
New text-editor example demonstrating SharedTree with Quill (#26217)
This example showcases a collaborative text editor using SharedTree for data storage and Quill as the editor. It demonstrates using withMemoizedTreeObservations from @fluidframework/react for reactive updates when the tree changes.
Change details
Commit: a7abfac
Affected packages:
- @fluid-example/text-editor
🐛 Bug Fixes
Self attendee is announced via "attendeeConnected" (#26247)
Local attendee connection is now announced via "attendeeConnected" presence event.
Change details
Commit: f838524
Affected packages:
- @fluidframework/presence
⚠️ Deprecations
getRevertible has moved onto ChangeMetadata (#26215)
The getRevertible factory provided by the changed event is now exposed on the ChangeMetadata object instead of as the second callback parameter. The second parameter is deprecated and will be removed in a future release.
Why this change?
Keeping all per-change data on ChangeMetadata makes the API:
- Easier to discover.
- Easier to ignore.
- Require less parameter churn to use.
- Consistent with the
getChangeAPI, which is also only available on local commits.
Migration
Before (deprecated):
The getRevertible argument passed to the event had the following shape:
| Data change | Schema change | |
|---|---|---|
| Local change | () => Revertible |
undefined |
| Remote change | undefined |
undefined |
checkout.events.on("changed", (_data, getRevertible) => {
if (getRevertible !== undefined) {
const revertible = getRevertible();
// ...
}
});After:
The new getRevertible property has the following shape:
| Data change | Schema change | |
|---|---|---|
| Local change | () => Revertible |
() => undefined |
| Remote change | undefined |
undefined |
checkout.events.on("changed", ({ getRevertible }) => {
const revertible = getRevertible?.();
if (revertible !== undefined) {
// ...
}
});This applies potentially anywhere you listen to changed (for example on TreeViewAlpha.events/TreeBranchEvents).
Change details
Commit: 922f579
Affected packages:
- @fluidframework/tree
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!
Fluid Framework v2.80.0 (minor)
Contents
- 🚨 Breaking Changes
- Removal of number key support in LatestMap (#25904)
- Added layerIncompatibilityError to FluidErrorTypes, ContainerErrorTypes, DriverErrorTypes and OdspErrorTypes (#26068)
- TreeBranch operations throw when called during transactions (#26097)
- map: Emit valueChanged events for deleted keys after a clear operation (#26102)
- 🐛 Bug Fixes
- Legacy API Changes
🚨 Breaking Changes
Removal of number key support in LatestMap (#25904)
number keys have never been successfully propagated as numbers at runtime and this type clarification makes that clear. See issue 25919 for more details.
Change details
Commit: c1d91d8
Affected packages:
- @fluidframework/presence
Added layerIncompatibilityError to FluidErrorTypes, ContainerErrorTypes, DriverErrorTypes and OdspErrorTypes (#26068)
The Fluid error type layerIncompatibilityError is added to FluidErrorTypes and is now @legacy @beta. It is also added to ContainerErrorTypes, DriverErrorTypes and OdspErrorTypes which extend FluidErrorTypes. layerIncompatibilityError was added as @legacy @Alpha in version 2.72.0. The corresponding interface ILayerIncompatibilityError for errors of type layerIncompatibilityError is now also @legacy @beta.
See this issue for more details.
Change details
Commit: a8532bd
Affected packages:
- @fluidframework/container-definitions
- @fluidframework/core-interfaces
- @fluidframework/driver-definitions
- @fluidframework/odsp-driver-definitions
TreeBranch operations throw when called during transactions (#26097)
This breaking change only affects the behavior of TreeBranch methods (currently released as beta).
- Invoking
TreeBranch.fork()now throws an error if a transaction is ongoing on the branch. - Invoking
TreeBranch.merge(sourceBranch)now throws an error if a transaction is ongoing on the source branch. As before, it also throws an error if a transaction is ongoing on the target (i.e.,this) branch. - Invoking
TreeBranch.rebaseOnto(targetBranch)now throws an error if a transaction is ongoing on the target branch. As before, it also throws an error if a transaction is ongoing on the source (i.e.,this) branch.
These new restrictions insulate branches and their dependents from experiencing incomplete transaction changes. This is important because incomplete transaction changes may not uphold application invariants.
In scenarios that experience the new errors, application authors should consider whether the ongoing transaction can safely be closed before invoking these methods.
Change details
Commit: 33b1ec0
Affected packages:
- @fluidframework/tree
- fluid-framework
map: Emit valueChanged events for deleted keys after a clear operation (#26102)
When a clear op is processed on SharedMap, valueChanged events are now emitted for each key that was deleted. Previously, only the clear event was emitted with no subsequent valueChanged events.
Change details
Commit: 7c9be0e
Affected packages:
- @fluidframework/map
🐛 Bug Fixes
Attendee status fixes on reconnect (#26111)
Fix "Connected" status for Attendees when local client reconnects (intermittent connection or transition from read-only to read-write connection). This includes no longer emitting incorrect "attendeeDisconnected" events.
Change details
Commit: 836f22f
Affected packages:
- @fluidframework/presence
Legacy API Changes
Types not intended for consumer implementation/extension are now @Sealed (#26024)
The following types are now explicitly marked as @sealed to indicate that they are not intended for consumer implementation or extension.
MockFluidDataStoreRuntimeclass in@fluidframework/test-runtime-utilsIFluidParentContextinterface in@fluidframework/runtime-definitionsIFluidDataStoreContextinterface in@fluidframework/runtime-definitionsIFluidDataStoreContextDetachedinterface in@fluidframework/runtime-definitions
Change details
Commit: 75a3861
Affected packages:
- @fluidframework/runtime-definitions
- @fluidframework/test-runtime-utils
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!
Fluid Framework v2.74.0 (minor)
Contents
🌳 SharedTree DDS Changes
Fixed bug in sending of revert edits after an aborted transaction (#25978)
Aborting a transaction used to put the tree in a state that would trigger an assert when sending some undo/redo edits to peers. This would prevent some undo/redo edits from being sent and would put the tree in a broken state that prevented any further edits. This issue could not have caused document corruption, so reopening the document was a possible remedy. Aborting a transaction no longer puts the tree in such a state, so it is safe to perform undo/redo edits after that.
Change details
Commit: 93ec6c7
Affected packages:
- @fluidframework/tree
- fluid-framework
⚠️ Deprecations
ai-collab library has been removed (#26008)
The team is no longer pursuing this direction for SharedTree-based collaboration with AI agents. This library is now considered deprecated. No future versions of this library will be published.
Change details
Commit: b084ac5
Affected packages:
Legacy API Changes
Some keys in IFluidCodeDetailsConfig are now reserved for Fluid Framework use (#25641)
The keys of IFluidCodeDetailsConfig (the type of the config property on IFluidCodeDetails) used to be entirely free for consumer use. Going forward, keys with the "FluidFramework." prefix are reserved for Fluid Framework's internal use.
We do not expect this to affect any consumers.
Change details
Commit: 1eaf526
Affected packages:
- @fluidframework/container-definitions
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!
Fluid Framework v2.73.0 (minor)
Contents
🌳 SharedTree DDS Changes
Schema snapshot compatibility checker (#25861)
This change adds alpha APIs for creating snapshots of view schema and testing their compatibility for the purposes of schema migrations.
New APIs:
checkCompatibility- Checks the compatibility of the view schema which created the document against the view schema being used to open it.importCompatibilitySchemaSnapshot- Parse a JSON representation of a tree schema into a concrete schema.exportCompatibilitySchemaSnapshot- Returns a JSON representation of the tree schema for snapshot compatibility checking.
Example: Current view schema vs. historical view schema
An application author is developing an app that has a schema for storing 2D Points. They wish to maintain backwards compatibility in future versions and avoid changing their view schema in a way that breaks this behavior. When introducing a new initial schema, they persists a snapshot using exportCompatibilitySchemaSnapshot:
const factory = new SchemaFactory("test");
// The past view schema, for the purposes of illustration. This wouldn't normally appear as a concrete schema in the test
// checking compatibility, but rather would be loaded from a snapshot.
class Point2D extends factory.object("Point", {
x: factory.number,
y: factory.number,
}) {}
const viewSchema = new TreeViewConfiguration({ schema: Point2D });
const encodedSchema = JSON.stringify(
exportCompatibilitySchemaSnapshot(viewSchema),
);
fs.writeFileSync("PointSchema.json", encodedSchema);Next they create a regression test to ensure that the current view schema can read content written by the original view schema (SchemaCompatibilityStatus.canUpgrade). Initially currentViewSchema === Point2D:
const encodedSchema = JSON.parse(fs.readFileSync("PointSchema.json", "utf8"));
const oldViewSchema = importCompatibilitySchemaSnapshot(encodedSchema);
// Check to see if the document created by the historical view schema can be opened with the current view schema
const compatibilityStatus = checkCompatibility(
oldViewSchema,
currentViewSchema,
);
// Check to see if the document created by the historical view schema can be opened with the current view schema
const backwardsCompatibilityStatus = checkCompatibility(
oldViewSchema,
currentViewSchema,
);
// z is not present in Point2D, so the schema must be upgraded
assert.equal(backwardsCompatibilityStatus.canView, false);
// The schema can be upgraded to add the new optional field
assert.equal(backwardsCompatibilityStatus.canUpgrade, true);Additionally, they a regression test to ensure that older view schemas can read content written by the current view schema (SchemaCompatibilityStatus.canView):
// Test what the old version of the application would do with a tree using the new schema:
const forwardsCompatibilityStatus = checkCompatibility(
currentViewSchema,
oldViewSchema,
);
// If the old schema set allowUnknownOptionalFields, this would be true, but since it did not,
// this assert will fail, detecting the forwards compatibility break:
// this means these two versions of the application cannot collaborate on content using these schema.
assert.equal(forwardsCompatibilityStatus.canView, true);Later in the application development cycle, the application author decides they want to change their Point2D to a Point3D, adding an extra field:
// Build the current view schema
const schemaFactory = new SchemaFactory("test");
class Point3D extends schemaFactory.object("Point", {
x: factory.number,
y: factory.number,
// The current schema has a new optional field that was not present on Point2D
z: factory.optional(factory.number),
}) {}The test first compatibility test will pass as the Point2D schema is upgradeable to a Point3D schema. However, the second compatibility test fill fail as an application using the Point2D view schema cannot collaborate on content authored using the Point3D schema.
Change details
Commit: e5be416
Affected packages:
- @fluidframework/tree
- fluid-framework
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!
Fluid Framework v2.72.0 (minor)
Contents
✨ New Features
Expose staged, types, stagedRecursive and typesRecursive on SchemaFactoryBeta (#25779)
These APIs were previously only available on SchemaFactoryAlpha, but are now available on SchemaFactoryBeta.
Change details
Commit: 75d7f11
Affected packages:
- @fluidframework/tree
🌳 SharedTree DDS Changes
formatVersion removed from the options passed to configuredSharedTree (#25752)
Note: this change may break users of alpha APIs. See below for details.
SharedTreeOptions (which is passed to configuredSharedTree) no longer includes a formatVersion: SharedTreeFormatVersion[keyof SharedTreeFormatVersion] field. The concept of SharedTreeFormatVersion has been removed altogether. Instead, users are expected to leverage the already existing minVersionForCollab field.
For migration purposes, the mapping from SharedTreeFormatVersion to minVersionForCollab is as follows:
SharedTreeFormatVersion.v1: no supported equivalentSharedTreeFormatVersion.v2: no supported equivalentSharedTreeFormatVersion.v3:minVersionForCollab: FluidClientVersion.v2_0SharedTreeFormatVersion.v5:minVersionForCollab: FluidClientVersion.v2_43SharedTreeFormatVersion.vSharedBranches:minVersionForCollab: FluidClientVersion.v2_43+SharedTreeOptions.enableSharedBranches
The values for which there is no supported equivalent minVersionForCollab were never given official support. Contact the Fluid Framework team if you need help migrating away from them.
Change details
Commit: df53390
Affected packages:
- @fluidframework/tree
- fluid-framework
Legacy API Changes
Added a new Fluid error type layerIncompatibilityError (#25784)
A new Fluid error type layerIncompatibilityError is added to FluidErrorTypesAlpha as @legacy @Alpha. This will be moved to FluidErrorTypes as @legacy @beta in a future legacy breaking release. It will also be added to ContainerErrorTypes since it extends FluidErrorTypes.
Change details
Commit: 01d568b
Affected packages:
- @fluidframework/core-interfaces
- @fluidframework/container-definitions
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!
Fluid Framework v2.71.0 (minor)
Contents
✨ New Features
delete keyword support for ObjectNodes (#25738)
Added support for using the delete keyword to remove content under optional fields for ObjectNodes.
// This is now equivalent to node.foo = undefined
delete node.foo;Change details
Commit: 31dca54
Affected packages:
- @fluidframework/tree
🌳 SharedTree DDS Changes
Add IndependentTree API (#25785)
New IndependentTreeAlpha and IndependentTreeBeta APIs provide similar utility to the existing alpha IndependentView API, except providing access to the ViewableTree.
This allows for multiple views (in sequence, not concurrently) to be created to test things like schema upgrades and incompatible view schema much more easily (see example below). For IndependentTreeAlpha, this also provides access to exportVerbose and exportSimpleSchema from ITreeAlpha.
An example of how to use createIndependentTreeBeta to create multiple views to test a schema upgrade:
const tree = createIndependentTreeBeta();
const stagedConfig = new TreeViewConfiguration({
schema: SchemaFactoryAlpha.types([
SchemaFactory.number,
SchemaFactoryAlpha.staged(SchemaFactory.string),
]),
});
const afterConfig = new TreeViewConfigurationAlpha({
schema: [SchemaFactory.number, SchemaFactory.string],
});
// Initialize tree
{
const view = tree.viewWith(stagedConfig);
view.initialize(1);
view.dispose();
}
// Do schema upgrade
{
const view = tree.viewWith(afterConfig);
view.upgradeSchema();
view.root = "A";
view.dispose();
}
// Can still view tree with staged schema
{
const view = tree.viewWith(stagedConfig);
assert.equal(view.root, "A");
view.dispose();
}Change details
Commit: 21c4245
Affected packages:
- fluid-framework
- @fluidframework/tree
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!
Fluid Framework v2.70.0 (minor)
Contents
- 🚨 Breaking Changes
- Deprecated properties have been removed from IRuntimeStorageService and IContainerStorageService (#25708)
- getSnapshotTree is now required in IChannelStorageService (#25707)
- Deprecated property processCore has been removed from SharedObject (#25749)
- Remove submitMessage from FluidDataStoreRuntime and MockFluidDataStoreRuntime (#25755)
- ✨ New Features
- 🌳 SharedTree DDS Changes
⚠️ Deprecations
🚨 Breaking Changes
Deprecated properties have been removed from IRuntimeStorageService and IContainerStorageService (#25708)
The following deprecated properties have been removed from IRuntimeStorageService:
createBlobdisposedisposeddownloadSummarygetSnapshotgetSnapshotTreegetVersionspoliciesuploadSummaryWithContext
The following deprecated properties have been removed from IContainerStorageService:
disposedisposeddownloadSummary
Please see this Github issue for more details.
Change details
Commit: 82c936e
Affected packages:
- @fluidframework/container-definitions
- @fluidframework/runtime-definitions
getSnapshotTree is now required in IChannelStorageService (#25707)
The getSnapshotTree property was added as optional to IChannelStorageService in version 2.51.0. It is now a required property. See this github issue for more details.
Change details
Commit: d1c4c0a
Affected packages:
- @fluidframework/datastore-definitions
- @fluidframework/test-runtime-utils
Deprecated property processCore has been removed from SharedObject (#25749)
The deprecated property processCore has been removed from SharedObject.
Please see this github issue for more details.
Change details
Commit: a33a2e3
Affected packages:
- @fluidframework/ordered-collection
- @fluidframework/register-collection
- @fluidframework/shared-object-base
Remove submitMessage from FluidDataStoreRuntime and MockFluidDataStoreRuntime (#25755)
As needed, access submitMessage via IFluidDataStoreContext/IFluidParentContext. See #24406 for details.
Change details
Commit: 88860f3
Affected packages:
- @fluidframework/datastore
- @fluidframework/test-runtime-utils
✨ New Features
Promote core devtools APIs from alpha to beta (#25695)
The primary devtools APIs may now be imported from /beta. This includes:
initializeDevtools- Initialize the devtools singletontryGetFluidDevtools- Get the existing devtools instance if initializedIFluidDevtools- Main devtools interface for registering containersContainerDevtoolsProps- Properties for registering containers with devtools
For example:
import {
initializeDevtools,
tryGetFluidDevtools,
type IFluidDevtools,
type ContainerDevtoolsProps,
} from "@fluidframework/devtools-core/beta";
// Initialize devtools
const devtools = initializeDevtools();
// Register a container
devtools.registerContainerDevtools({
containerKey: "my-container",
container: myContainer,
});Change details
Commit: 7c8e203
Affected packages:
- @fluidframework/devtools-core
Added Tree.ensureSchema (#25740)
This helper function allows content to be tagged with a schema type before being inserted into the tree. This allows content that would otherwise be ambiguous to be well-defined, without having to wrap it in a node constructor.
Example:
const sf = new SchemaFactory("example");
class Dog extends sf.object("Dog", { name: sf.string() }) {}
class Cat extends sf.object("Cat", { name: sf.string() }) {}
class Root extends sf.object("Root", { pet: [Dog, Cat] }) {}
// ...
const pet = { name: "Max" };
view.root.pet = pet; // Error: `pet` is ambiguous - is it a Dog or a Cat?
view.root.pet = new Dog(pet); // This works, but has the overhead of creating a Dog node before the insertion actually happens.
TreeAlpha.ensureSchema(Dog, pet); // Instead, this tags the `pet` object as a Dog...
view.root.pet = pet; // So now there is no error for a normal insertion - it's a Dog.This function works by leveraging the new schemaSymbol, which is also available for use. See its documentation for more information.
Change details
Commit: 8213407
Affected packages:
- @fluidframework/tree
A minimal set of branching APIs has been promoted to beta. (#25744)
The following APIs have been promoted to beta in @fluidframework/tree:
TreeBranch.fork()TreeBranch.merge()TreeBranch.rebaseOnto()TreeBranch.dispose()TreeView.fork()
These APIs enable applications to implement basic local branching flows.
Change details
Commit: 32cc2c7
Affected packages:
- fluid-framework
- @fluidframework/tree
- @fluidframework/tree-agent
Improved join scalability (#25371)
Protocol for attendees joining has been updated to more efficiently accommodate a larger number of attendees, including when few-to-none have write access.
Change details
Commit: 98dadd3
Affected packages:
- @fluidframework/presence
🌳 SharedTree DDS Changes
Update TableSchema APIs (alpha) to accept SchemaFactoryBeta in addition to SchemaFactoryAlpha ([#25613](https://github.com/microso...
Fluid Framework v2.63.0 (minor)
Contents
- 🌳 SharedTree DDS Changes
- Add FluidSerializableAsTree domain for representing trees of serializable data (alpha) (#25604)
- Promote Record node types and factories to beta (#25606)
- Add TreeBeta.create (#25623)
- Alpha APIs for annotated allowed types have been refactored (#25595)
- Promote importConcise and exportConcise to beta (#25629)
- Stabilize allowUnknownOptionalFields to beta (#25638)
- Add SchemaFactoryAlpha.typesRecursive and SchemaFactoryAlpha.stagedRecursive (#25199)
- MinimumVersionForCollab is now used in place of tree's alpha FluidClientVersion (#25402)
🌳 SharedTree DDS Changes
Add FluidSerializableAsTree domain for representing trees of serializable data (alpha) (#25604)
Like JsonAsTree, but also supports Fluid Handles.
Change details
Commit: 46e6dce
Affected packages:
- @fluidframework/tree
- fluid-framework
Promote Record node types and factories to beta (#25606)
Record tree node schema may now be declared using SchemaFactoryBeta in addition to SchemaFactoryAlpha.
Change details
Commit: 2e2de30
Affected packages:
- @fluidframework/tree
- fluid-framework
Add TreeBeta.create (#25623)
Adds TreeBeta.create, which is a more stable version of the existing TreeAlpha.create. The only difference is the new TreeBeta.create does not support the @alpha UnsafeUnknownSchema option.
Change details
Commit: 376c2d1
Affected packages:
- fluid-framework
- @fluidframework/tree
Alpha APIs for annotated allowed types have been refactored (#25595)
Staged allowed types must now be run through SchemaFactoryAlpha.types to convert them into an AllowedTypes. This change also means that it is now possible to use the produced AllowedTypesFull in non-alpha APIs since it implements AllowedTypes.
Reading data out of ImplicitAllowedTypes should now be done via normalizeAllowedTypes which now returns a AllowedTypesFull providing access to all the data in a friendly format.
Change details
Commit: c6ba37e
Affected packages:
- fluid-framework
- @fluidframework/tree
Promote importConcise and exportConcise to beta (#25629)
importConcise and exportConcise were previously available via TreeAlpha. They may now also be accessed via TreeBeta.
Note that the beta form of importConcise does not support UnsafeUnknownSchema.
Change details
Commit: b5d4602
Affected packages:
- @fluidframework/tree
- fluid-framework
Stabilize allowUnknownOptionalFields to beta (#25638)
When constructing object node schema with SchemaFactoryBeta.object or SchemaFactoryBeta.objectRecursive you can now provide the allowUnknownOptionalFields option as well as other metadata which were previously only available in SchemaFactoryAlpha.objectAlpha and SchemaFactoryAlpha.objectRecursive.
Additionally the alpha interface SchemaFactoryObjectOptions has been renamed to ObjectSchemaOptionsAlpha to better align with the other related types.
Change details
Commit: b7222d1
Affected packages:
- fluid-framework
- @fluidframework/tree
Add SchemaFactoryAlpha.typesRecursive and SchemaFactoryAlpha.stagedRecursive (#25199)
With these new APIs, it is now possible to stage changes to recursive types.
Change details
Commit: 931e986
Affected packages:
- fluid-framework
- @fluidframework/tree
MinimumVersionForCollab is now used in place of tree's alpha FluidClientVersion (#25402)
FluidClientVersion: No longer used as the type for Fluid Client versions in APIs/codecs (for example, oldestCompatibleClient). Additionally, FluidClientVersion is now a const object with members that declare specific MinimumVersionForCollab versions. These are intended to be used with APIs that require a version (such as TreeAlpha.exportCompressed).
CodecWriteOptions and SharedTreeOptions: oldestCompatibleClient has been replaced by minVersionForCollab. See migration guide below.
TreeAlpha.exportCompressed: The options parameter previously had oldestCompatibleClient and now has minVersionForCollab. Migrating requires a rename. Existing FluidClientVersion.* values are now MinimumClientVersions.
Migrating
If an application is calling loadContainerRuntime directly and previously specified the minimum client version when initializing Shared Tree like:
const factory = configuredSharedTree({ ..., oldestCompatibleClient: FluidClientVersion.v2_52 });Then the new implementation depends on how the application initializes Fluid.
Applications using AzureClient/OdspClient
If an application is using the declarative model (for example, AzureClient/OdspClient), it should continue to call configuredSharedTree but specify minVersionForCollab instead:
const factory = configuredSharedTree({ ..., minVersionForCollab: "2.52.0" });Applications calling loadContainerRuntime
If an application is initializing the ContainerRuntime directly, it should now specify the minVersionForCollab there:
const runtime = await loadContainerRuntime({ ..., minVersionForCollab: "2.52.0" });Change details
Commit: 7f59e31
Affected packages:
- @fluidframework/tree
- fluid-framework
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!
Fluid Framework v2.62.0 (minor)
Contents
🚨 Breaking Changes
The exports of @fluid-experimental/tree-react-api have been moved to the new @fluidframework/react package and placed under its /alpha exports (#25542)
@fluid-experimental/tree-react-api has been adjusted to align with Fluid Framework's API Support Levels. It has been renamed to @fluidframework/react and all existing APIs are now available under @fluidframework/react/alpha.
Since this package was under @fluid-experimental, previously it implicitly made no guarantees. Now all the APIs are @alpha, which also amounts to making no guarantees but makes it possible to promote APIs to @beta in the future to offer some stability.
To accommodate this change, all users of this package will need to adjust:
- Package dependencies from
"@fluid-experimental/tree-react-api"to"@fluidframework/react". - Imports from
"@fluid-experimental/tree-react-api"to"@fluidframework/react/alpha".
Change details
Commit: b388c7b
Affected packages:
- @fluid-experimental/tree-react-api
- @fluidframework/react
🌳 SharedTree DDS Changes
Added APIs for tracking observations of SharedTree content for automatic invalidation (#25459)
TreeAlpha.trackObservations and TreeAlpha.trackObservationsOnce have been added. These provide a way to run some operation which reads content from TreeNodes, then run a call back when anything observed by that operation changes.
This functionality has also been exposed in the form of React hooks and React higher order components via the @fluid-experimental/tree-react-api package. It is now possible to use these utilities to implement React applications which pass TreeNodes in their props and get all necessary invalidation from tree changes handled automatically. The recommended pattern for doing this is to use treeDataObject or TreeViewComponent at the root, then withTreeObservations or withMemoizedTreeObservations for any sub-components which read from TreeNodes. Alternatively more localized changes can be made by using PropNode to type erase TreeNodes passed in props, then use one of the usePropTreeNode or usePropTreeRecord hooks to read from them.
These APIs work with both hydrated and un-hydrated TreeNodes.
React Support
Here is a simple example of a React components which has an invalidation bug due to reading a mutable field from a TreeNode that was provided in a prop:
const builder = new SchemaFactory("example");
class Item extends builder.object("Item", { text: SchemaFactory.string }) {}
const ItemComponentBug = ({ item }: { item: Item }): JSX.Element => (
<span>{item.text}</span> // Reading `text`, a mutable value from a React prop, causes an invalidation bug.
);This bug can now easily be fixed using withTreeObservations or withMemoizedTreeObservations:
const ItemComponent = withTreeObservations(
({ item }: { item: Item }): JSX.Element => <span>{item.text}</span>,
);For components which take in TreeNodes, but merely forward them and do not read their properties, they can use PropTreeNode as shown:
const ItemParentComponent = ({ item }: { item: PropTreeNode<Item> }): JSX.Element => (
<ItemComponent item={item} />
);If such a component reads from the TreeNode, it gets a compile error instead of an invalidation bug. In this case the invalidation bug would be that if item.text is modified, the component would not re-render.
const InvalidItemParentComponent = ({
item,
}: { item: PropTreeNode<Item> }): JSX.Element => (
// @ts-expect-error PropTreeNode turns this invalidation bug into a compile error
<span>{item.text}</span>
);To provide access to TreeNode content in only part of a component the usePropTreeNode or usePropTreeRecord hooks can be used.
TreeAlpha.trackObservationsOnce Examples
Here is a rather minimal example of how TreeAlpha.trackObservationsOnce can be used:
cachedFoo ??= TreeAlpha.trackObservationsOnce(
() => {
cachedFoo = undefined;
},
() => nodeA.someChild.bar + nodeB.someChild.baz,
).result;That is equivalent to doing the following:
if (cachedFoo === undefined) {
cachedFoo = nodeA.someChild.bar + nodeB.someChild.baz;
const invalidate = (): void => {
cachedFoo = undefined;
for (const u of unsubscribe) {
u();
}
};
const unsubscribe: (() => void)[] = [
TreeBeta.on(nodeA, "nodeChanged", (data) => {
if (data.changedProperties.has("someChild")) {
invalidate();
}
}),
TreeBeta.on(nodeB, "nodeChanged", (data) => {
if (data.changedProperties.has("someChild")) {
invalidate();
}
}),
TreeBeta.on(nodeA.someChild, "nodeChanged", (data) => {
if (data.changedProperties.has("bar")) {
invalidate();
}
}),
TreeBeta.on(nodeB.someChild, "nodeChanged", (data) => {
if (data.changedProperties.has("baz")) {
invalidate();
}
}),
];
}Here is more complete example showing how to use TreeAlpha.trackObservationsOnce invalidate a property derived from its tree fields.
const factory = new SchemaFactory("com.example");
class Vector extends factory.object("Vector", {
x: SchemaFactory.number,
y: SchemaFactory.number,
}) {
#length: number | undefined = undefined;
public length(): number {
if (this.#length === undefined) {
const result = TreeAlpha.trackObservationsOnce(
() => {
this.#length = undefined;
},
() => Math.hypot(this.x, this.y),
);
this.#length = result.result;
}
return this.#length;
}
}
const vec = new Vector({ x: 3, y: 4 });
assert.equal(vec.length(), 5);
vec.x = 0;
assert.equal(vec.length(), 4);Change details
Commit: 21d45d5
Affected packages:
- fluid-framework
- @fluidframework/tree
- @fluid-experimental/tree-react-api
- @fluidframework/react
Remove JsonValidator (#25381)
The @alpha API JsonValidator has been removed: its replacement FormatValidator must now be used.
As part of this:
typeboxValidatorhas been replaced withFormatValidatorBasic.noopValidatorhas been replaced withFormatValidatorNoOp.
Change details
Commit: 64a9b88
Affected packages:
- fluid-framework
- @fluidframework/tree
Add configuredSharedTreeBeta (#25531)
A limited subset of the options from the existing @alpha configuredSharedTree API have been stabilized to @beta in the form of configuredSharedTreeBeta.
import {
configuredSharedTreeBeta,
ForestTypeExpensiveDebug,
} from "fluid-framework/beta";
const SharedTree = configuredSharedTreeBeta({
forest: ForestTypeExpensiveDebug,
});Change details
Commit: 1e2d48f
Affected packages:
- fluid-framework
- @fluidframework/tree
⚠️ Deprecations
asTreeViewAlpha has been deprecated in favor of asAlpha. ([#25512](#255...
Fluid Framework v2.61.0 (minor)
Contents
✨ New Features
minVersionForCollab is now available on IFluidDataStoreContext (#25130)
minVersionForCollab is now passed down from the ContainerRuntime to the Datastore layer where it is made available for SharedObject construction. DDSes may optionally consume this value and use it to determine which sets of feature flags should be enabled.
Public type changes
- @fluidframework/datastore:
FluidDataStoreRuntime- ExposesminVersionForCollab. - @fluidframework/runtime-definitions:
IFluidDataStoreContext- Exposes optional memberminVersionForCollab. SeeFluidDataStoreContextfor an example implementation. - @fluidframework/test-runtime-utils:
MockFluidDataStoreContext,MockFluidDataStoreRuntime- ExposesminVersionForCollabeither via a getter or as a readonly field.
Note that the new implementations are optional fields and in some cases accept undefined. This is needed for layer compatibility, and in a future release these members will no longer be optional.
Change details
Commit: 2566772
Affected packages:
- @fluidframework/datastore
- @fluidframework/runtime-definitions
- @fluidframework/test-runtime-utils
⚠️ Deprecations
Deprecate submitMessage on FluidDataStoreRuntime and MockFluidDataStoreRuntime (#25332)
As needed, access submitMessage via IFluidDataStoreContext/IFluidParentContext. See #24406 for details.
Change details
Commit: 687378a
Affected packages:
- @fluidframework/datastore
- @fluidframework/test-runtime-utils
Legacy API Changes
Wrapped errors preserved as cause property (#25485)
IFluidErrorBase (internal basis for FluidFramework client errors) declares cause property matching ES2022 lib (whether targeted or not). When an error is wrapped, cause will be set to the originating error (which may or may not itself be an Error).
Change details
Commit: c69d56d
Affected packages:
- @fluidframework/telemetry-utils
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!