diff --git a/CrossClientCompatibility.md b/CrossClientCompatibility.md index 98cd157decf5..c4c068e0e8e8 100644 --- a/CrossClientCompatibility.md +++ b/CrossClientCompatibility.md @@ -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). - - -| 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) @@ -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. diff --git a/packages/framework/fluid-static/api-report/fluid-static.alpha.api.md b/packages/framework/fluid-static/api-report/fluid-static.alpha.api.md index 56b3c969c8cb..b43e5f026aa4 100644 --- a/packages/framework/fluid-static/api-report/fluid-static.alpha.api.md +++ b/packages/framework/fluid-static/api-report/fluid-static.alpha.api.md @@ -4,7 +4,7 @@ ```ts -// @public +// @public @deprecated export type CompatibilityMode = "1" | "2"; // @public diff --git a/packages/framework/fluid-static/api-report/fluid-static.beta.api.md b/packages/framework/fluid-static/api-report/fluid-static.beta.api.md index 3b329602039e..a3076610f0d6 100644 --- a/packages/framework/fluid-static/api-report/fluid-static.beta.api.md +++ b/packages/framework/fluid-static/api-report/fluid-static.beta.api.md @@ -4,7 +4,7 @@ ```ts -// @public +// @public @deprecated export type CompatibilityMode = "1" | "2"; // @public diff --git a/packages/framework/fluid-static/api-report/fluid-static.legacy.beta.api.md b/packages/framework/fluid-static/api-report/fluid-static.legacy.beta.api.md index ad89f685e26a..daaf74ade5eb 100644 --- a/packages/framework/fluid-static/api-report/fluid-static.legacy.beta.api.md +++ b/packages/framework/fluid-static/api-report/fluid-static.legacy.beta.api.md @@ -4,7 +4,7 @@ ```ts -// @public +// @public @deprecated export type CompatibilityMode = "1" | "2"; // @public @@ -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; readonly minVersionForCollabOverride?: MinimumVersionForCollab; diff --git a/packages/framework/fluid-static/api-report/fluid-static.legacy.public.api.md b/packages/framework/fluid-static/api-report/fluid-static.legacy.public.api.md index e6bcd3fc736f..0467bd8f6778 100644 --- a/packages/framework/fluid-static/api-report/fluid-static.legacy.public.api.md +++ b/packages/framework/fluid-static/api-report/fluid-static.legacy.public.api.md @@ -4,7 +4,7 @@ ```ts -// @public +// @public @deprecated export type CompatibilityMode = "1" | "2"; // @public diff --git a/packages/framework/fluid-static/api-report/fluid-static.public.api.md b/packages/framework/fluid-static/api-report/fluid-static.public.api.md index e6bcd3fc736f..0467bd8f6778 100644 --- a/packages/framework/fluid-static/api-report/fluid-static.public.api.md +++ b/packages/framework/fluid-static/api-report/fluid-static.public.api.md @@ -4,7 +4,7 @@ ```ts -// @public +// @public @deprecated export type CompatibilityMode = "1" | "2"; // @public diff --git a/packages/framework/fluid-static/package.json b/packages/framework/fluid-static/package.json index 744b1547c521..905abd5a1da2 100644 --- a/packages/framework/fluid-static/package.json +++ b/packages/framework/fluid-static/package.json @@ -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", diff --git a/packages/framework/fluid-static/src/compatibilityConfiguration.ts b/packages/framework/fluid-static/src/compatibilityConfiguration.ts index 39b554b2399e..fc24abb3024b 100644 --- a/packages/framework/fluid-static/src/compatibilityConfiguration.ts +++ b/packages/framework/fluid-static/src/compatibilityConfiguration.ts @@ -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": {}, @@ -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" + ]; +} diff --git a/packages/framework/fluid-static/src/rootDataObject.ts b/packages/framework/fluid-static/src/rootDataObject.ts index 53818d6a4324..f16ebfce021d 100644 --- a/packages/framework/fluid-static/src/rootDataObject.ts +++ b/packages/framework/fluid-static/src/rootDataObject.ts @@ -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, @@ -42,13 +43,13 @@ import type { LoadableObjectRecord, } from "./types.js"; import { - compatibilityModeToMinVersionForCollab, createDataObject, createSharedObject, isDataObjectKind, isSharedObjectKind, makeFluidObject, parseDataObjectsFromSharedObjects, + resolveCompatibilityModeToMinVersionForCollab, } from "./utils.js"; /** @@ -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. @@ -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, }, ); } @@ -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; + config: { minVersionForCollab: MinimumVersionForCollab; - }>, + runtimeOptions?: Partial; + }, ) { 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; diff --git a/packages/framework/fluid-static/src/treeRootDataObject.ts b/packages/framework/fluid-static/src/treeRootDataObject.ts index 0a7cb85bb01f..a8c1ad589272 100644 --- a/packages/framework/fluid-static/src/treeRootDataObject.ts +++ b/packages/framework/fluid-static/src/treeRootDataObject.ts @@ -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, @@ -41,13 +42,13 @@ import type { TreeContainerSchema, } from "./types.js"; import { - compatibilityModeToMinVersionForCollab, createDataObject, createSharedObject, isDataObjectKind, isSharedObjectKind, makeFluidObject, parseDataObjectsFromSharedObjects, + resolveCompatibilityModeToMinVersionForCollab, } from "./utils.js"; /** @@ -135,23 +136,20 @@ class TreeContainerRuntimeFactory extends BaseContainerRuntimeFactory { readonly #treeRootDataObjectFactory: TreeDataObjectFactory; public constructor( - compatibilityMode: CompatibilityMode, treeRootDataObjectFactory: TreeDataObjectFactory, - overrides?: Partial<{ - runtimeOptions: Partial; + config: { minVersionForCollab: MinimumVersionForCollab; - }>, + runtimeOptions?: Partial; + }, ) { 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; } @@ -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. @@ -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, }, ); } diff --git a/packages/framework/fluid-static/src/types.ts b/packages/framework/fluid-static/src/types.ts index af0b2c442845..91de09c155bc 100644 --- a/packages/framework/fluid-static/src/types.ts +++ b/packages/framework/fluid-static/src/types.ts @@ -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"; diff --git a/packages/framework/fluid-static/src/utils.ts b/packages/framework/fluid-static/src/utils.ts index 41fcb4b8bf33..fedfa9faeb04 100644 --- a/packages/framework/fluid-static/src/utils.ts +++ b/packages/framework/fluid-static/src/utils.ts @@ -20,6 +20,7 @@ import { UsageError } from "@fluidframework/telemetry-utils/internal"; import { SharedTreeFactoryType } from "@fluidframework/tree/internal"; import type { + // eslint-disable-next-line import-x/no-deprecated CompatibilityMode, ContainerSchema, LoadableObjectKind, @@ -147,12 +148,24 @@ export function makeFluidObject< } /** - * Maps CompatibilityMode to a semver valid string that can be passed to the container runtime. + * Resolves the `compatibilityMode` input — either a {@link MinimumVersionForCollab} + * semver string or a legacy {@link CompatibilityMode} value — into a precise + * {@link MinimumVersionForCollab}. + * + * TODO: This can be removed when the deprecated CompatibilityMode is removed. + * + * @internal */ -export const compatibilityModeToMinVersionForCollab = { - "1": "1.0.0", - "2": "2.0.0", -} as const satisfies Record; +export function resolveCompatibilityModeToMinVersionForCollab( + // eslint-disable-next-line import-x/no-deprecated + compatibilityMode: MinimumVersionForCollab | CompatibilityMode, +): MinimumVersionForCollab { + return compatibilityMode === "1" + ? "1.0.0" + : compatibilityMode === "2" + ? "2.0.0" + : compatibilityMode; +} /** * Determines if the provided schema is a valid tree-based container schema. diff --git a/packages/runtime/runtime-definitions/api-report/runtime-definitions.beta.api.md b/packages/runtime/runtime-definitions/api-report/runtime-definitions.beta.api.md index d20a3e70d70d..56d71f69b5b5 100644 --- a/packages/runtime/runtime-definitions/api-report/runtime-definitions.beta.api.md +++ b/packages/runtime/runtime-definitions/api-report/runtime-definitions.beta.api.md @@ -4,7 +4,7 @@ ```ts -// @beta @input +// @public @input export type MinimumVersionForCollab = `${1 | 2}.${bigint}.${bigint}` | `${1 | 2}.${bigint}.${bigint}-${string}`; // (No @packageDocumentation comment for this package) diff --git a/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.alpha.api.md b/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.alpha.api.md index 9f18e360b28c..756b235f8efc 100644 --- a/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.alpha.api.md +++ b/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.alpha.api.md @@ -398,7 +398,7 @@ export interface LocalAttributionKey { type: "local"; } -// @beta @input +// @public @input export type MinimumVersionForCollab = `${1 | 2}.${bigint}.${bigint}` | `${1 | 2}.${bigint}.${bigint}-${string}`; // @beta @legacy diff --git a/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.beta.api.md b/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.beta.api.md index 75f077ccfa54..aeee28a6ab04 100644 --- a/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.beta.api.md +++ b/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.beta.api.md @@ -391,7 +391,7 @@ export interface LocalAttributionKey { type: "local"; } -// @beta @input +// @public @input export type MinimumVersionForCollab = `${1 | 2}.${bigint}.${bigint}` | `${1 | 2}.${bigint}.${bigint}-${string}`; // @beta @legacy diff --git a/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.public.api.md b/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.public.api.md index 26348215bc12..8850043fa4ea 100644 --- a/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.public.api.md +++ b/packages/runtime/runtime-definitions/api-report/runtime-definitions.legacy.public.api.md @@ -4,6 +4,9 @@ ```ts +// @public @input +export type MinimumVersionForCollab = `${1 | 2}.${bigint}.${bigint}` | `${1 | 2}.${bigint}.${bigint}-${string}`; + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/runtime/runtime-definitions/api-report/runtime-definitions.public.api.md b/packages/runtime/runtime-definitions/api-report/runtime-definitions.public.api.md index 26348215bc12..8850043fa4ea 100644 --- a/packages/runtime/runtime-definitions/api-report/runtime-definitions.public.api.md +++ b/packages/runtime/runtime-definitions/api-report/runtime-definitions.public.api.md @@ -4,6 +4,9 @@ ```ts +// @public @input +export type MinimumVersionForCollab = `${1 | 2}.${bigint}.${bigint}` | `${1 | 2}.${bigint}.${bigint}-${string}`; + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/runtime/runtime-definitions/src/compatibilityDefinitions.ts b/packages/runtime/runtime-definitions/src/compatibilityDefinitions.ts index a8176b2ee323..d43c0314a354 100644 --- a/packages/runtime/runtime-definitions/src/compatibilityDefinitions.ts +++ b/packages/runtime/runtime-definitions/src/compatibilityDefinitions.ts @@ -26,7 +26,7 @@ * For example it might make sense to constrain this to something like `"1.4.0" | typeof defaultMinVersionForCollab | 2.${bigint}.0"`. * * @input - * @beta + * @public */ export type MinimumVersionForCollab = | `${1 | 2}.${bigint}.${bigint}` diff --git a/packages/service-clients/azure-client/api-report/azure-client.beta.api.md b/packages/service-clients/azure-client/api-report/azure-client.beta.api.md index 4ab351c4ddee..b586e38af11d 100644 --- a/packages/service-clients/azure-client/api-report/azure-client.beta.api.md +++ b/packages/service-clients/azure-client/api-report/azure-client.beta.api.md @@ -7,16 +7,16 @@ // @public export class AzureClient { constructor(properties: AzureClientProps); - createContainer(containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + createContainer(containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: AzureContainerServices; }>; - getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: AzureContainerServices; }>; getContainerVersions(id: string, options?: AzureGetVersionsOptions): Promise; - viewContainerVersion(id: string, containerSchema: TContainerSchema, version: AzureContainerVersion, compatibilityMode: CompatibilityMode): Promise<{ + viewContainerVersion(id: string, containerSchema: TContainerSchema, version: AzureContainerVersion, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; }>; } @@ -73,7 +73,7 @@ export interface AzureRemoteConnectionConfig extends AzureConnectionConfig { type: "remote"; } -// @public +// @public @deprecated export type CompatibilityMode = "1" | "2"; // @public diff --git a/packages/service-clients/azure-client/api-report/azure-client.legacy.beta.api.md b/packages/service-clients/azure-client/api-report/azure-client.legacy.beta.api.md index 4ab351c4ddee..b586e38af11d 100644 --- a/packages/service-clients/azure-client/api-report/azure-client.legacy.beta.api.md +++ b/packages/service-clients/azure-client/api-report/azure-client.legacy.beta.api.md @@ -7,16 +7,16 @@ // @public export class AzureClient { constructor(properties: AzureClientProps); - createContainer(containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + createContainer(containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: AzureContainerServices; }>; - getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: AzureContainerServices; }>; getContainerVersions(id: string, options?: AzureGetVersionsOptions): Promise; - viewContainerVersion(id: string, containerSchema: TContainerSchema, version: AzureContainerVersion, compatibilityMode: CompatibilityMode): Promise<{ + viewContainerVersion(id: string, containerSchema: TContainerSchema, version: AzureContainerVersion, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; }>; } @@ -73,7 +73,7 @@ export interface AzureRemoteConnectionConfig extends AzureConnectionConfig { type: "remote"; } -// @public +// @public @deprecated export type CompatibilityMode = "1" | "2"; // @public diff --git a/packages/service-clients/azure-client/api-report/azure-client.legacy.public.api.md b/packages/service-clients/azure-client/api-report/azure-client.legacy.public.api.md index 57c9ead9db3b..60fcadf641fe 100644 --- a/packages/service-clients/azure-client/api-report/azure-client.legacy.public.api.md +++ b/packages/service-clients/azure-client/api-report/azure-client.legacy.public.api.md @@ -7,16 +7,16 @@ // @public export class AzureClient { constructor(properties: AzureClientProps); - createContainer(containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + createContainer(containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: AzureContainerServices; }>; - getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: AzureContainerServices; }>; getContainerVersions(id: string, options?: AzureGetVersionsOptions): Promise; - viewContainerVersion(id: string, containerSchema: TContainerSchema, version: AzureContainerVersion, compatibilityMode: CompatibilityMode): Promise<{ + viewContainerVersion(id: string, containerSchema: TContainerSchema, version: AzureContainerVersion, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; }>; } @@ -73,7 +73,7 @@ export interface AzureRemoteConnectionConfig extends AzureConnectionConfig { type: "remote"; } -// @public +// @public @deprecated export type CompatibilityMode = "1" | "2"; // @public diff --git a/packages/service-clients/azure-client/api-report/azure-client.public.api.md b/packages/service-clients/azure-client/api-report/azure-client.public.api.md index 57c9ead9db3b..60fcadf641fe 100644 --- a/packages/service-clients/azure-client/api-report/azure-client.public.api.md +++ b/packages/service-clients/azure-client/api-report/azure-client.public.api.md @@ -7,16 +7,16 @@ // @public export class AzureClient { constructor(properties: AzureClientProps); - createContainer(containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + createContainer(containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: AzureContainerServices; }>; - getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: AzureContainerServices; }>; getContainerVersions(id: string, options?: AzureGetVersionsOptions): Promise; - viewContainerVersion(id: string, containerSchema: TContainerSchema, version: AzureContainerVersion, compatibilityMode: CompatibilityMode): Promise<{ + viewContainerVersion(id: string, containerSchema: TContainerSchema, version: AzureContainerVersion, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; }>; } @@ -73,7 +73,7 @@ export interface AzureRemoteConnectionConfig extends AzureConnectionConfig { type: "remote"; } -// @public +// @public @deprecated export type CompatibilityMode = "1" | "2"; // @public diff --git a/packages/service-clients/azure-client/package.json b/packages/service-clients/azure-client/package.json index b6e66beec923..662a47a1f1dc 100644 --- a/packages/service-clients/azure-client/package.json +++ b/packages/service-clients/azure-client/package.json @@ -98,6 +98,7 @@ "@fluidframework/driver-utils": "workspace:~", "@fluidframework/fluid-static": "workspace:~", "@fluidframework/routerlicious-driver": "workspace:~", + "@fluidframework/runtime-definitions": "workspace:~", "@fluidframework/telemetry-utils": "workspace:~" }, "devDependencies": { diff --git a/packages/service-clients/azure-client/src/AzureClient.ts b/packages/service-clients/azure-client/src/AzureClient.ts index 7a392714ae7c..2db7ea7f88a5 100644 --- a/packages/service-clients/azure-client/src/AzureClient.ts +++ b/packages/service-clients/azure-client/src/AzureClient.ts @@ -29,6 +29,7 @@ import { applyStorageCompression } from "@fluidframework/driver-utils/internal"; import type { ContainerSchema, IFluidContainer, + // eslint-disable-next-line import-x/no-deprecated CompatibilityMode, } from "@fluidframework/fluid-static"; import { @@ -37,6 +38,7 @@ import { createServiceAudience, } from "@fluidframework/fluid-static/internal"; import { RouterliciousDocumentServiceFactory } from "@fluidframework/routerlicious-driver/internal"; +import type { MinimumVersionForCollab } from "@fluidframework/runtime-definitions"; import { wrapConfigProviderWithDefaults } from "@fluidframework/telemetry-utils/internal"; import { createAzureAudienceMember } from "./AzureAudience.js"; @@ -100,7 +102,8 @@ export class AzureClient { compatibilityMode, }: { schema: ContainerSchema; - compatibilityMode: CompatibilityMode; + // eslint-disable-next-line import-x/no-deprecated + compatibilityMode: MinimumVersionForCollab | CompatibilityMode; }) => IRuntimeFactory; /** @@ -138,12 +141,16 @@ export class AzureClient { * @typeparam TContainerSchema - Used to infer the the type of 'initialObjects' in the returned container. * (normally not explicitly specified.) * @param containerSchema - Container schema for the new container. - * @param compatibilityMode - Compatibility mode the container should run in. + * @param compatibilityMode - Minimum Fluid Framework version required for collaboration. Accepts + * either a `MinimumVersionForCollab` semver string (e.g. `"1.0.0"`, `"2.0.0"`) or a legacy + * {@link @fluidframework/fluid-static#CompatibilityMode} value. The legacy values `"1"` and + * `"2"` are **deprecated** equivalents of `"1.0.0"` and `"2.0.0"`. * @returns New detached container instance along with associated services. */ public async createContainer( containerSchema: TContainerSchema, - compatibilityMode: CompatibilityMode, + // eslint-disable-next-line import-x/no-deprecated + compatibilityMode: MinimumVersionForCollab | CompatibilityMode, ): Promise<{ container: IFluidContainer; services: AzureContainerServices; @@ -172,13 +179,17 @@ export class AzureClient { * (normally not explicitly specified.) * @param id - Unique ID of the container in Azure Fluid Relay. * @param containerSchema - Container schema used to access data objects in the container. - * @param compatibilityMode - Compatibility mode the container should run in. + * @param compatibilityMode - Minimum framework version required for collaboration. Accepts + * either a `MinimumVersionForCollab` semver string (e.g. `"1.0.0"`, `"2.0.0"`) or a legacy + * {@link @fluidframework/fluid-static#CompatibilityMode} value. The legacy values `"1"` and + * `"2"` are **deprecated** equivalents of `"1.0.0"` and `"2.0.0"`. * @returns Existing container instance along with associated services. */ public async getContainer( id: string, containerSchema: TContainerSchema, - compatibilityMode: CompatibilityMode, + // eslint-disable-next-line import-x/no-deprecated + compatibilityMode: MinimumVersionForCollab | CompatibilityMode, ): Promise<{ container: IFluidContainer; services: AzureContainerServices; @@ -210,14 +221,18 @@ export class AzureClient { * @param id - Unique ID of the source container in Azure Fluid Relay. * @param containerSchema - Container schema used to access data objects in the container. * @param version - Unique version of the source container in Azure Fluid Relay. - * @param compatibilityMode - Compatibility mode the container should run in. + * @param compatibilityMode - Minimum framework version required for collaboration. Accepts + * either a `MinimumVersionForCollab` semver string (e.g. `"1.0.0"`, `"2.0.0"`) or a legacy + * {@link @fluidframework/fluid-static#CompatibilityMode} value. The legacy values `"1"` and + * `"2"` are **deprecated** equivalents of `"1.0.0"` and `"2.0.0"`. * @returns Loaded container instance at the specified version. */ public async viewContainerVersion( id: string, containerSchema: TContainerSchema, version: AzureContainerVersion, - compatibilityMode: CompatibilityMode, + // eslint-disable-next-line import-x/no-deprecated + compatibilityMode: MinimumVersionForCollab | CompatibilityMode, ): Promise<{ container: IFluidContainer; }> { @@ -286,17 +301,13 @@ export class AzureClient { private getLoaderProps( schema: ContainerSchema, - compatibilityMode: CompatibilityMode, + // eslint-disable-next-line import-x/no-deprecated + compatibilityMode: MinimumVersionForCollab | CompatibilityMode, ): ILoaderProps { + const factoryArguments = { schema, compatibilityMode }; const runtimeFactory = this.createContainerRuntimeFactory - ? this.createContainerRuntimeFactory({ - schema, - compatibilityMode, - }) - : createDOProviderContainerRuntimeFactory({ - schema, - compatibilityMode, - }); + ? this.createContainerRuntimeFactory(factoryArguments) + : createDOProviderContainerRuntimeFactory(factoryArguments); const load = async (): Promise => { return { diff --git a/packages/service-clients/azure-client/src/interfaces.ts b/packages/service-clients/azure-client/src/interfaces.ts index cbc26d467fa2..36381311fbfe 100644 --- a/packages/service-clients/azure-client/src/interfaces.ts +++ b/packages/service-clients/azure-client/src/interfaces.ts @@ -11,12 +11,14 @@ import type { import type { IUser } from "@fluidframework/driver-definitions"; import type { ICompressionStorageConfig } from "@fluidframework/driver-utils"; import type { + // eslint-disable-next-line import-x/no-deprecated CompatibilityMode, ContainerSchema, IMember, IServiceAudience, } from "@fluidframework/fluid-static"; import type { ITokenProvider } from "@fluidframework/routerlicious-driver"; +import type { MinimumVersionForCollab } from "@fluidframework/runtime-definitions"; /** * Props for initializing a new AzureClient instance @@ -53,7 +55,8 @@ export interface AzureClientPropsInternal extends AzureClientProps { compatibilityMode, }: { schema: ContainerSchema; - compatibilityMode: CompatibilityMode; + // eslint-disable-next-line import-x/no-deprecated + compatibilityMode: MinimumVersionForCollab | CompatibilityMode; }) => IRuntimeFactory; } diff --git a/packages/service-clients/azure-client/src/test/AzureClient.spec.ts b/packages/service-clients/azure-client/src/test/AzureClient.spec.ts index 20875f56d72d..c3845fdfad4e 100644 --- a/packages/service-clients/azure-client/src/test/AzureClient.spec.ts +++ b/packages/service-clients/azure-client/src/test/AzureClient.spec.ts @@ -76,7 +76,7 @@ const connectionModeOf = (container: IFluidContainer): ConnectionMode => { return getContainerConnectionMode(container.container); }; -for (const compatibilityMode of ["1", "2"] as const) { +for (const compatibilityMode of ["1.0.0", "2.0.0"] as const) { describe(`AzureClient (compatibilityMode: ${compatibilityMode})`, function () { const connectTimeoutMs = 1000; let client: AzureClient; @@ -363,7 +363,7 @@ for (const compatibilityMode of ["1", "2"] as const) { it("preserves 'SharedTree' type", async function () { // SharedTree is not supported in compatibilityMode "1", because it requires idCompressor to be enabled. - if (compatibilityMode === "1") { + if (compatibilityMode === "1.0.0") { this.skip(); } const { container } = await client.createContainer( @@ -438,7 +438,7 @@ for (const compatibilityMode of ["1", "2"] as const) { } as const satisfies ContainerRuntimeOptionsInternal; const expectedRuntimeOptions = - compatibilityMode === "1" ? expectedRuntimeOptions1 : expectedRuntimeOptions2; + compatibilityMode === "1.0.0" ? expectedRuntimeOptions1 : expectedRuntimeOptions2; assert(isInternalFluidContainer(container_defaultConfig)); const actualRuntimeOptions = getRuntimeOptions( getContainerRuntime(container_defaultConfig.container), diff --git a/packages/service-clients/end-to-end-tests/azure-client/src/test/AzureClientFactory.ts b/packages/service-clients/end-to-end-tests/azure-client/src/test/AzureClientFactory.ts index a29919a66985..6b6c4846ea69 100644 --- a/packages/service-clients/end-to-end-tests/azure-client/src/test/AzureClientFactory.ts +++ b/packages/service-clients/end-to-end-tests/azure-client/src/test/AzureClientFactory.ts @@ -20,7 +20,12 @@ import { import type { IRuntimeFactory } from "@fluidframework/container-definitions/legacy"; import type { IConfigProviderBase } from "@fluidframework/core-interfaces"; import { ScopeType } from "@fluidframework/driver-definitions/legacy"; -import type { CompatibilityMode, ContainerSchema } from "@fluidframework/fluid-static"; +import type { + // eslint-disable-next-line import-x/no-deprecated + CompatibilityMode, + ContainerSchema, +} from "@fluidframework/fluid-static"; +import type { MinimumVersionForCollab } from "@fluidframework/runtime-definitions"; import { type MockLogger, createChildLogger, @@ -59,7 +64,8 @@ export function createAzureClient( compatibilityMode, }: { schema: ContainerSchema; - compatibilityMode: CompatibilityMode; + // eslint-disable-next-line import-x/no-deprecated + compatibilityMode: MinimumVersionForCollab | CompatibilityMode; }) => IRuntimeFactory, ): AzureClient { const args = process.argv.slice(2); diff --git a/packages/service-clients/end-to-end-tests/azure-client/src/test/audience.spec.ts b/packages/service-clients/end-to-end-tests/azure-client/src/test/audience.spec.ts index 821832d4a872..755172d344c5 100644 --- a/packages/service-clients/end-to-end-tests/azure-client/src/test/audience.spec.ts +++ b/packages/service-clients/end-to-end-tests/azure-client/src/test/audience.spec.ts @@ -54,9 +54,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container, services } = await client.getContainer(containerId, schema, "2")); + ({ container, services } = await client.getContainer(containerId, schema, "2.0.0")); } else { - ({ container, services } = await client.createContainer(schema, "2")); + ({ container, services } = await client.createContainer(schema, "2.0.0")); containerId = await container.attach(); } @@ -99,9 +99,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container, services } = await client.getContainer(containerId, schema, "2")); + ({ container, services } = await client.getContainer(containerId, schema, "2.0.0")); } else { - ({ container, services } = await client.createContainer(schema, "2")); + ({ container, services } = await client.createContainer(schema, "2.0.0")); containerId = await container.attach(); } @@ -131,7 +131,11 @@ for (const testOpts of testMatrix) { "Fluid.Container.ForceWriteConnection": true, }), ); - const { services: servicesGet } = await client2.getContainer(containerId, schema, "2"); + const { services: servicesGet } = await client2.getContainer( + containerId, + schema, + "2.0.0", + ); /* This is a workaround for a known bug, we should have one member (self) upon container connection */ const partner = await waitForMember(servicesGet.audience, "test-user-id-2"); @@ -163,9 +167,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container } = await client.getContainer(containerId, schema, "2")); + ({ container } = await client.getContainer(containerId, schema, "2.0.0")); } else { - ({ container } = await client.createContainer(schema, "2")); + ({ container } = await client.createContainer(schema, "2.0.0")); containerId = await container.attach(); } @@ -184,7 +188,11 @@ for (const testOpts of testMatrix) { "Fluid.Container.ForceWriteConnection": true, }), ); - const { services: servicesGet } = await client2.getContainer(containerId, schema, "2"); + const { services: servicesGet } = await client2.getContainer( + containerId, + schema, + "2.0.0", + ); /* This is a workaround for a known bug, we should have one member (self) upon container connection */ const partner = await waitForMember(servicesGet.audience, "test-user-id-2"); @@ -222,9 +230,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container, services } = await client.getContainer(containerId, schema, "2")); + ({ container, services } = await client.getContainer(containerId, schema, "2.0.0")); } else { - ({ container, services } = await client.createContainer(schema, "2")); + ({ container, services } = await client.createContainer(schema, "2.0.0")); containerId = await container.attach(); } @@ -254,7 +262,7 @@ for (const testOpts of testMatrix) { [ScopeType.DocRead], ); const { container: partnerContainer, services: partnerServices } = - await partnerClient.getContainer(containerId, schema, "2"); + await partnerClient.getContainer(containerId, schema, "2.0.0"); if (partnerContainer.connectionState !== ConnectionState.Connected) { await timeoutPromise( @@ -331,9 +339,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container } = await client.getContainer(containerId, schema, "2")); + ({ container } = await client.getContainer(containerId, schema, "2.0.0")); } else { - ({ container } = await client.createContainer(schema, "2")); + ({ container } = await client.createContainer(schema, "2.0.0")); containerId = await container.attach(); } @@ -352,7 +360,7 @@ for (const testOpts of testMatrix) { [ScopeType.DocRead], ); const { container: partnerContainer, services: partnerServices } = - await partnerClient.getContainer(containerId, schema, "2"); + await partnerClient.getContainer(containerId, schema, "2.0.0"); if (partnerContainer.connectionState !== ConnectionState.Connected) { await timeoutPromise( @@ -398,7 +406,7 @@ for (const testOpts of testMatrix) { [ScopeType.DocRead], ); const { container: partnerContainer2, services: partnerServices2 } = - await partnerClient2.getContainer(containerId, schema, "2"); + await partnerClient2.getContainer(containerId, schema, "2.0.0"); if (partnerContainer2.connectionState !== ConnectionState.Connected) { await timeoutPromise( diff --git a/packages/service-clients/end-to-end-tests/azure-client/src/test/containerCreate.spec.ts b/packages/service-clients/end-to-end-tests/azure-client/src/test/containerCreate.spec.ts index 9207a3c9accf..37dd7702c6e6 100644 --- a/packages/service-clients/end-to-end-tests/azure-client/src/test/containerCreate.spec.ts +++ b/packages/service-clients/end-to-end-tests/azure-client/src/test/containerCreate.spec.ts @@ -73,7 +73,7 @@ for (const testOpts of testMatrix) { if (isEphemeral) { this.skip(); } - const { container } = await client.createContainer(schema, "2"); + const { container } = await client.createContainer(schema, "2.0.0"); assert.strictEqual( container.attachState, AttachState.Detached, @@ -101,9 +101,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container } = await client.getContainer(containerId, schema, "2")); + ({ container } = await client.getContainer(containerId, schema, "2.0.0")); } else { - ({ container } = await client.createContainer(schema, "2")); + ({ container } = await client.createContainer(schema, "2.0.0")); containerId = await container.attach(); } @@ -138,9 +138,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container } = await client.getContainer(containerId, schema, "2")); + ({ container } = await client.getContainer(containerId, schema, "2.0.0")); } else { - ({ container } = await client.createContainer(schema, "2")); + ({ container } = await client.createContainer(schema, "2.0.0")); containerId = await container.attach(); } @@ -181,7 +181,7 @@ for (const testOpts of testMatrix) { ); containerId = getContainerIdFromPayloadResponse(containerResponse); } else { - ({ container: newContainer } = await client.createContainer(schema, "2")); + ({ container: newContainer } = await client.createContainer(schema, "2.0.0")); containerId = await newContainer.attach(); if (newContainer.connectionState !== ConnectionState.Connected) { @@ -192,7 +192,7 @@ for (const testOpts of testMatrix) { } } - const resources = client.getContainer(containerId, schema, "2"); + const resources = client.getContainer(containerId, schema, "2.0.0"); await assert.doesNotReject( resources, () => true, @@ -210,7 +210,7 @@ for (const testOpts of testMatrix) { it("cannot load improperly created container (cannot load a non-existent container)", async () => { const consoleErrorFn = console.error; console.error = (): void => {}; - const containerAndServicesP = client.getContainer("containerConfig", schema, "2"); + const containerAndServicesP = client.getContainer("containerConfig", schema, "2.0.0"); const errorFn = (error: Error): boolean => { assert.notStrictEqual(error.message, undefined, "Azure Client error is undefined"); @@ -266,7 +266,7 @@ for (const testOpts of testMatrix) { if (isEphemeral) { this.skip(); } - await client.createContainer(schema, "2"); + await client.createContainer(schema, "2.0.0"); const event = mockLogger.events.find((e) => e.eventName.endsWith("ContainerLoadStats")); assert(event !== undefined, "ContainerLoadStats event should exist"); const featureGates = event.featureGates as string; @@ -310,7 +310,7 @@ for (const testOpts of testMatrix) { * Expected behavior: an error should not be thrown nor should a rejected promise * be returned. */ - for (const compatibilityMode of ["1", "2"] as const) { + for (const compatibilityMode of ["1.0.0", "2.0.0"] as const) { it(`Current AzureClient (mode: "${compatibilityMode}") can get container made by legacy AzureClient`, async () => { const { container: containerLegacy } = await clientLegacy.createContainer(schemaLegacy); @@ -348,7 +348,7 @@ for (const testOpts of testMatrix) { // Await the value being saved, especially important if we dispose the legacy container. await valueSetP; - if (compatibilityMode === "2") { + if (compatibilityMode === "2.0.0") { // We don't support interop between legacy containers and "2" mode, dispose the legacy // container to avoid this case. containerLegacy.dispose(); @@ -429,7 +429,7 @@ for (const testOpts of testMatrix) { const { container: containerCurrent } = await clientCurrent1.createContainer( schemaCurrent, // Note: Only containers created in compatibility mode "1" may be loaded by legacy client. - "1", + "1.0.0", ); const containerId = await containerCurrent.attach(); @@ -470,7 +470,7 @@ for (const testOpts of testMatrix) { it(`Current AzureClient (mode: "2") can get container made by current AzureClient (mode: "1")`, async () => { const { container: containerCurrent1 } = await clientCurrent1.createContainer( schemaCurrent, - "1", + "1.0.0", ); const containerId = await containerCurrent1.attach(); @@ -486,7 +486,7 @@ for (const testOpts of testMatrix) { containerCurrent1.initialObjects.map1.set("key", "value"); - const resources = clientCurrent2.getContainer(containerId, schemaCurrent, "2"); + const resources = clientCurrent2.getContainer(containerId, schemaCurrent, "2.0.0"); await assert.doesNotReject(resources, () => true, "container could not be loaded"); const { container: containerCurrent2 } = await resources; @@ -512,7 +512,7 @@ for (const testOpts of testMatrix) { it(`Current AzureClient (mode: "1") can get container made by current AzureClient (mode: "2")`, async () => { const { container: containerCurrent2 } = await clientCurrent2.createContainer( schemaCurrent, - "2", + "2.0.0", ); const containerId = await containerCurrent2.attach(); @@ -528,7 +528,7 @@ for (const testOpts of testMatrix) { containerCurrent2.initialObjects.map1.set("key", "value"); - const resources = clientCurrent1.getContainer(containerId, schemaCurrent, "1"); + const resources = clientCurrent1.getContainer(containerId, schemaCurrent, "1.0.0"); await assert.doesNotReject(resources, () => true, "container could not be loaded"); const { container: containerCurrent1 } = await resources; @@ -549,7 +549,7 @@ for (const testOpts of testMatrix) { it("op grouping disabled as expected for 1.x clients", async () => { const { container: container1 } = await clientCurrent1.createContainer( schemaCurrent, - "1", + "1.0.0", ); const containerId = await container1.attach(); @@ -605,7 +605,7 @@ for (const testOpts of testMatrix) { } }); - for (const compatibilityMode of ["1", "2"] as const) { + for (const compatibilityMode of ["1.0.0", "2.0.0"] as const) { it(`op grouping works as expected (compatibilityMode: ${compatibilityMode})`, async () => { const { container: container1 } = await clientCurrent1.createContainer( schemaCurrent, @@ -660,7 +660,7 @@ for (const testOpts of testMatrix) { } } - if (compatibilityMode === "1") { + if (compatibilityMode === "1.0.0") { assert.strictEqual( groupedBatchCount, 0, @@ -706,7 +706,7 @@ describe("Container create in tree-only mode", () => { tree: SharedTree, }, }; - const { container } = await client.createContainer(schema, "2"); + const { container } = await client.createContainer(schema, "2.0.0"); assert(SharedTree.is(container.initialObjects.tree)); }); @@ -721,7 +721,7 @@ describe("Container create in tree-only mode", () => { }; await assert.rejects( - client.createContainer(schema, "2"), + client.createContainer(schema, "2.0.0"), (error: unknown) => { assert(error instanceof UsageError); assert.strictEqual(error.message, invalidSchemaErrorMessage); diff --git a/packages/service-clients/end-to-end-tests/azure-client/src/test/ddsTests.spec.ts b/packages/service-clients/end-to-end-tests/azure-client/src/test/ddsTests.spec.ts index c8dfdc2650d9..5e60c0959b97 100644 --- a/packages/service-clients/end-to-end-tests/azure-client/src/test/ddsTests.spec.ts +++ b/packages/service-clients/end-to-end-tests/azure-client/src/test/ddsTests.spec.ts @@ -54,9 +54,13 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container: newContainer } = await client.getContainer(containerId, schema, "2")); + ({ container: newContainer } = await client.getContainer( + containerId, + schema, + "2.0.0", + )); } else { - ({ container: newContainer } = await client.createContainer(schema, "2")); + ({ container: newContainer } = await client.createContainer(schema, "2.0.0")); containerId = await newContainer.attach(); } @@ -67,7 +71,7 @@ for (const testOpts of testMatrix) { }); } - const resources = client.getContainer(containerId, schema, "2"); + const resources = client.getContainer(containerId, schema, "2.0.0"); await assert.doesNotReject( resources, () => true, @@ -97,9 +101,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container } = await client.getContainer(containerId, schema, "2")); + ({ container } = await client.getContainer(containerId, schema, "2.0.0")); } else { - ({ container } = await client.createContainer(schema, "2")); + ({ container } = await client.createContainer(schema, "2.0.0")); containerId = await container.attach(); } @@ -115,7 +119,11 @@ for (const testOpts of testMatrix) { map1Create.set("new-key", "new-value"); const valueCreate: string | undefined = map1Create.get("new-key"); - const { container: containerGet } = await client.getContainer(containerId, schema, "2"); + const { container: containerGet } = await client.getContainer( + containerId, + schema, + "2.0.0", + ); const map1Get = containerGet.initialObjects.map1; const valueGet: string | undefined = await mapWait(map1Get, "new-key"); assert.strictEqual(valueGet, valueCreate, "container can't change initial objects"); @@ -142,9 +150,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container } = await client.getContainer(containerId, doSchema, "2")); + ({ container } = await client.getContainer(containerId, doSchema, "2.0.0")); } else { - ({ container } = await client.createContainer(doSchema, "2")); + ({ container } = await client.createContainer(doSchema, "2.0.0")); containerId = await container.attach(); } @@ -168,7 +176,7 @@ for (const testOpts of testMatrix) { const { container: containerGet } = await client.getContainer( containerId, doSchema, - "2", + "2.0.0", ); const initialObjectsGet = containerGet.initialObjects; assert( @@ -205,9 +213,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container } = await client.getContainer(containerId, doSchema, "2")); + ({ container } = await client.getContainer(containerId, doSchema, "2.0.0")); } else { - ({ container } = await client.createContainer(doSchema, "2")); + ({ container } = await client.createContainer(doSchema, "2.0.0")); containerId = await container.attach(); } @@ -235,7 +243,7 @@ for (const testOpts of testMatrix) { const { container: containerGet } = await client.getContainer( containerId, doSchema, - "2", + "2.0.0", ); const initialObjectsGet = containerGet.initialObjects; assert( @@ -274,7 +282,7 @@ for (const testOpts of testMatrix) { ); containerId = getContainerIdFromPayloadResponse(containerResponse); } else { - ({ container } = await client.createContainer(doSchema, "2")); + ({ container } = await client.createContainer(doSchema, "2.0.0")); const initialObjectsCreate = container.initialObjects; const mdo2 = initialObjectsCreate.mdo2 as CounterTestDataObject; @@ -297,7 +305,7 @@ for (const testOpts of testMatrix) { const { container: containerGet } = await client.getContainer( containerId, doSchema, - "2", + "2.0.0", ); const initialObjectsGet = containerGet.initialObjects; const mdo2get = initialObjectsGet.mdo2 as CounterTestDataObject; @@ -333,9 +341,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container } = await client.getContainer(containerId, dynamicSchema, "2")); + ({ container } = await client.getContainer(containerId, dynamicSchema, "2.0.0")); } else { - ({ container } = await client.createContainer(dynamicSchema, "2")); + ({ container } = await client.createContainer(dynamicSchema, "2.0.0")); containerId = await container.attach(); } diff --git a/packages/service-clients/end-to-end-tests/azure-client/src/test/multiprocess/childClient.tool.ts b/packages/service-clients/end-to-end-tests/azure-client/src/test/multiprocess/childClient.tool.ts index d8574fa2329a..1d94eef0c3b7 100644 --- a/packages/service-clients/end-to-end-tests/azure-client/src/test/multiprocess/childClient.tool.ts +++ b/packages/service-clients/end-to-end-tests/azure-client/src/test/multiprocess/childClient.tool.ts @@ -145,10 +145,14 @@ const getOrCreateContainer = async (params: { }); let services: AzureContainerServices; if (containerId === undefined) { - ({ container, services } = await client.createContainer(containerSchema, "2")); + ({ container, services } = await client.createContainer(containerSchema, "2.0.0")); containerId = await container.attach(); } else { - ({ container, services } = await client.getContainer(containerId, containerSchema, "2")); + ({ container, services } = await client.getContainer( + containerId, + containerSchema, + "2.0.0", + )); } container.on("disconnected", onDisconnected); diff --git a/packages/service-clients/end-to-end-tests/azure-client/src/test/signals.spec.ts b/packages/service-clients/end-to-end-tests/azure-client/src/test/signals.spec.ts index 098699380195..d770c1ee77a0 100644 --- a/packages/service-clients/end-to-end-tests/azure-client/src/test/signals.spec.ts +++ b/packages/service-clients/end-to-end-tests/azure-client/src/test/signals.spec.ts @@ -108,14 +108,14 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container, services } = await client.getContainer(containerId, schema, "2")); + ({ container, services } = await client.getContainer(containerId, schema, "2.0.0")); } else { - ({ container, services } = await client.createContainer(schema, "2")); + ({ container, services } = await client.createContainer(schema, "2.0.0")); containerId = await container.attach(); } } else { containerId = id; - ({ container, services } = await client.getContainer(containerId, schema, "2")); + ({ container, services } = await client.getContainer(containerId, schema, "2.0.0")); } if (container.connectionState !== ConnectionState.Connected) { diff --git a/packages/service-clients/end-to-end-tests/azure-client/src/test/tree.spec.ts b/packages/service-clients/end-to-end-tests/azure-client/src/test/tree.spec.ts index 10a3a2042f9f..a5d798e9227d 100644 --- a/packages/service-clients/end-to-end-tests/azure-client/src/test/tree.spec.ts +++ b/packages/service-clients/end-to-end-tests/azure-client/src/test/tree.spec.ts @@ -87,7 +87,7 @@ for (const testOpts of testMatrix) { let treeData: TreeView; if (summaryTree === undefined) { - const { container } = await client.createContainer(schema, "2"); + const { container } = await client.createContainer(schema, "2.0.0"); treeData = container.initialObjects.tree1.viewWith(treeConfiguration); treeData.initialize(new StringArray([])); containerId = await container.attach(); @@ -100,7 +100,7 @@ for (const testOpts of testMatrix) { ); containerId = getContainerIdFromPayloadResponse(containerResponse); - const { container } = await client.getContainer(containerId, schema, "2"); + const { container } = await client.getContainer(containerId, schema, "2.0.0"); treeData = container.initialObjects.tree1.viewWith(treeConfiguration); await waitForConnection(container); } @@ -137,7 +137,7 @@ for (const testOpts of testMatrix) { treeData.root.insertNew("test string 1"); - const resources = client.getContainer(containerId, schema, "2"); + const resources = client.getContainer(containerId, schema, "2.0.0"); await assert.doesNotReject( resources, () => true, @@ -172,7 +172,7 @@ for (const testOpts of testMatrix) { }) {} it("can read and edit data", async () => { - const { container } = await client.createContainer(schema, "2"); + const { container } = await client.createContainer(schema, "2.0.0"); await container.attach(); const view = container.initialObjects.tree1.viewWith( new TreeViewConfiguration({ schema: User, enableSchemaValidation: true }), @@ -213,7 +213,7 @@ for (const testOpts of testMatrix) { }); it("can handle undo/redo and transactions", async () => { - const { container } = await client.createContainer(schema, "2"); + const { container } = await client.createContainer(schema, "2.0.0"); await container.attach(); const view = asAlpha( container.initialObjects.tree1.viewWith( @@ -262,7 +262,7 @@ for (const testOpts of testMatrix) { it("can use identifiers and the static Tree APIs", async () => { class Widget extends sf.object("Widget", { id: sf.identifier }) {} - const { container } = await client.createContainer(schema, "2"); + const { container } = await client.createContainer(schema, "2.0.0"); await container.attach(); const view = container.initialObjects.tree1.viewWith( new TreeViewConfiguration({ @@ -297,7 +297,7 @@ for (const testOpts of testMatrix) { }) {} allowUnused>(); - const { container } = await client.createContainer(schema, "2"); + const { container } = await client.createContainer(schema, "2.0.0"); await container.attach(); const view = container.initialObjects.tree1.viewWith( new TreeViewConfiguration({ schema: Doll, enableSchemaValidation: true }), diff --git a/packages/service-clients/end-to-end-tests/azure-client/src/test/viewContainerVersion.spec.ts b/packages/service-clients/end-to-end-tests/azure-client/src/test/viewContainerVersion.spec.ts index 6c02cdc15440..4e0e499a5b70 100644 --- a/packages/service-clients/end-to-end-tests/azure-client/src/test/viewContainerVersion.spec.ts +++ b/packages/service-clients/end-to-end-tests/azure-client/src/test/viewContainerVersion.spec.ts @@ -63,9 +63,9 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container } = await client.getContainer(containerId, schema, "2")); + ({ container } = await client.getContainer(containerId, schema, "2.0.0")); } else { - ({ container } = await client.createContainer(schema, "2")); + ({ container } = await client.createContainer(schema, "2.0.0")); containerId = await container.attach(); } @@ -126,7 +126,7 @@ for (const testOpts of testMatrix) { ); containerId = getContainerIdFromPayloadResponse(containerResponse); } else { - ({ container } = await client.createContainer(schema, "2")); + ({ container } = await client.createContainer(schema, "2.0.0")); containerId = await container.attach(); if (container.connectionState !== ConnectionState.Connected) { @@ -143,7 +143,7 @@ for (const testOpts of testMatrix) { containerId, schema, versions[0], - "2", + "2.0.0", ); await assert.doesNotReject(viewContainerVersionAttempt); const { container: containerView } = await viewContainerVersionAttempt; @@ -169,10 +169,10 @@ for (const testOpts of testMatrix) { "test-user-name-1", ); containerId = getContainerIdFromPayloadResponse(containerResponse); - ({ container } = await client.getContainer(containerId, schema, "2")); + ({ container } = await client.getContainer(containerId, schema, "2.0.0")); map1 = container.initialObjects.map1 as SharedMap; } else { - ({ container } = await client.createContainer(schema, "2")); + ({ container } = await client.createContainer(schema, "2.0.0")); map1 = container.initialObjects.map1 as SharedMap; map1.set(testKey, expectedValue); @@ -197,7 +197,7 @@ for (const testOpts of testMatrix) { containerId, schema, versions[versions.length - 1], - "2", + "2.0.0", ); await assert.doesNotReject(viewContainerVersionAttempt); const { container: containerView } = await viewContainerVersionAttempt; @@ -216,7 +216,7 @@ for (const testOpts of testMatrix) { { id: "whatever", }, - "2", + "2.0.0", ); const errorFn = (error: Error): boolean => { assert.notStrictEqual(error.message, undefined, "Azure Client error is undefined"); diff --git a/packages/service-clients/odsp-client/src/odspClient.ts b/packages/service-clients/odsp-client/src/odspClient.ts index db8690c54095..1f5868169abd 100644 --- a/packages/service-clients/odsp-client/src/odspClient.ts +++ b/packages/service-clients/odsp-client/src/odspClient.ts @@ -166,7 +166,7 @@ export class OdspClient { private getLoaderProps(schema: ContainerSchema): ILoaderProps { const runtimeFactory = createDOProviderContainerRuntimeFactory({ schema, - compatibilityMode: "2", + compatibilityMode: "2.0.0", }); const load = async (): Promise => { return { diff --git a/packages/service-clients/tinylicious-client/api-report/tinylicious-client.alpha.api.md b/packages/service-clients/tinylicious-client/api-report/tinylicious-client.alpha.api.md index 52ea8da37ab4..a0ad08f545ac 100644 --- a/packages/service-clients/tinylicious-client/api-report/tinylicious-client.alpha.api.md +++ b/packages/service-clients/tinylicious-client/api-report/tinylicious-client.alpha.api.md @@ -12,11 +12,11 @@ export type ITinyliciousAudience = IServiceAudience; // @public @sealed export class TinyliciousClient { constructor(properties?: TinyliciousClientProps); - createContainer(containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + createContainer(containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: TinyliciousContainerServices; }>; - getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: TinyliciousContainerServices; }>; diff --git a/packages/service-clients/tinylicious-client/api-report/tinylicious-client.beta.api.md b/packages/service-clients/tinylicious-client/api-report/tinylicious-client.beta.api.md index d6facf41cd8a..1c4f1237ef04 100644 --- a/packages/service-clients/tinylicious-client/api-report/tinylicious-client.beta.api.md +++ b/packages/service-clients/tinylicious-client/api-report/tinylicious-client.beta.api.md @@ -12,11 +12,11 @@ export type ITinyliciousAudience = IServiceAudience; // @public @sealed export class TinyliciousClient { constructor(properties?: TinyliciousClientProps); - createContainer(containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + createContainer(containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: TinyliciousContainerServices; }>; - getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: TinyliciousContainerServices; }>; diff --git a/packages/service-clients/tinylicious-client/api-report/tinylicious-client.public.api.md b/packages/service-clients/tinylicious-client/api-report/tinylicious-client.public.api.md index a9336956c0da..cd30b58e584e 100644 --- a/packages/service-clients/tinylicious-client/api-report/tinylicious-client.public.api.md +++ b/packages/service-clients/tinylicious-client/api-report/tinylicious-client.public.api.md @@ -12,11 +12,11 @@ export type ITinyliciousAudience = IServiceAudience; // @public @sealed export class TinyliciousClient { constructor(properties?: TinyliciousClientProps); - createContainer(containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + createContainer(containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: TinyliciousContainerServices; }>; - getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: CompatibilityMode): Promise<{ + getContainer(id: string, containerSchema: TContainerSchema, compatibilityMode: MinimumVersionForCollab | CompatibilityMode): Promise<{ container: IFluidContainer; services: TinyliciousContainerServices; }>; diff --git a/packages/service-clients/tinylicious-client/package.json b/packages/service-clients/tinylicious-client/package.json index 494a3ae9b602..5f581c825889 100644 --- a/packages/service-clients/tinylicious-client/package.json +++ b/packages/service-clients/tinylicious-client/package.json @@ -93,6 +93,7 @@ "@fluidframework/fluid-static": "workspace:~", "@fluidframework/map": "workspace:~", "@fluidframework/routerlicious-driver": "workspace:~", + "@fluidframework/runtime-definitions": "workspace:~", "@fluidframework/runtime-utils": "workspace:~", "@fluidframework/telemetry-utils": "workspace:~", "@fluidframework/tinylicious-driver": "workspace:~" diff --git a/packages/service-clients/tinylicious-client/src/TinyliciousClient.ts b/packages/service-clients/tinylicious-client/src/TinyliciousClient.ts index 8e30c30194fc..1e06bc2fe75b 100644 --- a/packages/service-clients/tinylicious-client/src/TinyliciousClient.ts +++ b/packages/service-clients/tinylicious-client/src/TinyliciousClient.ts @@ -22,6 +22,7 @@ import type { import type { ContainerSchema, IFluidContainer, + // eslint-disable-next-line import-x/no-deprecated CompatibilityMode, } from "@fluidframework/fluid-static"; import { @@ -30,6 +31,7 @@ import { createServiceAudience, } from "@fluidframework/fluid-static/internal"; import { RouterliciousDocumentServiceFactory } from "@fluidframework/routerlicious-driver/internal"; +import type { MinimumVersionForCollab } from "@fluidframework/runtime-definitions"; import { wrapConfigProviderWithDefaults } from "@fluidframework/telemetry-utils/internal"; import { InsecureTinyliciousTokenProvider, @@ -72,12 +74,16 @@ export class TinyliciousClient { /** * Creates a new detached container instance in Tinylicious server. * @param containerSchema - Container schema for the new container. - * @param compatibilityMode - Compatibility mode the container should run in. + * @param compatibilityMode - Minimum framework version required for collaboration. Accepts + * either a `MinimumVersionForCollab` semver string (e.g. `"1.0.0"`, `"2.0.0"`) or a legacy + * {@link @fluidframework/fluid-static#CompatibilityMode} value. The legacy values `"1"` and + * `"2"` are **deprecated** equivalents of `"1.0.0"` and `"2.0.0"`. * @returns New detached container instance along with associated services. */ public async createContainer( containerSchema: TContainerSchema, - compatibilityMode: CompatibilityMode, + // eslint-disable-next-line import-x/no-deprecated + compatibilityMode: MinimumVersionForCollab | CompatibilityMode, ): Promise<{ container: IFluidContainer; services: TinyliciousContainerServices; @@ -123,13 +129,17 @@ export class TinyliciousClient { * Accesses the existing container given its unique ID in the tinylicious server. * @param id - Unique ID of the container. * @param containerSchema - Container schema used to access data objects in the container. - * @param compatibilityMode - Compatibility mode the container should run in. + * @param compatibilityMode - Minimum Fluid Framework version required for collaboration. Accepts + * either a `MinimumVersionForCollab` semver string (e.g. `"1.0.0"`, `"2.0.0"`) or a legacy + * {@link @fluidframework/fluid-static#CompatibilityMode} value. The legacy values `"1"` and + * `"2"` are **deprecated** equivalents of `"1.0.0"` and `"2.0.0"`. * @returns Existing container instance along with associated services. */ public async getContainer( id: string, containerSchema: TContainerSchema, - compatibilityMode: CompatibilityMode, + // eslint-disable-next-line import-x/no-deprecated + compatibilityMode: MinimumVersionForCollab | CompatibilityMode, ): Promise<{ container: IFluidContainer; services: TinyliciousContainerServices; @@ -155,7 +165,8 @@ export class TinyliciousClient { private getLoaderProps( schema: ContainerSchema, - compatibilityMode: CompatibilityMode, + // eslint-disable-next-line import-x/no-deprecated + compatibilityMode: MinimumVersionForCollab | CompatibilityMode, ): ILoaderProps { const containerRuntimeFactory = createDOProviderContainerRuntimeFactory({ schema, diff --git a/packages/service-clients/tinylicious-client/src/test/TinyliciousClient.spec.ts b/packages/service-clients/tinylicious-client/src/test/TinyliciousClient.spec.ts index e90f44a20564..26ed4173d9c0 100644 --- a/packages/service-clients/tinylicious-client/src/test/TinyliciousClient.spec.ts +++ b/packages/service-clients/tinylicious-client/src/test/TinyliciousClient.spec.ts @@ -50,7 +50,7 @@ const waitForDataCorruption = async (container: IFluidContainer): Promise }), ); -for (const compatibilityMode of ["1", "2"] as const) { +for (const compatibilityMode of ["1.0.0", "2.0.0"] as const) { describe(`TinyliciousClient (compatibilityMode: ${compatibilityMode})`, function () { let tinyliciousClient: TinyliciousClient; const schema = { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 61befecbce85..46291d7e573e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11485,6 +11485,9 @@ importers: '@fluidframework/tree': specifier: workspace:~ version: link:../../dds/tree + semver-ts: + specifier: ^1.0.3 + version: 1.0.3 devDependencies: '@arethetypeswrong/cli': specifier: ^0.18.2 @@ -13745,6 +13748,9 @@ importers: '@fluidframework/routerlicious-driver': specifier: workspace:~ version: link:../../drivers/routerlicious-driver + '@fluidframework/runtime-definitions': + specifier: workspace:~ + version: link:../../runtime/runtime-definitions '@fluidframework/telemetry-utils': specifier: workspace:~ version: link:../../utils/telemetry-utils @@ -14208,6 +14214,9 @@ importers: '@fluidframework/routerlicious-driver': specifier: workspace:~ version: link:../../drivers/routerlicious-driver + '@fluidframework/runtime-definitions': + specifier: workspace:~ + version: link:../../runtime/runtime-definitions '@fluidframework/runtime-utils': specifier: workspace:~ version: link:../../runtime/runtime-utils