@fluidframework/shared-object-base 2.118.0 → 3.0.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +34 -4
  2. package/README.md +53 -50
  3. package/{api-extractor.json → api-extractor/api-extractor-model.json} +1 -1
  4. package/dist/dataStoreKind.js +2 -3
  5. package/dist/dataStoreKind.js.map +1 -1
  6. package/dist/gcHandleVisitor.js +1 -4
  7. package/dist/gcHandleVisitor.js.map +1 -1
  8. package/dist/handle.js +9 -7
  9. package/dist/handle.js.map +1 -1
  10. package/dist/packageVersion.d.ts +1 -1
  11. package/dist/packageVersion.d.ts.map +1 -1
  12. package/dist/packageVersion.js +1 -1
  13. package/dist/packageVersion.js.map +1 -1
  14. package/dist/serializer.js +2 -0
  15. package/dist/serializer.js.map +1 -1
  16. package/dist/sharedObject.js +42 -15
  17. package/dist/sharedObject.js.map +1 -1
  18. package/dist/sharedObjectKernel.js +41 -52
  19. package/dist/sharedObjectKernel.js.map +1 -1
  20. package/dist/stubSharedObject.js +1 -2
  21. package/dist/stubSharedObject.js.map +1 -1
  22. package/dist/utils.js +5 -6
  23. package/dist/utils.js.map +1 -1
  24. package/lib/gcHandleVisitor.js +1 -4
  25. package/lib/gcHandleVisitor.js.map +1 -1
  26. package/lib/handle.js +7 -5
  27. package/lib/handle.js.map +1 -1
  28. package/lib/legacy.d.ts +1 -1
  29. package/lib/packageVersion.d.ts +1 -1
  30. package/lib/packageVersion.d.ts.map +1 -1
  31. package/lib/packageVersion.js +1 -1
  32. package/lib/packageVersion.js.map +1 -1
  33. package/lib/public.d.ts +1 -1
  34. package/lib/serializer.js +2 -0
  35. package/lib/serializer.js.map +1 -1
  36. package/lib/sharedObject.js +39 -12
  37. package/lib/sharedObject.js.map +1 -1
  38. package/lib/sharedObjectKernel.js +38 -49
  39. package/lib/sharedObjectKernel.js.map +1 -1
  40. package/package.json +36 -50
  41. package/src/packageVersion.ts +1 -1
  42. package/tsconfig.json +1 -1
  43. package/internal.d.ts +0 -11
  44. package/legacy.d.ts +0 -11
  45. /package/api-extractor/{api-extractor.current.json → api-extractor-report.current.json} +0 -0
  46. /package/api-extractor/{api-extractor.legacy.json → api-extractor-report.legacy.json} +0 -0
@@ -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\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.\"type\"}\n\t\t */\n\t\tpublic get type(): string {\n\t\t\treturn ChannelFactory.Type;\n\t\t}\n\n\t\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.attributes}\n\t\t */\n\t\tpublic get attributes(): IChannelAttributes {\n\t\t\treturn ChannelFactory.Attributes;\n\t\t}\n\n\t\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}\n\t\t */\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\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.create}\n\t\t */\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\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\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.\"type\"}\n\t\t */\n\t\tpublic get type(): string {\n\t\t\treturn ChannelFactory.Type;\n\t\t}\n\n\t\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.attributes}\n\t\t */\n\t\tpublic get attributes(): IChannelAttributes {\n\t\t\treturn ChannelFactory.Attributes;\n\t\t}\n\n\t\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}\n\t\t */\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\t/**\n\t\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.create}\n\t\t */\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"]}
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.makeStubDataStoreKind = void 0;
7
+ exports.makeStubDataStoreKind = makeStubDataStoreKind;
8
8
  const dataStoreKind_js_1 = require("./dataStoreKind.js");
9
9
  const sharedObjectKernel_js_1 = require("./sharedObjectKernel.js");
10
10
  const utils_js_1 = require("./utils.js");
@@ -54,5 +54,4 @@ function makeStubDataStoreKind(type) {
54
54
  },
55
55
  });
56
56
  }
57
- exports.makeStubDataStoreKind = makeStubDataStoreKind;
58
57
  //# sourceMappingURL=stubSharedObject.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stubSharedObject.js","sourceRoot":"","sources":["../src/stubSharedObject.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAMH,yDAAuF;AACvF,mEAIiC;AACjC,yCAAqD;AAErD,MAAM,eAAe;IACpB,aAAa;QACZ,OAAO,IAAA,kCAAuB,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,YAAY,KAAU,CAAC;IACvB,YAAY,KAAU,CAAC;IACvB,cAAc,KAAU,CAAC;IACzB,mBAAmB,KAAU,CAAC;CAC9B;AAED,MAAM,sBAAsB,GAAgC;IAC3D,MAAM;QACL,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QACrC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAC7B,CAAC;IACD,KAAK,CAAC,QAAQ;QACb,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QACrC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAC7B,CAAC;CACD,CAAC;AAEF,MAAM,yBAAyB,GAAG,IAAA,4CAAoB,EAAiB;IACtE,IAAI,EAAE,oCAAoC;IAC1C,UAAU,EAAE;QACX,IAAI,EAAE,oCAAoC;QAC1C,qBAAqB,EAAE,KAAK;KAC5B;IACD,sBAAsB,EAAE,iBAAiB;IACzC,OAAO,EAAE,sBAAsB;CAC/B,CAAC,CAAC;AAEH;;;;;GAKG;AACH,SAAgB,qBAAqB,CAAC,IAAY;IACjD,OAAO,IAAA,kCAAe,EAAC;QACtB,IAAI;QACJ,QAAQ,EAAE,IAAA,mDAAgC,EAAC,CAAC,yBAAyB,CAAC,CAAC;QACvE,KAAK,CAAC,oBAAoB,CAAC,WAAW;YACrC,OAAO,WAAW,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,CAAC;QAClE,CAAC;QACD,KAAK,CAAC,IAAI;YACT,OAAO,EAAE,CAAC;QACX,CAAC;KACD,CAAC,CAAC;AACJ,CAAC;AAXD,sDAWC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidLoadable } from \"@fluidframework/core-interfaces\";\nimport type { DataStoreKind } from \"@fluidframework/driver-definitions/internal\";\nimport type { ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions/internal\";\n\nimport { defineDataStore, sharedObjectRegistryFromIterable } from \"./dataStoreKind.js\";\nimport {\n\ttype SharedKernel,\n\ttype SharedKernelFactory,\n\tmakeSharedObjectKind,\n} from \"./sharedObjectKernel.js\";\nimport { createSingleBlobSummary } from \"./utils.js\";\n\nclass StatelessKernel implements SharedKernel {\n\tsummarizeCore(): ISummaryTreeWithStats {\n\t\treturn createSingleBlobSummary(\"header\", \"{}\");\n\t}\n\tonDisconnect(): void {}\n\treSubmitCore(): void {}\n\tapplyStashedOp(): void {}\n\tprocessMessagesCore(): void {}\n}\n\nconst statelessKernelFactory: SharedKernelFactory<object> = {\n\tcreate() {\n\t\tconst kernel = new StatelessKernel();\n\t\treturn { kernel, view: {} };\n\t},\n\tasync loadCore() {\n\t\tconst kernel = new StatelessKernel();\n\t\treturn { kernel, view: {} };\n\t},\n};\n\nconst statelessSharedObjectKind = makeSharedObjectKind<IFluidLoadable>({\n\ttype: \"com.microsoft.fluid.test.stateless\",\n\tattributes: {\n\t\ttype: \"com.microsoft.fluid.test.stateless\",\n\t\tsnapshotFormatVersion: \"0.1\",\n\t},\n\ttelemetryContextPrefix: \"test_stateless_\",\n\tfactory: statelessKernelFactory,\n});\n\n/**\n * Creates a trivial stub {@link @fluidframework/driver-definitions#DataStoreKind} backed by a\n * stateless shared object.\n * Useful in tests that need a valid data store but don't care about the content.\n * @internal\n */\nexport function makeStubDataStoreKind(type: string): DataStoreKind {\n\treturn defineDataStore({\n\t\ttype,\n\t\tregistry: sharedObjectRegistryFromIterable([statelessSharedObjectKind]),\n\t\tasync instantiateFirstTime(rootCreator) {\n\t\t\treturn rootCreator.createSharedObject(statelessSharedObjectKind);\n\t\t},\n\t\tasync view() {\n\t\t\treturn {};\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"stubSharedObject.js","sourceRoot":"","sources":["../src/stubSharedObject.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAmDH,sDAWC;AAxDD,yDAAuF;AACvF,mEAIiC;AACjC,yCAAqD;AAErD,MAAM,eAAe;IACpB,aAAa;QACZ,OAAO,IAAA,kCAAuB,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,YAAY,KAAU,CAAC;IACvB,YAAY,KAAU,CAAC;IACvB,cAAc,KAAU,CAAC;IACzB,mBAAmB,KAAU,CAAC;CAC9B;AAED,MAAM,sBAAsB,GAAgC;IAC3D,MAAM;QACL,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QACrC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAC7B,CAAC;IACD,KAAK,CAAC,QAAQ;QACb,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QACrC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAC7B,CAAC;CACD,CAAC;AAEF,MAAM,yBAAyB,GAAG,IAAA,4CAAoB,EAAiB;IACtE,IAAI,EAAE,oCAAoC;IAC1C,UAAU,EAAE;QACX,IAAI,EAAE,oCAAoC;QAC1C,qBAAqB,EAAE,KAAK;KAC5B;IACD,sBAAsB,EAAE,iBAAiB;IACzC,OAAO,EAAE,sBAAsB;CAC/B,CAAC,CAAC;AAEH;;;;;GAKG;AACH,SAAgB,qBAAqB,CAAC,IAAY;IACjD,OAAO,IAAA,kCAAe,EAAC;QACtB,IAAI;QACJ,QAAQ,EAAE,IAAA,mDAAgC,EAAC,CAAC,yBAAyB,CAAC,CAAC;QACvE,KAAK,CAAC,oBAAoB,CAAC,WAAW;YACrC,OAAO,WAAW,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,CAAC;QAClE,CAAC;QACD,KAAK,CAAC,IAAI;YACT,OAAO,EAAE,CAAC;QACX,CAAC;KACD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidLoadable } from \"@fluidframework/core-interfaces\";\nimport type { DataStoreKind } from \"@fluidframework/driver-definitions/internal\";\nimport type { ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions/internal\";\n\nimport { defineDataStore, sharedObjectRegistryFromIterable } from \"./dataStoreKind.js\";\nimport {\n\ttype SharedKernel,\n\ttype SharedKernelFactory,\n\tmakeSharedObjectKind,\n} from \"./sharedObjectKernel.js\";\nimport { createSingleBlobSummary } from \"./utils.js\";\n\nclass StatelessKernel implements SharedKernel {\n\tsummarizeCore(): ISummaryTreeWithStats {\n\t\treturn createSingleBlobSummary(\"header\", \"{}\");\n\t}\n\tonDisconnect(): void {}\n\treSubmitCore(): void {}\n\tapplyStashedOp(): void {}\n\tprocessMessagesCore(): void {}\n}\n\nconst statelessKernelFactory: SharedKernelFactory<object> = {\n\tcreate() {\n\t\tconst kernel = new StatelessKernel();\n\t\treturn { kernel, view: {} };\n\t},\n\tasync loadCore() {\n\t\tconst kernel = new StatelessKernel();\n\t\treturn { kernel, view: {} };\n\t},\n};\n\nconst statelessSharedObjectKind = makeSharedObjectKind<IFluidLoadable>({\n\ttype: \"com.microsoft.fluid.test.stateless\",\n\tattributes: {\n\t\ttype: \"com.microsoft.fluid.test.stateless\",\n\t\tsnapshotFormatVersion: \"0.1\",\n\t},\n\ttelemetryContextPrefix: \"test_stateless_\",\n\tfactory: statelessKernelFactory,\n});\n\n/**\n * Creates a trivial stub {@link @fluidframework/driver-definitions#DataStoreKind} backed by a\n * stateless shared object.\n * Useful in tests that need a valid data store but don't care about the content.\n * @internal\n */\nexport function makeStubDataStoreKind(type: string): DataStoreKind {\n\treturn defineDataStore({\n\t\ttype,\n\t\tregistry: sharedObjectRegistryFromIterable([statelessSharedObjectKind]),\n\t\tasync instantiateFirstTime(rootCreator) {\n\t\t\treturn rootCreator.createSharedObject(statelessSharedObjectKind);\n\t\t},\n\t\tasync view() {\n\t\t\treturn {};\n\t\t},\n\t});\n}\n"]}
package/dist/utils.js CHANGED
@@ -4,7 +4,11 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.bindHandles = exports.createSingleBlobSummary = exports.parseHandles = exports.makeHandlesSerializable = exports.serializeHandles = void 0;
7
+ exports.serializeHandles = serializeHandles;
8
+ exports.makeHandlesSerializable = makeHandlesSerializable;
9
+ exports.parseHandles = parseHandles;
10
+ exports.createSingleBlobSummary = createSingleBlobSummary;
11
+ exports.bindHandles = bindHandles;
8
12
  const internal_1 = require("@fluidframework/core-utils/internal");
9
13
  const internal_2 = require("@fluidframework/runtime-utils/internal");
10
14
  const handle_js_1 = require("./handle.js");
@@ -21,7 +25,6 @@ const handle_js_1 = require("./handle.js");
21
25
  function serializeHandles(value, serializer, bind) {
22
26
  return value === undefined ? value : serializer.stringify(value, bind);
23
27
  }
24
- exports.serializeHandles = serializeHandles;
25
28
  /**
26
29
  * Given a mostly-plain object that may have handle objects embedded within, will return a fully-plain object
27
30
  * where any embedded IFluidHandles have been replaced with a serializable form.
@@ -38,7 +41,6 @@ exports.serializeHandles = serializeHandles;
38
41
  function makeHandlesSerializable(value, serializer, bind) {
39
42
  return serializer.encode(value, bind);
40
43
  }
41
- exports.makeHandlesSerializable = makeHandlesSerializable;
42
44
  /**
43
45
  * Given a fully-plain object that may have serializable-form handles within, will return the mostly-plain object
44
46
  * with handle objects created instead.
@@ -52,7 +54,6 @@ exports.makeHandlesSerializable = makeHandlesSerializable;
52
54
  function parseHandles(value, serializer) {
53
55
  return serializer.decode(value);
54
56
  }
55
- exports.parseHandles = parseHandles;
56
57
  /**
57
58
  * Create a new summary containing one blob
58
59
  * @param key - the key for the blob in the summary
@@ -65,7 +66,6 @@ function createSingleBlobSummary(key, content) {
65
66
  builder.addBlob(key, content);
66
67
  return builder.getSummaryTree();
67
68
  }
68
- exports.createSingleBlobSummary = createSingleBlobSummary;
69
69
  /**
70
70
  * Binds all handles found in `value` to `bind`. Does not modify original input.
71
71
  *
@@ -101,5 +101,4 @@ function bindHandles(value, bind) {
101
101
  // Return the input value so this function can be swapped in for makeHandlesSerializable
102
102
  return value;
103
103
  }
104
- exports.bindHandles = bindHandles;
105
104
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,kEAAuE;AAGvE,qEAIgD;AAEhD,2CAAoD;AAGpD;;;;;;;;;GASG;AACH,SAAgB,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;AAND,4CAMC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,uBAAuB,CACtC,KAAc,EACd,UAA4B,EAC5B,IAAkB;IAElB,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAND,0DAMC;AAED;;;;;;;;;GASG;AACH,SAAgB,YAAY,CAAC,KAAc,EAAE,UAA4B;IACxE,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAFD,oCAEC;AAED;;;;;;GAMG;AACH,SAAgB,uBAAuB,CACtC,GAAW,EACX,OAA4B;IAE5B,MAAM,OAAO,GAAG,IAAI,6BAAkB,EAAE,CAAC;IACzC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,OAAO,CAAC,cAAc,EAAE,CAAC;AACjC,CAAC;AAPD,0DAOC;AAED;;;;GAIG;AACH,SAAgB,WAAW,CAAc,KAAQ,EAAE,IAAkB;IACpE,MAAM,cAAc,GAAc,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAW,CAAC;IAExC,IAAA,iBAAM,EAAC,IAAA,iCAAqB,EAAC,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,IAAA,wBAAa,EAAC,IAAI,CAAC,EAAE,CAAC;YACzB,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,IAAA,gCAAqB,EAAC,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,IAAA,mBAAQ,EAAC,IAAI,CAAC,EAAE,CAAC;oBACpB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC3B,CAAC;YACF,CAAC;QACF,CAAC;aAAM,IAAI,IAAA,mBAAQ,EAAC,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,IAAA,mBAAQ,EAAC,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;AA/BD,kCA+BC","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;;AAyBH,4CAMC;AAeD,0DAMC;AAYD,oCAEC;AASD,0DAOC;AAOD,kCA+BC;AArHD,kEAAuE;AAGvE,qEAIgD;AAEhD,2CAAoD;AAGpD;;;;;;;;;GASG;AACH,SAAgB,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,SAAgB,uBAAuB,CACtC,KAAc,EACd,UAA4B,EAC5B,IAAkB;IAElB,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,YAAY,CAAC,KAAc,EAAE,UAA4B;IACxE,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,uBAAuB,CACtC,GAAW,EACX,OAA4B;IAE5B,MAAM,OAAO,GAAG,IAAI,6BAAkB,EAAE,CAAC;IACzC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,OAAO,CAAC,cAAc,EAAE,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,SAAgB,WAAW,CAAc,KAAQ,EAAE,IAAkB;IACpE,MAAM,cAAc,GAAc,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAW,CAAC;IAExC,IAAA,iBAAM,EAAC,IAAA,iCAAqB,EAAC,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,IAAA,wBAAa,EAAC,IAAI,CAAC,EAAE,CAAC;YACzB,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,IAAA,gCAAqB,EAAC,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,IAAA,mBAAQ,EAAC,IAAI,CAAC,EAAE,CAAC;oBACpB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC3B,CAAC;YACF,CAAC;QACF,CAAC;aAAM,IAAI,IAAA,mBAAQ,EAAC,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,IAAA,mBAAQ,EAAC,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"]}
@@ -10,10 +10,7 @@ import { FluidSerializer } from "./serializer.js";
10
10
  * All that is needed is getSerializedRoutes() to get the routes. This strategy could be optimized if needed.
11
11
  */
12
12
  export class GCHandleVisitor extends FluidSerializer {
13
- constructor() {
14
- super(...arguments);
15
- this.visitedHandlePaths = new Set();
16
- }
13
+ visitedHandlePaths = new Set();
17
14
  getVisitedHandlePaths() {
18
15
  return [...this.visitedHandlePaths];
19
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gcHandleVisitor.js","sourceRoot":"","sources":["../src/gcHandleVisitor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD;;;;;GAKG;AACH,MAAM,OAAO,eAAgB,SAAQ,eAAe;IAApD;;QACkB,uBAAkB,GAAgB,IAAI,GAAG,EAAE,CAAC;IAe9D,CAAC;IAdO,qBAAqB;QAC3B,OAAO,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACrC,CAAC;IAES,mBAAmB,CAAC,MAA4B;QACzD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAEjD,mEAAmE;QACnE,iGAAiG;QACjG,OAAO;YACN,IAAI,EAAE,kBAAkB;YACxB,GAAG,EAAE,8BAA8B;SACnC,CAAC;IACH,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidHandleInternal } from \"@fluidframework/core-interfaces/internal\";\nimport type { ISerializedHandle } from \"@fluidframework/runtime-utils/internal\";\n\nimport { FluidSerializer } from \"./serializer.js\";\n\n/**\n * Implementation of IFluidSerializer used by GC to visit all the handles in the DDS to collect its outbound routes\n *\n * @remarks This is given to DDS code that typically produces a serialization of the data, which is then ignored.\n * All that is needed is getSerializedRoutes() to get the routes. This strategy could be optimized if needed.\n */\nexport class GCHandleVisitor extends FluidSerializer {\n\tprivate readonly visitedHandlePaths: Set<string> = new Set();\n\tpublic getVisitedHandlePaths(): string[] {\n\t\treturn [...this.visitedHandlePaths];\n\t}\n\n\tprotected bindAndEncodeHandle(handle: IFluidHandleInternal): ISerializedHandle {\n\t\tthis.visitedHandlePaths.add(handle.absolutePath);\n\n\t\t// Just return a dummy value. The serialization itself is not used.\n\t\t// It's especially important we don't bind since that has side effects that are irrelevant to GC.\n\t\treturn {\n\t\t\ttype: \"__fluid_handle__\",\n\t\t\turl: \"UNUSED (see GCHandleVisitor)\",\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"gcHandleVisitor.js","sourceRoot":"","sources":["../src/gcHandleVisitor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD;;;;;GAKG;AACH,MAAM,OAAO,eAAgB,SAAQ,eAAe;IAClC,kBAAkB,GAAgB,IAAI,GAAG,EAAE,CAAC;IACtD,qBAAqB;QAC3B,OAAO,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACrC,CAAC;IAES,mBAAmB,CAAC,MAA4B;QACzD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAEjD,mEAAmE;QACnE,iGAAiG;QACjG,OAAO;YACN,IAAI,EAAE,kBAAkB;YACxB,GAAG,EAAE,8BAA8B;SACnC,CAAC;IACH,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidHandleInternal } from \"@fluidframework/core-interfaces/internal\";\nimport type { ISerializedHandle } from \"@fluidframework/runtime-utils/internal\";\n\nimport { FluidSerializer } from \"./serializer.js\";\n\n/**\n * Implementation of IFluidSerializer used by GC to visit all the handles in the DDS to collect its outbound routes\n *\n * @remarks This is given to DDS code that typically produces a serialization of the data, which is then ignored.\n * All that is needed is getSerializedRoutes() to get the routes. This strategy could be optimized if needed.\n */\nexport class GCHandleVisitor extends FluidSerializer {\n\tprivate readonly visitedHandlePaths: Set<string> = new Set();\n\tpublic getVisitedHandlePaths(): string[] {\n\t\treturn [...this.visitedHandlePaths];\n\t}\n\n\tprotected bindAndEncodeHandle(handle: IFluidHandleInternal): ISerializedHandle {\n\t\tthis.visitedHandlePaths.add(handle.absolutePath);\n\n\t\t// Just return a dummy value. The serialization itself is not used.\n\t\t// It's especially important we don't bind since that has side effects that are irrelevant to GC.\n\t\treturn {\n\t\t\ttype: \"__fluid_handle__\",\n\t\t\turl: \"UNUSED (see GCHandleVisitor)\",\n\t\t};\n\t}\n}\n"]}
package/lib/handle.js CHANGED
@@ -22,6 +22,8 @@ export function isISharedObjectHandle(handle) {
22
22
  * ensuring the target object becomes attached along with this DDS.
23
23
  */
24
24
  export class SharedObjectHandle extends FluidObjectHandle {
25
+ value;
26
+ runtime;
25
27
  /**
26
28
  * Whether services have been attached for the associated shared object.
27
29
  */
@@ -46,6 +48,11 @@ export class SharedObjectHandle extends FluidObjectHandle {
46
48
  */
47
49
  return this.isAttached || this.isLocallyVisible;
48
50
  }
51
+ /**
52
+ * Tracks whether this handle is locally visible in the container.
53
+ */
54
+ isLocallyVisible = false;
55
+ pendingHandles = new Set();
49
56
  /**
50
57
  * Creates a new SharedObjectHandle.
51
58
  * @param value - The shared object this handle is for.
@@ -57,11 +64,6 @@ export class SharedObjectHandle extends FluidObjectHandle {
57
64
  super(value, path, runtime.IFluidHandleContext);
58
65
  this.value = value;
59
66
  this.runtime = runtime;
60
- /**
61
- * Tracks whether this handle is locally visible in the container.
62
- */
63
- this.isLocallyVisible = false;
64
- this.pendingHandles = new Set();
65
67
  }
66
68
  /**
67
69
  * Attaches all bound handles first (which may in turn attach further handles), then attaches this handle.
package/lib/handle.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"handle.js","sourceRoot":"","sources":["../src/handle.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAEvE,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAoBvE;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAe;IACpD,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,OAAQ,MAA8B,CAAC,IAAI,KAAK,UAAU,CAAC;AAC5F,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,kBACZ,SAAQ,iBAAgC;IAGxC;;OAEG;IACH,IAAW,UAAU;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,IAAY,SAAS;QACpB;;;;;;;;;;;WAWG;QACH,OAAO,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,gBAAgB,CAAC;IACjD,CAAC;IASD;;;;;;OAMG;IACH,YACoB,KAAoB,EACvC,IAAY,EACK,OAA+B;QAEhD,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAJ7B,UAAK,GAAL,KAAK,CAAe;QAEtB,YAAO,GAAP,OAAO,CAAwB;QAjBjD;;WAEG;QACK,qBAAgB,GAAY,KAAK,CAAC;QAEzB,mBAAc,GAA8B,IAAI,GAAG,EAAE,CAAC;IAevE,CAAC;IAED;;;OAGG;IACI,WAAW;QACjB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QAED,yCAAyC;QACzC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YAC1C,MAAM,CAAC,WAAW,EAAE,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAE5B,yFAAyF;QACzF,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QAE3B,8EAA8E;QAC9E,KAAK,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAEM,IAAI,CAAC,MAA4B;QACvC,mFAAmF;QACnF,8GAA8G;QAC9G,wEAAwE;QACxE,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YACzC,OAAO;QACR,CAAC;QAED,8EAA8E;QAC9E,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO;QACR,CAAC;QAED,mGAAmG;QACnG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidHandleInternal } from \"@fluidframework/core-interfaces/internal\";\nimport { FluidObjectHandle } from \"@fluidframework/datastore/internal\";\nimport type { IFluidDataStoreRuntime } from \"@fluidframework/datastore-definitions/internal\";\nimport { isFluidHandle } from \"@fluidframework/runtime-utils/internal\";\n\nimport type { ISharedObject } from \"./types.js\";\n\n/**\n * Handle for a shared object. See also `SharedObjectHandle`.\n * Supports binding other handles to the underlying Shared Object (see {@link ISharedObjectHandle.bind}).\n *\n * @internal\n */\nexport interface ISharedObjectHandle extends IFluidHandleInternal<ISharedObject> {\n\t/**\n\t * Binds the given handle to this DDS or attach the given handle if this DDS is attached.\n\t * A bound handle will also be attached once this DDS is attached.\n\t *\n\t * @param handle - The target handle to bind to this DDS\n\t */\n\tbind(handle: IFluidHandleInternal): void;\n}\n\n/**\n * Type guard for {@link ISharedObjectHandle}.\n * @internal\n */\nexport function isISharedObjectHandle(handle: unknown): handle is ISharedObjectHandle {\n\treturn isFluidHandle(handle) && typeof (handle as ISharedObjectHandle).bind === \"function\";\n}\n\n/**\n * Handle for a shared object (DDS).\n *\n * @remarks\n *\n * This object is used for already loaded (in-memory) shared objects.\n *\n * It provides a \"bind\" function that is expected to be invoked on all handles stored in this DDS,\n * ensuring the target object becomes attached along with this DDS.\n */\nexport class SharedObjectHandle\n\textends FluidObjectHandle<ISharedObject>\n\timplements ISharedObjectHandle\n{\n\t/**\n\t * Whether services have been attached for the associated shared object.\n\t */\n\tpublic get isAttached(): boolean {\n\t\treturn this.value.isAttached();\n\t}\n\n\t/**\n\t * Tells whether the object of this handle is visible in the container locally or globally.\n\t */\n\tprivate get isVisible(): boolean {\n\t\t/**\n\t\t * If the object of this handle is attached, it is visible in the container. Ideally, checking local visibility\n\t\t * should be enough for a handle. However, there are scenarios where the object becomes locally visible but the\n\t\t * handle does not know this - This will happen is attachGraph is never called on the handle. Couple of examples\n\t\t * where this can happen:\n\t\t *\n\t\t * 1. Handles to DDS other than the default handle won't know if the DDS becomes visible after the handle was\n\t\t * created.\n\t\t *\n\t\t * 2. Handles to root data stores will never know that it was visible because the handle will not be stores in\n\t\t * another DDS and so, attachGraph will never be called on it.\n\t\t */\n\t\treturn this.isAttached || this.isLocallyVisible;\n\t}\n\n\t/**\n\t * Tracks whether this handle is locally visible in the container.\n\t */\n\tprivate isLocallyVisible: boolean = false;\n\n\tprivate readonly pendingHandles: Set<IFluidHandleInternal> = new Set();\n\n\t/**\n\t * Creates a new SharedObjectHandle.\n\t * @param value - The shared object this handle is for.\n\t * @param path - The id of the shared object. It is also the path to this object relative to the routeContext.\n\t * @param routeContext - The parent {@link @fluidframework/core-interfaces#IFluidHandleContext} that has a route\n\t * to this handle.\n\t */\n\tconstructor(\n\t\tprotected readonly value: ISharedObject,\n\t\tpath: string,\n\t\tprivate readonly runtime: IFluidDataStoreRuntime,\n\t) {\n\t\tsuper(value, path, runtime.IFluidHandleContext);\n\t}\n\n\t/**\n\t * Attaches all bound handles first (which may in turn attach further handles), then attaches this handle.\n\t * When attaching the handle, it registers the associated shared object.\n\t */\n\tpublic attachGraph(): void {\n\t\tif (this.isVisible) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Recursively attach all pending handles\n\t\tthis.isLocallyVisible = true;\n\t\tfor (const handle of this.pendingHandles) {\n\t\t\thandle.attachGraph();\n\t\t}\n\t\tthis.pendingHandles.clear();\n\n\t\t// Bind this SharedObject to its context (typically the DataStore) so it attaches with it\n\t\tthis.value.bindToContext();\n\n\t\t// This will trigger the context (typically the DataStore) to attach its graph\n\t\tsuper.attachGraph();\n\t}\n\n\tpublic bind(handle: IFluidHandleInternal): void {\n\t\t// We don't bind handles in staging mode to defer the attachment of any new objects\n\t\t// until we've exited staging mode. This way if we discard changes or a new handle is not present in the final\n\t\t// committed state, we will never end up attaching the discarded object.\n\t\tif (this.runtime.inStagingMode === true) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If this handle is visible, attach the graph of the incoming handle as well.\n\t\tif (this.isVisible) {\n\t\t\thandle.attachGraph();\n\t\t\treturn;\n\t\t}\n\n\t\t// If this handle is not visible, we will attach it later when this handle's attachGraph is called.\n\t\tthis.pendingHandles.add(handle);\n\t}\n}\n"]}
1
+ {"version":3,"file":"handle.js","sourceRoot":"","sources":["../src/handle.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAEvE,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAoBvE;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAe;IACpD,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,OAAQ,MAA8B,CAAC,IAAI,KAAK,UAAU,CAAC;AAC5F,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,kBACZ,SAAQ,iBAAgC;IA4CpB;IAEF;IA3ClB;;OAEG;IACH,IAAW,UAAU;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,IAAY,SAAS;QACpB;;;;;;;;;;;WAWG;QACH,OAAO,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,gBAAgB,CAAC;IACjD,CAAC;IAED;;OAEG;IACK,gBAAgB,GAAY,KAAK,CAAC;IAEzB,cAAc,GAA8B,IAAI,GAAG,EAAE,CAAC;IAEvE;;;;;;OAMG;IACH,YACoB,KAAoB,EACvC,IAAY,EACK,OAA+B;QAEhD,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAJ7B,UAAK,GAAL,KAAK,CAAe;QAEtB,YAAO,GAAP,OAAO,CAAwB;IAGjD,CAAC;IAED;;;OAGG;IACI,WAAW;QACjB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QAED,yCAAyC;QACzC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YAC1C,MAAM,CAAC,WAAW,EAAE,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAE5B,yFAAyF;QACzF,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QAE3B,8EAA8E;QAC9E,KAAK,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAEM,IAAI,CAAC,MAA4B;QACvC,mFAAmF;QACnF,8GAA8G;QAC9G,wEAAwE;QACxE,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YACzC,OAAO;QACR,CAAC;QAED,8EAA8E;QAC9E,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO;QACR,CAAC;QAED,mGAAmG;QACnG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidHandleInternal } from \"@fluidframework/core-interfaces/internal\";\nimport { FluidObjectHandle } from \"@fluidframework/datastore/internal\";\nimport type { IFluidDataStoreRuntime } from \"@fluidframework/datastore-definitions/internal\";\nimport { isFluidHandle } from \"@fluidframework/runtime-utils/internal\";\n\nimport type { ISharedObject } from \"./types.js\";\n\n/**\n * Handle for a shared object. See also `SharedObjectHandle`.\n * Supports binding other handles to the underlying Shared Object (see {@link ISharedObjectHandle.bind}).\n *\n * @internal\n */\nexport interface ISharedObjectHandle extends IFluidHandleInternal<ISharedObject> {\n\t/**\n\t * Binds the given handle to this DDS or attach the given handle if this DDS is attached.\n\t * A bound handle will also be attached once this DDS is attached.\n\t *\n\t * @param handle - The target handle to bind to this DDS\n\t */\n\tbind(handle: IFluidHandleInternal): void;\n}\n\n/**\n * Type guard for {@link ISharedObjectHandle}.\n * @internal\n */\nexport function isISharedObjectHandle(handle: unknown): handle is ISharedObjectHandle {\n\treturn isFluidHandle(handle) && typeof (handle as ISharedObjectHandle).bind === \"function\";\n}\n\n/**\n * Handle for a shared object (DDS).\n *\n * @remarks\n *\n * This object is used for already loaded (in-memory) shared objects.\n *\n * It provides a \"bind\" function that is expected to be invoked on all handles stored in this DDS,\n * ensuring the target object becomes attached along with this DDS.\n */\nexport class SharedObjectHandle\n\textends FluidObjectHandle<ISharedObject>\n\timplements ISharedObjectHandle\n{\n\t/**\n\t * Whether services have been attached for the associated shared object.\n\t */\n\tpublic get isAttached(): boolean {\n\t\treturn this.value.isAttached();\n\t}\n\n\t/**\n\t * Tells whether the object of this handle is visible in the container locally or globally.\n\t */\n\tprivate get isVisible(): boolean {\n\t\t/**\n\t\t * If the object of this handle is attached, it is visible in the container. Ideally, checking local visibility\n\t\t * should be enough for a handle. However, there are scenarios where the object becomes locally visible but the\n\t\t * handle does not know this - This will happen is attachGraph is never called on the handle. Couple of examples\n\t\t * where this can happen:\n\t\t *\n\t\t * 1. Handles to DDS other than the default handle won't know if the DDS becomes visible after the handle was\n\t\t * created.\n\t\t *\n\t\t * 2. Handles to root data stores will never know that it was visible because the handle will not be stores in\n\t\t * another DDS and so, attachGraph will never be called on it.\n\t\t */\n\t\treturn this.isAttached || this.isLocallyVisible;\n\t}\n\n\t/**\n\t * Tracks whether this handle is locally visible in the container.\n\t */\n\tprivate isLocallyVisible: boolean = false;\n\n\tprivate readonly pendingHandles: Set<IFluidHandleInternal> = new Set();\n\n\t/**\n\t * Creates a new SharedObjectHandle.\n\t * @param value - The shared object this handle is for.\n\t * @param path - The id of the shared object. It is also the path to this object relative to the routeContext.\n\t * @param routeContext - The parent {@link @fluidframework/core-interfaces#IFluidHandleContext} that has a route\n\t * to this handle.\n\t */\n\tconstructor(\n\t\tprotected readonly value: ISharedObject,\n\t\tpath: string,\n\t\tprivate readonly runtime: IFluidDataStoreRuntime,\n\t) {\n\t\tsuper(value, path, runtime.IFluidHandleContext);\n\t}\n\n\t/**\n\t * Attaches all bound handles first (which may in turn attach further handles), then attaches this handle.\n\t * When attaching the handle, it registers the associated shared object.\n\t */\n\tpublic attachGraph(): void {\n\t\tif (this.isVisible) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Recursively attach all pending handles\n\t\tthis.isLocallyVisible = true;\n\t\tfor (const handle of this.pendingHandles) {\n\t\t\thandle.attachGraph();\n\t\t}\n\t\tthis.pendingHandles.clear();\n\n\t\t// Bind this SharedObject to its context (typically the DataStore) so it attaches with it\n\t\tthis.value.bindToContext();\n\n\t\t// This will trigger the context (typically the DataStore) to attach its graph\n\t\tsuper.attachGraph();\n\t}\n\n\tpublic bind(handle: IFluidHandleInternal): void {\n\t\t// We don't bind handles in staging mode to defer the attachment of any new objects\n\t\t// until we've exited staging mode. This way if we discard changes or a new handle is not present in the final\n\t\t// committed state, we will never end up attaching the discarded object.\n\t\tif (this.runtime.inStagingMode === true) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If this handle is visible, attach the graph of the incoming handle as well.\n\t\tif (this.isVisible) {\n\t\t\thandle.attachGraph();\n\t\t\treturn;\n\t\t}\n\n\t\t// If this handle is not visible, we will attach it later when this handle's attachGraph is called.\n\t\tthis.pendingHandles.add(handle);\n\t}\n}\n"]}
package/lib/legacy.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  /*
7
7
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
8
+ * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib" in @fluid-tools/build-cli.
9
9
  */
10
10
 
11
11
  export {
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/shared-object-base";
8
- export declare const pkgVersion = "2.118.0";
8
+ export declare const pkgVersion = "3.0.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,uCAAuC,CAAC;AAC5D,eAAO,MAAM,UAAU,YAAY,CAAC"}
1
+ {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,uCAAuC,CAAC;AAC5D,eAAO,MAAM,UAAU,UAAU,CAAC"}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/shared-object-base";
8
- export const pkgVersion = "2.118.0";
8
+ export const pkgVersion = "3.0.0";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,oCAAoC,CAAC;AAC5D,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/shared-object-base\";\nexport const pkgVersion = \"2.118.0\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,oCAAoC,CAAC;AAC5D,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/shared-object-base\";\nexport const pkgVersion = \"3.0.0\";\n"]}
package/lib/public.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  /*
7
7
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
8
+ * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib" in @fluid-tools/build-cli.
9
9
  */
10
10
 
11
11
  export {
package/lib/serializer.js CHANGED
@@ -10,6 +10,8 @@ import { isISharedObjectHandle } from "./handle.js";
10
10
  * @internal
11
11
  */
12
12
  export class FluidSerializer {
13
+ context;
14
+ root;
13
15
  constructor(context) {
14
16
  this.context = context;
15
17
  this.root = this.context;
@@ -1 +1 @@
1
- {"version":3,"file":"serializer.js","sourceRoot":"","sources":["../src/serializer.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 { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport type {\n\tIFluidHandleContext,\n\tIFluidHandleInternal,\n} from \"@fluidframework/core-interfaces/internal\";\nimport { assert, shallowCloneObject } from \"@fluidframework/core-utils/internal\";\nimport {\n\tencodeHandleForSerialization,\n\tgenerateHandleContextPath,\n\tisSerializedHandle,\n\tisFluidHandle,\n\ttoFluidHandleInternal,\n\ttype ISerializedHandle,\n\tRemoteFluidObjectHandle,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport { isISharedObjectHandle, type ISharedObjectHandle } from \"./handle.js\";\n\n/**\n * @legacy @beta\n */\nexport interface IFluidSerializer {\n\t/**\n\t * Given a mostly-plain object that may have handle objects embedded within, will return a fully-plain object\n\t * where any embedded IFluidHandles have been replaced with a serializable form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clones all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t */\n\tencode(value: unknown, bind: IFluidHandle): unknown;\n\n\t/**\n\t * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an\n\t * equivalent object tree where any encoded IFluidHandles have been replaced with their decoded form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * The decoded handles are implicitly bound to the handle context of this serializer.\n\t */\n\tdecode(input: unknown): unknown;\n\n\t/**\n\t * Stringifies a given value. Converts any IFluidHandle to its stringified equivalent.\n\t */\n\tstringify(value: unknown, bind: IFluidHandle): string;\n\n\t/**\n\t * Parses the given JSON input string and returns the JavaScript object defined by it. Any Fluid\n\t * handles will be realized as part of the parse\n\t */\n\tparse(value: string): unknown;\n}\n\n/**\n * Data Store serializer implementation\n * @internal\n */\nexport class FluidSerializer implements IFluidSerializer {\n\tprivate readonly root: IFluidHandleContext;\n\n\tpublic constructor(private readonly context: IFluidHandleContext) {\n\t\tthis.root = this.context;\n\t\twhile (this.root.routeContext !== undefined) {\n\t\t\tthis.root = this.root.routeContext;\n\t\t}\n\t}\n\n\tpublic get IFluidSerializer(): IFluidSerializer {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Given a mostly-jsonable object tree that may have handle objects embedded within, will return a\n\t * fully-jsonable object tree where any embedded IFluidHandles have been replaced with a serializable form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * Any unbound handles encountered are bound to the provided IFluidHandle.\n\t */\n\tpublic encode(input: unknown, bind: IFluidHandleInternal): unknown {\n\t\tassert(isISharedObjectHandle(bind), 0xb8c /* bind must be an ISharedObjectHandle */);\n\t\t// If the given 'input' cannot contain handles, return it immediately. Otherwise,\n\t\t// return the result of 'recursivelyReplace()'.\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\treturn !!input && typeof input === \"object\"\n\t\t\t? this.recursivelyReplace(input, this.encodeValue.bind(this), bind)\n\t\t\t: input;\n\t}\n\n\t/**\n\t * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an\n\t * equivalent object tree where any encoded IFluidHandles have been replaced with their decoded form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * The decoded handles are implicitly bound to the handle context of this serializer.\n\t */\n\tpublic decode(input: unknown): unknown {\n\t\t// If the given 'input' cannot contain handles, return it immediately. Otherwise,\n\t\t// return the result of 'recursivelyReplace()'.\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\treturn !!input && typeof input === \"object\"\n\t\t\t? this.recursivelyReplace(input, this.decodeValue.bind(this))\n\t\t\t: input;\n\t}\n\n\t/**\n\t * Serializes the input object into a JSON string.\n\t * Any IFluidHandles in the object will be replaced with their serialized form before stringify,\n\t * being bound to the given bind context in the process.\n\t */\n\tpublic stringify(input: unknown, bind: IFluidHandle): string {\n\t\tassert(isISharedObjectHandle(bind), 0xb8d /* bind must be an ISharedObjectHandle */);\n\t\treturn JSON.stringify(input, (key, value) => this.encodeValue(value, bind));\n\t}\n\n\t/**\n\t * Parses the serialized data - context must match the context with which the JSON was stringified\n\t */\n\tpublic parse(input: string): unknown {\n\t\treturn JSON.parse(input, (key, value) => this.decodeValue(value));\n\t}\n\n\t/**\n\t * If the given 'value' is an IFluidHandle, returns the encoded IFluidHandle.\n\t * Otherwise returns the original 'value'. Used by 'encode()' and 'stringify()'.\n\t */\n\tprotected encodeValue(value: unknown, bind?: ISharedObjectHandle): unknown {\n\t\t// If 'value' is an IFluidHandle return its encoded form.\n\t\tif (isFluidHandle(value)) {\n\t\t\tassert(bind !== undefined, 0xa93 /* Cannot encode a handle without a bind context */);\n\t\t\treturn this.bindAndEncodeHandle(toFluidHandleInternal(value), bind);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * If the given 'value' is an encoded IFluidHandle, returns the decoded IFluidHandle.\n\t * Otherwise returns the original 'value'. Used by 'decode()' and 'parse()'.\n\t */\n\tprotected decodeValue(value: unknown): unknown {\n\t\t// If 'value' is a serialized IFluidHandle return the deserialized result.\n\t\tif (isSerializedHandle(value)) {\n\t\t\t// Old documents may have handles with relative path in their summaries. Convert these to absolute\n\t\t\t// paths. This will ensure that future summaries will have absolute paths for these handles.\n\t\t\tconst absolutePath = value.url.startsWith(\"/\")\n\t\t\t\t? value.url\n\t\t\t\t: generateHandleContextPath(value.url, this.context);\n\n\t\t\treturn new RemoteFluidObjectHandle(\n\t\t\t\tabsolutePath,\n\t\t\t\tthis.root,\n\t\t\t\tvalue.payloadPending === true,\n\t\t\t);\n\t\t} else {\n\t\t\treturn value;\n\t\t}\n\t}\n\n\t/**\n\t * Invoked for non-null objects to recursively replace references to IFluidHandles.\n\t * Clones as-needed to avoid mutating the `input` object. If no IFluidHandles are present,\n\t * returns the original `input`.\n\t */\n\tprivate recursivelyReplace<TContext = unknown>(\n\t\tinput: object,\n\t\treplacer: (input: unknown, context?: TContext) => unknown,\n\t\tcontext?: TContext,\n\t): unknown {\n\t\t// Note: Caller is responsible for ensuring that `input` is defined / non-null.\n\t\t// (Required for Object.keys() below.)\n\n\t\t// Execute the `replace` on the current input. Note that Caller is responsible for ensuring that `input`\n\t\t// is a non-null object.\n\t\tconst maybeReplaced = replacer(input, context);\n\n\t\t// If either input or the replaced result is a Fluid Handle, there is no need to descend further.\n\t\t// IFluidHandles are always leaves in the object graph, and the code below cannot deal with IFluidHandle's structure.\n\t\tif (isFluidHandle(input) || isFluidHandle(maybeReplaced)) {\n\t\t\treturn maybeReplaced;\n\t\t}\n\n\t\t// Otherwise descend into the object graph looking for IFluidHandle instances.\n\t\tlet clone: object | undefined;\n\t\tfor (const key of Object.keys(input)) {\n\t\t\tconst value: unknown = input[key];\n\t\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\t\tif (!!value && typeof value === \"object\") {\n\t\t\t\t// Note: Except for IFluidHandle, `input` must not contain circular references (as object must\n\t\t\t\t// be JSON serializable.) Therefore, guarding against infinite recursion here would only\n\t\t\t\t// lead to a later error when attempting to stringify().\n\t\t\t\tconst replaced = this.recursivelyReplace(value, replacer, context);\n\n\t\t\t\t// If the `replaced` object is different than the original `value` then the subgraph contained one\n\t\t\t\t// or more handles. If this happens, we need to return a clone of the `input` object where the\n\t\t\t\t// current property is replaced by the `replaced` value.\n\t\t\t\tif (replaced !== value) {\n\t\t\t\t\t// Lazily create a shallow clone of the `input` object if we haven't done so already.\n\t\t\t\t\tclone ??= shallowCloneObject(input);\n\n\t\t\t\t\t// Overwrite the current property `key` in the clone with the `replaced` value.\n\t\t\t\t\tclone[key] = replaced;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn clone ?? input;\n\t}\n\n\t/**\n\t * Encodes the given IFluidHandle into a JSON-serializable form,\n\t * also binding it to another node to ensure it attaches at the right time.\n\t * @param handle - The IFluidHandle to serialize.\n\t * @param bind - The binding context for the handle (the handle will become attached whenever this context is attached).\n\t * @returns The serialized handle.\n\t */\n\tprotected bindAndEncodeHandle(\n\t\thandle: IFluidHandleInternal,\n\t\tbind: ISharedObjectHandle,\n\t): ISerializedHandle {\n\t\tbind.bind(handle);\n\t\treturn encodeHandleForSerialization(handle);\n\t}\n}\n"]}
1
+ {"version":3,"file":"serializer.js","sourceRoot":"","sources":["../src/serializer.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 { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport type {\n\tIFluidHandleContext,\n\tIFluidHandleInternal,\n} from \"@fluidframework/core-interfaces/internal\";\nimport { assert, shallowCloneObject } from \"@fluidframework/core-utils/internal\";\nimport {\n\tencodeHandleForSerialization,\n\tgenerateHandleContextPath,\n\tisSerializedHandle,\n\tisFluidHandle,\n\ttoFluidHandleInternal,\n\ttype ISerializedHandle,\n\tRemoteFluidObjectHandle,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport { isISharedObjectHandle, type ISharedObjectHandle } from \"./handle.js\";\n\n/**\n * @legacy @beta\n */\nexport interface IFluidSerializer {\n\t/**\n\t * Given a mostly-plain object that may have handle objects embedded within, will return a fully-plain object\n\t * where any embedded IFluidHandles have been replaced with a serializable form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clones all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t */\n\tencode(value: unknown, bind: IFluidHandle): unknown;\n\n\t/**\n\t * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an\n\t * equivalent object tree where any encoded IFluidHandles have been replaced with their decoded form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * The decoded handles are implicitly bound to the handle context of this serializer.\n\t */\n\tdecode(input: unknown): unknown;\n\n\t/**\n\t * Stringifies a given value. Converts any IFluidHandle to its stringified equivalent.\n\t */\n\tstringify(value: unknown, bind: IFluidHandle): string;\n\n\t/**\n\t * Parses the given JSON input string and returns the JavaScript object defined by it. Any Fluid\n\t * handles will be realized as part of the parse\n\t */\n\tparse(value: string): unknown;\n}\n\n/**\n * Data Store serializer implementation\n * @internal\n */\nexport class FluidSerializer implements IFluidSerializer {\n\tprivate readonly root: IFluidHandleContext;\n\n\tpublic constructor(private readonly context: IFluidHandleContext) {\n\t\tthis.root = this.context;\n\t\twhile (this.root.routeContext !== undefined) {\n\t\t\tthis.root = this.root.routeContext;\n\t\t}\n\t}\n\n\tpublic get IFluidSerializer(): IFluidSerializer {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Given a mostly-jsonable object tree that may have handle objects embedded within, will return a\n\t * fully-jsonable object tree where any embedded IFluidHandles have been replaced with a serializable form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * Any unbound handles encountered are bound to the provided IFluidHandle.\n\t */\n\tpublic encode(input: unknown, bind: IFluidHandleInternal): unknown {\n\t\tassert(isISharedObjectHandle(bind), 0xb8c /* bind must be an ISharedObjectHandle */);\n\t\t// If the given 'input' cannot contain handles, return it immediately. Otherwise,\n\t\t// return the result of 'recursivelyReplace()'.\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\treturn !!input && typeof input === \"object\"\n\t\t\t? this.recursivelyReplace(input, this.encodeValue.bind(this), bind)\n\t\t\t: input;\n\t}\n\n\t/**\n\t * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an\n\t * equivalent object tree where any encoded IFluidHandles have been replaced with their decoded form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * The decoded handles are implicitly bound to the handle context of this serializer.\n\t */\n\tpublic decode(input: unknown): unknown {\n\t\t// If the given 'input' cannot contain handles, return it immediately. Otherwise,\n\t\t// return the result of 'recursivelyReplace()'.\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\treturn !!input && typeof input === \"object\"\n\t\t\t? this.recursivelyReplace(input, this.decodeValue.bind(this))\n\t\t\t: input;\n\t}\n\n\t/**\n\t * Serializes the input object into a JSON string.\n\t * Any IFluidHandles in the object will be replaced with their serialized form before stringify,\n\t * being bound to the given bind context in the process.\n\t */\n\tpublic stringify(input: unknown, bind: IFluidHandle): string {\n\t\tassert(isISharedObjectHandle(bind), 0xb8d /* bind must be an ISharedObjectHandle */);\n\t\treturn JSON.stringify(input, (key, value) => this.encodeValue(value, bind));\n\t}\n\n\t/**\n\t * Parses the serialized data - context must match the context with which the JSON was stringified\n\t */\n\tpublic parse(input: string): unknown {\n\t\treturn JSON.parse(input, (key, value) => this.decodeValue(value));\n\t}\n\n\t/**\n\t * If the given 'value' is an IFluidHandle, returns the encoded IFluidHandle.\n\t * Otherwise returns the original 'value'. Used by 'encode()' and 'stringify()'.\n\t */\n\tprotected encodeValue(value: unknown, bind?: ISharedObjectHandle): unknown {\n\t\t// If 'value' is an IFluidHandle return its encoded form.\n\t\tif (isFluidHandle(value)) {\n\t\t\tassert(bind !== undefined, 0xa93 /* Cannot encode a handle without a bind context */);\n\t\t\treturn this.bindAndEncodeHandle(toFluidHandleInternal(value), bind);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * If the given 'value' is an encoded IFluidHandle, returns the decoded IFluidHandle.\n\t * Otherwise returns the original 'value'. Used by 'decode()' and 'parse()'.\n\t */\n\tprotected decodeValue(value: unknown): unknown {\n\t\t// If 'value' is a serialized IFluidHandle return the deserialized result.\n\t\tif (isSerializedHandle(value)) {\n\t\t\t// Old documents may have handles with relative path in their summaries. Convert these to absolute\n\t\t\t// paths. This will ensure that future summaries will have absolute paths for these handles.\n\t\t\tconst absolutePath = value.url.startsWith(\"/\")\n\t\t\t\t? value.url\n\t\t\t\t: generateHandleContextPath(value.url, this.context);\n\n\t\t\treturn new RemoteFluidObjectHandle(\n\t\t\t\tabsolutePath,\n\t\t\t\tthis.root,\n\t\t\t\tvalue.payloadPending === true,\n\t\t\t);\n\t\t} else {\n\t\t\treturn value;\n\t\t}\n\t}\n\n\t/**\n\t * Invoked for non-null objects to recursively replace references to IFluidHandles.\n\t * Clones as-needed to avoid mutating the `input` object. If no IFluidHandles are present,\n\t * returns the original `input`.\n\t */\n\tprivate recursivelyReplace<TContext = unknown>(\n\t\tinput: object,\n\t\treplacer: (input: unknown, context?: TContext) => unknown,\n\t\tcontext?: TContext,\n\t): unknown {\n\t\t// Note: Caller is responsible for ensuring that `input` is defined / non-null.\n\t\t// (Required for Object.keys() below.)\n\n\t\t// Execute the `replace` on the current input. Note that Caller is responsible for ensuring that `input`\n\t\t// is a non-null object.\n\t\tconst maybeReplaced = replacer(input, context);\n\n\t\t// If either input or the replaced result is a Fluid Handle, there is no need to descend further.\n\t\t// IFluidHandles are always leaves in the object graph, and the code below cannot deal with IFluidHandle's structure.\n\t\tif (isFluidHandle(input) || isFluidHandle(maybeReplaced)) {\n\t\t\treturn maybeReplaced;\n\t\t}\n\n\t\t// Otherwise descend into the object graph looking for IFluidHandle instances.\n\t\tlet clone: object | undefined;\n\t\tfor (const key of Object.keys(input)) {\n\t\t\tconst value: unknown = input[key];\n\t\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\t\tif (!!value && typeof value === \"object\") {\n\t\t\t\t// Note: Except for IFluidHandle, `input` must not contain circular references (as object must\n\t\t\t\t// be JSON serializable.) Therefore, guarding against infinite recursion here would only\n\t\t\t\t// lead to a later error when attempting to stringify().\n\t\t\t\tconst replaced = this.recursivelyReplace(value, replacer, context);\n\n\t\t\t\t// If the `replaced` object is different than the original `value` then the subgraph contained one\n\t\t\t\t// or more handles. If this happens, we need to return a clone of the `input` object where the\n\t\t\t\t// current property is replaced by the `replaced` value.\n\t\t\t\tif (replaced !== value) {\n\t\t\t\t\t// Lazily create a shallow clone of the `input` object if we haven't done so already.\n\t\t\t\t\tclone ??= shallowCloneObject(input);\n\n\t\t\t\t\t// Overwrite the current property `key` in the clone with the `replaced` value.\n\t\t\t\t\tclone[key] = replaced;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn clone ?? input;\n\t}\n\n\t/**\n\t * Encodes the given IFluidHandle into a JSON-serializable form,\n\t * also binding it to another node to ensure it attaches at the right time.\n\t * @param handle - The IFluidHandle to serialize.\n\t * @param bind - The binding context for the handle (the handle will become attached whenever this context is attached).\n\t * @returns The serialized handle.\n\t */\n\tprotected bindAndEncodeHandle(\n\t\thandle: IFluidHandleInternal,\n\t\tbind: ISharedObjectHandle,\n\t): ISerializedHandle {\n\t\tbind.bind(handle);\n\t\treturn encodeHandleForSerialization(handle);\n\t}\n}\n"]}
@@ -28,9 +28,39 @@ import { bindHandles, makeHandlesSerializable, parseHandles } from "./utils.js";
28
28
  * @legacy @beta
29
29
  */
30
30
  export class SharedObjectCore extends EventEmitterWithErrorHandling {
31
+ id;
32
+ runtime;
33
+ attributes;
31
34
  get IFluidLoadable() {
32
35
  return this;
33
36
  }
37
+ opProcessingHelper;
38
+ callbacksHelper;
39
+ /**
40
+ * The handle referring to this SharedObject
41
+ */
42
+ handle;
43
+ /**
44
+ * Telemetry logger for the shared object
45
+ */
46
+ logger;
47
+ mc;
48
+ /**
49
+ * Connection state
50
+ */
51
+ _connected = false;
52
+ /**
53
+ * Services used by the shared object
54
+ */
55
+ services;
56
+ /**
57
+ * True if the dds is bound to its parent.
58
+ */
59
+ _isBoundToContext = false;
60
+ /**
61
+ * Tracks error that closed this object.
62
+ */
63
+ closeError;
34
64
  /**
35
65
  * Gets the connection state
36
66
  * @returns The state of the connection
@@ -55,14 +85,6 @@ export class SharedObjectCore extends EventEmitterWithErrorHandling {
55
85
  this.id = id;
56
86
  this.runtime = runtime;
57
87
  this.attributes = attributes;
58
- /**
59
- * Connection state
60
- */
61
- this._connected = false;
62
- /**
63
- * True if the dds is bound to its parent.
64
- */
65
- this._isBoundToContext = false;
66
88
  assert(!id.includes("/"), 0x304 /* Id cannot contain slashes */);
67
89
  this.handle = new SharedObjectHandle(this, id, runtime);
68
90
  const internalLogger = createChildLogger({
@@ -491,6 +513,15 @@ export class SharedObjectCore extends EventEmitterWithErrorHandling {
491
513
  * @legacy @beta
492
514
  */
493
515
  export class SharedObject extends SharedObjectCore {
516
+ telemetryContextPrefix;
517
+ /**
518
+ * True while we are garbage collecting this object's data.
519
+ */
520
+ _isGCing = false;
521
+ /**
522
+ * The serializer to use to serialize / parse handles, if any.
523
+ */
524
+ _serializer;
494
525
  get serializer() {
495
526
  /**
496
527
  * During garbage collection, the GCHandleVisitor "serializer" keeps track of IFluidHandles that are serialized. These
@@ -509,10 +540,6 @@ export class SharedObject extends SharedObjectCore {
509
540
  telemetryContextPrefix) {
510
541
  super(id, runtime, attributes);
511
542
  this.telemetryContextPrefix = telemetryContextPrefix;
512
- /**
513
- * True while we are garbage collecting this object's data.
514
- */
515
- this._isGCing = false;
516
543
  this._serializer = new FluidSerializer(this.runtime.channelsRoutingContext);
517
544
  }
518
545
  /**