Skip to content

Releases: microsoft/FluidFramework

Fluid Framework v2.81.0 (minor)

21 Jan 02:53
55a7af3

Choose a tag to compare

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

⬆️ Table of contents

🌳 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 (where tf is aliased from typeFactory)
  • Same API surface: The existing expose, exposeProperty, and buildFunc methods 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

⬆️ Table of contents

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

⬆️ Table of contents

🐛 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

⬆️ Table of contents

⚠️ 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:

  1. Easier to discover.
  2. Easier to ignore.
  3. Require less parameter churn to use.
  4. Consistent with the getChange API, 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

⬆️ Table of contents

🛠️ 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)

06 Jan 21:37
bffbb3b

Choose a tag to compare

Contents

🚨 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

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

🐛 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

⬆️ Table of contents

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.

  • MockFluidDataStoreRuntime class in @fluidframework/test-runtime-utils
  • IFluidParentContext interface in @fluidframework/runtime-definitions
  • IFluidDataStoreContext interface in @fluidframework/runtime-definitions
  • IFluidDataStoreContextDetached interface in @fluidframework/runtime-definitions

Change details

Commit: 75a3861

Affected packages:

  • @fluidframework/runtime-definitions
  • @fluidframework/test-runtime-utils

⬆️ Table of contents

🛠️ 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)

15 Dec 21:46
c15438c

Choose a tag to compare

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

⬆️ Table of contents

⚠️ 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:

⬆️ Table of contents

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

⬆️ Table of contents

🛠️ 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)

24 Nov 22:05
d5a73d3

Choose a tag to compare

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

⬆️ Table of contents

🛠️ 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)

11 Nov 02:20
06083ca

Choose a tag to compare

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

⬆️ Table of contents

🌳 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 equivalent
  • SharedTreeFormatVersion.v2: no supported equivalent
  • SharedTreeFormatVersion.v3: minVersionForCollab: FluidClientVersion.v2_0
  • SharedTreeFormatVersion.v5: minVersionForCollab: FluidClientVersion.v2_43
  • SharedTreeFormatVersion.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

⬆️ Table of contents

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

⬆️ Table of contents

🛠️ 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)

03 Nov 21:41
a5456fd

Choose a tag to compare

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

⬆️ Table of contents

🌳 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

⬆️ Table of contents

🛠️ 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)

28 Oct 21:13
151d310

Choose a tag to compare

Contents

🚨 Breaking Changes

Deprecated properties have been removed from IRuntimeStorageService and IContainerStorageService (#25708)

The following deprecated properties have been removed from IRuntimeStorageService:

  • createBlob
  • dispose
  • disposed
  • downloadSummary
  • getSnapshot
  • getSnapshotTree
  • getVersions
  • policies
  • uploadSummaryWithContext

The following deprecated properties have been removed from IContainerStorageService:

  • dispose
  • disposed
  • downloadSummary

Please see this Github issue for more details.

Change details

Commit: 82c936e

Affected packages:

  • @fluidframework/container-definitions
  • @fluidframework/runtime-definitions

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

✨ 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 singleton
  • tryGetFluidDevtools - Get the existing devtools instance if initialized
  • IFluidDevtools - Main devtools interface for registering containers
  • ContainerDevtoolsProps - 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

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

🌳 SharedTree DDS Changes

Update TableSchema APIs (alpha) to accept SchemaFactoryBeta in addition to SchemaFactoryAlpha ([#25613](https://github.com/microso...

Read more

Fluid Framework v2.63.0 (minor)

14 Oct 18:23
4b609d4

Choose a tag to compare

Contents

🌳 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

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

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

⬆️ Table of contents

🛠️ 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)

30 Sep 19:41
37cf630

Choose a tag to compare

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

⬆️ Table of contents

🌳 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

⬆️ Table of contents

Remove JsonValidator (#25381)

The @alpha API JsonValidator has been removed: its replacement FormatValidator must now be used.

As part of this:

  • typeboxValidator has been replaced with FormatValidatorBasic.
  • noopValidator has been replaced with FormatValidatorNoOp.

Change details

Commit: 64a9b88

Affected packages:

  • fluid-framework
  • @fluidframework/tree

⬆️ Table of contents

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

⬆️ Table of contents

⚠️ Deprecations

asTreeViewAlpha has been deprecated in favor of asAlpha. ([#25512](#255...

Read more

Fluid Framework v2.61.0 (minor)

23 Sep 02:45
b34a58a

Choose a tag to compare

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 - Exposes minVersionForCollab.
  • @fluidframework/runtime-definitions: IFluidDataStoreContext - Exposes optional member minVersionForCollab. See FluidDataStoreContext for an example implementation.
  • @fluidframework/test-runtime-utils: MockFluidDataStoreContext, MockFluidDataStoreRuntime - Exposes minVersionForCollab either 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

⬆️ Table of contents

⚠️ 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

⬆️ Table of contents

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

⬆️ Table of contents

🛠️ Start Building Today!

Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!