Skip to content

feat!: remove public API surface for external custom DDS implementations#26413

Draft
tylerbutler wants to merge 16 commits intomainfrom
test/breaks/client/2.100/custom-dds-removal
Draft

feat!: remove public API surface for external custom DDS implementations#26413
tylerbutler wants to merge 16 commits intomainfrom
test/breaks/client/2.100/custom-dds-removal

Conversation

@tylerbutler
Copy link
Member

@tylerbutler tylerbutler commented Feb 11, 2026

Note

A minimal alternative is available: #26439 achieves the same "no custom DDSes" goal by only internalizing SharedObject and SharedObjectCore (2 files, 7 lines changed). This PR is the maximal version that also internalizes the runtime/factory layer. See the comparison table below.

Summary

Removes the public API surface that enabled external custom DDS implementations, making these types @internal:

@fluidframework/shared-object-base: SharedObject, SharedObjectCore, ISharedObjectKind, createSharedObjectKind — base classes and factory interfaces for DDS implementations

@fluidframework/datastore-definitions: IChannelFactory — the factory interface required to register custom DDSes

@fluidframework/datastore: FluidDataStoreRuntime, ISharedObjectRegistry, mixinRequestHandler, mixinSummaryHandler — runtime infrastructure for DDS hosting

@fluidframework/aqueduct: DataObjectFactory — the high-level factory that wires up DDSes with data objects

@fluidframework/test-runtime-utils: MockContainerRuntime, MockContainerRuntimeFactory, MockFluidDataStoreRuntime — test mocks that depend on the now-internal types

All existing DDSes (SharedTree, SharedMap, SharedCell, etc.) continue to work via SharedObjectKind, which remains public and sealed. The @fluid-experimental/tree package is updated to @internal release tags throughout since it depends on the now-internal SharedObject base class.

~45 example and test files are updated to import the affected types from /internal entry points instead of /legacy.

Comparison: maximal (this PR) vs minimal (#26439)

Maximal (this PR) Minimal (#26439)
Files changed 113 2
Lines changed +750 / -2026 +7 / -64
Breaking change packages 5+ (shared-object-base, datastore-definitions, datastore, aqueduct, experimental tree) 1 (shared-object-base)
Example files changed ~41 0
Symbols internalized ~15+ (SharedObject, SharedObjectCore, IChannelFactory, ISharedObjectKind, ISharedObjectRegistry, FluidDataStoreRuntime, DataObjectFactory, PureDataObjectFactory, TreeDataObjectFactory, mixinRequestHandler, mixinSummaryHandler, experimental tree types) 2 (SharedObject, SharedObjectCore)
Can create custom DDS? No No
Can iterate on IChannelFactory? Yes (now internal) No (still legacy beta)
Can iterate on FluidDataStoreRuntime? Yes (now internal) No (still legacy beta)

When to use which

- Expanded goals section to include faster iteration and API simplification
- Added experimental SharedTree to DDS inventory (now 20 total)
- Added IChannelAttributes, IChannelServices, IChannelStorageService,
  IDeltaConnection to the list of types to internalize
- Changed approach from deprecate-then-remove to direct internalization
- Added note about IChannel exposure at datastore layer needing special handling
- Updated changeset content to promote SharedTree as recommended DDS
- Added PR review notes section documenting feedback
- Move PactMap and Ink from Active/Stable to Experimental category
- Add type check/narrowing function approach to Future Considerations
- Add Follow-up Items section for IFluidDataStoreRuntime cleanup

Addresses feedback from @ChumpChief and @anthony-murphy.
Revert the explicit SharedObjectKind<ITree> type annotation on
SharedTree that was narrowing away ISharedObjectKind, breaking
getFactory()/create() calls in 31 files. Use inline import() syntax
for the return types of configuredSharedTree/configuredSharedTreeInternal
to avoid api-extractor ae-incompatible-release-tags detection.
- Mark AgentSchedulerFactory as @internal (returns @internal FluidDataStoreRuntime)
- Fix test-version-utils union type error by casting DDS entries for getFactory()
- Split /legacy imports in 6 example files: @internal types (DataObjectFactory,
  FluidDataStoreRuntime, IChannelFactory, MapFactory, ConsensusRegisterCollection)
  now import from /internal, non-@internal types remain at /legacy
DDSes was already accepted but the singular form DDS was missing,
causing vale to flag it in PR markdown.
@microsoft microsoft deleted a comment from github-actions bot Feb 11, 2026
@microsoft microsoft deleted a comment from github-actions bot Feb 11, 2026
Move DataObjectFactory, FluidDataStoreRuntime, IChannelFactory, MapFactory,
and test mock imports from /legacy to /internal entry points. Update
@fluid-experimental/tree release tags from @Alpha to @internal to resolve
api-extractor cascade from SharedObject being @internal.
@tylerbutler tylerbutler changed the title BREAKING CHANGE v 2.100: remove APIs for external custom DDSes BREAKING CHANGE v2.100: remove APIs for external custom DDSes Feb 11, 2026
@tylerbutler tylerbutler changed the title BREAKING CHANGE v2.100: remove APIs for external custom DDSes feat!: remove public API surface for external custom DDS implementations Feb 11, 2026
@github-actions
Copy link
Contributor

🔗 No broken links found! ✅

Your attention to detail is admirable.

linkcheck output


> fluid-framework-docs-site@0.0.0 ci:check-links /home/runner/work/FluidFramework/FluidFramework/docs
> start-server-and-test "npm run serve -- --no-open" 3000 check-links

1: starting server using command "npm run serve -- --no-open"
and when url "[ 'http://127.0.0.1:3000' ]" is responding with HTTP status code 200
running tests using command "npm run check-links"


> fluid-framework-docs-site@0.0.0 serve
> docusaurus serve --no-open

[SUCCESS] Serving "build" directory at: http://localhost:3000/

> fluid-framework-docs-site@0.0.0 check-links
> linkcheck http://localhost:3000 --skip-file skipped-urls.txt

Crawling...

Stats:
  257699 links
    1822 destination URLs
    2063 URLs ignored
       0 warnings
       0 errors


Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the public/legacy API surface that enabled external custom DDS implementations by internalizing key DDS base classes and factory/runtime infrastructure across several Fluid packages, and updates tests/examples to consume the new /internal entry points.

Changes:

  • Mark DDS implementation base types (e.g., SharedObject, SharedObjectCore, ISharedObjectKind) and runtime/factory-layer types (e.g., IChannelFactory, FluidDataStoreRuntime, DataObjectFactory) as @internal and update API reports accordingly.
  • Migrate affected tests, examples, and utilities from /legacy to /internal imports and adjust call sites where getFactory() is no longer available on the public SharedObjectKind type.
  • Internalize related “legacy beta” helper factories/types across several DDS packages (map, matrix, ordered-collection, register-collection, etc.), and update documentation/spelling tooling artifacts.

Reviewed changes

Copilot reviewed 113 out of 113 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
plans/custom-dds-removal.md Adds a written plan/analysis for internalizing custom DDS-enabling APIs.
packages/test/test-version-utils/src/compatUtils.ts Updates DDS registry mapping logic to work with internalized IChannelFactory.
packages/test/test-end-to-end-tests/src/test/offline/stashedOps.spec.ts Updates test imports and uses an internal kind cast to obtain a factory for SharedArray.
packages/service-clients/end-to-end-tests/azure-client/src/test/TestDataObject.ts Moves DataObjectFactory usage to aqueduct /internal.
packages/runtime/test-runtime-utils/src/mocksForReconnection.ts Changes reconnection mock release tags to @internal.
packages/runtime/test-runtime-utils/src/mocks.ts Changes core runtime mocks release tags to @internal.
packages/runtime/test-runtime-utils/api-report/test-runtime-utils.legacy.beta.api.md Removes runtime mocks from the legacy beta API report surface.
packages/runtime/datastore/src/dataStoreRuntime.ts Marks FluidDataStoreRuntime, ISharedObjectRegistry, and mixins as @internal.
packages/runtime/datastore/api-report/datastore.legacy.beta.api.md Removes the datastore runtime/factory APIs from the legacy beta API report surface.
packages/runtime/datastore-definitions/src/channel.ts Marks IChannelFactory as @internal.
packages/runtime/datastore-definitions/api-report/datastore-definitions.legacy.beta.api.md Removes IChannelFactory from legacy beta API report surface.
packages/runtime/datastore-definitions/api-report/datastore-definitions.legacy.alpha.api.md Removes IChannelFactory from legacy alpha API report surface.
packages/framework/aqueduct/src/data-objects/treeDataObject.ts Marks TreeDataObject as @internal and adjusts SharedTree factory access via internal kind.
packages/framework/aqueduct/src/data-object-factories/treeDataObjectFactory.ts Marks TreeDataObjectFactory as @internal and ensures SharedTree factory registration via internal kind.
packages/framework/aqueduct/src/data-object-factories/pureDataObjectFactory.ts Marks DataObjectFactoryProps and PureDataObjectFactory as @internal.
packages/framework/aqueduct/src/data-object-factories/dataObjectFactory.ts Marks DataObjectFactory as @internal.
packages/framework/aqueduct/api-report/aqueduct.legacy.beta.api.md Removes factory types from legacy beta API report surface.
packages/framework/agent-scheduler/src/scheduler.ts Marks AgentSchedulerFactory as @internal.
packages/framework/agent-scheduler/api-report/agent-scheduler.legacy.beta.api.md Removes AgentSchedulerFactory from legacy beta API report surface.
packages/dds/tree/src/treeFactory.ts Adjusts configured SharedTree helpers to avoid publicly returning legacy ISharedObjectKind while keeping internal paths typed.
packages/dds/tree/src/test/simple-tree/api/tree.spec.ts Updates tests to obtain the SharedTree factory via internal kind casting.
packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts Updates tests to create/register SharedTree via internal kind casting.
packages/dds/tree/api-report/tree.legacy.beta.api.md Updates legacy beta API report for configuredSharedTreeBetaLegacy return type.
packages/dds/test-dds-utils/src/utils.ts Switches imports to test-runtime-utils/internal.
packages/dds/shared-object-base/src/sharedObject.ts Marks SharedObjectCore, SharedObject, and ISharedObjectKind as @internal and updates docs.
packages/dds/shared-object-base/api-report/shared-object-base.legacy.beta.api.md Removes internalized base types from legacy beta API report surface.
packages/dds/register-collection/src/interfaces.ts Marks IConsensusRegisterCollectionFactory alias as @internal.
packages/dds/register-collection/src/consensusRegisterCollectionFactory.ts Marks factory/kind exports as @internal.
packages/dds/register-collection/src/consensusRegisterCollection.ts Marks ConsensusRegisterCollection class as @internal.
packages/dds/register-collection/api-report/register-collection.legacy.beta.api.md Removes internalized symbols from legacy beta API report surface.
packages/dds/ordered-collection/src/consensusQueue.ts Marks ConsensusQueueClass as @internal.
packages/dds/ordered-collection/src/consensusOrderedCollectionFactory.ts Marks ConsensusQueue exports as @internal.
packages/dds/ordered-collection/src/consensusOrderedCollection.ts Marks ConsensusOrderedCollection as @internal.
packages/dds/ordered-collection/api-report/ordered-collection.legacy.beta.api.md Removes internalized symbols from legacy beta API report surface.
packages/dds/matrix/src/runtime.ts Marks SharedMatrixFactory as @internal.
packages/dds/matrix/api-report/matrix.legacy.beta.api.md Removes SharedMatrixFactory from legacy beta API report surface.
packages/dds/map/src/mapFactory.ts Marks MapFactory as @internal.
packages/dds/map/src/directoryFactory.ts Marks DirectoryFactory as @internal.
packages/dds/map/api-report/map.legacy.beta.api.md Removes MapFactory/DirectoryFactory from legacy beta API report surface.
packages/dds/legacy-dds/src/test/utilities.ts Adds helper to obtain SharedArray factory via internal kind casting.
packages/dds/legacy-dds/src/test/array/sharedArrayReconnection.spec.ts Updates SharedArray tests to use the new helper factory function.
packages/dds/legacy-dds/src/test/array/sharedArrayConnected.spec.ts Updates SharedArray tests to use the new helper factory function.
packages/dds/legacy-dds/src/test/array/sharedArray.spec.ts Updates SharedArray tests to use the new helper factory function.
packages/dds/legacy-dds/src/array/sharedArrayFactory.ts Changes exported SharedArray/SharedArrayBuilder types to SharedObjectKind only.
packages/dds/legacy-dds/api-report/legacy-dds.legacy.beta.api.md Updates legacy beta API report for SharedArray; SharedSignal still references ISharedObjectKind.
experimental/dds/tree/src/persisted-types/0.1.1.ts Changes many experimental tree types from @alpha to @internal.
experimental/dds/tree/src/persisted-types/0.0.2.ts Changes many experimental tree types from @alpha to @internal.
experimental/dds/tree/src/UndoRedoHandler.ts Internalizes undo/redo interfaces/classes.
experimental/dds/tree/src/TreeView.ts Internalizes TreeView-related types.
experimental/dds/tree/src/TransactionInternal.ts Internalizes transaction internal result/failure types.
experimental/dds/tree/src/Transaction.ts Internalizes transaction types/events.
experimental/dds/tree/src/SharedTree.ts Internalizes experimental SharedTree types, factory, and events.
experimental/dds/tree/src/RevisionView.ts Internalizes revision/transaction view classes.
experimental/dds/tree/src/RevisionValueCache.ts Internalizes Revision type.
experimental/dds/tree/src/ReconciliationPath.ts Internalizes reconciliation path types.
experimental/dds/tree/src/PayloadUtilities.ts Internalizes payload utility API.
experimental/dds/tree/src/NodeIdUtilities.ts Internalizes node ID utility interfaces.
experimental/dds/tree/src/LogViewer.ts Internalizes log viewer interfaces/classes.
experimental/dds/tree/src/InitialTree.ts Internalizes initialTree.
experimental/dds/tree/src/Identifiers.ts Internalizes identifier/branding types.
experimental/dds/tree/src/Forest.ts Internalizes forest types/classes.
experimental/dds/tree/src/EventTypes.ts Internalizes shared tree event enum.
experimental/dds/tree/src/EditUtilities.ts Internalizes validation result types.
experimental/dds/tree/src/EditLog.ts Internalizes edit log types/events/classes.
experimental/dds/tree/src/EagerCheckout.ts Internalizes eager checkout.
experimental/dds/tree/src/Checkout.ts Internalizes checkout types/events/classes.
experimental/dds/tree/src/ChangeTypes.ts Internalizes change model types/constants.
experimental/dds/tree/api-report/experimental-tree.alpha.api.md Removes the experimental-tree alpha API surface after internalization.
examples/view-integration/view-framework-sampler/src/dataObject.ts Switches DataObjectFactory import to aqueduct /internal.
examples/view-integration/external-views/src/container/diceRoller/diceRoller.ts Moves runtime/factory imports to /internal where needed for example.
examples/view-integration/container-views/src/model.ts Switches DataObjectFactory import to aqueduct /internal.
examples/version-migration/tree-shim/src/model/inventoryList.ts Switches DataObjectFactory import to aqueduct /internal.
examples/version-migration/separate-container/src/modelVersion2/inventoryList.ts Switches DataObjectFactory import to aqueduct /internal.
examples/version-migration/separate-container/src/modelVersion1/inventoryList.ts Switches DataObjectFactory import to aqueduct /internal.
examples/version-migration/same-container/src/modelVersion2/inventoryList.ts Switches DataObjectFactory import to aqueduct /internal.
examples/version-migration/same-container/src/modelVersion1/inventoryList.ts Switches DataObjectFactory import to aqueduct /internal.
examples/version-migration/live-schema-upgrade/src/modelVersion2/diceRoller.ts Switches DataObjectFactory import to aqueduct /internal.
examples/version-migration/live-schema-upgrade/src/modelVersion2/diceCounter.ts Switches DataObjectFactory import to aqueduct /internal.
examples/version-migration/live-schema-upgrade/src/modelVersion1/diceRoller.ts Switches DataObjectFactory import to aqueduct /internal.
examples/utils/migration-tools/src/migrationTool/migrationTool.ts Uses /internal runtime/factory + register-collection where necessary.
examples/utils/example-utils/src/migrationTool/sameContainerMigrationTool.ts Switches DataObjectFactory import to aqueduct /internal.
examples/external-data/src/model/taskList.ts Switches DataObjectFactory import to aqueduct /internal.
examples/data-objects/webflow/src/host/webFlow.ts Switches DataObjectFactory import to aqueduct /internal.
examples/data-objects/webflow/src/document/index.ts Switches DataObjectFactory import to aqueduct /internal.
examples/data-objects/table-document/src/slice.ts Switches DataObjectFactory import to aqueduct /internal.
examples/data-objects/table-document/src/document.ts Switches DataObjectFactory import to aqueduct /internal.
examples/data-objects/smde/src/smde.ts Switches FluidDataStoreRuntime import to datastore /internal.
examples/data-objects/prosemirror/src/prosemirror.tsx Switches FluidDataStoreRuntime import to datastore /internal.
examples/data-objects/multiview/coordinate-model/src/model.ts Switches DataObjectFactory import to aqueduct /internal.
examples/data-objects/multiview/constellation-model/src/model.ts Switches DataObjectFactory import to aqueduct /internal.
examples/data-objects/monaco/src/index.ts Switches DataObjectFactory import to aqueduct /internal.
examples/data-objects/codemirror/src/codeMirror.ts Switches FluidDataStoreRuntime import to datastore /internal.
examples/data-objects/clicker/src/index.tsx Switches DataObjectFactory import to aqueduct /internal.
examples/data-objects/canvas/src/index.ts Switches DataObjectFactory import to aqueduct /internal.
examples/benchmarks/tablebench/src/test/utils.ts Uses internal IChannelFactory and internal test runtime mocks.
examples/benchmarks/bubblebench/shared-tree/src/bubblebench.ts Switches DataObjectFactory import to aqueduct /internal.
examples/benchmarks/bubblebench/ot/src/main.ts Switches DataObjectFactory import to aqueduct /internal.
examples/benchmarks/bubblebench/experimental-tree/src/main.tsx Switches DataObjectFactory import to aqueduct /internal.
examples/benchmarks/bubblebench/baseline/src/main.ts Switches DataObjectFactory import to aqueduct /internal.
examples/apps/tree-comparison/src/model/newTreeInventoryList.ts Switches DataObjectFactory import to aqueduct /internal.
examples/apps/tree-comparison/src/model/legacyTreeInventoryList.ts Switches DataObjectFactory import to aqueduct /internal.
examples/apps/task-selection/src/taskManagerDiceRoller.ts Switches DataObjectFactory import to aqueduct /internal.
examples/apps/task-selection/src/oldestClientDiceRoller.ts Switches DataObjectFactory import to aqueduct /internal.
examples/apps/staging/src/container/groceryList/groceryList.ts Switches runtime/factory and map factory imports to /internal where required.
examples/apps/presence-tracker/src/datastoreSupport.ts Switches FluidDataStoreRuntime import to datastore /internal.
examples/apps/diceroller/src/container/main.tsx Switches DataObjectFactory import to aqueduct /internal.
examples/apps/data-object-grid/src/dataObjectGrid.ts Switches DataObjectFactory import to aqueduct /internal.
examples/apps/contact-collection/src/dataObject.ts Switches DataObjectFactory import to aqueduct /internal.
examples/apps/collaborative-textarea/src/fluid-object/index.ts Switches DataObjectFactory import to aqueduct /internal.
examples/apps/blobs/src/container/blobCollection/blobCollection.ts Switches runtime/factory and map factory imports to /internal where required.
.vale/config/vocabularies/fluid/accept.txt Adds “DDS” to accepted vocabulary.
.changeset/custom-dds-removal-shared-object-base.md Adds breaking changeset for shared-object-base internalizations.
.changeset/custom-dds-removal-datastore-definitions.md Adds breaking changeset for datastore-definitions (IChannelFactory internalization).

Comment on lines +86 to +93
**From `@fluidframework/datastore-definitions`:**
- `IChannel` - channel interface (note: has exposure at datastore layer - need to sever typing)
- `IChannelFactory` - factory interface
- `IChannelServices` - services bundle
- `IChannelStorageService` - storage service interface
- `IDeltaConnection` - delta connection interface
- `IDeltaHandler` - op processing interface
- `IChannelAttributes` - channel attributes
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Phase 1 list says to move IChannel, IChannelServices, IChannelStorageService, IDeltaConnection, IDeltaHandler, and IChannelAttributes to internal. However, this PR’s actual changeset for @fluidframework/datastore-definitions only makes IChannelFactory internal and explicitly keeps the other channel-related interfaces in the legacy API due to IFluidDataStoreRuntime transitive references. Please update this plan section to match the implemented/announced scope (or clearly mark the additional internalization as a later phase).

Copilot uses AI. Check for mistakes.

// @beta @legacy
export const SharedSignal: ISharedObjectKind_2<ISharedSignal<any>> & SharedObjectKind_2<ISharedSignal<any>>;
export const SharedSignal: ISharedObjectKind<ISharedSignal<any>> & SharedObjectKind_2<ISharedSignal<any>>;
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The legacy-beta API report still exposes SharedSignal as ISharedObjectKind<...> & SharedObjectKind_2<...>. ISharedObjectKind has been changed to @internal in @fluidframework/shared-object-base, so this should not appear in a legacy/beta public surface. Consider updating the SharedSignal export in source to be typed as SharedObjectKind<ISharedSignal<...>> (similar to SharedArray) so the API report doesn’t reference the internal interface.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant