diff --git a/examples/data-objects/inventory-app/src/reactSharedTreeView.tsx b/examples/data-objects/inventory-app/src/reactSharedTreeView.tsx index b62ceb3fefc7..ed0299e604bd 100644 --- a/examples/data-objects/inventory-app/src/reactSharedTreeView.tsx +++ b/examples/data-objects/inventory-app/src/reactSharedTreeView.tsx @@ -10,11 +10,15 @@ import { ITree, type ImplicitFieldSchema, SchemaIncompatible, - SharedTree, TreeConfiguration, TreeFieldFromImplicitField, TreeView, } from "@fluidframework/tree"; +import { + configuredSharedTree, + typeboxValidator, + // eslint-disable-next-line import/no-internal-modules +} from "@fluidframework/tree/internal"; import * as React from "react"; /** @@ -22,6 +26,13 @@ import * as React from "react"; * Eventually this should be published as part of a package apps can use. */ +/** + * Opt into extra validation to detect encoding bugs and data corruption. + */ +const SharedTree = configuredSharedTree({ + jsonValidator: typeboxValidator, +}); + /** * TODO: once we add options to factory (for example controlling the write format), * apps will need a way to provide those. diff --git a/packages/dds/tree/api-report/tree.api.md b/packages/dds/tree/api-report/tree.api.md index 8012be41ce08..d9ddf99b4bb6 100644 --- a/packages/dds/tree/api-report/tree.api.md +++ b/packages/dds/tree/api-report/tree.api.md @@ -246,6 +246,9 @@ export interface CommitMetadata { // @internal export function compareLocalNodeKeys(a: LocalNodeKey, b: LocalNodeKey): -1 | 0 | 1; +// @internal +export function configuredSharedTree(options: SharedTreeOptions): ISharedObjectKind; + // @internal export type ContextuallyTypedFieldData = ContextuallyTypedNodeData | undefined; diff --git a/packages/dds/tree/src/index.ts b/packages/dds/tree/src/index.ts index 2bcb84923eb3..776bbef6a53b 100644 --- a/packages/dds/tree/src/index.ts +++ b/packages/dds/tree/src/index.ts @@ -327,7 +327,7 @@ export { test_RecursiveObject_base, test_RecursiveObjectPojoMode, } from "./simple-tree/index.js"; -export { SharedTree } from "./treeFactory.js"; +export { SharedTree, configuredSharedTree } from "./treeFactory.js"; export type { ICodecOptions, JsonValidator, SchemaValidationFunction } from "./codec/index.js"; export { noopValidator } from "./codec/index.js"; diff --git a/packages/dds/tree/src/treeFactory.ts b/packages/dds/tree/src/treeFactory.ts index 5c912966a0a7..d4c65f3b365b 100644 --- a/packages/dds/tree/src/treeFactory.ts +++ b/packages/dds/tree/src/treeFactory.ts @@ -51,17 +51,44 @@ export class TreeFactory implements IChannelFactory { /** * SharedTree is a hierarchical data structure for collaboratively editing strongly typed JSON-like trees * of objects, arrays, and other data types. - * @privateRemarks - * Due to the dependency structure and the placement of that interface SharedObjectClass, - * this interface implementation can not be recorded in the type here. * @public */ -export const SharedTree: ISharedObjectKind = { - getFactory(): IChannelFactory { - return new TreeFactory({}); - }, +export const SharedTree: ISharedObjectKind = configuredSharedTree({}); - create(runtime: IFluidDataStoreRuntime, id?: string): ITree { - return runtime.createChannel(id, TreeFactory.type) as ITree; - }, -}; +/** + * {@link SharedTree} but allowing a non-default configuration. + * @remarks + * This is useful for debugging and testing to opt into extra validation or see if opting out of some optimizations fixes an issue. + * @example + * ```typescript + * import { + * ForestType, + * TreeCompressionStrategy, + * configuredSharedTree, + * typeboxValidator, + * // eslint-disable-next-line import/no-internal-modules + * } from "@fluidframework/tree/internal"; + * const SharedTree = configuredSharedTree({ + * forest: ForestType.Reference, + * jsonValidator: typeboxValidator, + * treeEncodeType: TreeCompressionStrategy.Uncompressed, + * }); + * ``` + * @privateRemarks + * TODO: + * Expose Ajv validator for better error message quality somehow. + * Maybe as part of a test utils or dev-tool package? + * @internal + */ +export function configuredSharedTree(options: SharedTreeOptions): ISharedObjectKind { + const factory = new TreeFactory(options); + return { + getFactory(): IChannelFactory { + return factory; + }, + + create(runtime: IFluidDataStoreRuntime, id?: string): ITree { + return runtime.createChannel(id, TreeFactory.type) as ITree; + }, + }; +}