Distributed data structures for collaborative applications providing SharedMap and SharedDirectory implementations with real-time synchronization and last-write-wins conflict resolution
npx @tessl/cli install tessl/npm-fluidframework--map@2.60.0@fluidframework/map provides distributed data structures for collaborative applications. The package offers two main data structures: SharedMap and SharedDirectory, both designed for real-time synchronization across multiple clients with last-write-wins conflict resolution and comprehensive event-driven APIs.
npm install @fluidframework/mapimport { SharedMap, SharedDirectory } from "@fluidframework/map";For legacy factory classes (direct imports):
import {
SharedMap,
SharedDirectory,
MapFactory,
DirectoryFactory
} from "@fluidframework/map";import { SharedMap, SharedDirectory } from "@fluidframework/map";
// Create a SharedMap for key-value storage
const myMap = SharedMap.create(runtime, "my-map-id");
// Set and get values
myMap.set("user-count", 42);
myMap.set("app-config", { theme: "dark", lang: "en" });
const userCount = myMap.get("user-count");
console.log(userCount); // 42
// Listen for changes from other clients
myMap.on("valueChanged", (changed, local) => {
console.log(`Key ${changed.key} changed from ${changed.previousValue}`);
console.log(`Change was ${local ? "local" : "remote"}`);
});
// Create a SharedDirectory for hierarchical data
const myDir = SharedDirectory.create(runtime, "my-dir-id");
// Store values in the root directory
myDir.set("app-name", "My Collaborative App");
// Create and work with subdirectories
const userPrefs = myDir.createSubDirectory("user-preferences");
userPrefs.set("theme", "dark");
userPrefs.set("notifications", true);
// Navigate the directory structure
const prefsDir = myDir.getWorkingDirectory("user-preferences");
const theme = prefsDir?.get("theme");@fluidframework/map is built around several key components:
Distributed key-value data structure with JavaScript Map-compatible API for storing and retrieving data with automatic synchronization across clients.
const SharedMap: ISharedObjectKind<ISharedMap>;
interface ISharedMap extends ISharedObject<ISharedMapEvents>, Map<string, any> {
get<T = any>(key: string): T | undefined;
set<T = unknown>(key: string, value: T): this;
}
interface ISharedMapEvents extends ISharedObjectEvents {
(event: "valueChanged", listener: (changed: IValueChanged, local: boolean, target: IEventThisPlaceHolder) => void): any;
(event: "clear", listener: (local: boolean, target: IEventThisPlaceHolder) => void): any;
}Hierarchical distributed data structure that combines key-value storage with directory-like organization, enabling structured data storage with subdirectories.
const SharedDirectory: ISharedObjectKind<ISharedDirectory>;
interface ISharedDirectory extends ISharedObject<ISharedDirectoryEvents & IDirectoryEvents>, Omit<IDirectory, "on" | "once" | "off"> {
[Symbol.iterator](): IterableIterator<[string, any]>;
readonly [Symbol.toStringTag]: string;
}
interface IDirectory extends Map<string, any>, IEventProvider<IDirectoryEvents>, Partial<IDisposable> {
readonly absolutePath: string;
get<T = any>(key: string): T | undefined;
set<T = unknown>(key: string, value: T): this;
countSubDirectory?(): number;
createSubDirectory(subdirName: string): IDirectory;
getSubDirectory(subdirName: string): IDirectory | undefined;
hasSubDirectory(subdirName: string): boolean;
deleteSubDirectory(subdirName: string): boolean;
subdirectories(): IterableIterator<[string, IDirectory]>;
getWorkingDirectory(relativePath: string): IDirectory | undefined;
}Comprehensive event system for both SharedMap and SharedDirectory that enables reactive programming patterns and real-time collaborative features.
interface IValueChanged {
readonly key: string;
readonly previousValue: any;
}
interface IDirectoryValueChanged extends IValueChanged {
path: string;
}
interface ISharedDirectoryEvents extends ISharedObjectEvents {
(event: "valueChanged", listener: (changed: IDirectoryValueChanged, local: boolean, target: IEventThisPlaceHolder) => void): any;
(event: "clear", listener: (local: boolean, target: IEventThisPlaceHolder) => void): any;
(event: "subDirectoryCreated", listener: (path: string, local: boolean, target: IEventThisPlaceHolder) => void): any;
(event: "subDirectoryDeleted", listener: (path: string, local: boolean, target: IEventThisPlaceHolder) => void): any;
}
interface IDirectoryEvents extends IEvent {
(event: "containedValueChanged", listener: (changed: IValueChanged, local: boolean, target: IEventThisPlaceHolder) => void): any;
(event: "subDirectoryCreated", listener: (path: string, local: boolean, target: IEventThisPlaceHolder) => void): any;
(event: "subDirectoryDeleted", listener: (path: string, local: boolean, target: IEventThisPlaceHolder) => void): any;
(event: "disposed", listener: (target: IEventThisPlaceHolder) => void): any;
(event: "undisposed", listener: (target: IEventThisPlaceHolder) => void): any;
}Factory classes for advanced use cases and legacy compatibility, providing direct control over shared object creation and loading.
class MapFactory implements IChannelFactory<ISharedMap> {
static readonly Type: string;
static readonly Attributes: IChannelAttributes;
get type(): string;
get attributes(): IChannelAttributes;
create(runtime: IFluidDataStoreRuntime, id: string): ISharedMap;
load(runtime: IFluidDataStoreRuntime, id: string, services: IChannelServices, attributes: IChannelAttributes): Promise<ISharedMap>;
}
class DirectoryFactory implements IChannelFactory<ISharedDirectory> {
static readonly Type: string;
static readonly Attributes: IChannelAttributes;
get type(): string;
get attributes(): IChannelAttributes;
create(runtime: IFluidDataStoreRuntime, id: string): ISharedDirectory;
load(runtime: IFluidDataStoreRuntime, id: string, services: IChannelServices, attributes: IChannelAttributes): Promise<ISharedDirectory>;
}// Re-exported from @fluidframework/shared-object-base and related packages
interface ISharedObject<TEvent = ISharedObjectEvents> extends IEventProviderGeneric<TEvent> {
readonly attributes: IChannelAttributes;
readonly connected: boolean;
readonly id: string;
bindToContext(): void;
}
interface ISharedObjectEvents extends IEvent {
(event: "connected", listener: (value: boolean, clientId: string) => void);
(event: "disconnected", listener: () => void);
(event: "disposed", listener: () => void);
}
// Factory and creation types
interface ISharedObjectKind<T> {
create(runtime: IFluidDataStoreRuntime, id?: string): T;
getFactory(): IChannelFactory;
}
interface IChannelFactory<T = IFluidLoadable> {
readonly type: string;
readonly attributes: IChannelAttributes;
load(runtime: IFluidDataStoreRuntime, id: string, services: IChannelServices, channelAttributes: Readonly<IChannelAttributes>): Promise<T>;
create(document: IFluidDataStoreRuntime, id: string): T;
}
interface IChannelAttributes {
type: string;
snapshotFormatVersion: string;
packageVersion: string;
}
// Event system base types
interface IEvent {
(event: string | symbol, listener: (...args: any[]) => void): any;
}
interface IEventProvider<TEvent extends IEvent> {
on<K>(event: K, listener: TEvent[K]): this;
once<K>(event: K, listener: TEvent[K]): this;
off<K>(event: K, listener: TEvent[K]): this;
}
interface IEventThisPlaceHolder {
// Placeholder interface for event listener 'this' context
}
interface IDisposable {
readonly disposed: boolean;
dispose(): void;
}
// Legacy types (deprecated)
interface ISerializableValue {
type: string;
value: any;
}