Releases: microsoft/FluidFramework
Fluid Framework v2.30.0 (minor)
Contents
🌳 SharedTree DDS Changes
TreeBranchEvents now exposes the rootChanged event (#24014)
TreeBranchEvents
now includes the rootChanged
event from TreeViewEvents
.
Change details
Commit: 702a08a
Affected packages:
- fluid-framework
- @fluidframework/tree
New SchemaFactoryAlpha.scopedFactory method (#23987)
The SchemaFactoryAlpha.scopedFactory
method has been added, providing an easy way to create a new SchemaFactory
with a nested scope string.
Change details
Commit: cddd513
Affected packages:
- fluid-framework
- @fluidframework/tree
Rules regarding how and when lazy schema references are resolved have been clarified (#24030)
A lazy schema reference is a LazyItem referencing a TreeNodeSchema. They typically look like () => MySchema
and are used when a forward reference from one schema to another is required (including but not limited to recursive and co-recursive schema).
TreeViewConfiguration now documents its significance with respect to lazy schema references. Additionally some implicit assumptions like no modifications of AllowedTypes after resolving of lazy schema references have been enforced (such modifications would previously cause undefined behavior in the future, and now an error is thrown when trying to modify them).
evaluateLazySchema
has been added as an @alpha
API that is now consistently used by all internal code when evaluating lazy schema references. This ensures consistent behavior and error reporting, but also adds caching. Therefore it is now supported for applications to have lazy schema references which compute the schema when invoked, without having to implement their own caching as long as those applications use evaluateLazySchema
anytime they need to evaluate a lazy schema reference.
Change details
Commit: 23f3279
Affected packages:
- fluid-framework
- @fluidframework/tree
Alpha APIs for replacing handles in export formats have been redesigned (#24061)
The various import and export VerboseTree
and ConciseTree
APIs no longer include valueConverter
options. Instead the resulting tree can be further processed to do any desired replacements. The following @alpha
APIs have been added to assist with this:
cloneWithReplacements
replaceHandles
replaceConciseTreeHandles
replaceVerboseTreeHandles
Change details
Commit: 34b319c
Affected packages:
- @fluidframework/tree
- fluid-framework
⚠️ Deprecations
IContainer.getContainerPackageInfo() is now deprecated (#23840)
The IContainer.getContainerPackageInfo()
function is now deprecated. This API will be removed in version 2.40.0. Use IFluidCodeDetails.package
returned by IContainer.getLoadedCodeDetails()
instead.
See issue #23898 for details.
Change details
Commit: 521be72
Affected packages:
- @fluidframework/container-definitions
- @fluidframework/container-loader
Legacy API Changes
Unnecessary exports are now removed from container-runtime (#23981)
The following types in the @fluidframework/container-runtime are now removed. These types are unnecessary for external users of this package.
- currentDocumentVersionSchema
- DeletedResponseHeaderKey
- DocumentSchemaValueType
- DocumentsSchemaController
- GCFeatureMatrix
- GCNodeType
- GCVersion
- IBlobManagerLoadInfo
- ICancellableSummarizerController
- ICancellationToken
- IConnectableRuntime
- IContainerRuntimeMetadata
- ICreateContainerMetadata
- IDocumentSchema
- IDocumentSchemaChangeMessage
- IDocumentSchemaCurrent
- IDocumentSchemaFeatures
- IGCMetadata
- IGCStats
- IMarkPhaseStats
- IRefreshSummaryAckOptions
- ISerializedElection
- ISubmitSummaryOptions
- ISummarizerInternalsProvider
- ISummarizerRuntime
- ISummaryCancellationToken
- ISummaryMetadataMessage
- ISweepPhaseStats
- Summarizer
Change details
Commit: 74896b9
Affected packages:
- @fluidframework/container-runtime
The process and processDocumentSchemaOp functions have been removed (#24018)
process
has been replaced by processMessages
from the following:
FluidDataStoreRuntime
IDeltaHandler
IFluidDataStoreChannel
MockFluidDataStoreRuntime
MockDeltaConnection
processDocumentSchemaOp
has been replaced by processDocumentSchemaMessages
from DocumentsSchemaController
.
See the deprecation release note for more details.
Change details
Commit: bc35d54
Affected packages:
- @fluidframework/container-runtime
- @fluidframework/datastore
- @fluidframework/datastore-definitions
- @fluidframework/runtime-definitions
- @fluidframework/test-runtime-utils
Deprecated ILoaderOptions have been removed (#24046)
Previously ILoaderOptions
exported from container-loader
was extending the base ILoaderOptions
defined in container-definitions
to add an experimental summarizeProtocolTree
property which was used to test single-commit summaries. The option is no longer required or in use, so...
Fluid Framework v2.23.0 (minor)
Contents
✨ New Features
Local value changes in presence now raise events (#23858)
The presence value managers now raise events for local value changes. The new events are as follows:
-
LatestValueManager
localUpdated
raised whenlocal
is assigned
-
LatestMapValueManager
localItemUpdated
raised whenlocal.set
is calledlocalItemRemoved
raised whenlocal.delete
is called
Change details
Commit: 2896983
Affected packages:
- @fluidframework/presence
🌳 SharedTree DDS Changes
Op bunching performance enhancements (#23732)
SharedTree
now takes advantage of a new feature called "op bunching" where contiguous ops in a grouped batch are bunched and processed together. This improves the performance of processing ops asymptotically; as the number of local ops and incoming ops increase, the processing time will reduce.
For example, with 10 local ops + 10 incoming ops, the performance increases by 70%; with 100 local ops + 100 incoming ops, the performance increases by 94%.
This will help improve performance in the following scenarios:
- A client makes a large number of changes in a single JS turn. For example, copy pasting large data like a table.
- A client has a large number of local changes. For example, slow clients whose changes are slow to ack or clients with a local branch with large number of changes.
Change details
Commit: a98b04f
Affected packages:
- @fluidframework/tree
- fluid-framework
Invalid schema base classes in Tree.is now throw an error instead of returning false (#23938)
As documented in TreeNodeSchemaClass
, there are specific rules around sub-classing schema, mainly that only a single most derived class can be used. One place where it was easy to accidentally violate this rule and get hard-to-debug results was Tree.is
. This has been mitigated by adding a check in Tree.is
which detects this mistake (which used to result in false
being returned) and instead throws a UsageError
explaining the situation. The error will look something like:
Two schema classes were used (CustomObjectNode and Derived) which derived from the same SchemaFactory generated class ("com.example.Test"). This is invalid.
For applications wanting to test if a given TreeNode
is an instance of some schema base class, this can be done using instanceof
which includes base classes when doing the check.
Change details
Commit: 0099565
Affected packages:
- @fluidframework/tree
- fluid-framework
Creating large transactions and processing inbound changes is now faster (#23929)
SharedTree sometimes composes several sequential changes into a single change. It does so whenever a transaction is created and when processing inbound changes.
Version 2.23.0 makes this composition process asymptotically faster. For example, creating a transaction that performs 1000 edits on a single array now takes 170ms instead of 1.5s (an 89% improvement).
See Change #23902 for more details.
Change details
Commit: 35847b5
Affected packages:
- @fluidframework/tree
- fluid-framework
Faster processing of events for large transactions (#23939)
In versions prior to 2.23.0, event processing time could scale quadratically (O(N^2)
) with the change count when processing a batch of changes.
This performance characteristic has been corrected. See change #23908 for more details.
Change details
Commit: 2a1e7e0
Affected packages:
- fluid-framework
- @fluidframework/tree
⚠️ Deprecations
The FluidDataStoreRuntime.process function is now deprecated (#23866)
A new function processMessages
has been added in place of process
. The new function will be called to process multiple messages instead of a single one on the data store runtime. This is part of a feature called "op bunching" where contiguous ops of a given type and to a given data store / DDS are bunched and sent together for processing.
Note that process
may still be called in scenarios where this data store runtime (Datastore layer) is running with an older version of data store context (Runtime layer) in the same client. This is to support Fluid layer compatibility.
Change details
Commit: 3f44d43
Affected packages:
- @fluidframework/datastore
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!
Fluid Framework v2.22.1 (patch)
What's Changed
- [release/2.22] fix(merge-tree): Correctly bookkeep insert into local-only obliterate
#23937
- build(client): Update typetests in release branch after minor release 2.22.0
#23896
- [bump] client: 2.22.0 => 2.22.1 (patch)
#23891
Full Changelog: client_v2.22.0...client_v2.22.1
Fluid Framework v2.22.0 (minor)
Contents
🌳 SharedTree DDS Changes
Add leaves
and statics to SchemaFactory
. (#23787)
SchemaFactory
now has a leaves
member that is an array of all leaf schema.
SchemaFactory
now has static members to access leaf schema and create field schema.
Change details
Commit: efa90f6
Affected packages:
- fluid-framework
- @fluidframework/tree
⚠️ Deprecations
Deprecate processCore
on SharedObject
and SharedObjectCore
in favor of processMessagesCore
(#23836)
A new function processMessagesCore
has been added in place of processCore
, which will be called to process multiple messages instead of a single one on the channel. This is part of a feature called "Op bunching" where contiguous ops in a grouped batch are bunched and processed together by the shared object.
Implementations of SharedObject
and SharedObjectCore
must now also implement processMessagesCore
. A basic implementation could be to iterate over the messages' content and process them one by one as it happens now. Note that some DDS may be able to optimize processing by processing the messages together.
Change details
Commit: 5eb19a0
Affected packages:
- @fluidframework/shared-object-base
Other Changes
Target ES2021 (#23307)
The TypeScript build for Fluid Framework packages has been updated to target ES2021 instead of ES2020. This may result in newer JavaScript language features being used. This does not change TypeScript types, nor the JavaScript libraries being used. We only support users which support ES2022, so updating to target ES2021 should not break any supported use-case. Any users which do not have at least ES2021 language feature support may need to transpile out some additional cases after this change.
This should result in slightly reduced bundle size and slightly improved performance for users not transpiling these features out. No major impact is expected.
Change details
Commit: 091b2df
Affected packages:
- fluid-framework
odsp-driver no longer depends on node-fetch (#23796)
The @fluidframework/odsp-driver
package had a dependency on node-fetch to provide consistent behavior of the Fetch API across Node.js and browsers. Since v18 of Node.js, the Node-native Fetch API implementation no longer requires extra flags to be enabled, so the Fetch API is effectively now natively available on all browsers and Node.js. This dependency removal should reduce Fluid Framework's contribution to application bundle sizes.
We expect this change to have no impact for Fluid Framework consumers. However, if you are running Fluid in a Node.js environment with the --no-experimental-fetch
flag, this is no longer supported.
Change details
Commit: b17276c
Affected packages:
- @fluidframework/odsp-driver
Change when the pre-op
and op
events on ISharedObjectEvents
are emitted (#23836)
Previous behavior - pre-op
was emitted immediately before an op was processed. Then the op was processed and op
was emitted immediately after that.
New behavior - pre-op
will still be emitted before an op is processed and op
will still be emitted after an op is processed. However, these won't be immediate and other ops in a batch for the shared object may be processed in between.
Note that these events are for internal use only as mentioned in the @remarks section of their definition.
Change details
Commit: 5eb19a0
Affected packages:
- @fluidframework/shared-object-base
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!
Fluid Framework v2.21.0 (minor)
Contents
🐛 Bug Fixes
SharedMap, SharedIntervalCollection and AttributableMap now throw an error when they encounter unrecognized Ops (#23659)
To avoid future versions of DDSes with new Op types causing silent data corruption and de-sync between clients, DDSes should error when unable to apply an Op. This prevents data loss and corruption scenarios like a summary client using old code discarding all Ops from newer clients.
If updating applications using SharedMap, SharedIntervalCollection and AttributableMap use a newer version which adds Ops types in the future, old clients which are old enough to be from before this fix will ignore the new ops instead of erroring. Therefore it may be useful to ensure this update is deployed as widely as possible before migrating any to newer versions which add new op formats to these DDSes.
Change details
Commit: 3dd4208
Affected packages:
- @fluid-experimental/attributable-map
- @fluidframework/map
- @fluidframework/sequence
⚠️ Deprecations
Many unnecessary exports have been deprecated in the container-runtime package (#23607)
The following types in the @fluidframework/container-runtime
package are now deprecated. These types are unnecessary for external users of this package.
- currentDocumentVersionSchema
- DeletedResponseHeaderKey
- DocumentSchemaValueType
- DocumentsSchemaController
- GCFeatureMatrix
- GCNodeType
- GCVersion
- IBlobManagerLoadInfo
- ICancellableSummarizerController
- ICancellationToken
- IConnectableRuntime
- IContainerRuntimeMetadata
- ICreateContainerMetadata
- IDocumentSchema
- IDocumentSchemaChangeMessage
- IDocumentSchemaCurrent
- IDocumentSchemaFeatures
- IGCMetadata
- IGCStats
- IMarkPhaseStats
- IRefreshSummaryAckOptions
- ISerializedElection
- ISubmitSummaryOptions
- ISummarizerInternalsProvider
- ISummarizerRuntime
- ISummaryCancellationToken
- ISummaryMetadataMessage
- ISweepPhaseStats
- Summarizer
Change details
Commit: 3da5b42
Affected packages:
- @fluidframework/container-runtime
The IContainerContext.supportedFeatures property is now deprecated (#22877)
The IContainerContext.supportedFeatures
optional property was used internally to communicate features supported by the Loader layer to the Runtime layer. This has since been replaced with functionality that is not exposed externally.
Change details
Commit: 4c06412
Affected packages:
- @fluidframework/container-definitions
ITokenClaims and ScopeType types are now deprecated (#23703)
The ITokenClaims
and ScopeType
types in @fluidframework/azure-client
are now deprecated. These were isolated types re-exported for convenience but they do not directly interact with typical azure-client APIs.
See issue #23702 for details and alternatives.
Change details
Commit: f679945
Affected packages:
- @fluidframework/azure-client
🛠️ Start Building Today!
Please continue to engage with us on GitHub Discussion and Issue pages as you adopt Fluid Framework!
Fluid Framework v2.20.0 (minor)
Contents
- 🐛 Bug Fixes
⚠️ Deprecations- Legacy API Changes
- The MockLogger class has been removed (#23010)
- Previously deprecated Merge-Tree and SharedString ISegment members have been removed (#23448)
- The IContainerRuntimeOptions.flushMode property has been removed (#23337)
- The ContainerRuntime class has been removed (#23341)
- The createDataStoreWithProps APIs on ContainerRuntime and IContainerRuntimeBase have been removed (#22996)
- Replace 'any' in return type for several APIs (#23238)
- Summarizer-related types have been moved to container-runtime-definitions (#23483)
- Enabling Op Compression without Op Grouping is no longer supported (#23608)
🐛 Bug Fixes
Fix 'Error: PR-008: Trying to remove a non-existing entry' error in IndexedCollection class (#23243)
The IndexedCollection
class would throw the following error when applying a changeset:
Error: PR-008: Trying to remove a non-existing entry:
The underlying problem has been fixed and this error should no longer occur.
Thanks to @neerajcharokar for submitting this fix!
Change details
Commit: 5996be1
Affected packages:
- @fluid-experimental/property-changeset
⚠️ Deprecations
Events-related interfaces have been moved to core-interfaces (#23313)
The following interfaces and types have been moved from the @fluidframework/tree
package into the @fluidframework/core-interfaces
package. As such, they are now deprecated in the @fluidframework/tree
package.
- Listeners
- IsListener
- Listenable
- Off
Users should now import them from either @fluidframework/core-interfaces
or fluid-framework
.
These deprecated interfaces will be removed from the @fluidframework/tree
package in Fluid Framework v3.0.
Change details
Commit: 69a755e
Affected packages:
- @fluidframework/tree
Legacy API Changes
The MockLogger class has been removed (#23010)
The MockLogger
class, which was previously part of the alpha+legacy API in @fluidframework/telemetry-utils
, has been removed. No replacement is provided. This class was only intended for use in testing scenarios and should be trivial to re-implement in any codebase that still needs it.
Change details
Commit: 32ff6b9
Affected packages:
- @fluidframework/telemetry-utils
Previously deprecated Merge-Tree and SharedString ISegment members have been removed (#23448)
The current ISegment
interface over-exposes a number of properties which do not have an external use case, and any external usage could result in damage to the underlying merge-tree including data corruption. In Fluid Framework release 2.12.0 these properties and associated types were deprecated.
The only use case that will continue to be supported is determining if a segment is removed. For this purpose we've added the free function segmentIsRemoved(segment: ISegment): boolean
.
For example, checking if a segment is not removed would change as follows:
- if(segment.removedSeq === undefined){
+ if(!segmentIsRemoved(segment)){
The following properties are removed from ISegment
and its implementations:
- clientId
- index
- localMovedSeq
- localRefs
- localRemovedSeq
- localSeq
- movedClientsIds
- movedSeq
- movedSeqs
- ordinal
- removedClientIds
- removedSeq
- seq
- wasMovedOnInsert
Additionally, the following types are also removed:
- IMergeNodeCommon
- IMoveInfo
- IRemovalInfo
- LocalReferenceCollection
Change details
Commit: e98574f
Affected packages:
- @fluidframework/merge-tree
- @fluidframework/sequence
The IContainerRuntimeOptions.flushMode property has been removed (#23337)
The IContainerRuntimeOptions.flushMode
property was deprecated in version 2.12.0 and has been removed.
Only the default value, FlushMode.TurnBased
, is supported when calling ContainerRuntime.loadRuntime
directly, so there's no need for consumers to pass this option in.
Change details
Commit: fe8279c
Affected packages:
- @fluidframework/container-runtime
The ContainerRuntime class has been removed (#23341)
The ContainerRuntime
class was deprecated in version 2.12.0 and has been removed. Use IContainerRuntime
to replace type usages and use the free function loadContainerRuntime
to replace usages of the static method ContainerRuntime.loadRuntime
.
See the deprecation announcement for more details about how to update existing code.
Change details
Commit: 61ba06a
Affected packages:
- @fluidframework/aqueduct
- @fluid-experimental/attributor
- @fluidframework/container-runtime
- @fluidframework/test-utils
The createDataStoreWithProps APIs on ContainerRuntime and IContainerRuntimeBase have been removed (#22996)
ContainerRuntime.createDataStoreWithProps
and IContainerRuntimeBase.createDataStoreWithProps
were deprecated in version 0.25.0 and have been removed.
Replace uses of these APIs with PureDataObjectFactory.createInstanceWithDataStore
and pass in props via the initialState
parameter.
These changes were originally announced in version 0.25.0. See the following issues for more details:
Change details
Commit: bd243fb
Affected packages:
- @fluidframework/aqueduct
- @fluidframework/container-runtime
- @fluidframework/container-runtime-definitions
- @fluidframework/datastore
- @fluidframework/runtime-definitions
- @fluidframework/test-runtime-utils
Replace 'any' in return type for several APIs ([#23238](#23238...
Fluid Framework v2.13.0 (minor)
Contents
🌳 SharedTree DDS Changes
New alpha APIs for schema evolution (#23362)
There are now @alpha
APIs for schema evolution which support adding optional fields to object node types without a staged rollout.
SharedTree has many safety checks in place to ensure applications understand the format of documents they must support. One of these checks verifies that the view schema (defined in application's code) aligns with the document schema (determined by the document data at rest). This helps to ensure that clients running incompatible versions of the application's code don't collaborate at the same time on some document, which could cause data loss or disrupt application invariants. One general solution application authors can perform is to stage the rollout of a feature which changes document schema into multiple phases:
- Release an application version which understands documents written with the new format but doesn't attempt to upgrade any documents
- Wait for this application version to saturate in the app's ecosystem
- Release an application version which upgrades documents to start leveraging the new format.
However, this process can be cumbersome for application authors: for many types of changes, an app author doesn't particularly care if older application code collaborates with newer code, as the only downside is that the older application version might not present a fully faithful experience. As an example, consider an application which renders circles on a canvas (similar to what is presented here). The application author might anticipate adding support to render the circle with various different other properties (border style, border width, background color, varying radius, etc.). Therefore, they should declare their schema using SchemaFactoryObjectOptions.allowUnknownOptionalFields
like so:
import { SchemaFactoryAlpha } from "@fluidframework/tree/alpha";
// "Old" application code/schema
const factory = new SchemaFactoryAlpha("Geometry");
class Circle extends factory.object(
"Circle",
{
x: factory.number,
y: factory.number,
},
{ allowUnknownOptionalFields: true },
) {}
Later, they add some of these features to their application:
import { SchemaFactoryAlpha } from "@fluidframework/tree/alpha";
// "New" application code/schema
const factory = new SchemaFactoryAlpha("Geometry");
class Circle extends factory.object(
"Circle",
{
x: factory.number,
y: factory.number,
// Note that radius and color must both be declared as optional fields since this application must
// support opening up existing documents that didn't have this information.
radius: factory.optional(factory.number),
color: factory.optional(factory.string), // ex: #00FF00
},
{ allowUnknownOptionalFields: true },
) {}
When they go to deploy this newer version of the application, they could opt to start upgrading documents as soon as the newer code is rolled out, and the older code would still be able to open up (and collaborate on) documents using the newer schema version. Note that it's only important that the old application code elected to allow opening documents with unknown optional fields. This policy is not persisted into documents in any form, so applications are free to modify it at any point.
For specific API details, see documentation on SchemaFactoryObjectOptions.allowUnknownOptionalFields
. For a more thorough discussion of this topic, see Schema Evolvability in the SharedTree README.
Change details
Commit: 2406e00
Affected packages:
- @fluidframework/tree
- fluid-framework
Metadata can be associated with Node Schema (#23321)
Users of TreeView can now specify metadata when creating Node Schema, via SchemaFactoryAlpha
. This metadata may include system-understood properties like description
.
Example:
const schemaFactory = new SchemaFactoryAlpha(...);
class Point extends schemaFactory.object("Point", {
x: schemaFactory.required(schemaFactory.number),
y: schemaFactory.required(schemaFactory.number),
},
{
metadata: {
description: "A point in 2D space",
},
}) {}
Functionality like the experimental conversion of Tree Schema to JSON Schema (getJsonSchema) leverages such system-understood metadata to generate useful information. In the case of the description
property, it is mapped directly to the description
property supported by JSON Schema.
Custom, user-defined properties can also be specified. These properties will not be used by the system by default, but can be used to associate common application-specific properties with Node Schema.
SchemaFactoryAlpha
Updates
object
andobjectRecursive
,arrayRecursive
, andmapRecursive
now supportmetadata
in theiroptions
parameter.- (new)
arrayAlpha
- Variant ofarray
that accepts an options parameter which supportsmetadata
- (new)
mapAlpha
- Variant ofmap
that accepts an options parameter which supportsmetadata
Example
An application is implementing search functionality. By default, the app author wishes for all app content to be potentially indexable by search, unless otherwise specified. They can leverage schema metadata to decorate types of nodes that should be ignored by search, and leverage that information when walking the tree during a search.
interface AppMetadata {
/**
* Whether or not nodes of this type should be ignored by search.
* @defaultValue `false`
*/
searchIgnore?: boolean;
}
const schemaFactory = new SchemaFactoryAlpha(...);
class Point extends schemaFactory.object("Point", {
x: schemaFactory.required(schemaFactory.number),
y: schemaFactory.required(schemaFactory.number),
},
{
metadata: {
description: "A point in 2D space",
custom: {
searchIgnore: true,
},
}
}) {}
Search can then be implemented to look for the appropriate metadata, and leverage it to omit the unwanted position data from search.
Potential for breaking existing code
These changes add the new property "metadata" to the base type from which all node schema derive. If you have existing node schema subclasses that include a property of this name, there is a chance for potential conflict here that could be breaking. If you encounter issues here, consider renaming your property or leveraging the new metadata support.
Change details
Commit: 58619c3
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.12.0 (minor)
Contents
- ✨ New Features
⚠️ Deprecations- SummarizerStopReason, ISummarizeEventProps, and ISummarizerEvents are now deprecated (#23217)
- IContainerRuntimeOptions.enableGroupedBatching is now deprecated (#23260)
- IContainerRuntimeOptions.flushMode is now deprecated (#23288)
- Merge-Tree and SharedString ISegment Deprecations (#23323)
- The ContainerRuntime class is now deprecated (#23331)
✨ New Features
New APIs to create and load containers without using the Loader object (#22902)
Overview
Provide standalone APIs to create and load containers instead of using the Loader object to do so. Before, hosts were supposed to create the Loader object first and then call methods on it to create and load containers. Now they can just utilize these APIs directly and get rid of the Loader object.
Use createDetachedContainer
to create a detached container
export async function createDetachedContainer(
createDetachedContainerProps: ICreateDetachedContainerProps,
): Promise<IContainer> {}
ICreateDetachedContainerProps
are the properties that need to be supplied to the above API and include props like URL Resolver, IDocumentServiceFactory, etc., which were previously used to create the Loader
object.
Use loadExistingContainer
to load an existing container
export async function loadExistingContainer(
loadExistingContainerProps: ILoadExistingContainerProps,
): Promise<IContainer> {}
ILoadExistingContainerProps
are the properties that need to be supplied to the above API and include props like URL Resolver, IDocumentServiceFactory, etc., which were earlier used to create the Loader
object.
Use rehydrateDetachedContainer
to create a detached container from a serializedState of another container
export async function rehydrateDetachedContainer(
rehydrateDetachedContainerProps: IRehydrateDetachedContainerProps,
): Promise<IContainer> {}
IRehydrateDetachedContainerProps
are the properties that need to be supplied to the above API and include props like URL Resolver, IDocumentServiceFactory, etc., which were earlier used to create the Loader
object.
Note on ICreateAndLoadContainerProps
.
The props which were used to create the Loader
object are now moved to the ICreateAndLoadContainerProps
interface. ICreateDetachedContainerProps
, ILoadExistingContainerProps
and IRehydrateDetachedContainerProps
which extends ICreateAndLoadContainerProps
also contain some additional props which will be used to create and load containers like IFluidCodeDetails
, IRequest
, etc. Previously these were directly passed when calling APIs like Loader.createDetachedContainer
, Loader.resolve
and Loader.rehydrateDetachedContainerFromSnapshot
on the Loader
object. Also, ILoaderProps.ILoaderOptions
are now replaced with ICreateAndLoadContainerProps.IContainerPolicies
since there will be no concept of Loader
.
Change details
Commit: 51a1728
Affected packages:
- @fluidframework/azure-client
- @fluidframework/container-definitions
- @fluidframework/container-loader
- @fluidframework/fluid-runner
- @fluidframework/odsp-client
- @fluid-experimental/property-dds
- @fluid-private/test-end-to-end-tests
- @fluidframework/test-utils
- @fluidframework/tinylicious-client
- @fluidframework/tree
⚠️ Deprecations
SummarizerStopReason, ISummarizeEventProps, and ISummarizerEvents are now deprecated (#23217)
SummarizerStopReason
, ISummarizeEventProps
, and ISummarizerEvents
have all been deprecated from the "@fluidframework/container-runtime"
package. Please migrate all uses of these APIs to their counterparts in the "@fluidframework/container-runtime-definitions"
package.
Change details
Commit: cd88ee2
Affected packages:
- @fluidframework/container-runtime
IContainerRuntimeOptions.enableGroupedBatching is now deprecated (#23260)
The IContainerRuntimeOptions.enableGroupedBatching
property is deprecated and will be removed in version 2.20.0. This will mean that the grouped batching feature can no longer be disabled. In versions 2.20.0 and beyond, grouped batching is required for the proper functioning of the Fluid Framework.
The sole case where grouped batching will be disabled is for compatibility with older v1 clients, and this will be implemented without any need for the configurable IContainerRuntimeOptions.enableGroupedBatching
option.
Change details
Commit: 49d8e75
Affected packages:
- @fluidframework/container-runtime
- @fluidframework/fluid-static
IContainerRuntimeOptions.flushMode is now deprecated (#23288)
The IContainerRuntimeOptions.flushMode
property is deprecated and will be removed in version 2.20.0.
Only the default value FlushMode.TurnBased
is supported when calling ContainerRuntime.loadRuntime
directly, so there's no need for consumers to pass this option in.
Change details
Commit: af1cd7b
Affected packages:
- @fluidframework/container-runtime
Merge-Tree and SharedString ISegment Deprecations (#23323)
The current ISegment interface over-exposes a number of properties which do not have an external use case, and any external usage could result in damage to the underlying merge-tree including data corruption.
The only use case that will continue to be supported is determining if a segment is removed. For this purpose we've added the free function segmentIsRemoved(segment: ISegment): boolean
.
For example, checking if a segment is not removed would change as follows:
- if(segment.removedSeq === undefined){
+ if(!segmentIsRemoved(segment)){
The following properties are deprecated on ISegment and its implementations:
- clientId
- index
- localMovedSeq
- localRefs
- localRemovedSeq
- localSeq
- movedClientsIds
- movedSeq
- movedSeqs
- ordinal
- removedClientIds
- removedSeq
- seq
- wasMovedOnInsert
Additionally, the following types are also deprecated, and will become internal (i.e. users of the Fluid Framework will not have access to them):
- IMergeNodeCommon
- IMoveInfo
- IRemovalInfo
- LocalReferenceCollection
Change details
Commit: e8762e3
Affected packages:
- @fluidframework/merge-tree
- @fluidframework/sequence
The ContainerRuntime class is now deprecated (#23331)
The class ContainerRuntime
is deprecated and will no longer be exported starting in version 2.20.0.
There are two possible migration paths to stop using ContainerRuntime
:
- When using it as a type, replace it with an interface like
IContainerRuntime
- When using the static function
ContainerRuntime.loadRuntime
replace it with the free functionloadContainerRuntime
.
BaseContainerRuntimeFactory
has some changes as well, since it exposed ContainerRuntime
in several function signatures:
instantiateFirstTime
- Takes the wider typeIContainerRuntime
instead ofContainerRuntime
instantiateFromExisting
- Takes the wider typeIContainerRuntime
instead ofContainerRuntime
preInitialize
- deprecated as well, since it returnsContainerRuntime
These functions should never be called directly anyway - use `BaseContai...
Fluid Framework v2.11.0 (minor)
Contents
✨ New Features
Synchronous Child Datastore Creation (#23143)
Overview
This feature introduces a new pattern for creating datastores synchronously within the Fluid Framework. It allows for the synchronous creation of a child datastore from an existing datastore, provided that the child datastore is available synchronously via the existing datastore's registry and that the child's factory supports synchronous creation. This method also ensures strong typing for the consumer.
In this context, "child" refers specifically to the organization of factories and registries, not to any hierarchical or hosting relationship between datastores. The parent datastore does not control the runtime behaviors of the child datastore beyond its creation.
The synchronous creation of child datastores enhances the flexibility of datastore management within the Fluid Framework. It ensures type safety and provides a different way to manage datastores within a container. However, it is important to consider the overhead associated with datastores, as they are stored, summarized, garbage collected, loaded, and referenced independently. This overhead should be justified by the scenario's requirements.
Datastores offer increased capabilities, such as the ability to reference them via handles, allowing multiple references to exist and enabling those references to be moved, swapped, or changed. Additionally, datastores are garbage collected after becoming unreferenced, which can simplify final cleanup across clients. This is in contrast to subdirectories in a shared directory, which do not have native capabilities for referencing or garbage collection but are very low overhead to create.
Synchronous creation relies on both the factory and the datastore to support it. This means that asynchronous operations, such as resolving handles, some browser API calls, consensus-based operations, or other asynchronous tasks, cannot be performed during the creation flow. Therefore, synchronous child datastore creation is best limited to scenarios where the existing asynchronous process cannot be used, such as when a new datastore must be created in direct response to synchronous user input.
Key Benefits
- Synchronous Creation: Allows for the immediate creation of child datastores without waiting for asynchronous operations.
- Strong Typing: Ensures type safety and better developer experience by leveraging TypeScript's type system.
Use Cases
Example 1: Creating a Child Datastore
In this example, we demonstrate how to support creating a child datastore synchronously from a parent datastore.
/**
* This is the parent DataObject, which is also a datastore. It has a
* synchronous method to create child datastores, which could be called
* in response to synchronous user input, like a key press.
*/
class ParentDataObject extends DataObject {
createChild(name: string): ChildDataStore {
assert(
this.context.createChildDataStore !== undefined,
"this.context.createChildDataStore",
);
const { entrypoint } = this.context.createChildDataStore(
ChildDataStoreFactory.instance,
);
const dir = this.root.createSubDirectory("children");
dir.set(name, entrypoint.handle);
entrypoint.setProperty("childValue", name);
return entrypoint;
}
getChild(name: string): IFluidHandle<ChildDataStore> | undefined {
const dir = this.root.getSubDirectory("children");
return dir?.get<IFluidHandle<ChildDataStore>>(name);
}
}
For a complete example see the following test: https://github.com/microsoft/FluidFramework/blob/main/packages/test/local-server-tests/src/test/synchronousDataStoreCreation.spec.ts
Change details
Commit: 3426b43
Affected packages:
- @fluidframework/container-runtime
- @fluidframework/runtime-definitions
Presence-related events now support the off
event deregistration pattern (#23196)
Event subscriptions within @fluidframework/presence
may now use off
to deregister event listeners, including initial listeners provided to Notifications
.
Some type names have shifted within the API though no consumers are expected to be using those types directly. The most visible rename is NotificationSubscribable
to NotificationListenable
. Other shifts are to use types now exported through @fluidframework/core-interfaces
where the most notable is ISubscribable
that is now Listenable
.
Change details
Commit: f7be965
Affected packages:
- @fluidframework/presence
Presence updates are now grouped and throttled (#23075)
Presence updates are grouped together and throttled to prevent flooding the network with messages when presence values are rapidly updated. This means the presence infrastructure will not immediately broadcast updates but will broadcast them after a configurable delay.
The allowableUpdateLatencyMs
property configures how long a local update may be delayed under normal circumstances, enabling grouping with other updates. The default allowableUpdateLatencyMs
is 60 milliseconds but may be (1) specified during configuration of a States Workspace or Value Manager and/or (2) updated later using the controls
member of a Workspace or Value Manager. The States Workspace configuration applies when a Value Manager does not have its own setting.
Notifications are never queued; they effectively always have an allowableUpdateLatencyMs
of 0. However, they may be grouped with other updates that were already queued.
Note that due to throttling, clients receiving updates may not see updates for all values set by another. For example, with Latest*ValueManagers
, the only value sent is the value at the time the outgoing grouped message is sent. Previous values set by the client will not be broadcast or seen by other clients.
Example
You can configure the grouping and throttling behavior using the allowableUpdateLatencyMs
property as in the following example:
// Create and configure a states workspace
const stateWorkspace = presence.getStates(
"app:v1states",
{
// This value manager has an allowable latency of 100ms.
position: Latest({ x: 0, y: 0 }, { allowableUpdateLatencyMs: 100 }),
// This value manager uses the workspace default allowable latency of 60ms.
count: Latest({ num: 0 }),
},
// Set the default allowable latency for all value managers in this workspace to 200ms,
// overriding the default value of 60ms.
{ allowableUpdateLatencyMs: 200 },
);
// Temporarily set count updates to send as soon as possible.
const countState = stateWorkspace.props.count;
countState.controls.allowableUpdateLatencyMs = 0;
countState.local = { num: 5000 };
// Reset the update latency to the workspace default of 60ms.
countState.controls.allowableUpdateLatencyMs = undefined;
Change details
Commit: abde76d
Affected packages:
- @fluidframework/presence
🌳 SharedTree DDS Changes
✨ New! Alpha APIs for indexing (#22491)
SharedTree now supports indexing via two new APIs, createSimpleTreeIndex
and createIdentifierIndex
.
createSimpleTreeIndex
is used to create a `SimpleTre...
Fluid Framework v2.10.0 (minor)
Contents
- ✨ New Features
- 🌳 SharedTree DDS Changes
- Provide more comprehensive replacement to the
commitApplied
event (#22977) - SharedTree event listeners that implement
Listenable
now allow deregistration of event listeners via anoff()
function. (#23046) - Allow constructing recursive maps from objects (#23070)
- Fix typing bug in
adaptEnum
andenumFromStrings
(#23077)
- Provide more comprehensive replacement to the
⚠️ Deprecations- Legacy API Changes
- Other Changes
✨ New Features
New compareFluidHandle function for comparing FluidHandles (#22997)
The new compareFluidHandle
function has been added to allow comparing handles without having to inspect their internals.
Change details
Commit: 8d47008
Affected packages:
- @fluidframework/runtime-utils
SharedString DDS annotateAdjustRange (#22751)
This update introduces a new feature to the SharedString
DDS, allowing for the adjustment of properties over a specified range. The annotateAdjustRange
method enables users to apply adjustments to properties within a given range, providing more flexibility and control over property modifications.
An adjustment is a modification applied to a property value within a specified range. Adjustments can be used to increment or decrement property values dynamically. They are particularly useful in scenarios where property values need to be updated based on user interactions or other events. For example, in a rich text editor, adjustments can be used for modifying indentation levels or font sizes, where multiple users could apply differing numerical adjustments.
Key Features and Use Cases:
- Adjustments with Constraints: Adjustments can include optional minimum and maximum constraints to ensure the final value falls within specified bounds. This is particularly useful for maintaining consistent formatting in rich text editors.
- Consistent Property Changes: The feature ensures that property changes are consistent, managing both local and remote changes effectively. This is essential for collaborative rich text editing where multiple users may be making adjustments simultaneously.
- Rich Text Formatting: Adjustments can be used to modify text properties such as font size, indentation, or other formatting attributes dynamically based on user actions.
Configuration and Compatibility Requirements:
This feature is only available when the configuration Fluid.Sequence.mergeTreeEnableAnnotateAdjust
is set to true
. Additionally, all collaborating clients must have this feature enabled to use it. If any client does not have this feature enabled, it will lead to the client exiting collaboration. A future major version of Fluid will enable this feature by default.
Usage Example:
sharedString.annotateAdjustRange(start, end, {
key: { value: 5, min: 0, max: 10 },
});
Change details
Commit: d54b9dd
Affected packages:
- fluid-framework
- @fluidframework/merge-tree
- @fluidframework/sequence
- @fluidframework/undo-redo
🌳 SharedTree DDS Changes
Provide more comprehensive replacement to the commitApplied
event (#22977)
Adds a new changed
event to the (currently alpha) TreeBranchEvents
that replaces the commitApplied
event on TreeViewEvents
. This new event is fired for both local and remote changes and maintains the existing functionality of commitApplied
that is used for obtaining Revertibles
.
Change details
Commit: e51c94d
Affected packages:
- @fluidframework/tree
SharedTree event listeners that implement Listenable
now allow deregistration of event listeners via an off()
function. (#23046)
The ability to deregister events via a callback returned by on()
remains the same. Both strategies will remain supported and consumers of SharedTree events may choose which method of deregistration they prefer in a given instance.
// The new behavior
function deregisterViaOff(view: TreeView<MySchema>): {
const listener = () => { /* ... */ };
view.events.on("commitApplied", listener); // Register
view.events.off("commitApplied", listener); // Deregister
}
// The existing behavior (still supported)
function deregisterViaCallback(view: TreeView<MySchema>): {
const off = view.events.on("commitApplied", () => { /* ... */ }); // Register
off(); // Deregister
}
Change details
Commit: c59225d
Affected packages:
- fluid-framework
- @fluidframework/tree
Allow constructing recursive maps from objects (#23070)
Previously only non-recursive maps could be constructed from objects. Now all maps nodes can constructed from objects:
class MapRecursive extends sf.mapRecursive("Map", [() => MapRecursive]) {}
{
type _check = ValidateRecursiveSchema<typeof MapRecursive>;
}
// New:
const fromObject = new MapRecursive({ x: new MapRecursive() });
// Existing:
const fromIterator = new MapRecursive([["x", new MapRecursive()]]);
const fromMap = new MapRecursive(new Map([["x", new MapRecursive()]]));
const fromNothing = new MapRecursive();
const fromUndefined = new MapRecursive(undefined);
Change details
Commit: 0185a08
Affected packages:
- fluid-framework
- @fluidframework/tree
Fix typing bug in adaptEnum
and enumFromStrings
(#23077)
When using the return value from adaptEnum
as a function, passing in a value who's type is a union no longer produced an incorrectly typed return value. This has been fixed.
Additionally enumFromStrings
has improved the typing of its schema, ensuring the returned object's members have sufficiently specific types. Part of this improvement was fixing the .schema
property to be a tuple over each of the schema where it was previously a tuple of a single combined schema due to a bug.
One side-effect of these fixes is that narrowing of the value
field of a node typed from the .schema
behaves slightly different, such that the node type is now a union instead of it being a single type with a .value
that is a union. This means that narrowing based on .value
property narrows which node type you have, not just the value property. This mainly matters when matching all c...