Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 11 additions & 15 deletions CrossClientCompatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,25 +108,21 @@ compat internally (see

#### Configuring Cross-Client Compatibility (Declarative Model)

If you are using a service client (i.e. `AzureClient` or `OdspClient`), cross-client compatibility is configured via the `CompatibilityMode` parameter. This is a required argument when creating or loading a container:
If you are using a service client (i.e. `AzureClient` or `OdspClient`), cross-client compatibility is
configured by passing a `minVersionForCollab` semver string when creating or loading a container:

```typescript
// Creating a new container
const { container } = await azureClient.createContainer(schema, compatibilityMode);
const { container } = await azureClient.createContainer(schema, "2.0.0");

// Loading an existing container
const { container } = await azureClient.getContainer(id, schema, compatibilityMode);
const { container } = await azureClient.getContainer(id, schema, "2.0.0");
```

The client will map `CompatibilityMode` to a `minVersionForCollab` value (see [utils.ts](./packages/framework/fluid-static/src/utils.ts) for details) and automatically configure runtime options via [compatibilityConfiguration.ts](./packages/framework/fluid-static/src/compatibilityConfiguration.ts). This means you do not need to manage individual runtime options or version strings directly.

Below is the mapping of `CompatibilityMode` values to `minVersionForCollab` at the time of writing. For the most up-to-date mapping, please refer to `compatibilityModeToMinVersionForCollab` in [utils.ts](./packages/framework/fluid-static/src/utils.ts).

<!-- prettier-ignore -->
| Mode | Meaning | Mapped `minVersionForCollab` |
| --- | --- | --- |
| `"1"` | Supports collaboration with 1.x clients. Uses a conservative set of runtime options. | `"1.0.0"` |
| `"2"` | Supports collaboration with 2.x clients only. Enables newer features (e.g., runtime ID compressor for SharedTree support). | `"2.0.0"` |
This sets the minimum Fluid version allowed to collaborate on the document and automatically configures
runtime options to be compatible with that version (see
[compatibilityConfiguration.ts](./packages/framework/fluid-static/src/compatibilityConfiguration.ts)).
You do not need to manage individual runtime options directly.

#### Configuring Cross-Client Compatibility (Encapsulated Model)

Expand Down Expand Up @@ -165,9 +161,9 @@ version your users are [saturated](#terminology) on. This will ensure:
We recommend following the below pattern to ensure cross-client compatibility. Keeping your compatibility configuration up-to-date on an ongoing basis ensures you are always within a safe compatibility window.

1. Observe the distribution of Fluid versions across your application's clients. See [Observing Client Version Distribution](./FluidCompatibilityConsiderations.md#observing-client-version-distribution) for how to do this using telemetry.
2. Update your compatibility configuration to match the oldest deployed version that your clients are [saturated](#terminology) on:
- **Declarative model**: Set `CompatibilityMode` to the value corresponding to that saturated version.
- **Encapsulated model**: Set `minVersionForCollab` to the specific saturated version (e.g., `"2.10.0"`).
2. Update your compatibility configuration to match the oldest deployed version that your clients are
[saturated](#terminology) on. In both the declarative and encapsulated models, set `minVersionForCollab`
to that saturated version (e.g., `"2.10.0"`).
3. Verify that the configured compatibility checkpoint is within the supported compatibility window of the Fluid Framework version you want to upgrade to. If it is, bump your Fluid Framework dependencies and update your lock file (so a newer version isn't picked up implicitly); no further action is required. If not, wait for further saturation and return to step 1.
4. Monitor telemetry for warnings/errors to ensure safe rollout (see [Errors and Warnings to Monitor](#errors-and-warnings-to-monitor) below). At this point any clients running a version older than the configured `minVersionForCollab` may be blocked from accessing the document.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```ts

// @public
// @public @deprecated
export type CompatibilityMode = "1" | "2";

// @public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```ts

// @public
// @public @deprecated
export type CompatibilityMode = "1" | "2";

// @public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```ts

// @public
// @public @deprecated
export type CompatibilityMode = "1" | "2";

// @public
Expand All @@ -19,7 +19,7 @@ export interface ContainerSchema {
// @beta @legacy
export function createTreeContainerRuntimeFactory(props: {
readonly schema: TreeContainerSchema;
readonly compatibilityMode: CompatibilityMode;
readonly compatibilityMode: MinimumVersionForCollab | CompatibilityMode;
readonly rootDataStoreRegistry?: IFluidDataStoreRegistry;
readonly runtimeOptionOverrides?: Partial<IContainerRuntimeOptions>;
readonly minVersionForCollabOverride?: MinimumVersionForCollab;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```ts

// @public
// @public @deprecated
export type CompatibilityMode = "1" | "2";

// @public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```ts

// @public
// @public @deprecated
export type CompatibilityMode = "1" | "2";

// @public
Expand Down
3 changes: 2 additions & 1 deletion packages/framework/fluid-static/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@
"@fluidframework/runtime-utils": "workspace:~",
"@fluidframework/shared-object-base": "workspace:~",
"@fluidframework/telemetry-utils": "workspace:~",
"@fluidframework/tree": "workspace:~"
"@fluidframework/tree": "workspace:~",
"semver-ts": "^1.0.3"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.18.2",
Expand Down
31 changes: 22 additions & 9 deletions packages/framework/fluid-static/src/compatibilityConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
*/

import type { IContainerRuntimeOptionsInternal } from "@fluidframework/container-runtime/internal";

import type { CompatibilityMode } from "./types.js";
import type { MinimumVersionForCollab } from "@fluidframework/runtime-definitions/internal";
import { gte } from "semver-ts";

/**
* The CompatibilityMode selected determines the set of runtime options to use. In "1" mode we support
* full interop with true 1.x clients, while in "2" mode we only support interop with 2.x clients.
* The `minVersionForCollab` determines the set of runtime options to use.
* For a 1.x `minVersionForCollab` we support full interop with true 1.x clients.
* For a 2.x `minVersionForCollab` we only support interop with 2.x clients.
*
* @privateRemarks In general, we can use the `compatibilityMode` property of `LoadContainerRuntimeParams` to apply
* the proper configurations. However, there are some options that we need to explicity set that differ
* from the default values (i.e. `enableRuntimeIdCompressor` below).
* @privateRemarks The purpose of this map is to use a different set of defaults
* than what the runtime normally uses based on a given `minVersionForCollab` (e.g. `enableRuntimeIdCompressor` below).)
*/
export const compatibilityModeRuntimeOptions: Record<
CompatibilityMode,
const minVersionForCollabToDefaultRuntimeOptions: Record<
"1" | "2",
IContainerRuntimeOptionsInternal
> = {
"1": {},
Expand All @@ -27,3 +27,16 @@ export const compatibilityModeRuntimeOptions: Record<
enableRuntimeIdCompressor: "on",
},
};

/**
* Determines default runtime options for the given minVersionForCollab.
*
* @internal
*/
export function defaultRuntimeOptionsForMinVersion(
minVersionForCollab: MinimumVersionForCollab,
): IContainerRuntimeOptionsInternal {
return minVersionForCollabToDefaultRuntimeOptions[
gte(minVersionForCollab, "2.0.0") ? "2" : "1"
];
}
40 changes: 23 additions & 17 deletions packages/framework/fluid-static/src/rootDataObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ import type {
} from "@fluidframework/runtime-definitions/internal";
import type { SharedObjectKind } from "@fluidframework/shared-object-base/internal";

import { compatibilityModeRuntimeOptions } from "./compatibilityConfiguration.js";
import { defaultRuntimeOptionsForMinVersion } from "./compatibilityConfiguration.js";
import type {
// eslint-disable-next-line import-x/no-deprecated
CompatibilityMode,
ContainerSchema,
IRootDataObject,
Expand All @@ -42,13 +43,13 @@ import type {
LoadableObjectRecord,
} from "./types.js";
import {
compatibilityModeToMinVersionForCollab,
createDataObject,
createSharedObject,
isDataObjectKind,
isSharedObjectKind,
makeFluidObject,
parseDataObjectsFromSharedObjects,
resolveCompatibilityModeToMinVersionForCollab,
} from "./utils.js";

/**
Expand Down Expand Up @@ -196,9 +197,13 @@ export function createDOProviderContainerRuntimeFactory(props: {
*/
schema: ContainerSchema;
/**
* See {@link CompatibilityMode} and compatibilityModeRuntimeOptions for more details.
* Minimum Fluid Framework version required for collaboration. Accepts a
* {@link @fluidframework/runtime-definitions#MinimumVersionForCollab} semver string;
* the legacy {@link CompatibilityMode} values `"1"` and `"2"` are **deprecated**
* equivalents of `"1.0.0"` and `"2.0.0"`.
*/
compatibilityMode: CompatibilityMode;
// eslint-disable-next-line import-x/no-deprecated
compatibilityMode: MinimumVersionForCollab | CompatibilityMode;
/**
* Optional registry of data stores to pass to the DataObject factory.
* If not provided, one will be created based on the schema.
Expand All @@ -214,26 +219,30 @@ export function createDOProviderContainerRuntimeFactory(props: {
* If not provided, the default for the given compatibilityMode will be used.
* @remarks
* This is useful when runtime options are overridden and change the minimum version for collab.
*
* @deprecated Pass a {@link @fluidframework/runtime-definitions#MinimumVersionForCollab}
* semver string directly via `compatibilityMode` instead.
*/
minVersionForCollabOverride?: MinimumVersionForCollab;
}): IRuntimeFactory {
const {
compatibilityMode,
minVersionForCollabOverride,
rootDataStoreRegistry,
runtimeOptionOverrides,
schema,
} = props;
const minVersionForCollab = resolveCompatibilityModeToMinVersionForCollab(
props.compatibilityMode,
);
const [registryEntries, sharedObjects] = parseDataObjectsFromSharedObjects(schema);
const registry = rootDataStoreRegistry ?? new FluidDataStoreRegistry(registryEntries);

return new DOProviderContainerRuntimeFactory(
schema,
compatibilityMode,
new RootDataObjectFactory(sharedObjects, registry),
{
runtimeOptions: runtimeOptionOverrides,
minVersionForCollab: minVersionForCollabOverride,
minVersionForCollab: minVersionForCollabOverride ?? minVersionForCollab,
},
);
}
Expand Down Expand Up @@ -263,31 +272,28 @@ class DOProviderContainerRuntimeFactory extends BaseContainerRuntimeFactory {
* since it can take care of constructing the root data object factory based on the schema.
*
* @param schema - The schema for the container
* @param compatibilityMode - Compatibility mode
* @param rootDataObjectFactory - A factory that can construct the root data object.
* @param config - Resolved minimum version for collab (required) and optional runtime option overrides.
*/
public constructor(
schema: ContainerSchema,
compatibilityMode: CompatibilityMode,
rootDataObjectFactory: DataObjectFactory<
RootDataObject,
{ InitialState: RootDataObjectProps }
>,
overrides?: Partial<{
runtimeOptions: Partial<IContainerRuntimeOptions>;
config: {
minVersionForCollab: MinimumVersionForCollab;
}>,
runtimeOptions?: Partial<IContainerRuntimeOptions>;
},
) {
super({
registryEntries: [rootDataObjectFactory.registryEntry],
runtimeOptions: {
...compatibilityModeRuntimeOptions[compatibilityMode],
...overrides?.runtimeOptions,
...defaultRuntimeOptionsForMinVersion(config.minVersionForCollab),
...config.runtimeOptions,
},
provideEntryPoint,
minVersionForCollab:
overrides?.minVersionForCollab ??
compatibilityModeToMinVersionForCollab[compatibilityMode],
minVersionForCollab: config.minVersionForCollab,
});
this.rootDataObjectFactory = rootDataObjectFactory;
this.initialObjects = schema.initialObjects;
Expand Down
38 changes: 22 additions & 16 deletions packages/framework/fluid-static/src/treeRootDataObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ import type {
} from "@fluidframework/runtime-definitions/internal";
import type { SharedObjectKind } from "@fluidframework/shared-object-base/internal";

import { compatibilityModeRuntimeOptions } from "./compatibilityConfiguration.js";
import { defaultRuntimeOptionsForMinVersion } from "./compatibilityConfiguration.js";
import type {
// eslint-disable-next-line import-x/no-deprecated
CompatibilityMode,
IRootDataObject,
IStaticEntryPoint,
Expand All @@ -41,13 +42,13 @@ import type {
TreeContainerSchema,
} from "./types.js";
import {
compatibilityModeToMinVersionForCollab,
createDataObject,
createSharedObject,
isDataObjectKind,
isSharedObjectKind,
makeFluidObject,
parseDataObjectsFromSharedObjects,
resolveCompatibilityModeToMinVersionForCollab,
} from "./utils.js";

/**
Expand Down Expand Up @@ -135,23 +136,20 @@ class TreeContainerRuntimeFactory extends BaseContainerRuntimeFactory {
readonly #treeRootDataObjectFactory: TreeDataObjectFactory<TreeRootDataObject>;

public constructor(
compatibilityMode: CompatibilityMode,
treeRootDataObjectFactory: TreeDataObjectFactory<TreeRootDataObject>,
overrides?: Partial<{
runtimeOptions: Partial<IContainerRuntimeOptions>;
config: {
minVersionForCollab: MinimumVersionForCollab;
}>,
runtimeOptions?: Partial<IContainerRuntimeOptions>;
},
) {
super({
registryEntries: [treeRootDataObjectFactory.registryEntry],
runtimeOptions: {
...compatibilityModeRuntimeOptions[compatibilityMode],
...overrides?.runtimeOptions,
...defaultRuntimeOptionsForMinVersion(config.minVersionForCollab),
...config.runtimeOptions,
},
provideEntryPoint,
minVersionForCollab:
overrides?.minVersionForCollab ??
compatibilityModeToMinVersionForCollab[compatibilityMode],
minVersionForCollab: config.minVersionForCollab,
});
this.#treeRootDataObjectFactory = treeRootDataObjectFactory;
}
Expand Down Expand Up @@ -211,9 +209,13 @@ export function createTreeContainerRuntimeFactory(props: {
readonly schema: TreeContainerSchema;

/**
* See {@link CompatibilityMode} and compatibilityModeRuntimeOptions for more details.
* Minimum Fluid Framework version required for collaboration. Accepts a
* {@link @fluidframework/runtime-definitions#MinimumVersionForCollab} semver string;
* the legacy {@link CompatibilityMode} values `"1"` and `"2"` are **deprecated**
* equivalents of `"1.0.0"` and `"2.0.0"`.
*/
readonly compatibilityMode: CompatibilityMode;
// eslint-disable-next-line import-x/no-deprecated
readonly compatibilityMode: MinimumVersionForCollab | CompatibilityMode;
/**
* Optional registry of data stores to pass to the DataObject factory.
* If not provided, one will be created based on the schema.
Expand All @@ -229,26 +231,30 @@ export function createTreeContainerRuntimeFactory(props: {
* If not provided, the default for the given compatibilityMode will be used.
* @remarks
* This is useful when runtime options are overridden and change the minimum version for collab.
*
* @deprecated Pass a {@link @fluidframework/runtime-definitions#MinimumVersionForCollab}
* semver string directly via `compatibilityMode` instead.
*/
readonly minVersionForCollabOverride?: MinimumVersionForCollab;
}): IRuntimeFactory {
const {
compatibilityMode,
minVersionForCollabOverride,
rootDataStoreRegistry,
runtimeOptionOverrides,
schema,
} = props;
const minVersionForCollab = resolveCompatibilityModeToMinVersionForCollab(
props.compatibilityMode,
);

const [registryEntries, sharedObjects] = parseDataObjectsFromSharedObjects(schema);
const registry = rootDataStoreRegistry ?? new FluidDataStoreRegistry(registryEntries);

return new TreeContainerRuntimeFactory(
compatibilityMode,
new TreeRootDataObjectFactory(sharedObjects, registry),
{
runtimeOptions: runtimeOptionOverrides,
minVersionForCollab: minVersionForCollabOverride,
minVersionForCollab: minVersionForCollabOverride ?? minVersionForCollab,
},
);
}
6 changes: 6 additions & 0 deletions packages/framework/fluid-static/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ import type { ITree } from "@fluidframework/tree";
* In "1" mode we support full interop between 2.x clients and 1.x clients,
* while in "2" mode we only support interop between 2.x clients.
*
* @deprecated Specify the minimum Fluid Framework version directly via the
* `minVersionForCollab` parameter, which accepts a
* {@link @fluidframework/runtime-definitions#MinimumVersionForCollab} semver string. The
* legacy mode "1" is equivalent to `minVersionForCollab: "1.0.0"`; mode "2" is
* equivalent to `"2.0.0"`.
*
* @public
*/
export type CompatibilityMode = "1" | "2";
Expand Down
Loading
Loading