Core base classes for creating Fluid objects with different levels of built-in functionality. These abstract classes provide the foundation for building collaborative data objects with lifecycle management, provider integration, and varying degrees of built-in shared data structure support.
The most basic data object base class providing essential functionality for Fluid object creation and lifecycle management.
/**
* Bare-bones base class providing basic setup and factory initialization functionality.
* Most developers should use DataObject instead unless creating another base data store class.
* @typeParam I - The optional input types used to strongly type the data object
*/
abstract class PureDataObject<I extends DataObjectTypes = DataObjectTypes>
extends TypedEventEmitter<I["Events"] & IEvent>
implements IFluidLoadable, IProvideFluidHandleKey Properties:
/** FluidDataStoreRuntime object for managing the data object */
protected readonly runtime: IFluidDataStoreRuntime;
/** Context for communicating with the IContainerRuntime */
protected readonly context: IFluidDataStoreContext;
/** FluidObject keyed providers for dependency injection */
protected readonly providers: AsyncFluidObjectProvider<I["OptionalProviders"]>;
/** Optional initial properties passed during creation */
protected initProps?: I["InitialState"];
/** Data store identifier */
public get id(): string;
/** IFluidLoadable implementation */
public get IFluidLoadable(): this;
/** IFluidHandle implementation */
public get IFluidHandle(): IFluidHandleInternal<this>;
/** Handle to the data store */
public get handle(): IFluidHandleInternal<this>;Core Methods:
/**
* Ensure PureDataObject is fully initialized. Called automatically by factory.
* @param existing - Whether this is loading from an existing data store
*/
public async finishInitialization(existing: boolean): Promise<void>;
/**
* Handle requests to the data object. Returns this object for "/" and "" URLs.
* @param req - The request to handle
*/
public async request(req: IRequest): Promise<IResponse>;
/**
* Static factory method for getting data object from runtime
* @param runtime - The FluidDataStoreRuntime
*/
public static async getDataObject(runtime: IFluidDataStoreRuntime): Promise<PureDataObject>;Lifecycle Methods:
/** Called every time before initialization */
protected async preInitialize(): Promise<void>;
/**
* Called only the first time a data object is initialized
* @param props - Optional props passed during creation
*/
protected async initializingFirstTime(props?: I["InitialState"]): Promise<void>;
/** Called every time except the first time a data object is initialized */
protected async initializingFromExisting(): Promise<void>;
/** Called every time after initialization is complete */
protected async hasInitialized(): Promise<void>;
/** Internal initialization implementation - should not be overridden */
public async initializeInternal(existing: boolean): Promise<void>;Usage Example:
class MyPureDataObject extends PureDataObject {
protected async initializingFirstTime() {
// Initialize any data structures or state for new instances
}
protected async initializingFromExisting() {
// Load existing data structures or state
}
protected async hasInitialized() {
// Perform final setup after initialization
}
}Enhanced data object base class that extends PureDataObject with a built-in root SharedDirectory for easier data structure management.
/**
* DataObject extends PureDataObject with a root directory for easier development.
* Having a single root directory allows for easier development by automatically
* registering any new DDS set on the root.
* @typeParam I - The optional input types used to strongly type the data object
*/
abstract class DataObject<I extends DataObjectTypes = DataObjectTypes> extends PureDataObject<I>Additional Properties:
/**
* The root SharedDirectory for storing handles to other data structures.
* Automatically created and ready for use.
*/
protected get root(): ISharedDirectory;Additional Methods:
/**
* Override of initializeInternal that sets up the root directory
* @param existing - Whether loading from existing data store
*/
public override async initializeInternal(existing: boolean): Promise<void>;
/**
* Generates error messages for uninitialized items
* @param item - Name of the uninitialized item
*/
protected getUninitializedErrorString(item: string): string;Usage Example:
class ClickerDataObject extends DataObject {
private _counter: SharedCounter | undefined;
protected async initializingFirstTime() {
// Create and store a SharedCounter in the root directory
const counter = SharedCounter.create(this.runtime);
this.root.set("clicks", counter.handle);
}
protected async hasInitialized() {
// Retrieve the SharedCounter from the root directory
const counterHandle = this.root.get<IFluidHandle<SharedCounter>>("clicks");
this._counter = await counterHandle.get();
}
public get counter() {
if (this._counter === undefined) {
throw new Error(this.getUninitializedErrorString("counter"));
}
return this._counter;
}
}Advanced data object base class backed by a SharedTree for managing hierarchical, tree-structured collaborative data.
/**
* A data object backed by a SharedTree for hierarchical data structures.
* Implementers must apply appropriate view schemas to access tree data.
* @typeParam TDataObjectTypes - The optional input types used to strongly type the data object
*/
abstract class TreeDataObject<TDataObjectTypes extends DataObjectTypes = DataObjectTypes>
extends PureDataObject<TDataObjectTypes>Key Properties:
/**
* The underlying SharedTree instance. Created once during initialization.
* Access requires proper view schema application.
*/
protected get tree(): ITree;Core Methods:
/**
* Override of initializeInternal that sets up the SharedTree
* @param existing - Whether loading from existing data store
*/
public override async initializeInternal(existing: boolean): Promise<void>;Usage Example:
class DocumentDataObject extends TreeDataObject {
private treeView: TreeViewWithEvents<typeof DocumentSchema> | undefined;
protected override async initializingFirstTime(): Promise<void> {
// Generate the schema-aware view of the tree for new documents
this.treeView = this.tree.viewWith(DocumentSchema);
// Initialize the tree with initial data
this.treeView.initialize({
title: "New Document",
content: "",
sections: []
});
}
protected override async initializingFromExisting(): Promise<void> {
// Generate the schema-aware view for existing documents
this.treeView = this.tree.viewWith(DocumentSchema);
// Ensure the loaded tree is compatible with the view schema
if (!this.treeView.compatibility.canView) {
throw new Error("Document schema is incompatible");
}
}
public get document() {
if (this.treeView === undefined) {
throw new Error("Tree view not initialized");
}
return this.treeView.root;
}
}/**
* Base generic input type for DataObject and PureDataObject configuration
*/
interface DataObjectTypes {
/** Optional providers that will be injected via dependency injection */
OptionalProviders?: FluidObject;
/** Initial state type that the data object may receive during creation */
InitialState?: any;
/** Events that will be available in the EventForwarder */
Events?: IEvent;
}/**
* Construction properties passed to data object constructors
*/
interface IDataObjectProps<I extends DataObjectTypes = DataObjectTypes> {
/** The FluidDataStoreRuntime for this data object */
readonly runtime: IFluidDataStoreRuntime;
/** The FluidDataStoreContext for container communication */
readonly context: IFluidDataStoreContext;
/** Resolved providers based on factory configuration */
readonly providers: AsyncFluidObjectProvider<I["OptionalProviders"]>;
/** Optional initial state passed during creation */
readonly initProps?: I["InitialState"];
}/**
* Type representing an object that has a factory capable of creating data objects.
* Used for strong typing in advanced scenarios.
*/
type DataObjectKind<T = unknown> = {
readonly factory: IFluidDataStoreFactory;
} & (
| {
readonly makeCovariant?: T | undefined;
}
| (new (...args: never[]) => T)
);/**
* Utility function for creating SharedObjectKind instances for data objects.
* Used in advanced scenarios requiring SharedObjectKind compatibility.
* @typeParam T - The kind of data object
* @param factory - The data object factory
* @returns Enhanced factory with SharedObjectKind capabilities
*/
function createDataObjectKind<T extends DataObjectKind>(
factory: T
): T & SharedObjectKind<T extends DataObjectKind<infer I> ? I : unknown>;