#### Description
[13864](https://dev.azure.com/fluidframework/internal/_workitems/edit/13864/)
This PR adds forkable revertible feature to the `Revertible` object of
SharedTree.
- Removed `DisposableRevertible` and replaced by `RevertibleAlpha`.
- Added `clone()` method to the new interface.
- Uses `TreeBranch` (which is subset of `TreeCheckout`) to access data
necessary for revert operation.
---------
Co-authored-by: Noah Encke <78610362+noencke@users.noreply.github.com>
Co-authored-by: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com>
Co-authored-by: Jenn <jennle@microsoft.com>
## Description
This adds a collection of utilities that help to strongly-type arrays
which are known to have one or more elements in them. This allows some
of the SharedTreeBranchEvent arrays of commits to be more strongly typed
and benefit from these helpers. This PR also removes many usages of
`oob()` in favor of the new utilities. While `oob()` is still
appropriate in many places, the new utilities can help retrieve either
the first or the last element of an array in a type-safe way that is
(unlike `oob()`) enforced by the compiler.
## Description
ObjectNodes with no fields will now emit a compiler error if constructed
from an object literal with fields.
This matches the behavior of non-empty ObjectNodes which already gave
errors when unexpected properties were provided.
Also adds an "unsound union properties" test demoing a type soundness
issue which impacts tree but is a limitation of TypeScript which Tree
can no workaround.
## Breaking Changes
Any code which constructed object nodes with no fields from object
literals with fields should have those fields removed as they have no
impact at runtime.
---------
Co-authored-by: Craig Macomber <Craig.Macomber@microsoft.com>
Will ensure that core API members appear directly in website API docs
and will help detect transitive breaking changes from `devtools-core`.
Also updates `@packageDocumentation` comment with more details.
The API docs directories for the website contain a mix of generated and
manually authored files, so cleaning the API docs is not as simple as
just deleting the entire directory.
We previously had a sketchy workaround the cleaned all `.md` files, but
left any `.mdx` files alone, and had a script override in place to
ensure we ran `clean:api-documentation` before running
`build:api-documentation`.
This PR introduces a more wholistic solution to the fundamental problem,
which is that we want to clean up all of the git-ignored contents of the
API docs directories, while leaving the checked-in files alone.
[AB#24394](https://dev.azure.com/fluidframework/235294da-091d-4c29-84fc-cdfc3d90890b/_workitems/edit/24394)
## Description
This tightens the state machine space for `BranchCommitEnricher` and
makes various simplifications to the API and code.
* The API surface of `BranchCommitEnricher` is reduced to functions
that:
1. Process branch changes
2. Get enriched commits
3. Acknowledge transaction state transitions
Item (i) used to be made of a few different methods whose invocations
needed to be coordinated by `SharedTreeCore`. Now,
`BranchCommitEnricher` manages this internally. Previously, it needed to
know whether or not the commit being submitted was the commit of the
outermost transaction. This could be problematic for future refactors of
SharedTreeCore, so the enricher now derives that information from its
internals (since it already keeps track of ongoing transactions via the
`TransactionEnricher`.
* The map of processed commits stored in the enricher is now a WeakMap,
meaning that the enricher does not need to worry about accidentally
holding on to commits forever. The logic that "purges" map entries
between changes has been removed since the entries will now be dropped
automatically as the commits become unreferenced.
* TransactionEnricher no longer allows getting the enriched change in
the middle of a transaction.
* We now properly throw an error if a the SharedTree is attached in the
middle of a transaction - we do not and cannot currently support this
scenario.
* Various renames, conditional refactors, inlining, etc. to shorten
lines, improve code flow, simplify conditional logic, etc. and
additional documentation.
Docusaurus treats document files whose names start with `_` as "partial"
documents, which don't get included in site output. We have a couple of
API exports that start with `_`, and result in files that end up treated
as partials. To work around this, we now prepend "u" to any files that
would otherwise start with an underscore.
"u" is a pretty arbitrary choice. We can't simply remove the underscore,
as that would be much more likely to create filename collisions. While
it is technically possible that we could export an API item that starts
with "u_", doing so would violate our naming conventions, and seems
pretty unlikely. If such an API item is added, Docusaurus will start
failing on duplicate routes, at which point we can change strategies.
See https://docusaurus.io/docs/create-doc for more details on partial
documents.
[AB#23443](https://dev.azure.com/fluidframework/235294da-091d-4c29-84fc-cdfc3d90890b/_workitems/edit/23443)
## Description
Added a new page for the new Presence APIs and supported scenarios
---------
Co-authored-by: Rick Kirkham <Rick-Kirkham@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
## Overview
This feature introduces a new pattern for creating datastores
synchronously within the Fluid Framework. It allows for the synchronous
creation of a child datastore from an existing datastore, provided that
the child datastore is available synchronously via the existing
datastore's registry and that the child's factory supports synchronous
creation. This method also ensures strong typing for the consumer.
In this context, "child" refers specifically to the organization of
factories and registries, not to any hierarchical or hosting
relationship between datastores. The parent datastore does not control
the runtime behaviors of the child datastore beyond its creation.
The synchronous creation of child datastores enhances the flexibility of
datastore management within the Fluid Framework. It ensures type safety
and provides a different way to manage datastores within a container.
However, it is important to consider the overhead associated with
datastores, as they are stored, summarized, garbage collected, loaded,
and referenced independently. This overhead should be justified by the
scenario's requirements.
Datastores offer increased capabilities, such as the ability to
reference them via handles, allowing multiple references to exist and
enabling those references to be moved, swapped, or changed.
Additionally, datastores are garbage collected after becoming
unreferenced, which can simplify final cleanup across clients. This is
in contrast to subdirectories in a shared directory, which do not have
native capabilities for referencing or garbage collection but are very
low overhead to create.
Synchronous creation relies on both the factory and the datastore to
support it. This means that asynchronous operations, such as resolving
handles, some browser API calls, consensus-based operations, or other
asynchronous tasks, cannot be performed during the creation flow.
Therefore, synchronous child datastore creation is best limited to
scenarios where the existing asynchronous process cannot be used, such
as when a new datastore must be created in direct response to
synchronous user input.
## Key Benefits
- **Synchronous Creation**: Allows for the immediate creation of child
datastores without waiting for asynchronous operations.
- **Strong Typing**: Ensures type safety and better developer experience
by leveraging TypeScript's type system.
## Use Cases
### Example 1: Creating a Child Datastore
In this example, we demonstrate how to support creating a child
datastore synchronously from a parent datastore.
```typescript
/**
* This is the parent DataObject, which is also a datastore. It has a
* synchronous method to create child datastores, which could be called
* in response to synchronous user input, like a key press.
*/
class ParentDataObject extends DataObject {
get ParentDataObject() {
return this;
}
protected override async initializingFirstTime(): Promise<void> {
// create synchronously during initialization
this.createChild("parentCreation");
}
createChild(name: string): ChildDataStore {
assert(
this.context.createChildDataStore !== undefined,
"this.context.createChildDataStore",
);
// creates a detached context with a factory who's package path is the same
// as the current datastore, but with another copy of its own type.
const { entrypoint } = this.context.createChildDataStore(
ChildDataStoreFactory.instance,
);
const dir = this.root.createSubDirectory("children");
dir.set(name, entrypoint.handle);
entrypoint.setProperty("childValue", name);
return entrypoint;
}
getChild(name: string): IFluidHandle<ChildDataStore> | undefined {
const dir = this.root.getSubDirectory("children");
return dir?.get<IFluidHandle<ChildDataStore>>(name);
}
}
```
For a complete example see the follow test:
https://github.com/microsoft/FluidFramework/blob/main/packages/test/local-server-tests/src/test/synchronousDataStoreCreation.spec.ts
---------
Co-authored-by: jzaffiro <110866475+jzaffiro@users.noreply.github.com>
Co-authored-by: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com>
## Description
Switches all dependencies in the simplemde example app to be
devDependencies.
The example apps in the repo are not production code and aren't
published or deployed anywhere. Having prod dependencies in them causes
our lockfiles to mark them as such, and consequently Component
Governance potentially flags them for prod-level security
vulnerabilities. We have one outstanding prod-level alert about the
simplemde package (which seems abandoned); this change should remove the
prod-level severity from it while we migrate to another package for this
example, or get rid of it altogether.
The [ai-collab sample app already showcases this
pattern](https://github.com/microsoft/FluidFramework/blob/main/examples/apps/ai-collab/package.json#L33).
Removes changelog entries for the reverted changes in #23133. Also
removes some lingering entries in the release notes from that same
change. Finally, also fixes up some heading levels in the release notes
and TOC that were missed in review.
#### Description
[22739](https://dev.azure.com/fluidframework/internal/_workitems/edit/22739)
This PR adds step by step instructions for:
- Adding a new rule to the `estlint-plugin-fluid`
- Bumping the `eslint-plugin-fluid` version
- Bumping the `eslint-config-fluid` version
---------
Co-authored-by: Alex Villarreal <716334+alexvy86@users.noreply.github.com>
Co-authored-by: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com>
Current contents were copied from example boilerplate and were missed in
the initial Docusaurus PR.
This PR fixes the generated site title to be `Fluid Framework` instead
of `Fluid Framework | Hello from Fluid Framework!`.
Also removes the template page description.
Update to deployment and docs generation: adjustments to deploy v2
artifact instead of main artifacts. Note: while the update aims to
deploy artifacts from the latest release branches instead of main, the
actual website build is still done on the main branch. This will prevent
the pipeline from deploying docs which were generated with an outdated
version of the website.
Notable changes:
deploy-docs:
- shifted most of the stages from build-docs to deploy-docs
- build-docs now runs check_branch_version -> upload-json -> trigger
deploy
build-docs:
- shifted check_branch_version to the top since its output is required
to properly in the upload json step
upload-json-step:
- added a new upload step which uploads artifacts with the name
"latest-v*.tar.gz"
- takes in new parameters from check_branch_version to ensure it only
uploads with this name when the pipeline is running on the latest
release branch
latestVersions:
- since upload-json-step requires majorVersion, I figured it was best to
include it as an output variable for the function as it seems more
robust compared to relying on a string parsing script in the pipeline
itself
download-apis:
- update such that it only downloads "latest-v*.tar.gz" instead of the
main branch artifacts
This makes it so that changed events are not fired when rebases happen
on branches that are not the main branch and also adds a regression test
for this scenario. Rebases that happen on the main branch are remote
changes and therefore correct.
- `BroadcastControls` replace `LatestValueControls`
- `BroadcastControls` maybe specified on `PresenceStates` thru new
`controls` property as defaults for all value managers.
- `PresenceNotifications` redeclared apart from `PresenceStates` to
avoid `controls` exposure. Also yields better API documentation.
- `allowableUpdateLatencyMs` was renamed from `allowableUpdateLatency`
to clarify units are milliseconds. Specifying this value currently has
no effect.
- Unsupported `forcedRefreshInterval` has been removed until
implementation is closer.
## Overview
This feature introduces a new pattern for creating datastores
synchronously within the Fluid Framework. It allows for the synchronous
creation of a child datastore from an existing datastore, provided that
the child datastore is available synchronously via the existing
datastore's registry and that the child's factory supports synchronous
creation. This method also ensures strong typing for the consumer.
In this context, "child" refers specifically to the organization of
factories and registries, not to any hierarchical or hosting
relationship between datastores. The parent datastore does not control
the runtime behaviors of the child datastore beyond its creation.
The synchronous creation of child datastores enhances the flexibility of
datastore management within the Fluid Framework. It ensures type safety
and provides a different way to manage datastores within a container.
However, it is important to consider the overhead associated with
datastores, as they are stored, summarized, garbage collected, loaded,
and referenced independently. This overhead should be justified by the
scenario's requirements.
Datastores offer increased capabilities, such as the ability to
reference them via handles, allowing multiple references to exist and
enabling those references to be moved, swapped, or changed.
Additionally, datastores are garbage collected after becoming
unreferenced, which can simplify final cleanup across clients. This is
in contrast to subdirectories in a shared directory, which do not have
native capabilities for referencing or garbage collection but are very
low overhead to create.
Synchronous creation relies on both the factory and the datastore to
support it. This means that asynchronous operations, such as resolving
handles, some browser API calls, consensus-based operations, or other
asynchronous tasks, cannot be performed during the creation flow.
Therefore, synchronous child datastore creation is best limited to
scenarios where the existing asynchronous process cannot be used, such
as when a new datastore must be created in direct response to
synchronous user input.
## Key Benefits
- **Synchronous Creation**: Allows for the immediate creation of child
datastores without waiting for asynchronous operations.
- **Strong Typing**: Ensures type safety and better developer experience
by leveraging TypeScript's type system.
## Use Cases
### Example 1: Creating a Child Datastore
In this example, we demonstrate how to support creating a child
datastore synchronously from a parent datastore.
```typescript
/**
* This is the parent DataObject, which is also a datastore. It has a
* synchronous method to create child datastores, which could be called
* in response to synchronous user input, like a key press.
*/
class ParentDataObject extends DataObject {
get ParentDataObject() {
return this;
}
protected override async initializingFirstTime(): Promise<void> {
// create synchronously during initialization
this.createChild("parentCreation");
}
createChild(name: string): ChildDataStore {
assert(
this.context.createChildDataStore !== undefined,
"this.context.createChildDataStore",
);
// creates a detached context with a factory who's package path is the same
// as the current datastore, but with another copy of its own type.
const { entrypoint } = this.context.createChildDataStore(
ChildDataStoreFactory.instance,
);
const dir = this.root.createSubDirectory("children");
dir.set(name, entrypoint.handle);
entrypoint.setProperty("childValue", name);
return entrypoint;
}
getChild(name: string): IFluidHandle<ChildDataStore> | undefined {
const dir = this.root.getSubDirectory("children");
return dir?.get<IFluidHandle<ChildDataStore>>(name);
}
}
```
For a complete example see the follow test:
https://github.com/microsoft/FluidFramework/blob/main/packages/test/local-server-tests/src/test/synchronousDataStoreCreation.spec.ts
---------
Co-authored-by: Matt Rakow <ChumpChief@users.noreply.github.com>
Co-authored-by: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com>
We've added a new data structure for tracking "recent" (based on MSN)
batchIds which are at risk for seeing a duplicate sequence batchID come
in. This data structure is consulted and modified on each incoming
batch.
Whenever we summarize, we need to include this state as of the given
sequence number, and when we load from a snapshot we need to repopulate
it as well.
Why? Because summaries can happen at any time, and a future container
loading from that point will need to know the recent batch IDs that may
possibly be followed by a sequenced duplicate.
---------
Co-authored-by: Kian Thompson <102998837+kian-thompson@users.noreply.github.com>
Publishing step needs this config to live in the build output directory.
Placing it under `static` ensures it is copied to the right place.
See https://github.com/Azure/static-web-apps/issues/1071 for more
details.
Confirmed that the swa-cli is able to find this when run locally. This
is also how the site was setup previously, I was just misled by the
documentation leading me to believe that moving it to the root was okay.
It also worked using the local swa-cli tooling 🤷♂️
This update introduces a new feature to the `SharedString` DDS, allowing
for the adjustment of properties over a specified range. The
`annotateAdjustRange` method enables users to apply adjustments to
properties within a given range, providing more flexibility and control
over property modifications.
An adjustment is a modification applied to a property value within a
specified range. Adjustments can be used to increment or decrement
property values dynamically. They are particularly useful in scenarios
where property values need to be updated based on user interactions or
other events. For example, in a rich text editor, adjustments can be
used for modifying indentation levels or font sizes, where multiple
users could apply differing numerical adjustments.
### Key Features and Use Cases:
- **Adjustments with Constraints**: Adjustments can include optional
minimum and maximum constraints to ensure the final value falls within
specified bounds. This is particularly useful for maintaining consistent
formatting in rich text editors.
- **Consistent Property Changes**: The feature ensures that property
changes are consistent, managing both local and remote changes
effectively. This is essential for collaborative rich text editing where
multiple users may be making adjustments simultaneously.
- **Rich Text Formatting**: Adjustments can be used to modify text
properties such as font size, indentation, or other formatting
attributes dynamically based on user actions.
### Configuration and Compatibility Requirements:
This feature is only available when the configuration
`Fluid.Sequence.mergeTreeEnableAnnotateAdjust` is set to `true`.
Additionally, all collaborating clients must have this feature enabled
to use it. If any client does not have this feature enabled, it will
lead to the client exiting collaboration. A future major version of
Fluid will enable this feature by default.
### Usage Example:
```typescript
sharedString.annotateAdjustRange(start, end, {
key: { value: 5, min: 0, max: 10 }
});
```
[AB#11819](https://dev.azure.com/fluidframework/235294da-091d-4c29-84fc-cdfc3d90890b/_workitems/edit/11819)
---------
Co-authored-by: Tyler Butler <tylerbu@microsoft.com>
# Docusaurus
Updates the website (/docs) to leverage
[Docusaurus](https://docusaurus.io/) in place of Hugo as its static site
generator.
## Functional changes
### Versioning
The existing Hugo-based site only has a partial versioning story.
The API docs are versioned, but the rest of the content isn't.
This creates a messy story where our hand-written docs likely only
discuss topics related to the current version, and we have no place to
put docs discussing earlier versions.
Or, even worse, we have a mixed bag of documentation for different
versions, creating a very unclear user story.
This prototype includes an end-to-end versioning story, [automated by
Docusaurus](https://docusaurus.io/docs/versioning).
Current (v2) docs live under `docs`.
Old (v1) docs live under `versioned_docs/version-1`.
Most of the documentation has been duplicated between the two versions,
but some minor changes have been made to make the docs better line up
with the corresponding version of the API.
These changes should be reviewed before being merged into main /
deploying the new website.
### Search
This branch includes an offline implementation of search.
An offline solution comes with some downsides (slower build, larger
bundle), and probably isn't what we want long term.
That said, it is much better than what our current website has (no
search whatsoever).
We should come back to this after v1 of our new website.
---------
Co-authored-by: Wayne Ferrao <wayneferrao@microsoft.com>