Skip to content

Commit

Permalink
Avoid exporting SharedObject as public (#19717)
Browse files Browse the repository at this point in the history
## Description

Remove the requirement that factories are classes, then avoid exporting
DDS classes and SharedObject (and some related types) as public: they
are instead exported as `@alpha`.

## Breaking Changes

Users of DDS concreate classes should migrate onto the corresponding
interface types.
Any code using APIs intended only for authoring of new DDSes (such as
SharedObject, SharedObjectCore and EventEmitterWithErrorHandling) will
have to use the unstable `@alpha` APIs, and should find alternatives or
be up streamed into this repository.

This also makes ContainerSchema read-only: as this type is intended for
defining input to the these packages this should make the APIs more
tolerant and thus be non-breaking, however its possible for some users
of this type to use it in ways where this could be a breaking change:
any such users should remove their mutations and/or use different types.
  • Loading branch information
CraigMacomber authored Mar 7, 2024
1 parent d7d712c commit ae1d0be
Show file tree
Hide file tree
Showing 22 changed files with 202 additions and 266 deletions.
10 changes: 10 additions & 0 deletions .changeset/chatty-ears-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"fluid-framework": minor
"@fluidframework/telemetry-utils": minor
---

EventEmitterWithErrorHandling is no longer publicly exported

EventEmitterWithErrorHandling is intended for authoring DDSes, and thus is only intended for use within the Fluid Framework client packages.
It is no longer publicly exported: any users should fine their own solution or be upstreamed.
EventEmitterWithErrorHandling is available for now as `@alpha` to make this migration less disrupting for any existing users.
10 changes: 10 additions & 0 deletions .changeset/itchy-spies-laugh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"fluid-framework": minor
"@fluidframework/shared-object-base": minor
---

SharedObject classes are no longer exported as public

`SharedObject` and `SharedObjectCore` are intended for authoring DDSes, and thus are only intended for use within the Fluid Framework client packages.
They is no longer publicly exported: any users should fine their own solution or be upstreamed.
`SharedObject` and `SharedObjectCore` are available for now as `@alpha` to make this migration less disrupting for any existing users.
12 changes: 12 additions & 0 deletions .changeset/mean-terms-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"fluid-framework": minor
"@fluidframework/map": minor
"@fluidframework/tree": minor
---

DDS classes are no longer publicly exported

SharedMap and SharedTree now only export their factories and the interface types.
The actual concrete classes which leak implementation details are no longer exported.
Users of the `SharedMap` type should use `ISharedMap`.
Users of the `SharedTree` type should use `ISharedTree`.
8 changes: 8 additions & 0 deletions .changeset/weak-areas-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"fluid-framework": minor
"@fluidframework/fluid-static": minor
---

ContainerSchema is now readonly

ContainerSchema type is intended for defining input to the these packages. This should make the APIs more tolerant and thus be non-breaking, however its possible for some users of ContainerSchema to use it in ways where this could be a breaking change: any such users should remove their mutations and/or use a different type.
31 changes: 7 additions & 24 deletions packages/dds/map/api-report/map.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,29 +243,12 @@ export class SharedDirectory extends SharedObject<ISharedDirectoryEvents> implem
}

// @public @deprecated
export class SharedMap extends SharedObject<ISharedMapEvents> implements ISharedMap {
[Symbol.iterator](): IterableIterator<[string, any]>;
readonly [Symbol.toStringTag]: string;
constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes);
protected applyStashedOp(content: unknown): void;
clear(): void;
static create(runtime: IFluidDataStoreRuntime, id?: string): SharedMap;
delete(key: string): boolean;
entries(): IterableIterator<[string, any]>;
forEach(callbackFn: (value: any, key: string, map: Map<string, any>) => void): void;
get<T = any>(key: string): T | undefined;
static getFactory(): IChannelFactory<ISharedMap>;
has(key: string): boolean;
keys(): IterableIterator<string>;
protected loadCore(storage: IChannelStorageService): Promise<void>;
protected onDisconnect(): void;
protected processCore(message: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown): void;
protected reSubmitCore(content: unknown, localOpMetadata: unknown): void;
protected rollback(content: unknown, localOpMetadata: unknown): void;
set(key: string, value: unknown): this;
get size(): number;
protected summarizeCore(serializer: IFluidSerializer, telemetryContext?: ITelemetryContext): ISummaryTreeWithStats;
values(): IterableIterator<any>;
}
export const SharedMap: {
getFactory(): IChannelFactory<ISharedMap>;
create(runtime: IFluidDataStoreRuntime, id?: string): ISharedMap;
};

// @public @deprecated
export type SharedMap = ISharedMap;

```
10 changes: 9 additions & 1 deletion packages/dds/map/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@
}
},
"typeValidation": {
"broken": {}
"broken": {
"RemovedClassDeclaration_SharedMap": {
"forwardCompat": false,
"backCompat": false
},
"ClassDeclaration_SharedMap": {
"backCompat": false
}
}
}
}
55 changes: 54 additions & 1 deletion packages/dds/map/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,57 @@ export {
IValueChanged,
} from "./interfaces.js";
export { LocalValueMaker, ILocalValue } from "./localValues.js";
export { MapFactory, SharedMap } from "./map.js";
export { MapFactory } from "./map.js";

import type {
IChannelFactory,
IFluidDataStoreRuntime,
} from "@fluidframework/datastore-definitions";
import { MapFactory } from "./map.js";
import { ISharedMap } from "./interfaces.js";

/**
* {@inheritDoc ISharedMap}
* @public
* @deprecated Please use SharedTree for new containers. SharedMap is supported for loading preexisting Fluid Framework 1.0 containers only.
*/
export const SharedMap = {
/**
* Get a factory for SharedMap to register with the data store.
* @returns A factory that creates SharedMaps and loads them from storage.
*/
getFactory(): IChannelFactory<ISharedMap> {
return new MapFactory();
},

/**
* Create a new shared map.
* @param runtime - The data store runtime that the new shared map belongs to.
* @param id - Optional name of the shared map.
* @returns Newly created shared map.
*
* @example
* To create a `SharedMap`, call the static create method:
*
* ```typescript
* const myMap = SharedMap.create(this.runtime, id);
* ```
* @privateRemarks
* TODO:
* Clarify how this differs from `MapFactory.create`.
* They are different since making this forward to MapFactory.create breaks some things,
* but the difference is unclear from the documentation.
*/
create(runtime: IFluidDataStoreRuntime, id?: string): ISharedMap {
return runtime.createChannel(id, MapFactory.Type) as ISharedMap;
},
};

/**
* {@inheritDoc ISharedMap}
* @public
* @deprecated Use ISharedMap instead.
* @privateRemarks
* This alias is for legacy compat from when the SharedMap class was exported as public.
*/
export type SharedMap = ISharedMap;
25 changes: 0 additions & 25 deletions packages/dds/map/src/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,31 +93,6 @@ export class MapFactory implements IChannelFactory<ISharedMap> {
* @deprecated Please use SharedTree for new containers. SharedMap is supported for loading preexisting Fluid Framework 1.0 containers only.
*/
export class SharedMap extends SharedObject<ISharedMapEvents> implements ISharedMap {
/**
* Create a new shared map.
* @param runtime - The data store runtime that the new shared map belongs to.
* @param id - Optional name of the shared map.
* @returns Newly created shared map.
*
* @example
* To create a `SharedMap`, call the static create method:
*
* ```typescript
* const myMap = SharedMap.create(this.runtime, id);
* ```
*/
public static create(runtime: IFluidDataStoreRuntime, id?: string): SharedMap {
return runtime.createChannel(id, MapFactory.Type) as SharedMap;
}

/**
* Get a factory for SharedMap to register with the data store.
* @returns A factory that creates SharedMaps and loads them from storage.
*/
public static getFactory(): IChannelFactory<ISharedMap> {
return new MapFactory();
}

/**
* String representation for the class.
*/
Expand Down
16 changes: 2 additions & 14 deletions packages/dds/map/src/test/types/validateMapPrevious.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -672,23 +672,11 @@ use_old_ClassDeclaration_SharedDirectory(
/*
* Validate forward compat by using old type in place of current type
* If breaking change required, add in package.json under typeValidation.broken:
* "ClassDeclaration_SharedMap": {"forwardCompat": false}
* "RemovedClassDeclaration_SharedMap": {"forwardCompat": false}
*/
declare function get_old_ClassDeclaration_SharedMap():
TypeOnly<old.SharedMap>;
declare function use_current_ClassDeclaration_SharedMap(
use: TypeOnly<current.SharedMap>): void;
use_current_ClassDeclaration_SharedMap(
get_old_ClassDeclaration_SharedMap());

/*
* Validate back compat by using current type in place of old type
* If breaking change required, add in package.json under typeValidation.broken:
* "ClassDeclaration_SharedMap": {"backCompat": false}
* "RemovedClassDeclaration_SharedMap": {"backCompat": false}
*/
declare function get_current_ClassDeclaration_SharedMap():
TypeOnly<current.SharedMap>;
declare function use_old_ClassDeclaration_SharedMap(
use: TypeOnly<old.SharedMap>): void;
use_old_ClassDeclaration_SharedMap(
get_current_ClassDeclaration_SharedMap());
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export function parseHandles(value: any, serializer: IFluidSerializer): any;
// @internal
export function serializeHandles(value: any, serializer: IFluidSerializer, bind: IFluidHandle): string | undefined;

// @public
// @alpha
export abstract class SharedObject<TEvent extends ISharedObjectEvents = ISharedObjectEvents> extends SharedObjectCore<TEvent> {
constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes, telemetryContextPrefix: string);
getAttachSummary(fullTree?: boolean, trackState?: boolean, telemetryContext?: ITelemetryContext): ISummaryTreeWithStats;
Expand All @@ -90,7 +90,7 @@ export abstract class SharedObject<TEvent extends ISharedObjectEvents = ISharedO
protected abstract summarizeCore(serializer: IFluidSerializer, telemetryContext?: ITelemetryContext, incrementalSummaryContext?: IExperimentalIncrementalSummaryContext): ISummaryTreeWithStats;
}

// @public
// @alpha
export abstract class SharedObjectCore<TEvent extends ISharedObjectEvents = ISharedObjectEvents> extends EventEmitterWithErrorHandling<TEvent> implements ISharedObject<TEvent> {
constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes);
protected abstract applyStashedOp(content: any): void;
Expand Down
4 changes: 2 additions & 2 deletions packages/dds/shared-object-base/src/sharedObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { makeHandlesSerializable, parseHandles } from "./utils.js";

/**
* Base class from which all shared objects derive.
* @public
* @alpha
*/
export abstract class SharedObjectCore<TEvent extends ISharedObjectEvents = ISharedObjectEvents>
extends EventEmitterWithErrorHandling<TEvent>
Expand Down Expand Up @@ -612,7 +612,7 @@ export abstract class SharedObjectCore<TEvent extends ISharedObjectEvents = ISha
/**
* SharedObject with simplified, synchronous summarization and GC.
* DDS implementations with async and incremental summarization should extend SharedObjectCore directly instead.
* @public
* @alpha
*/
export abstract class SharedObject<
TEvent extends ISharedObjectEvents = ISharedObjectEvents,
Expand Down
31 changes: 3 additions & 28 deletions packages/dds/tree/api-report/tree.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,10 @@ import { IChannel } from '@fluidframework/datastore-definitions';
import { IChannelAttributes } from '@fluidframework/datastore-definitions';
import { IChannelFactory } from '@fluidframework/datastore-definitions';
import { IChannelServices } from '@fluidframework/datastore-definitions';
import { IExperimentalIncrementalSummaryContext } from '@fluidframework/runtime-definitions';
import { IFluidDataStoreRuntime } from '@fluidframework/datastore-definitions';
import { IFluidHandle } from '@fluidframework/core-interfaces';
import { IFluidLoadable } from '@fluidframework/core-interfaces';
import { IGarbageCollectionData } from '@fluidframework/runtime-definitions';
import { ISharedObject } from '@fluidframework/shared-object-base';
import { ISummaryTreeWithStats } from '@fluidframework/runtime-definitions';
import { ITelemetryContext } from '@fluidframework/runtime-definitions';
import { SessionSpaceCompressedId } from '@fluidframework/id-compressor';
import { StableId } from '@fluidframework/id-compressor';
import type { Static } from '@sinclair/typebox';
Expand Down Expand Up @@ -1635,30 +1631,9 @@ export interface SequenceFieldEditBuilder {
}

// @public
export class SharedTree implements ITree {
// (undocumented)
get attributes(): IChannelAttributes;
// (undocumented)
connect(services: IChannelServices): void;
// (undocumented)
getAttachSummary(fullTree?: boolean | undefined, trackState?: boolean | undefined, telemetryContext?: ITelemetryContext | undefined): ISummaryTreeWithStats;
// (undocumented)
static getFactory(): IChannelFactory<ITree>;
// (undocumented)
getGCData(fullGC?: boolean | undefined): IGarbageCollectionData;
// (undocumented)
get handle(): IFluidHandle;
// (undocumented)
get id(): string;
// (undocumented)
get IFluidLoadable(): IFluidLoadable;
// (undocumented)
isAttached(): boolean;
// (undocumented)
schematize<TRoot extends ImplicitFieldSchema>(config: TreeConfiguration<TRoot>): TreeView<TreeFieldFromImplicitField<TRoot>>;
// (undocumented)
summarize(fullTree?: boolean | undefined, trackState?: boolean | undefined, telemetryContext?: ITelemetryContext | undefined, incrementalSummaryContext?: IExperimentalIncrementalSummaryContext | undefined): Promise<ISummaryTreeWithStats>;
}
export const SharedTree: {
getFactory(): IChannelFactory<ITree>;
};

// @internal
export interface SharedTreeContentSnapshot {
Expand Down
Loading

0 comments on commit ae1d0be

Please sign in to comment.