Skip to content

Commit 5e87573

Browse files
StagingMode: Unify exposed interfaces on legacy alpha (#25721)
This change moves the remaining experimental Staging mode interface to `@legacy @alpha`. The update also refactors usages of staging mode and related types throughout the codebase to use the new interface and supporting types. Additionally, API extraction and package configuration are updated to support the new alpha interface and its reporting. **Interface and API changes:** * Removed the deprecated `IFluidDataStoreRuntimeExperimental` interface and replaced it with `IFluidDataStoreRuntimeAlpha`, which now provides non-optional `inStagingMode` and `isDirty` properties and is marked as `@legacy @alpha`. * Updated all references and type imports from `IFluidDataStoreRuntimeExperimental` to `IFluidDataStoreRuntimeAlpha` in code and tests, including `handle.ts`, `dataStore.ts`, and `dataStoreRuntime.ts`. **Staging mode and runtime changes:** * Refactored staging mode logic to use the new `asLegacyAlpha` helper and the updated internal types (`StageControlsInternal`, `IContainerRuntimeBaseInternal`) instead of deprecated experimental types. --------- Co-authored-by: Joshua Smithrud <[email protected]>
1 parent 5721d4a commit 5e87573

29 files changed

+412
-155
lines changed

packages/dds/shared-object-base/src/handle.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55

66
import type { IFluidHandleInternal } from "@fluidframework/core-interfaces/internal";
77
import { FluidObjectHandle } from "@fluidframework/datastore/internal";
8-
// eslint-disable-next-line import/no-deprecated
9-
import type { IFluidDataStoreRuntimeExperimental } from "@fluidframework/datastore-definitions/internal";
10-
import { isFluidHandle } from "@fluidframework/runtime-utils";
8+
import type { IFluidDataStoreRuntime } from "@fluidframework/datastore-definitions/internal";
9+
import { isFluidHandle, asLegacyAlpha } from "@fluidframework/runtime-utils/internal";
1110

1211
import type { ISharedObject } from "./types.js";
1312

@@ -92,8 +91,7 @@ export class SharedObjectHandle
9291
constructor(
9392
protected readonly value: ISharedObject,
9493
path: string,
95-
// eslint-disable-next-line import/no-deprecated
96-
private readonly runtime: IFluidDataStoreRuntimeExperimental,
94+
private readonly runtime: IFluidDataStoreRuntime,
9795
) {
9896
super(value, path, runtime.IFluidHandleContext);
9997
}
@@ -125,7 +123,7 @@ export class SharedObjectHandle
125123
// We don't bind handles in staging mode to defer the attachment of any new objects
126124
// until we've exited staging mode. This way if we discard changes or a new handle is not present in the final
127125
// committed state, we will never end up attaching the discarded object.
128-
if (this.runtime.inStagingMode === true) {
126+
if (asLegacyAlpha(this.runtime).inStagingMode === true) {
129127
return;
130128
}
131129

packages/runtime/container-runtime/src/containerRuntime.ts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,8 @@ import type {
121121
IInboundSignalMessage,
122122
IRuntimeMessagesContent,
123123
ISummarizerNodeWithGC,
124-
// eslint-disable-next-line import/no-deprecated
125-
StageControlsExperimental,
126-
// eslint-disable-next-line import/no-deprecated
127-
IContainerRuntimeBaseExperimental,
124+
StageControlsInternal,
125+
IContainerRuntimeBaseInternal,
128126
IFluidParentContext,
129127
MinimumVersionForCollab,
130128
} from "@fluidframework/runtime-definitions/internal";
@@ -818,8 +816,7 @@ export class ContainerRuntime
818816
extends TypedEventEmitter<IContainerRuntimeEvents>
819817
implements
820818
IContainerRuntimeInternal,
821-
// eslint-disable-next-line import/no-deprecated
822-
IContainerRuntimeBaseExperimental,
819+
IContainerRuntimeBaseInternal,
823820
// eslint-disable-next-line import/no-deprecated
824821
IContainerRuntimeWithResolveHandle_Deprecated,
825822
IRuntime,
@@ -3509,8 +3506,7 @@ export class ContainerRuntime
35093506
*/
35103507
public orderSequentially<T>(callback: () => T): T {
35113508
let checkpoint: IBatchCheckpoint | undefined;
3512-
// eslint-disable-next-line import/no-deprecated
3513-
let stageControls: StageControlsExperimental | undefined;
3509+
let stageControls: StageControlsInternal | undefined;
35143510
if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback") === true) {
35153511
if (!this.batchRunner.running && !this.inStagingMode) {
35163512
stageControls = this.enterStagingMode();
@@ -3574,8 +3570,7 @@ export class ContainerRuntime
35743570
return result;
35753571
}
35763572

3577-
// eslint-disable-next-line import/no-deprecated
3578-
private stageControls: StageControlsExperimental | undefined;
3573+
private stageControls: StageControlsInternal | undefined;
35793574

35803575
/**
35813576
* If true, the ContainerRuntime is not submitting any new ops to the ordering service.
@@ -3590,10 +3585,9 @@ export class ContainerRuntime
35903585
* Enter Staging Mode, such that ops submitted to the ContainerRuntime will not be sent to the ordering service.
35913586
* To exit Staging Mode, call either discardChanges or commitChanges on the Stage Controls returned from this method.
35923587
*
3593-
* @returns StageControlsExperimental - Controls for exiting Staging Mode.
3588+
* @returns Controls for exiting Staging Mode.
35943589
*/
3595-
// eslint-disable-next-line import/no-deprecated
3596-
public enterStagingMode = (): StageControlsExperimental => {
3590+
public enterStagingMode = (): StageControlsInternal => {
35973591
if (this.stageControls !== undefined) {
35983592
throw new UsageError("Already in staging mode");
35993593
}
@@ -3626,8 +3620,7 @@ export class ContainerRuntime
36263620
}
36273621
};
36283622

3629-
// eslint-disable-next-line import/no-deprecated
3630-
const stageControls: StageControlsExperimental = {
3623+
const stageControls: StageControlsInternal = {
36313624
discardChanges: () =>
36323625
exitStagingMode(() => {
36333626
// Pop all staged batches from the PSM and roll them back in LIFO order

packages/runtime/container-runtime/src/dataStore.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ import { AttachState } from "@fluidframework/container-definitions";
77
import type { FluidObject } from "@fluidframework/core-interfaces";
88
import type { IFluidHandleInternal } from "@fluidframework/core-interfaces/internal";
99
import { assert, unreachableCase } from "@fluidframework/core-utils/internal";
10-
import type {
11-
AliasResult,
12-
IDataStore,
13-
IFluidDataStoreChannel,
14-
// eslint-disable-next-line import/no-deprecated
15-
IContainerRuntimeBaseExperimental,
10+
import {
11+
type AliasResult,
12+
type IDataStore,
13+
type IFluidDataStoreChannel,
14+
asLegacyAlpha,
1615
} from "@fluidframework/runtime-definitions/internal";
1716
import {
1817
type ITelemetryLoggerExt,
@@ -80,9 +79,7 @@ class DataStore implements IDataStore {
8079
if (alias.includes("/")) {
8180
throw new UsageError(`The alias cannot contain slashes: '${alias}'`);
8281
}
83-
// eslint-disable-next-line import/no-deprecated
84-
const runtime = this.parentContext.containerRuntime as IContainerRuntimeBaseExperimental;
85-
if (runtime.inStagingMode === true) {
82+
if (asLegacyAlpha(this.parentContext.containerRuntime).inStagingMode === true) {
8683
throw new UsageError("Cannot set aliases while in staging mode");
8784
}
8885

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3+
"extends": "<projectFolder>/../../../common/build/build-common/api-extractor-lint.entrypoint.json",
4+
"mainEntryPointFilePath": "<projectFolder>/dist/legacyAlpha.d.ts"
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3+
"extends": "<projectFolder>/../../../common/build/build-common/api-extractor-lint.entrypoint.json",
4+
"mainEntryPointFilePath": "<projectFolder>/lib/legacyAlpha.d.ts"
5+
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
22
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3-
"extends": "<projectFolder>/../../../common/build/build-common/api-extractor-report.esm.legacy.json"
3+
"extends": "<projectFolder>/../../../common/build/build-common/api-extractor-report.esm.legacy.json",
4+
"mainEntryPointFilePath": "<projectFolder>/lib/legacyAlpha.d.ts",
5+
"apiReport": {
6+
"reportVariants": ["public", "beta", "alpha"]
7+
}
48
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
## Alpha API Report File for "@fluidframework/datastore-definitions"
2+
3+
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
4+
5+
```ts
6+
7+
// @beta @legacy
8+
export interface IChannel extends IFluidLoadable {
9+
// (undocumented)
10+
readonly attributes: IChannelAttributes;
11+
connect(services: IChannelServices): void;
12+
getAttachSummary(fullTree?: boolean, trackState?: boolean, telemetryContext?: ITelemetryContext): ISummaryTreeWithStats;
13+
getGCData(fullGC?: boolean): IGarbageCollectionData;
14+
readonly id: string;
15+
isAttached(): boolean;
16+
summarize(fullTree?: boolean, trackState?: boolean, telemetryContext?: ITelemetryContext, incrementalSummaryContext?: IExperimentalIncrementalSummaryContext): Promise<ISummaryTreeWithStats>;
17+
}
18+
19+
// @beta @legacy
20+
export interface IChannelAttributes {
21+
readonly packageVersion?: string;
22+
readonly snapshotFormatVersion: string;
23+
readonly type: string;
24+
}
25+
26+
// @beta @legacy
27+
export interface IChannelFactory<out TChannel = unknown> {
28+
readonly attributes: IChannelAttributes;
29+
create(runtime: IFluidDataStoreRuntime, id: string): TChannel & IChannel;
30+
load(runtime: IFluidDataStoreRuntime, id: string, services: IChannelServices, channelAttributes: Readonly<IChannelAttributes>): Promise<TChannel & IChannel>;
31+
readonly type: string;
32+
}
33+
34+
// @beta @legacy
35+
export interface IChannelServices {
36+
// (undocumented)
37+
deltaConnection: IDeltaConnection;
38+
// (undocumented)
39+
objectStorage: IChannelStorageService;
40+
}
41+
42+
// @beta @legacy
43+
export interface IChannelStorageService {
44+
contains(path: string): Promise<boolean>;
45+
getSnapshotTree(): ISnapshotTree | undefined;
46+
list(path: string): Promise<string[]>;
47+
readBlob(path: string): Promise<ArrayBufferLike>;
48+
}
49+
50+
// @beta @legacy
51+
export interface IDeltaConnection {
52+
attach(handler: IDeltaHandler): void;
53+
// (undocumented)
54+
connected: boolean;
55+
dirty(): void;
56+
submit(messageContent: any, localOpMetadata: unknown): void;
57+
}
58+
59+
// @beta @legacy
60+
export interface IDeltaHandler {
61+
applyStashedOp(message: any): void;
62+
processMessages: (messageCollection: IRuntimeMessageCollection) => void;
63+
reSubmit(message: any, localOpMetadata: unknown, squash?: boolean): void;
64+
rollback?(message: any, localOpMetadata: unknown): void;
65+
setConnectionState(connected: boolean): void;
66+
}
67+
68+
// @beta @legacy
69+
export type IDeltaManagerErased = ErasedType<"@fluidframework/container-definitions.IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>">;
70+
71+
// @beta @sealed @legacy
72+
export interface IFluidDataStoreRuntime extends IEventProvider<IFluidDataStoreRuntimeEvents>, IDisposable {
73+
addChannel(channel: IChannel): void;
74+
readonly attachState: AttachState;
75+
bindChannel(channel: IChannel): void;
76+
// (undocumented)
77+
readonly channelsRoutingContext: IFluidHandleContext;
78+
// (undocumented)
79+
readonly clientId: string | undefined;
80+
// (undocumented)
81+
readonly connected: boolean;
82+
createChannel(id: string | undefined, type: string): IChannel;
83+
// (undocumented)
84+
readonly deltaManager: IDeltaManagerErased;
85+
readonly entryPoint: IFluidHandle<FluidObject>;
86+
getAudience(): IAudience;
87+
getChannel(id: string): Promise<IChannel>;
88+
getQuorum(): IQuorumClients;
89+
// (undocumented)
90+
readonly id: string;
91+
readonly idCompressor: IIdCompressor | undefined;
92+
// (undocumented)
93+
readonly IFluidHandleContext: IFluidHandleContext;
94+
readonly isReadOnly: () => boolean;
95+
// (undocumented)
96+
readonly logger: ITelemetryBaseLogger;
97+
// (undocumented)
98+
readonly objectsRoutingContext: IFluidHandleContext;
99+
// (undocumented)
100+
readonly options: Record<string | number, any>;
101+
// (undocumented)
102+
readonly rootRoutingContext: IFluidHandleContext;
103+
submitSignal: (type: string, content: unknown, targetClientId?: string) => void;
104+
uploadBlob(blob: ArrayBufferLike, signal?: AbortSignal): Promise<IFluidHandle<ArrayBufferLike>>;
105+
waitAttached(): Promise<void>;
106+
}
107+
108+
// @alpha @sealed @legacy (undocumented)
109+
export interface IFluidDataStoreRuntimeAlpha extends IFluidDataStoreRuntime {
110+
// (undocumented)
111+
readonly inStagingMode: boolean;
112+
// (undocumented)
113+
readonly isDirty: boolean;
114+
}
115+
116+
// @beta @legacy
117+
export interface IFluidDataStoreRuntimeEvents extends IEvent {
118+
// (undocumented)
119+
(event: "disconnected", listener: () => void): any;
120+
// (undocumented)
121+
(event: "dispose", listener: () => void): any;
122+
// (undocumented)
123+
(event: "attaching", listener: () => void): any;
124+
// (undocumented)
125+
(event: "attached", listener: () => void): any;
126+
// (undocumented)
127+
(event: "op", listener: (message: ISequencedDocumentMessage) => void): any;
128+
// (undocumented)
129+
(event: "signal", listener: (message: IInboundSignalMessage, local: boolean) => void): any;
130+
// (undocumented)
131+
(event: "connected", listener: (clientId: string) => void): any;
132+
// (undocumented)
133+
(event: "readonly", listener: (isReadOnly: boolean) => void): any;
134+
}
135+
136+
// @beta @legacy (undocumented)
137+
export interface Internal_InterfaceOfJsonableTypesWith<T> {
138+
// (undocumented)
139+
[index: string | number]: JsonableTypeWith<T>;
140+
}
141+
142+
// @beta @legacy
143+
export type Jsonable<T, TReplaced = never> = boolean extends (T extends never ? true : false) ? JsonableTypeWith<TReplaced> : unknown extends T ? JsonableTypeWith<TReplaced> : T extends undefined | null | boolean | number | string | TReplaced ? T : Extract<T, Function> extends never ? T extends object ? T extends (infer U)[] ? Jsonable<U, TReplaced>[] : {
144+
[K in keyof T]: Extract<K, symbol> extends never ? Jsonable<T[K], TReplaced> : never;
145+
} : never : never;
146+
147+
// @beta @legacy
148+
export type JsonableTypeWith<T> = undefined | null | boolean | number | string | T | Internal_InterfaceOfJsonableTypesWith<T> | ArrayLike<JsonableTypeWith<T>>;
149+
150+
// @beta @legacy
151+
export type Serializable<T> = Jsonable<T, IFluidHandle>;
152+
153+
```

packages/runtime/datastore-definitions/api-report/datastore-definitions.legacy.beta.api.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,6 @@ export interface IFluidDataStoreRuntimeEvents extends IEvent {
125125
(event: "readonly", listener: (isReadOnly: boolean) => void): any;
126126
}
127127

128-
// @beta @sealed @deprecated @legacy (undocumented)
129-
export interface IFluidDataStoreRuntimeExperimental extends IFluidDataStoreRuntime {
130-
// (undocumented)
131-
readonly inStagingMode?: boolean;
132-
// (undocumented)
133-
readonly isDirty?: boolean;
134-
}
135-
136128
// @beta @legacy (undocumented)
137129
export interface Internal_InterfaceOfJsonableTypesWith<T> {
138130
// (undocumented)

packages/runtime/datastore-definitions/package.json

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@
2929
"types": "./dist/legacy.d.ts"
3030
}
3131
},
32+
"./legacy/alpha": {
33+
"import": {
34+
"types": "./lib/legacyAlpha.d.ts"
35+
},
36+
"require": {
37+
"types": "./dist/legacyAlpha.d.ts"
38+
}
39+
},
3240
"./internal": {
3341
"import": {
3442
"types": "./lib/index.d.ts"
@@ -42,8 +50,8 @@
4250
"types": "lib/public.d.ts",
4351
"scripts": {
4452
"api": "fluid-build . --task api",
45-
"api-extractor:commonjs": "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./dist",
46-
"api-extractor:esnext": "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat",
53+
"api-extractor:commonjs": "flub generate entrypoints --outFileLegacyBeta legacy --outFileLegacyAlpha legacyAlpha --outDir ./dist",
54+
"api-extractor:esnext": "flub generate entrypoints --outFileLegacyBeta legacy --outFileLegacyAlpha legacyAlpha --outDir ./lib --node10TypeCompat",
4755
"build": "fluid-build . --task build",
4856
"build:api-reports": "concurrently \"npm:build:api-reports:*\"",
4957
"build:api-reports:current": "api-extractor run --local --config api-extractor/api-extractor.current.json",
@@ -59,8 +67,10 @@
5967
"check:exports": "concurrently \"npm:check:exports:*\"",
6068
"check:exports:bundle-release-tags": "api-extractor run --config api-extractor/api-extractor-lint-bundle.json",
6169
"check:exports:cjs:legacy": "api-extractor run --config api-extractor/api-extractor-lint-legacy.cjs.json",
70+
"check:exports:cjs:legacyAlpha": "api-extractor run --config api-extractor/api-extractor-lint-legacyAlpha.cjs.json",
6271
"check:exports:cjs:public": "api-extractor run --config api-extractor/api-extractor-lint-public.cjs.json",
6372
"check:exports:esm:legacy": "api-extractor run --config api-extractor/api-extractor-lint-legacy.esm.json",
73+
"check:exports:esm:legacyAlpha": "api-extractor run --config api-extractor/api-extractor-lint-legacyAlpha.esm.json",
6474
"check:exports:esm:public": "api-extractor run --config api-extractor/api-extractor-lint-public.esm.json",
6575
"check:format": "npm run check:biome",
6676
"ci:build:api-reports": "concurrently \"npm:ci:build:api-reports:*\"",
@@ -102,6 +112,9 @@
102112
},
103113
"typeValidation": {
104114
"broken": {
115+
"Interface_IFluidDataStoreRuntimeExperimental": {
116+
"backCompat": false
117+
},
105118
"Interface_IChannelServices": {
106119
"forwardCompat": false
107120
},

packages/runtime/datastore-definitions/src/dataStoreRuntime.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,12 @@ export interface IFluidDataStoreRuntime
177177
}
178178

179179
/**
180-
* @experimental
181-
* @deprecated These APIs are unstable, and can be changed at will. They should only be used with direct agreement with the Fluid Framework.
182-
* @legacy @beta
180+
* @legacy @alpha
183181
* @sealed
184182
*/
185-
export interface IFluidDataStoreRuntimeExperimental extends IFluidDataStoreRuntime {
186-
readonly inStagingMode?: boolean;
187-
readonly isDirty?: boolean;
183+
export interface IFluidDataStoreRuntimeAlpha extends IFluidDataStoreRuntime {
184+
readonly inStagingMode: boolean;
185+
readonly isDirty: boolean;
188186
}
189187

190188
/**

0 commit comments

Comments
 (0)