@fluidframework/shared-object-base 3.7.0 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"sharedObjectKernel.js","sourceRoot":"","sources":["../src/sharedObjectKernel.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { IFluidLoadable } from \"@fluidframework/core-interfaces\";\nimport { assert, fail } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIChannelStorageService,\n\tIChannel,\n\tIChannelAttributes,\n\tIChannelFactory,\n\tIChannelServices,\n\tIFluidDataStoreRuntime,\n\tIFluidDataStoreRuntimeInternalConfig,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport type { IIdCompressor } from \"@fluidframework/id-compressor/internal\";\nimport type {\n\tISummaryTreeWithStats,\n\tITelemetryContext,\n\tIExperimentalIncrementalSummaryContext,\n\tIRuntimeMessageCollection,\n\tOldestSupportedClientVersion,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport type { TelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\nimport { extractTelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { IFluidSerializer } from \"./serializer.js\";\nimport {\n\tcreateSharedObjectKindAlpha,\n\tSharedObject,\n\ttype ISharedObjectKind,\n\ttype SharedObjectKindAlpha,\n} from \"./sharedObject.js\";\nimport type { ISharedObjectEvents, ISharedObject } from \"./types.js\";\nimport type { IChannelView } from \"./utils.js\";\n\n/**\n * Functionality specific to a particular kind of {@link ISharedObject}.\n * @remarks\n * Shared objects expose APIs for two consumers:\n *\n * 1. The runtime, which uses {@link @fluidframework/datastore-definitions#IChannel} to summarize and apply ops and {@link @fluidframework/datastore-definitions#IChannelFactory} to create the load summaries.\n *\n * 2. The app, which uses shared object kind specific APIs to read and write data.\n *\n * There is some common functionality all shared objects use, provided by {@link SharedObject} and {@link SharedObjectCore}.\n * SharedKernel describes the portion of the behavior required by the runtime which\n * differs between different kinds of shared objects.\n *\n * {@link makeSharedObjectKind} is then used to wrap up the kernel into a full {@link ISharedObject} implementation.\n * The runtime specific APIs are then type erased into a {@link SharedObjectKind}.\n * @privateRemarks\n * Unlike the `SharedObject` class, this interface is internal, and thus can be adjusted more easily.\n * Therefore this interface is not intended to address all needs, and will likely need small changes as it gets more adoption.\n *\n * @internal\n */\nexport interface SharedKernel {\n\t/**\n\t * {@inheritDoc SharedObject.summarizeCore}\n\t */\n\tsummarizeCore(\n\t\tserializer: IFluidSerializer,\n\t\ttelemetryContext: ITelemetryContext | undefined,\n\t\tincrementalSummaryContext: IExperimentalIncrementalSummaryContext | undefined,\n\t\tfullTree?: boolean,\n\t): ISummaryTreeWithStats;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.onDisconnect}\n\t */\n\tonDisconnect(): void;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.reSubmitCore}\n\t */\n\treSubmitCore(content: unknown, localOpMetadata: unknown): void;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.applyStashedOp}\n\t */\n\tapplyStashedOp(content: unknown): void;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.processMessagesCore}\n\t */\n\tprocessMessagesCore(messagesCollection: IRuntimeMessageCollection): void;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.rollback}\n\t */\n\trollback?(content: unknown, localOpMetadata: unknown): void;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.didAttach}\n\t */\n\tdidAttach?(): void;\n}\n\n/**\n * SharedObject implementation that delegates to a SharedKernel.\n * @typeParam TOut - The type of the object exposed to the app.\n * Once initialized, instances of this class forward properties to the `TOut` value provided by the factory.\n * See {@link mergeAPIs} for more limitations.\n *\n * @remarks\n * The App facing API (TOut) needs to be implemented by this object which also has to implement the runtime facing API (ISharedObject).\n *\n * Requiring both of these to be implemented by the same object adds some otherwise unnecessary coupling.\n * This class is a workaround for that, which takes separate implementations of the two APIs and merges them into one using {@link mergeAPIs}.\n */\nclass SharedObjectFromKernel<\n\tTOut extends object,\n\tTEvent extends ISharedObjectEvents,\n> extends SharedObject<TEvent> {\n\t/**\n\t * Lazy init here so kernel can be constructed in loadCore when loading from existing data.\n\t *\n\t * Explicit initialization to undefined is done so Proxy knows this property is from this class (via `Reflect.has`),\n\t * not from the grafted APIs.\n\t */\n\t#lazyData: FactoryOut<TOut> | undefined = undefined;\n\n\treadonly #kernelArgs: KernelArgs;\n\n\tpublic constructor(\n\t\tid: string,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tattributes: IChannelAttributes,\n\t\tpublic readonly factory: SharedKernelFactory<TOut>,\n\t\ttelemetryContextPrefix: string,\n\t) {\n\t\tsuper(id, runtime, attributes, telemetryContextPrefix);\n\n\t\t// This cast is needed since IFluidDataStoreRuntimeInternalConfig does not extend IFluidDataStoreRuntime directly. This pattern\n\t\t// allows us to avoid breaking changes to IFluidDataStoreRuntime by hiding internal members in a separate interface, but comes\n\t\t// at the cost of less compile-time enforcement. For example, if the runtime did not implement `minVersionForCollab` and the\n\t\t// member was still optional (e.g., during the deprecation window where backwards-compatibility is maintained), the compiler\n\t\t// would emit an error.\n\t\tconst minVersionForCollab: OldestSupportedClientVersion | undefined = (\n\t\t\truntime as IFluidDataStoreRuntimeInternalConfig\n\t\t).minVersionForCollab;\n\n\t\tassert(minVersionForCollab !== undefined, 0xcee /* minVersionForCollab must be defined */);\n\n\t\tthis.#kernelArgs = {\n\t\t\tsharedObject: this,\n\t\t\tserializer: this.serializer,\n\t\t\tsubmitLocalMessage: (op, localOpMetadata) =>\n\t\t\t\tthis.submitLocalMessage(op, localOpMetadata),\n\t\t\teventEmitter: this,\n\t\t\tlogger: extractTelemetryLoggerExt(this.logger),\n\t\t\tidCompressor: runtime.idCompressor,\n\t\t\tlastSequenceNumber: () => this.deltaManager.lastSequenceNumber,\n\t\t\tinitialSequenceNumber: this.deltaManager.initialSequenceNumber,\n\t\t\tminVersionForCollab,\n\t\t};\n\t}\n\n\tprotected override summarizeCore(\n\t\tserializer: IFluidSerializer,\n\t\ttelemetryContext?: ITelemetryContext,\n\t\tincrementalSummaryContext?: IExperimentalIncrementalSummaryContext,\n\t\tfullTree?: boolean,\n\t): ISummaryTreeWithStats {\n\t\treturn this.#kernel.summarizeCore(\n\t\t\tserializer,\n\t\t\ttelemetryContext,\n\t\t\tincrementalSummaryContext,\n\t\t\tfullTree,\n\t\t);\n\t}\n\n\tprotected override initializeLocalCore(): void {\n\t\tthis.#initializeData(this.factory.create(this.#kernelArgs));\n\t}\n\n\t#initializeData(data: FactoryOut<TOut>): void {\n\t\tassert(\n\t\t\tthis.#lazyData === undefined,\n\t\t\t0xb99 /* initializeData must be called first and only once */,\n\t\t);\n\t\tthis.#lazyData = data;\n\n\t\t// Make `this` implement TOut.\n\t\tmergeAPIs(this, data.view);\n\t}\n\n\tget #kernel(): SharedKernel {\n\t\treturn (this.#lazyData ?? fail(0xcb0 /* must initializeData first */)).kernel;\n\t}\n\n\tprotected override async loadCore(storage: IChannelStorageService): Promise<void> {\n\t\tthis.#initializeData(await this.factory.loadCore(this.#kernelArgs, storage));\n\t}\n\n\tprotected override onDisconnect(): void {\n\t\tthis.#kernel.onDisconnect();\n\t}\n\n\tprotected override reSubmitCore(content: unknown, localOpMetadata: unknown): void {\n\t\tthis.#kernel.reSubmitCore(content, localOpMetadata);\n\t}\n\n\tprotected override applyStashedOp(content: unknown): void {\n\t\tthis.#kernel.applyStashedOp(content);\n\t}\n\n\tprotected override processMessagesCore(messagesCollection: IRuntimeMessageCollection): void {\n\t\tthis.#kernel.processMessagesCore(messagesCollection);\n\t}\n\n\tprotected override rollback(content: unknown, localOpMetadata: unknown): void {\n\t\tif (this.#kernel.rollback === undefined) {\n\t\t\tsuper.rollback(content, localOpMetadata);\n\t\t} else {\n\t\t\tthis.#kernel.rollback(content, localOpMetadata);\n\t\t}\n\t}\n\n\tprotected override didAttach(): void {\n\t\tthis.#kernel.didAttach?.();\n\t}\n}\n\n/**\n * When present on a method, it indicates the methods return value should be replaced with `this` (the wrapper)\n * when wrapping the object with the method.\n * @remarks\n * This is useful when using {@link mergeAPIs} with methods where the return type is `this`, like `Map.set`.\n * @internal\n */\nexport const thisWrap: unique symbol = Symbol(\"selfWrap\");\n\n/**\n * A {@link SharedKernel} providing the implementation of some distributed data structure (DDS) and the needed runtime facing APIs,\n * and a separate view object which exposes the app facing APIs (`T`)\n * for reading and writing data which are specific to this particular data structure.\n * @remarks\n * Output from {@link SharedKernelFactory}.\n * This is an alternative to defining DDSs by sub-classing {@link SharedObject}.\n * @internal\n */\nexport interface FactoryOut<T extends object> {\n\treadonly kernel: SharedKernel;\n\treadonly view: T;\n}\n\n/**\n * A factory for creating DDSs.\n * @remarks\n * Outputs {@link FactoryOut}.\n * This is an alternative to directly implementing {@link @fluidframework/datastore-definitions#IChannelFactory}.\n * Use with {@link makeSharedObjectKind} to create a {@link SharedObjectKind}.\n * @internal\n */\nexport interface SharedKernelFactory<T extends object> {\n\tcreate(args: KernelArgs): FactoryOut<T>;\n\n\t/**\n\t * Create combined with {@link SharedObjectCore.loadCore}.\n\t */\n\tloadCore(args: KernelArgs, storage: IChannelStorageService): Promise<FactoryOut<T>>;\n}\n\n/**\n * Inputs for building a {@link SharedKernel} via {@link SharedKernelFactory}.\n * @internal\n */\nexport interface KernelArgs {\n\t/**\n\t * The shared object whose behavior is being implemented.\n\t */\n\treadonly sharedObject: IChannelView & IFluidLoadable;\n\t/**\n\t * {@inheritdoc SharedObject.serializer}\n\t */\n\treadonly serializer: IFluidSerializer;\n\t/**\n\t * {@inheritdoc SharedObjectCore.submitLocalMessage}\n\t */\n\treadonly submitLocalMessage: (op: unknown, localOpMetadata: unknown) => void;\n\t/**\n\t * Top level emitter for events for this object.\n\t * @remarks\n\t * This is needed since the separate kernel and view from {@link FactoryOut} currently have to be recombined,\n\t * and having this as its own thing helps accomplish that.\n\t */\n\treadonly eventEmitter: TypedEventEmitter<ISharedObjectEvents>;\n\t/**\n\t * {@inheritdoc SharedObjectCore.logger}\n\t */\n\treadonly logger: TelemetryLoggerExt;\n\t/**\n\t * {@inheritdoc @fluidframework/datastore-definitions#IFluidDataStoreRuntime.idCompressor}\n\t */\n\treadonly idCompressor: IIdCompressor | undefined;\n\t/**\n\t * {@inheritdoc @fluidframework/container-definitions#IDeltaManager.lastSequenceNumber}\n\t */\n\treadonly lastSequenceNumber: () => number;\n\t/**\n\t * {@inheritdoc @fluidframework/container-definitions#IDeltaManager.initialSequenceNumber}\n\t */\n\treadonly initialSequenceNumber: number;\n\t/**\n\t * Oldest Fluid Framework client version that must be able to process documents containing ops\n\t * generated by the SharedObject implementation. Used to select compatible feature flags and\n\t * formats, so choosing an older version may limit available features and write formats.\n\t * See {@link @fluidframework/container-runtime#LoadContainerRuntimeParams.oldestSupportedClient}\n\t * for more details.\n\t */\n\treadonly minVersionForCollab: OldestSupportedClientVersion;\n}\n\n/**\n * Add getters to `base` which forward own properties from `extra`.\n * @remarks\n * This only handles use of \"get\" and \"has\".\n * Therefore, APIs involving setting properties should not be used as `Extra`.\n *\n * Functions from `extra` are bound to the `extra` object and support {@link thisWrap}.\n *\n * Asserts when properties collide.\n * @internal\n */\nexport function mergeAPIs<const Base extends object, const Extra extends object>(\n\tbase: Base,\n\textra: Extra,\n): asserts base is Base & Extra {\n\tfor (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(extra))) {\n\t\tassert(!Reflect.has(base, key), 0xb9a /* colliding properties */);\n\n\t\t// Detect and special case functions.\n\t\t// Currently this is done eagerly (when mergeAPIs is called) rather than lazily (when the property is read):\n\t\t// this eager approach should result in slightly better performance,\n\t\t// but if functions on `extra` are reassigned over time it will produce incorrect behavior.\n\t\t// If this functionality is required, the design can be changed.\n\t\tlet getter: () => unknown;\n\t\t// Bind functions to the extra object and handle thisWrap.\n\t\tif (typeof descriptor.value === \"function\") {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tconst fromExtra: () => Extra | Base = descriptor.value;\n\t\t\tgetter = () => forwardMethod(fromExtra, extra, base);\n\t\t\t// To catch (and error on) cases where the function is reassigned and this eager binding approach is not appropriate, make it non-writable.\n\t\t\tObject.defineProperty(extra, key, { ...descriptor, writable: false });\n\t\t} else {\n\t\t\tgetter = () => extra[key];\n\t\t}\n\n\t\tObject.defineProperty(base, key, {\n\t\t\tconfigurable: false,\n\t\t\tenumerable: descriptor.enumerable,\n\t\t\tget: getter,\n\t\t\t// If setters become required, support them here.\n\t\t});\n\t}\n}\n\n/**\n * Wrap a method `f` of `oldThis` to be a method of `newThis`.\n * @remarks\n * The wrapped function will be called with `oldThis` as the `this` parameter.\n * It also accounts for when `f` is marked with {@link thisWrap}.\n */\nfunction forwardMethod<TArgs extends [], TReturn>(\n\tf: (...args: TArgs) => TReturn,\n\toldThis: TReturn,\n\tnewThis: TReturn,\n): (...args: TArgs) => TReturn {\n\t// eslint-disable-next-line unicorn/prefer-ternary\n\tif (thisWrap in f) {\n\t\treturn (...args: TArgs) => {\n\t\t\tconst result = f.call(oldThis, ...args);\n\t\t\tassert(result === oldThis, 0xb9b /* methods returning thisWrap should return this */);\n\t\t\treturn newThis;\n\t\t};\n\t} else {\n\t\treturn f.bind(oldThis);\n\t}\n}\n\n/**\n * Options for creating a {@link SharedObjectKind} via {@link makeSharedObjectKind}.\n * @typeParam T - The type of the object exposed to the app.\n * This can optionally include members from {@link ISharedObject} which will be provided automatically.\n * @internal\n */\nexport interface SharedObjectOptions<T extends object> {\n\t/**\n\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.\"type\"}\n\t */\n\treadonly type: string;\n\n\t/**\n\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.attributes}\n\t */\n\treadonly attributes: IChannelAttributes;\n\n\t/**\n\t * The factory used to create the kernel and its view.\n\t * @remarks\n\t * The view produced by this factory will be grafted onto the {@link SharedObject} using {@link mergeAPIs}.\n\t * See {@link mergeAPIs} for more information on limitations that apply.\n\t */\n\treadonly factory: SharedKernelFactory<Omit<T, keyof ISharedObject>>;\n\n\t/**\n\t * {@inheritDoc SharedObject.telemetryContextPrefix}\n\t */\n\treadonly telemetryContextPrefix: string;\n}\n\n/**\n * Utility to create a {@link @fluidframework/datastore-definitions#IChannelFactory} classes.\n * @remarks\n * Use {@link makeSharedObjectKind} instead unless exposing the factory is required for legacy API compatibility.\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nfunction makeChannelFactory<T extends object>(options: SharedObjectOptions<T>) {\n\tclass ChannelFactory implements IChannelFactory<T> {\n\t\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.\"type\"}\n\t\t */\n\t\tpublic static readonly Type = options.type;\n\n\t\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.attributes}\n\t\t */\n\t\tpublic static readonly Attributes: IChannelAttributes = options.attributes;\n\n\t\tpublic get type(): string {\n\t\t\treturn ChannelFactory.Type;\n\t\t}\n\n\t\tpublic get attributes(): IChannelAttributes {\n\t\t\treturn ChannelFactory.Attributes;\n\t\t}\n\n\t\tpublic async load(\n\t\t\truntime: IFluidDataStoreRuntime,\n\t\t\tid: string,\n\t\t\tservices: IChannelServices,\n\t\t\tattributes: IChannelAttributes,\n\t\t): Promise<T & IChannel> {\n\t\t\tconst shared = new SharedObjectFromKernel(\n\t\t\t\tid,\n\t\t\t\truntime,\n\t\t\t\tattributes,\n\t\t\t\toptions.factory,\n\t\t\t\toptions.telemetryContextPrefix,\n\t\t\t);\n\t\t\tawait shared.load(services);\n\t\t\treturn shared as unknown as T & IChannel;\n\t\t}\n\n\t\tpublic create(runtime: IFluidDataStoreRuntime, id: string): T & IChannel {\n\t\t\tconst shared = new SharedObjectFromKernel(\n\t\t\t\tid,\n\t\t\t\truntime,\n\t\t\t\tChannelFactory.Attributes,\n\t\t\t\toptions.factory,\n\t\t\t\toptions.telemetryContextPrefix,\n\t\t\t);\n\n\t\t\tshared.initializeLocal();\n\n\t\t\treturn shared as unknown as T & IChannel;\n\t\t}\n\t}\n\n\treturn ChannelFactory;\n}\n\n/**\n * Utility to create a {@link SharedObjectKind}.\n * @privateRemarks\n * Using this API avoids having to subclasses any Fluid Framework types,\n * reducing the coupling between the framework and the SharedObject implementation.\n * @internal\n */\nexport function makeSharedObjectKind<T extends object>(\n\toptions: SharedObjectOptions<T>,\n): ISharedObjectKind<T> & SharedObjectKindAlpha<T> {\n\treturn createSharedObjectKindAlpha<T>(makeChannelFactory(options));\n}\n"]}
1
+ {"version":3,"file":"sharedObjectKernel.js","sourceRoot":"","sources":["../src/sharedObjectKernel.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { IFluidLoadable } from \"@fluidframework/core-interfaces\";\nimport { assert, fail } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIChannelStorageService,\n\tIChannel,\n\tIChannelAttributes,\n\tIChannelFactory,\n\tIChannelServices,\n\tIFluidDataStoreRuntime,\n\tIFluidDataStoreRuntimeInternalConfig,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport type { IIdCompressor } from \"@fluidframework/id-compressor/internal\";\nimport type {\n\tISummaryTreeWithStats,\n\tITelemetryContext,\n\tIExperimentalIncrementalSummaryContext,\n\tIRuntimeMessageCollection,\n\tOldestSupportedClientVersion,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport type { TelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\nimport { extractTelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { IFluidSerializer } from \"./serializer.js\";\nimport {\n\tcreateSharedObjectKindAlpha,\n\t// eslint-disable-next-line import-x/no-deprecated -- Internal implementations still use this base class.\n\tSharedObject,\n\ttype ISharedObjectKind,\n\ttype SharedObjectKindAlpha,\n} from \"./sharedObject.js\";\nimport type { ISharedObjectEvents, ISharedObject } from \"./types.js\";\nimport type { IChannelView } from \"./utils.js\";\n\n/**\n * Functionality specific to a particular kind of {@link ISharedObject}.\n * @remarks\n * Shared objects expose APIs for two consumers:\n *\n * 1. The runtime, which uses {@link @fluidframework/datastore-definitions#IChannel} to summarize and apply ops and {@link @fluidframework/datastore-definitions#IChannelFactory} to create the load summaries.\n *\n * 2. The app, which uses shared object kind specific APIs to read and write data.\n *\n * There is some common functionality all shared objects use, provided by {@link SharedObject} and {@link SharedObjectCore}.\n * SharedKernel describes the portion of the behavior required by the runtime which\n * differs between different kinds of shared objects.\n *\n * {@link makeSharedObjectKind} is then used to wrap up the kernel into a full {@link ISharedObject} implementation.\n * The runtime specific APIs are then type erased into a {@link SharedObjectKind}.\n * @privateRemarks\n * Unlike the `SharedObject` class, this interface is internal, and thus can be adjusted more easily.\n * Therefore this interface is not intended to address all needs, and will likely need small changes as it gets more adoption.\n *\n * @internal\n */\nexport interface SharedKernel {\n\t/**\n\t * {@inheritDoc SharedObject.summarizeCore}\n\t */\n\tsummarizeCore(\n\t\tserializer: IFluidSerializer,\n\t\ttelemetryContext: ITelemetryContext | undefined,\n\t\tincrementalSummaryContext: IExperimentalIncrementalSummaryContext | undefined,\n\t\tfullTree?: boolean,\n\t): ISummaryTreeWithStats;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.onDisconnect}\n\t */\n\tonDisconnect(): void;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.reSubmitCore}\n\t */\n\treSubmitCore(content: unknown, localOpMetadata: unknown): void;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.applyStashedOp}\n\t */\n\tapplyStashedOp(content: unknown): void;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.processMessagesCore}\n\t */\n\tprocessMessagesCore(messagesCollection: IRuntimeMessageCollection): void;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.rollback}\n\t */\n\trollback?(content: unknown, localOpMetadata: unknown): void;\n\n\t/**\n\t * {@inheritDoc SharedObjectCore.didAttach}\n\t */\n\tdidAttach?(): void;\n}\n\n/**\n * SharedObject implementation that delegates to a SharedKernel.\n * @typeParam TOut - The type of the object exposed to the app.\n * Once initialized, instances of this class forward properties to the `TOut` value provided by the factory.\n * See {@link mergeAPIs} for more limitations.\n *\n * @remarks\n * The App facing API (TOut) needs to be implemented by this object which also has to implement the runtime facing API (ISharedObject).\n *\n * Requiring both of these to be implemented by the same object adds some otherwise unnecessary coupling.\n * This class is a workaround for that, which takes separate implementations of the two APIs and merges them into one using {@link mergeAPIs}.\n */\nclass SharedObjectFromKernel<\n\tTOut extends object,\n\tTEvent extends ISharedObjectEvents,\n\t// eslint-disable-next-line import-x/no-deprecated -- Internal implementations still use this base class.\n> extends SharedObject<TEvent> {\n\t/**\n\t * Lazy init here so kernel can be constructed in loadCore when loading from existing data.\n\t *\n\t * Explicit initialization to undefined is done so Proxy knows this property is from this class (via `Reflect.has`),\n\t * not from the grafted APIs.\n\t */\n\t#lazyData: FactoryOut<TOut> | undefined = undefined;\n\n\treadonly #kernelArgs: KernelArgs;\n\n\tpublic constructor(\n\t\tid: string,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tattributes: IChannelAttributes,\n\t\tpublic readonly factory: SharedKernelFactory<TOut>,\n\t\ttelemetryContextPrefix: string,\n\t) {\n\t\tsuper(id, runtime, attributes, telemetryContextPrefix);\n\n\t\t// This cast is needed since IFluidDataStoreRuntimeInternalConfig does not extend IFluidDataStoreRuntime directly. This pattern\n\t\t// allows us to avoid breaking changes to IFluidDataStoreRuntime by hiding internal members in a separate interface, but comes\n\t\t// at the cost of less compile-time enforcement. For example, if the runtime did not implement `minVersionForCollab` and the\n\t\t// member was still optional (e.g., during the deprecation window where backwards-compatibility is maintained), the compiler\n\t\t// would emit an error.\n\t\tconst minVersionForCollab: OldestSupportedClientVersion | undefined =\n\t\t\t(runtime as IFluidDataStoreRuntimeInternalConfig).oldestSupportedClient ??\n\t\t\t(runtime as IFluidDataStoreRuntimeInternalConfig).minVersionForCollab;\n\n\t\tassert(minVersionForCollab !== undefined, 0xcee /* minVersionForCollab must be defined */);\n\n\t\tthis.#kernelArgs = {\n\t\t\tsharedObject: this,\n\t\t\tserializer: this.serializer,\n\t\t\tsubmitLocalMessage: (op, localOpMetadata) =>\n\t\t\t\tthis.submitLocalMessage(op, localOpMetadata),\n\t\t\teventEmitter: this,\n\t\t\tlogger: extractTelemetryLoggerExt(this.logger),\n\t\t\tidCompressor: runtime.idCompressor,\n\t\t\tlastSequenceNumber: () => this.deltaManager.lastSequenceNumber,\n\t\t\tinitialSequenceNumber: this.deltaManager.initialSequenceNumber,\n\t\t\tminVersionForCollab,\n\t\t\toldestSupportedClient: minVersionForCollab,\n\t\t};\n\t}\n\n\tprotected override summarizeCore(\n\t\tserializer: IFluidSerializer,\n\t\ttelemetryContext?: ITelemetryContext,\n\t\tincrementalSummaryContext?: IExperimentalIncrementalSummaryContext,\n\t\tfullTree?: boolean,\n\t): ISummaryTreeWithStats {\n\t\treturn this.#kernel.summarizeCore(\n\t\t\tserializer,\n\t\t\ttelemetryContext,\n\t\t\tincrementalSummaryContext,\n\t\t\tfullTree,\n\t\t);\n\t}\n\n\tprotected override initializeLocalCore(): void {\n\t\tthis.#initializeData(this.factory.create(this.#kernelArgs));\n\t}\n\n\t#initializeData(data: FactoryOut<TOut>): void {\n\t\tassert(\n\t\t\tthis.#lazyData === undefined,\n\t\t\t0xb99 /* initializeData must be called first and only once */,\n\t\t);\n\t\tthis.#lazyData = data;\n\n\t\t// Make `this` implement TOut.\n\t\tmergeAPIs(this, data.view);\n\t}\n\n\tget #kernel(): SharedKernel {\n\t\treturn (this.#lazyData ?? fail(0xcb0 /* must initializeData first */)).kernel;\n\t}\n\n\tprotected override async loadCore(storage: IChannelStorageService): Promise<void> {\n\t\tthis.#initializeData(await this.factory.loadCore(this.#kernelArgs, storage));\n\t}\n\n\tprotected override onDisconnect(): void {\n\t\tthis.#kernel.onDisconnect();\n\t}\n\n\tprotected override reSubmitCore(content: unknown, localOpMetadata: unknown): void {\n\t\tthis.#kernel.reSubmitCore(content, localOpMetadata);\n\t}\n\n\tprotected override applyStashedOp(content: unknown): void {\n\t\tthis.#kernel.applyStashedOp(content);\n\t}\n\n\tprotected override processMessagesCore(messagesCollection: IRuntimeMessageCollection): void {\n\t\tthis.#kernel.processMessagesCore(messagesCollection);\n\t}\n\n\tprotected override rollback(content: unknown, localOpMetadata: unknown): void {\n\t\tif (this.#kernel.rollback === undefined) {\n\t\t\tsuper.rollback(content, localOpMetadata);\n\t\t} else {\n\t\t\tthis.#kernel.rollback(content, localOpMetadata);\n\t\t}\n\t}\n\n\tprotected override didAttach(): void {\n\t\tthis.#kernel.didAttach?.();\n\t}\n}\n\n/**\n * When present on a method, it indicates the methods return value should be replaced with `this` (the wrapper)\n * when wrapping the object with the method.\n * @remarks\n * This is useful when using {@link mergeAPIs} with methods where the return type is `this`, like `Map.set`.\n * @internal\n */\nexport const thisWrap: unique symbol = Symbol(\"selfWrap\");\n\n/**\n * A {@link SharedKernel} providing the implementation of some distributed data structure (DDS) and the needed runtime facing APIs,\n * and a separate view object which exposes the app facing APIs (`T`)\n * for reading and writing data which are specific to this particular data structure.\n * @remarks\n * Output from {@link SharedKernelFactory}.\n * This is an alternative to defining DDSs by sub-classing {@link SharedObject}.\n * @internal\n */\nexport interface FactoryOut<T extends object> {\n\treadonly kernel: SharedKernel;\n\treadonly view: T;\n}\n\n/**\n * A factory for creating DDSs.\n * @remarks\n * Outputs {@link FactoryOut}.\n * This is an alternative to directly implementing {@link @fluidframework/datastore-definitions#IChannelFactory}.\n * Use with {@link makeSharedObjectKind} to create a {@link SharedObjectKind}.\n * @internal\n */\nexport interface SharedKernelFactory<T extends object> {\n\tcreate(args: KernelArgs): FactoryOut<T>;\n\n\t/**\n\t * Create combined with {@link SharedObjectCore.loadCore}.\n\t */\n\tloadCore(args: KernelArgs, storage: IChannelStorageService): Promise<FactoryOut<T>>;\n}\n\n/**\n * Inputs for building a {@link SharedKernel} via {@link SharedKernelFactory}.\n * @internal\n */\nexport interface KernelArgs {\n\t/**\n\t * The shared object whose behavior is being implemented.\n\t */\n\treadonly sharedObject: IChannelView & IFluidLoadable;\n\t/**\n\t * {@inheritdoc SharedObject.serializer}\n\t */\n\treadonly serializer: IFluidSerializer;\n\t/**\n\t * {@inheritdoc SharedObjectCore.submitLocalMessage}\n\t */\n\treadonly submitLocalMessage: (op: unknown, localOpMetadata: unknown) => void;\n\t/**\n\t * Top level emitter for events for this object.\n\t * @remarks\n\t * This is needed since the separate kernel and view from {@link FactoryOut} currently have to be recombined,\n\t * and having this as its own thing helps accomplish that.\n\t */\n\treadonly eventEmitter: TypedEventEmitter<ISharedObjectEvents>;\n\t/**\n\t * {@inheritdoc SharedObjectCore.logger}\n\t */\n\treadonly logger: TelemetryLoggerExt;\n\t/**\n\t * {@inheritdoc @fluidframework/datastore-definitions#IFluidDataStoreRuntime.idCompressor}\n\t */\n\treadonly idCompressor: IIdCompressor | undefined;\n\t/**\n\t * {@inheritdoc @fluidframework/container-definitions#IDeltaManager.lastSequenceNumber}\n\t */\n\treadonly lastSequenceNumber: () => number;\n\t/**\n\t * {@inheritdoc @fluidframework/container-definitions#IDeltaManager.initialSequenceNumber}\n\t */\n\treadonly initialSequenceNumber: number;\n\t/**\n\t * Oldest Fluid Framework client version that must be able to process documents containing ops\n\t * generated by the SharedObject implementation. Used to select compatible feature flags and\n\t * formats, so choosing an older version may limit available features and write formats.\n\t * See {@link @fluidframework/container-runtime#LoadContainerRuntimeParams.oldestSupportedClient}\n\t * for more details.\n\t */\n\treadonly minVersionForCollab: OldestSupportedClientVersion;\n\n\t/**\n\t * Oldest Fluid Framework client version that must be able to process documents with operations from this SharedObject implementation.\n\t *\n\t * @remarks\n\t * To keep these documents compatible with the specified client version, the implementation uses this value to select feature flags and formats.\n\t * As a result, an older version can limit available features and write formats.\n\t * See {@link @fluidframework/container-runtime#LoadContainerRuntimeParams.oldestSupportedClient}\n\t * for details about this compatibility setting.\n\t */\n\treadonly oldestSupportedClient: OldestSupportedClientVersion;\n}\n\n/**\n * Add getters to `base` which forward own properties from `extra`.\n * @remarks\n * This only handles use of \"get\" and \"has\".\n * Therefore, APIs involving setting properties should not be used as `Extra`.\n *\n * Functions from `extra` are bound to the `extra` object and support {@link thisWrap}.\n *\n * Asserts when properties collide.\n * @internal\n */\nexport function mergeAPIs<const Base extends object, const Extra extends object>(\n\tbase: Base,\n\textra: Extra,\n): asserts base is Base & Extra {\n\tfor (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(extra))) {\n\t\tassert(!Reflect.has(base, key), 0xb9a /* colliding properties */);\n\n\t\t// Detect and special case functions.\n\t\t// Currently this is done eagerly (when mergeAPIs is called) rather than lazily (when the property is read):\n\t\t// this eager approach should result in slightly better performance,\n\t\t// but if functions on `extra` are reassigned over time it will produce incorrect behavior.\n\t\t// If this functionality is required, the design can be changed.\n\t\tlet getter: () => unknown;\n\t\t// Bind functions to the extra object and handle thisWrap.\n\t\tif (typeof descriptor.value === \"function\") {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tconst fromExtra: () => Extra | Base = descriptor.value;\n\t\t\tgetter = () => forwardMethod(fromExtra, extra, base);\n\t\t\t// To catch (and error on) cases where the function is reassigned and this eager binding approach is not appropriate, make it non-writable.\n\t\t\tObject.defineProperty(extra, key, { ...descriptor, writable: false });\n\t\t} else {\n\t\t\tgetter = () => extra[key];\n\t\t}\n\n\t\tObject.defineProperty(base, key, {\n\t\t\tconfigurable: false,\n\t\t\tenumerable: descriptor.enumerable,\n\t\t\tget: getter,\n\t\t\t// If setters become required, support them here.\n\t\t});\n\t}\n}\n\n/**\n * Wrap a method `f` of `oldThis` to be a method of `newThis`.\n * @remarks\n * The wrapped function will be called with `oldThis` as the `this` parameter.\n * It also accounts for when `f` is marked with {@link thisWrap}.\n */\nfunction forwardMethod<TArgs extends [], TReturn>(\n\tf: (...args: TArgs) => TReturn,\n\toldThis: TReturn,\n\tnewThis: TReturn,\n): (...args: TArgs) => TReturn {\n\t// eslint-disable-next-line unicorn/prefer-ternary\n\tif (thisWrap in f) {\n\t\treturn (...args: TArgs) => {\n\t\t\tconst result = f.call(oldThis, ...args);\n\t\t\tassert(result === oldThis, 0xb9b /* methods returning thisWrap should return this */);\n\t\t\treturn newThis;\n\t\t};\n\t} else {\n\t\treturn f.bind(oldThis);\n\t}\n}\n\n/**\n * Options for creating a {@link SharedObjectKind} via {@link makeSharedObjectKind}.\n * @typeParam T - The type of the object exposed to the app.\n * This can optionally include members from {@link ISharedObject} which will be provided automatically.\n * @internal\n */\nexport interface SharedObjectOptions<T extends object> {\n\t/**\n\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.\"type\"}\n\t */\n\treadonly type: string;\n\n\t/**\n\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.attributes}\n\t */\n\treadonly attributes: IChannelAttributes;\n\n\t/**\n\t * The factory used to create the kernel and its view.\n\t * @remarks\n\t * The view produced by this factory will be grafted onto the {@link SharedObject} using {@link mergeAPIs}.\n\t * See {@link mergeAPIs} for more information on limitations that apply.\n\t */\n\treadonly factory: SharedKernelFactory<Omit<T, keyof ISharedObject>>;\n\n\t/**\n\t * {@inheritDoc SharedObject.telemetryContextPrefix}\n\t */\n\treadonly telemetryContextPrefix: string;\n}\n\n/**\n * Utility to create a {@link @fluidframework/datastore-definitions#IChannelFactory} classes.\n * @remarks\n * Use {@link makeSharedObjectKind} instead unless exposing the factory is required for legacy API compatibility.\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nfunction makeChannelFactory<T extends object>(options: SharedObjectOptions<T>) {\n\tclass ChannelFactory implements IChannelFactory<T> {\n\t\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.\"type\"}\n\t\t */\n\t\tpublic static readonly Type = options.type;\n\n\t\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.attributes}\n\t\t */\n\t\tpublic static readonly Attributes: IChannelAttributes = options.attributes;\n\n\t\tpublic get type(): string {\n\t\t\treturn ChannelFactory.Type;\n\t\t}\n\n\t\tpublic get attributes(): IChannelAttributes {\n\t\t\treturn ChannelFactory.Attributes;\n\t\t}\n\n\t\tpublic async load(\n\t\t\truntime: IFluidDataStoreRuntime,\n\t\t\tid: string,\n\t\t\tservices: IChannelServices,\n\t\t\tattributes: IChannelAttributes,\n\t\t): Promise<T & IChannel> {\n\t\t\tconst shared = new SharedObjectFromKernel(\n\t\t\t\tid,\n\t\t\t\truntime,\n\t\t\t\tattributes,\n\t\t\t\toptions.factory,\n\t\t\t\toptions.telemetryContextPrefix,\n\t\t\t);\n\t\t\tawait shared.load(services);\n\t\t\treturn shared as unknown as T & IChannel;\n\t\t}\n\n\t\tpublic create(runtime: IFluidDataStoreRuntime, id: string): T & IChannel {\n\t\t\tconst shared = new SharedObjectFromKernel(\n\t\t\t\tid,\n\t\t\t\truntime,\n\t\t\t\tChannelFactory.Attributes,\n\t\t\t\toptions.factory,\n\t\t\t\toptions.telemetryContextPrefix,\n\t\t\t);\n\n\t\t\tshared.initializeLocal();\n\n\t\t\treturn shared as unknown as T & IChannel;\n\t\t}\n\t}\n\n\treturn ChannelFactory;\n}\n\n/**\n * Utility to create a {@link SharedObjectKind}.\n * @privateRemarks\n * Using this API avoids having to subclasses any Fluid Framework types,\n * reducing the coupling between the framework and the SharedObject implementation.\n * @internal\n */\nexport function makeSharedObjectKind<T extends object>(\n\toptions: SharedObjectOptions<T>,\n): ISharedObjectKind<T> & SharedObjectKindAlpha<T> {\n\treturn createSharedObjectKindAlpha<T>(makeChannelFactory(options));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAC/E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AAQ1F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,OAAO,EACd,UAAU,EAAE,gBAAgB,EAC5B,IAAI,EAAE,YAAY,GAChB,MAAM,GAAG,SAAS,CAEpB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACtC,KAAK,EAAE,OAAO,EACd,UAAU,EAAE,gBAAgB,EAC5B,IAAI,EAAE,YAAY,GAChB,OAAO,CAET;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAElF;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACtC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GAAG,UAAU,GAC1B,qBAAqB,CAIvB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,GAAG,CAAC,CA+BxE;AAED;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAC/E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AAS1F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,OAAO,EACd,UAAU,EAAE,gBAAgB,EAC5B,IAAI,EAAE,YAAY,GAChB,MAAM,GAAG,SAAS,CAEpB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACtC,KAAK,EAAE,OAAO,EACd,UAAU,EAAE,gBAAgB,EAC5B,IAAI,EAAE,YAAY,GAChB,OAAO,CAET;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAElF;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACtC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GAAG,UAAU,GAC1B,qBAAqB,CAKvB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,GAAG,CAAC,CA+BxE;AAED;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC"}
package/lib/utils.js CHANGED
@@ -3,7 +3,9 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { assert, isObject } from "@fluidframework/core-utils/internal";
6
- import { isFluidHandle, SummaryTreeBuilder, toFluidHandleInternal, } from "@fluidframework/runtime-utils/internal";
6
+ import { isFluidHandle,
7
+ // eslint-disable-next-line import-x/no-deprecated -- Internal implementation use is supported (AB#88250).
8
+ SummaryTreeBuilder, toFluidHandleInternal, } from "@fluidframework/runtime-utils/internal";
7
9
  import { isISharedObjectHandle } from "./handle.js";
8
10
  /**
9
11
  * Given a mostly-plain object that may have handle objects embedded within, return a string representation of an object
@@ -55,6 +57,7 @@ export function parseHandles(value, serializer) {
55
57
  * @internal
56
58
  */
57
59
  export function createSingleBlobSummary(key, content) {
60
+ // eslint-disable-next-line import-x/no-deprecated -- Internal implementation use is supported (AB#88250).
58
61
  const builder = new SummaryTreeBuilder();
59
62
  builder.addBlob(key, content);
60
63
  return builder.getSummaryTree();
package/lib/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAGvE,OAAO,EACN,aAAa,EACb,kBAAkB,EAClB,qBAAqB,GACrB,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGpD;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC/B,KAAc,EACd,UAA4B,EAC5B,IAAkB;IAElB,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACxE,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CACtC,KAAc,EACd,UAA4B,EAC5B,IAAkB;IAElB,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc,EAAE,UAA4B;IACxE,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACtC,GAAW,EACX,OAA4B;IAE5B,MAAM,OAAO,GAAG,IAAI,kBAAkB,EAAE,CAAC;IACzC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,OAAO,CAAC,cAAc,EAAE,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAc,KAAQ,EAAE,IAAkB;IACpE,MAAM,cAAc,GAAc,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAW,CAAC;IAExC,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAErF,OAAO,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,EAAE,CAAC;QAElC,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;QACxC,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3D,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;gBACzB,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBACpB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC3B,CAAC;YACF,CAAC;QACF,CAAC;aAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACtD,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;oBACnB,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC1B,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAED,wFAAwF;IACxF,OAAO,KAAK,CAAC;AACd,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport { assert, isObject } from \"@fluidframework/core-utils/internal\";\nimport type { IChannel } from \"@fluidframework/datastore-definitions/internal\";\nimport type { ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions/internal\";\nimport {\n\tisFluidHandle,\n\tSummaryTreeBuilder,\n\ttoFluidHandleInternal,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport { isISharedObjectHandle } from \"./handle.js\";\nimport type { IFluidSerializer } from \"./serializer.js\";\n\n/**\n * Given a mostly-plain object that may have handle objects embedded within, return a string representation of an object\n * where the handle objects have been replaced with a serializable form.\n * @param value - The mostly-plain object\n * @param serializer - The serializer that knows how to convert handles into serializable format\n * @param context - The handle context for the container\n * @param bind - Bind any other handles we find in the object against this given handle.\n * @returns Result of strigifying an object\n * @internal\n */\nexport function serializeHandles(\n\tvalue: unknown,\n\tserializer: IFluidSerializer,\n\tbind: IFluidHandle,\n): string | undefined {\n\treturn value === undefined ? value : serializer.stringify(value, bind);\n}\n\n/**\n * Given a mostly-plain object that may have handle objects embedded within, will return a fully-plain object\n * where any embedded IFluidHandles have been replaced with a serializable form.\n *\n * The original `input` object is not mutated. This method will shallowly clones all objects in the path from\n * the root to any replaced handles. (If no handles are found, returns the original object.)\n *\n * @param input - The mostly-plain object\n * @param context - The handle context for the container\n * @param bind - Bind any other handles we find in the object against this given handle.\n * @returns The fully-plain object\n * @legacy @beta\n */\nexport function makeHandlesSerializable(\n\tvalue: unknown,\n\tserializer: IFluidSerializer,\n\tbind: IFluidHandle,\n): unknown {\n\treturn serializer.encode(value, bind);\n}\n\n/**\n * Given a fully-plain object that may have serializable-form handles within, will return the mostly-plain object\n * with handle objects created instead.\n * @remarks Idempotent when called multiple times.\n * @param value - The fully-plain object\n * @param serializer - The serializer that knows how to convert serializable-form handles into handle objects\n * @param context - The handle context for the container\n * @returns The mostly-plain object with handle objects within\n * @legacy @beta\n */\nexport function parseHandles(value: unknown, serializer: IFluidSerializer): unknown {\n\treturn serializer.decode(value);\n}\n\n/**\n * Create a new summary containing one blob\n * @param key - the key for the blob in the summary\n * @param content - blob content\n * @returns The summary containing the blob\n * @internal\n */\nexport function createSingleBlobSummary(\n\tkey: string,\n\tcontent: string | Uint8Array,\n): ISummaryTreeWithStats {\n\tconst builder = new SummaryTreeBuilder();\n\tbuilder.addBlob(key, content);\n\treturn builder.getSummaryTree();\n}\n\n/**\n * Binds all handles found in `value` to `bind`. Does not modify original input.\n *\n * @internal\n */\nexport function bindHandles<T = unknown>(value: T, bind: IFluidHandle): T {\n\tconst nodesToProcess: unknown[] = [value];\n\tconst visitedNodes = new Set<unknown>();\n\n\tassert(isISharedObjectHandle(bind), 0xc85 /* bind must be an ISharedObjectHandle */);\n\n\twhile (nodesToProcess.length > 0) {\n\t\tconst node = nodesToProcess.pop();\n\n\t\tif (isFluidHandle(node)) {\n\t\t\tvisitedNodes.add(node);\n\t\t\tbind.bind(toFluidHandleInternal(node));\n\t\t} else if (Array.isArray(node) && !visitedNodes.has(node)) {\n\t\t\tvisitedNodes.add(node);\n\t\t\tfor (const item of node) {\n\t\t\t\tif (isObject(item)) {\n\t\t\t\t\tnodesToProcess.push(item);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (isObject(node) && !visitedNodes.has(node)) {\n\t\t\tvisitedNodes.add(node);\n\t\t\tfor (const val of Object.values(node)) {\n\t\t\t\tif (isObject(val)) {\n\t\t\t\t\tnodesToProcess.push(val);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the input value so this function can be swapped in for makeHandlesSerializable\n\treturn value;\n}\n\n/**\n * Information about a Fluid channel.\n * @privateRemarks\n * This is distinct from {@link IChannel} as it omits the APIs used by the runtime to manage the channel and instead only has things which are useful (and safe) to expose to users of the channel.\n * @internal\n */\nexport type IChannelView = Pick<IChannel, \"id\" | \"attributes\" | \"isAttached\">;\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAGvE,OAAO,EACN,aAAa;AACb,0GAA0G;AAC1G,kBAAkB,EAClB,qBAAqB,GACrB,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGpD;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC/B,KAAc,EACd,UAA4B,EAC5B,IAAkB;IAElB,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACxE,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CACtC,KAAc,EACd,UAA4B,EAC5B,IAAkB;IAElB,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc,EAAE,UAA4B;IACxE,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACtC,GAAW,EACX,OAA4B;IAE5B,0GAA0G;IAC1G,MAAM,OAAO,GAAG,IAAI,kBAAkB,EAAE,CAAC;IACzC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,OAAO,CAAC,cAAc,EAAE,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAc,KAAQ,EAAE,IAAkB;IACpE,MAAM,cAAc,GAAc,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAW,CAAC;IAExC,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAErF,OAAO,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,EAAE,CAAC;QAElC,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;QACxC,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3D,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;gBACzB,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBACpB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC3B,CAAC;YACF,CAAC;QACF,CAAC;aAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACtD,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;oBACnB,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC1B,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAED,wFAAwF;IACxF,OAAO,KAAK,CAAC;AACd,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport { assert, isObject } from \"@fluidframework/core-utils/internal\";\nimport type { IChannel } from \"@fluidframework/datastore-definitions/internal\";\nimport type { ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions/internal\";\nimport {\n\tisFluidHandle,\n\t// eslint-disable-next-line import-x/no-deprecated -- Internal implementation use is supported (AB#88250).\n\tSummaryTreeBuilder,\n\ttoFluidHandleInternal,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport { isISharedObjectHandle } from \"./handle.js\";\nimport type { IFluidSerializer } from \"./serializer.js\";\n\n/**\n * Given a mostly-plain object that may have handle objects embedded within, return a string representation of an object\n * where the handle objects have been replaced with a serializable form.\n * @param value - The mostly-plain object\n * @param serializer - The serializer that knows how to convert handles into serializable format\n * @param context - The handle context for the container\n * @param bind - Bind any other handles we find in the object against this given handle.\n * @returns Result of strigifying an object\n * @internal\n */\nexport function serializeHandles(\n\tvalue: unknown,\n\tserializer: IFluidSerializer,\n\tbind: IFluidHandle,\n): string | undefined {\n\treturn value === undefined ? value : serializer.stringify(value, bind);\n}\n\n/**\n * Given a mostly-plain object that may have handle objects embedded within, will return a fully-plain object\n * where any embedded IFluidHandles have been replaced with a serializable form.\n *\n * The original `input` object is not mutated. This method will shallowly clones all objects in the path from\n * the root to any replaced handles. (If no handles are found, returns the original object.)\n *\n * @param input - The mostly-plain object\n * @param context - The handle context for the container\n * @param bind - Bind any other handles we find in the object against this given handle.\n * @returns The fully-plain object\n * @legacy @beta\n */\nexport function makeHandlesSerializable(\n\tvalue: unknown,\n\tserializer: IFluidSerializer,\n\tbind: IFluidHandle,\n): unknown {\n\treturn serializer.encode(value, bind);\n}\n\n/**\n * Given a fully-plain object that may have serializable-form handles within, will return the mostly-plain object\n * with handle objects created instead.\n * @remarks Idempotent when called multiple times.\n * @param value - The fully-plain object\n * @param serializer - The serializer that knows how to convert serializable-form handles into handle objects\n * @param context - The handle context for the container\n * @returns The mostly-plain object with handle objects within\n * @legacy @beta\n */\nexport function parseHandles(value: unknown, serializer: IFluidSerializer): unknown {\n\treturn serializer.decode(value);\n}\n\n/**\n * Create a new summary containing one blob\n * @param key - the key for the blob in the summary\n * @param content - blob content\n * @returns The summary containing the blob\n * @internal\n */\nexport function createSingleBlobSummary(\n\tkey: string,\n\tcontent: string | Uint8Array,\n): ISummaryTreeWithStats {\n\t// eslint-disable-next-line import-x/no-deprecated -- Internal implementation use is supported (AB#88250).\n\tconst builder = new SummaryTreeBuilder();\n\tbuilder.addBlob(key, content);\n\treturn builder.getSummaryTree();\n}\n\n/**\n * Binds all handles found in `value` to `bind`. Does not modify original input.\n *\n * @internal\n */\nexport function bindHandles<T = unknown>(value: T, bind: IFluidHandle): T {\n\tconst nodesToProcess: unknown[] = [value];\n\tconst visitedNodes = new Set<unknown>();\n\n\tassert(isISharedObjectHandle(bind), 0xc85 /* bind must be an ISharedObjectHandle */);\n\n\twhile (nodesToProcess.length > 0) {\n\t\tconst node = nodesToProcess.pop();\n\n\t\tif (isFluidHandle(node)) {\n\t\t\tvisitedNodes.add(node);\n\t\t\tbind.bind(toFluidHandleInternal(node));\n\t\t} else if (Array.isArray(node) && !visitedNodes.has(node)) {\n\t\t\tvisitedNodes.add(node);\n\t\t\tfor (const item of node) {\n\t\t\t\tif (isObject(item)) {\n\t\t\t\t\tnodesToProcess.push(item);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (isObject(node) && !visitedNodes.has(node)) {\n\t\t\tvisitedNodes.add(node);\n\t\t\tfor (const val of Object.values(node)) {\n\t\t\t\tif (isObject(val)) {\n\t\t\t\t\tnodesToProcess.push(val);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the input value so this function can be swapped in for makeHandlesSerializable\n\treturn value;\n}\n\n/**\n * Information about a Fluid channel.\n * @privateRemarks\n * This is distinct from {@link IChannel} as it omits the APIs used by the runtime to manage the channel and instead only has things which are useful (and safe) to expose to users of the channel.\n * @internal\n */\nexport type IChannelView = Pick<IChannel, \"id\" | \"attributes\" | \"isAttached\">;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/shared-object-base",
3
- "version": "3.7.0",
3
+ "version": "3.11.0",
4
4
  "description": "Fluid base class for shared distributed data structures",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -55,31 +55,31 @@
55
55
  "temp-directory": "nyc/.nyc_output"
56
56
  },
57
57
  "dependencies": {
58
- "@fluid-internal/client-utils": "~3.7.0",
59
- "@fluidframework/container-definitions": "~3.7.0",
60
- "@fluidframework/core-interfaces": "~3.7.0",
61
- "@fluidframework/core-utils": "~3.7.0",
62
- "@fluidframework/datastore": "~3.7.0",
63
- "@fluidframework/datastore-definitions": "~3.7.0",
64
- "@fluidframework/driver-definitions": "~3.7.0",
65
- "@fluidframework/id-compressor": "~3.7.0",
66
- "@fluidframework/runtime-definitions": "~3.7.0",
67
- "@fluidframework/runtime-utils": "~3.7.0",
68
- "@fluidframework/telemetry-utils": "~3.7.0",
58
+ "@fluid-internal/client-utils": "~3.11.0",
59
+ "@fluidframework/container-definitions": "~3.11.0",
60
+ "@fluidframework/core-interfaces": "~3.11.0",
61
+ "@fluidframework/core-utils": "~3.11.0",
62
+ "@fluidframework/datastore": "~3.11.0",
63
+ "@fluidframework/datastore-definitions": "~3.11.0",
64
+ "@fluidframework/driver-definitions": "~3.11.0",
65
+ "@fluidframework/id-compressor": "~3.11.0",
66
+ "@fluidframework/runtime-definitions": "~3.11.0",
67
+ "@fluidframework/runtime-utils": "~3.11.0",
68
+ "@fluidframework/telemetry-utils": "~3.11.0",
69
69
  "uuid": "^11.1.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@arethetypeswrong/cli": "^0.18.5",
73
73
  "@biomejs/biome": "~2.4.5",
74
- "@fluid-internal/mocha-test-setup": "~3.7.0",
75
- "@fluid-private/test-pairwise-generator": "~3.7.0",
74
+ "@fluid-internal/mocha-test-setup": "~3.11.0",
75
+ "@fluid-private/test-pairwise-generator": "~3.11.0",
76
76
  "@fluid-tools/benchmark": "^0.59.0",
77
77
  "@fluid-tools/build-cli": "^0.68.0",
78
78
  "@fluidframework/build-common": "^2.0.3",
79
79
  "@fluidframework/build-tools": "^0.68.0",
80
80
  "@fluidframework/eslint-config-fluid": "^14.0.0",
81
- "@fluidframework/shared-object-base-previous": "npm:@fluidframework/shared-object-base@3.6.0",
82
- "@fluidframework/test-runtime-utils": "~3.7.0",
81
+ "@fluidframework/shared-object-base-previous": "npm:@fluidframework/shared-object-base@3.7.0",
82
+ "@fluidframework/test-runtime-utils": "~3.11.0",
83
83
  "@microsoft/api-extractor": "7.58.1",
84
84
  "@types/mocha": "^10.0.10",
85
85
  "@types/node": "~22.19.17",
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/shared-object-base";
9
- export const pkgVersion = "3.7.0";
9
+ export const pkgVersion = "3.11.0";
@@ -79,6 +79,10 @@ interface ProcessTelemetryProperties {
79
79
  * @remarks
80
80
  * This class implements common behaviors that implementations of {@link ISharedObject} may want to reuse.
81
81
  * Even more such behaviors are implemented in the {@link SharedObject} class.
82
+ * @deprecated This class will become internal in release 3.20.0.
83
+ * Use existing distributed data structures instead of custom subclasses.
84
+ * Use {@link ISharedObject} for types that do not expose implementation details.
85
+ * See {@link https://github.com/microsoft/FluidFramework/issues/26284} for details.
82
86
  * @privateRemarks
83
87
  * Currently some documentation (like the above) implies that this is supposed to be the only implementation of ISharedObject, which is both package-exported and not `@sealed`.
84
88
  * This situation should be clarified to indicate if other implementations of ISharedObject are allowed and just currently don't exist,
@@ -725,6 +729,10 @@ export abstract class SharedObjectCore<
725
729
  * Helper for implementing {@link ISharedObject} with simplified, synchronous summarization and garbage collection.
726
730
  * @remarks
727
731
  * DDS implementations with async and incremental summarization should extend {@link SharedObjectCore} directly instead.
732
+ * @deprecated This class will become internal in release 3.20.0.
733
+ * Use existing distributed data structures instead of custom subclasses.
734
+ * Use {@link ISharedObject} for types that do not expose implementation details.
735
+ * See {@link https://github.com/microsoft/FluidFramework/issues/26284} for details.
728
736
  * @privateRemarks
729
737
  * TODO:
730
738
  * This class is badly named.
@@ -29,6 +29,7 @@ import { extractTelemetryLoggerExt } from "@fluidframework/telemetry-utils/inter
29
29
  import type { IFluidSerializer } from "./serializer.js";
30
30
  import {
31
31
  createSharedObjectKindAlpha,
32
+ // eslint-disable-next-line import-x/no-deprecated -- Internal implementations still use this base class.
32
33
  SharedObject,
33
34
  type ISharedObjectKind,
34
35
  type SharedObjectKindAlpha,
@@ -114,6 +115,7 @@ export interface SharedKernel {
114
115
  class SharedObjectFromKernel<
115
116
  TOut extends object,
116
117
  TEvent extends ISharedObjectEvents,
118
+ // eslint-disable-next-line import-x/no-deprecated -- Internal implementations still use this base class.
117
119
  > extends SharedObject<TEvent> {
118
120
  /**
119
121
  * Lazy init here so kernel can be constructed in loadCore when loading from existing data.
@@ -139,9 +141,9 @@ class SharedObjectFromKernel<
139
141
  // at the cost of less compile-time enforcement. For example, if the runtime did not implement `minVersionForCollab` and the
140
142
  // member was still optional (e.g., during the deprecation window where backwards-compatibility is maintained), the compiler
141
143
  // would emit an error.
142
- const minVersionForCollab: OldestSupportedClientVersion | undefined = (
143
- runtime as IFluidDataStoreRuntimeInternalConfig
144
- ).minVersionForCollab;
144
+ const minVersionForCollab: OldestSupportedClientVersion | undefined =
145
+ (runtime as IFluidDataStoreRuntimeInternalConfig).oldestSupportedClient ??
146
+ (runtime as IFluidDataStoreRuntimeInternalConfig).minVersionForCollab;
145
147
 
146
148
  assert(minVersionForCollab !== undefined, 0xcee /* minVersionForCollab must be defined */);
147
149
 
@@ -156,6 +158,7 @@ class SharedObjectFromKernel<
156
158
  lastSequenceNumber: () => this.deltaManager.lastSequenceNumber,
157
159
  initialSequenceNumber: this.deltaManager.initialSequenceNumber,
158
160
  minVersionForCollab,
161
+ oldestSupportedClient: minVersionForCollab,
159
162
  };
160
163
  }
161
164
 
@@ -313,6 +316,17 @@ export interface KernelArgs {
313
316
  * for more details.
314
317
  */
315
318
  readonly minVersionForCollab: OldestSupportedClientVersion;
319
+
320
+ /**
321
+ * Oldest Fluid Framework client version that must be able to process documents with operations from this SharedObject implementation.
322
+ *
323
+ * @remarks
324
+ * To keep these documents compatible with the specified client version, the implementation uses this value to select feature flags and formats.
325
+ * As a result, an older version can limit available features and write formats.
326
+ * See {@link @fluidframework/container-runtime#LoadContainerRuntimeParams.oldestSupportedClient}
327
+ * for details about this compatibility setting.
328
+ */
329
+ readonly oldestSupportedClient: OldestSupportedClientVersion;
316
330
  }
317
331
 
318
332
  /**
package/src/utils.ts CHANGED
@@ -9,6 +9,7 @@ import type { IChannel } from "@fluidframework/datastore-definitions/internal";
9
9
  import type { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions/internal";
10
10
  import {
11
11
  isFluidHandle,
12
+ // eslint-disable-next-line import-x/no-deprecated -- Internal implementation use is supported (AB#88250).
12
13
  SummaryTreeBuilder,
13
14
  toFluidHandleInternal,
14
15
  } from "@fluidframework/runtime-utils/internal";
@@ -80,6 +81,7 @@ export function createSingleBlobSummary(
80
81
  key: string,
81
82
  content: string | Uint8Array,
82
83
  ): ISummaryTreeWithStats {
84
+ // eslint-disable-next-line import-x/no-deprecated -- Internal implementation use is supported (AB#88250).
83
85
  const builder = new SummaryTreeBuilder();
84
86
  builder.addBlob(key, content);
85
87
  return builder.getSummaryTree();