fluid-framework 2.114.0 → 2.115.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,205 @@
1
1
  # fluid-framework
2
2
 
3
+ ## 2.115.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Promote FormattedText APIs to alpha ([#27843](https://github.com/microsoft/FluidFramework/pull/27843)) [71895da92a](https://github.com/microsoft/FluidFramework/commit/71895da92ad598a366694ae6cd2cd8c296533804)
8
+
9
+ The [`FormattedText`](https://fluidframework.com/docs/api/fluid-framework/formattedtext-namespace) namespace is now available from the `fluid-framework/alpha` entrypoint.
10
+ It provides a generic, collaborative rich-text domain built on SharedTree, parameterized by the formatting you want to associate with each unit of text and by any extra "atom" (embedded object) types you want to allow alongside plain characters.
11
+
12
+ Use `FormattedText.createSchema` to generate a text schema for your chosen formatting, then treat the resulting node like a formatted string.
13
+
14
+ ```typescript
15
+ import { SchemaFactory } from "fluid-framework";
16
+ import { SchemaFactoryBeta } from "fluid-framework/beta";
17
+ import { FormattedText } from "fluid-framework/alpha";
18
+
19
+ // Note that a beta schema factory is currently required for use with `FormattedText`
20
+ const schemaFactory = new SchemaFactoryBeta("com.example.doc");
21
+
22
+ // Describe the formatting associated with each character.
23
+ class CharacterFormat extends schemaFactory.object("CharacterFormat", {
24
+ bold: SchemaFactory.boolean,
25
+ italic: SchemaFactory.boolean,
26
+ }) {}
27
+
28
+ // Generate the formatted-text schema. The last argument is the format applied
29
+ // to text inserted through the non-formatted APIs (for example `fromString`).
30
+ class RichText extends FormattedText.createSchema(
31
+ schemaFactory,
32
+ CharacterFormat,
33
+ [], // No extra embedded atom types.
34
+ { bold: false, italic: false },
35
+ ) {}
36
+ ```
37
+
38
+ Once you have a schema, you can construct and edit formatted text:
39
+
40
+ ```typescript
41
+ // Create some text using the default format.
42
+ const text = RichText.fromString("hello world");
43
+
44
+ // Append more text with an explicit format.
45
+ text.insertAt(text.characterCount(), "!", { bold: true, italic: false });
46
+
47
+ // Bold everything from index 0 up to (but not including) index 5.
48
+ text.formatRange(0, 5, { bold: true });
49
+
50
+ // Read back the content with its associated formatting.
51
+ for (const atom of text.charactersWithFormatting()) {
52
+ console.log(atom.content, atom.format.bold, atom.format.italic);
53
+ }
54
+ ```
55
+
56
+ `FormattedText` is currently surfaced as an alpha API and is subject to change.
57
+
58
+ - Array node deltas now cover the complete array ([#27809](https://github.com/microsoft/FluidFramework/pull/27809)) [6af2aba044](https://github.com/microsoft/FluidFramework/commit/6af2aba044e050b20386ae9e67111693117da5bd)
59
+
60
+ `ArrayNodeDeltaOp` and `ArrayNodeTreeChangedDeltaOp` sequences now include a final retain operation for an unchanged trailing portion of the array. Consumers can process the operations as a complete delta without separately retaining an omitted suffix.
61
+
62
+ Text deltas inherit the same complete-coverage behavior.
63
+
64
+ This should not break any existing users as this behavior was allowed under the old specification, but may allow some users to simplify their processing of the delta.
65
+
66
+ - Settled change notification ([#27814](https://github.com/microsoft/FluidFramework/pull/27814)) [73360b3d70](https://github.com/microsoft/FluidFramework/commit/73360b3d7036a5ce8be1f88a1ada3cfbe680541b)
67
+
68
+ `LocalChangeMetadata` now exposes an `events: Listenable<LocalCommitEvents>` property that fires a `"settled"` event once a commit has been ordered by the sequencing service.
69
+
70
+ Once a commit is sequenced, the following guarantees hold:
71
+ 1. The changes carried by the commit have been persisted and other peers are able to see them.
72
+ 2. There can be no more concurrent changes sequenced before this commit, which means this commit has reached its settled form.
73
+
74
+ The `"settled"` event provides details about the outcome of applying this settled form.
75
+ This can be used by an application to determine whether any constraints associated with the commits were violated.
76
+
77
+ This event can be used by applications to inform the end user that their changes have been saved (`CommitOutcome.FullyApplied`) or rejected (`CommitOutcome.FullyDropped` and `CommitOutcome.NewContentOnly`).
78
+ It can also be used to queue up a new attempt at making the rejected changes. Note however that new edits must be made outside of the event callback.
79
+
80
+ Example:
81
+
82
+ ```typescript
83
+ // Use `asAlpha` API to access the settled event API
84
+ const view = asAlpha(tree.viewWith(config));
85
+
86
+ // Function to clear all contents of the tree, with a precondition that no changes have occurred.
87
+ const clearAllContents = () => {
88
+ view.runTransaction(
89
+ () => {
90
+ // Remove all contents at the root
91
+ view.root.removeRange();
92
+ },
93
+ { preconditions: [{ type: "noChange" }] },
94
+ );
95
+ };
96
+
97
+ // Register the logic for notifying the user of the outcome and allow them to retry
98
+ view.events.on("changed", (metadata) => {
99
+ if (metadata.isLocal) {
100
+ metadata.events.on("settled", (outcome) => {
101
+ if (outcome === CommitOutcome.FullyApplied) {
102
+ alert("Clear operation succeeded.");
103
+ } else {
104
+ const shouldTryAgain = confirm(
105
+ "The contents have changed. Do you still want to clear everything?",
106
+ );
107
+ if (shouldTryAgain) {
108
+ // It is invalid to make edits during the event callback, so we schedule the retry to occur asynchronously.
109
+ setTimeout(clearAllContents);
110
+ } else {
111
+ alert("Clear operation aborted.");
112
+ }
113
+ }
114
+ });
115
+ }
116
+ });
117
+
118
+ // First attempt to clear all contents.
119
+ // This will synchronously trigger the changed "event" and register the listener for the settled event.
120
+ clearAllContents();
121
+ ```
122
+
123
+ - SharedTree now emits telemetry when it heals an unresolvable identifier on decode ([#27756](https://github.com/microsoft/FluidFramework/pull/27756)) [e5ada10ff4](https://github.com/microsoft/FluidFramework/commit/e5ada10ff41a959abe599bb407300e42e1008be3)
124
+
125
+ When [`SharedTreeOptionsBeta.healUnresolvableIdentifiersOnDecode`](https://fluidframework.com/docs/api/tree/sharedtreeoptionsbeta-interface#healunresolvableidentifiersondecode-propertysignature) is enabled and an unresolvable identifier is healed while loading a summary, SharedTree now records a `HealUnresolvableIdentifierOnDecode` telemetry event (at `LogLevel.essential`). This lets applications relying on the healing workaround detect which documents actually required healing.
126
+
127
+ This only affects applications that have opted into `healUnresolvableIdentifiersOnDecode`; the telemetry is emitted through the same logger the DDS already uses, and no behavior other than the added telemetry has changed.
128
+
129
+ - Simplify creating attached Fluid containers with ServiceClient ([#27789](https://github.com/microsoft/FluidFramework/pull/27789)) [1671447b57](https://github.com/microsoft/FluidFramework/commit/1671447b57852875ec90a9d1c16b3817ce25e004)
130
+
131
+ Added `ServiceClient.createAttachedContainer` which creates and attaches a Fluid container in one operation.
132
+ It is a convenient shorthand for calling `createContainer` followed by `attach` when detached-container access is not needed.
133
+
134
+ ```typescript
135
+ const container = await client.createAttachedContainer(dataStoreKind);
136
+ ```
137
+
138
+ - Array insertion anchors now track their index from change deltas ([#27697](https://github.com/microsoft/FluidFramework/pull/27697)) [99d71d7054](https://github.com/microsoft/FluidFramework/commit/99d71d7054dd3ae5b2451c902bb7f7daf925c9f3)
139
+
140
+ The `@alpha` [`ArrayPlaceAnchor`](https://fluidframework.com/docs/api/tree/arrayplaceanchor-interface) returned by [`createArrayInsertionAnchor`](https://fluidframework.com/docs/api/tree/#createarrayinsertionanchor-function) now maintains its `index` incrementally from the array node's change delta instead of re-deriving it from the child that happened to sit at the anchor point when it was created. Inserts and removes before the anchor shift it, while edits after it leave it in place.
141
+
142
+ As a result, removing the child originally at the anchor's index no longer sends the anchor to the end of the array: it now stays in the gap between the surviving neighbors, which is the behavior an insertion point (such as a text cursor) needs.
143
+
144
+ Because the anchor now holds a subscription to the array node to receive those deltas, `ArrayPlaceAnchor` gained a `dispose()` method. Call it when the anchor is no longer needed to release the subscription. Interacting with an anchor after it has been disposed is invalid and will throw.
145
+
146
+ ```typescript
147
+ const anchor = createArrayInsertionAnchor(array, 1);
148
+ // ... use anchor.index as content is inserted and removed around it ...
149
+ anchor.dispose(); // release the subscription when done
150
+ ```
151
+
152
+ - Rename the TextAsTree domain to PlainText ([#27853](https://github.com/microsoft/FluidFramework/pull/27853)) [cd26d781f4](https://github.com/microsoft/FluidFramework/commit/cd26d781f436da469abb79c9d63e40d3c3b8c5dc)
153
+
154
+ The experimental (`@alpha`) text domain namespace exported from `@fluidframework/tree` has been renamed: `TextAsTree` is now `PlainText`.
155
+ This is a breaking rename.
156
+
157
+ Consumers should update their imports and usages accordingly. For example:
158
+
159
+ ```typescript
160
+ // Before
161
+ import { TextAsTree } from "@fluidframework/tree/alpha";
162
+ const node = TextAsTree.Tree.fromString("hello");
163
+
164
+ // After
165
+ import { PlainText } from "@fluidframework/tree/alpha";
166
+ const node = PlainText.Tree.fromString("hello");
167
+ ```
168
+
169
+ The persisted schema identifiers for this domain are unchanged, so existing documents remain compatible.
170
+
171
+ - Add getOrInsert and getOrInsertComputed methods to TreeMapNodeAlpha ([#27787](https://github.com/microsoft/FluidFramework/pull/27787)) [e84cb5f754](https://github.com/microsoft/FluidFramework/commit/e84cb5f754d4e916b02896c128c11b6526c8cef3)
172
+
173
+ [`TreeMapNodeAlpha`](https://fluidframework.com/docs/api/fluid-framework/treemapnodealpha-interface) now has `getOrInsert` and `getOrInsertComputed` methods, further aligning it with JavaScript's built-in Map API.
174
+ Both return the value at a key, first inserting a value if the map has no entry for that key: `getOrInsert` takes the fallback value directly, while `getOrInsertComputed` takes a callback which is only invoked (with the key) when an insert is needed, which is preferable when producing the fallback value is expensive.
175
+
176
+ When the fallback value is inserted and is not already a [`TreeNode`](https://fluidframework.com/docs/api/fluid-framework/treenode-class), the inserted and returned value is the result of implicitly constructing a node from it.
177
+
178
+ These methods are available on `TreeMapNodeAlpha`, which can be obtained from an existing `TreeMapNode` via `asAlpha`, or by declaring the schema with `SchemaFactoryAlpha`'s `mapAlpha`.
179
+
180
+ ```typescript
181
+ const schemaFactory = new SchemaFactoryAlpha("example");
182
+ class Inventory extends schemaFactory.mapAlpha(
183
+ "Inventory",
184
+ schemaFactory.number,
185
+ ) {}
186
+
187
+ const inventory = new Inventory(
188
+ new Map([
189
+ ["apples", 5],
190
+ ["pears", 3],
191
+ ]),
192
+ );
193
+
194
+ inventory.getOrInsert("apples", 10); // 5 (existing value returned, not overwritten)
195
+ inventory.getOrInsert("oranges", 10); // 10 (inserted and returned)
196
+
197
+ inventory.getOrInsertComputed("pears", () => computeRestockAmount()); // 3 (existing value returned, callback not invoked)
198
+ inventory.getOrInsertComputed("plums", () => computeRestockAmount()); // inserts and returns the computed value
199
+
200
+ inventory.size; // 4
201
+ ```
202
+
3
203
  ## 2.114.0
4
204
 
5
205
  ### Minor Changes
@@ -155,6 +155,7 @@ export interface ArrayNodeTreeChangedRetainOp extends ArrayNodeRetainOp {
155
155
 
156
156
  // @alpha @sealed
157
157
  export interface ArrayPlaceAnchor {
158
+ dispose(): void;
158
159
  get index(): number;
159
160
  }
160
161
 
@@ -222,6 +223,13 @@ export interface CommitMetadata {
222
223
  readonly kind: CommitKind;
223
224
  }
224
225
 
226
+ // @alpha
227
+ export enum CommitOutcome {
228
+ FullyApplied = 0,
229
+ FullyDropped = 1,
230
+ NewContentOnly = 2
231
+ }
232
+
225
233
  // @alpha
226
234
  export function comparePersistedSchema(persisted: JsonCompatible, view: ImplicitFieldSchema, options: ICodecOptions): Omit<SchemaCompatibilityStatus, "canInitialize">;
227
235
 
@@ -705,6 +713,56 @@ export const ForestTypeOptimized: ForestType;
705
713
  // @beta
706
714
  export const ForestTypeReference: ForestType;
707
715
 
716
+ // @alpha
717
+ export namespace FormattedText {
718
+ export function createSchema<const TUserScope extends string, const FormatSchema extends ImplicitAllowedTypes, const ExtraAtomsSchema extends readonly LazyItem<TreeNodeSchema<string, NodeKind, TextAtom & TreeNode>>[]>(inputSchemaFactory: SchemaFactoryBeta<TUserScope>, formatSchema: FormatSchema, extraAtoms: ExtraAtomsSchema, defaultFormatInsertable: InsertableTreeFieldFromImplicitField<FormatSchema>): FormattedTextSchema<TUserScope, FormatSchema, ExtraAtomsSchema>;
719
+ // @sealed
720
+ export interface FormattedAtom<TFormat, TText> {
721
+ readonly content: TText;
722
+ format: TFormat;
723
+ }
724
+ // @input
725
+ export interface FormattedAtomInsertable<TFormat, TContent> {
726
+ // (undocumented)
727
+ readonly content: TContent;
728
+ // (undocumented)
729
+ readonly format: TFormat;
730
+ }
731
+ // @sealed
732
+ export type FormattedTextSchema<TUserScope extends string, FormatSchema extends ImplicitAllowedTypes, ExtraAtomsSchema extends readonly LazyItem<TreeNodeSchema<string, NodeKind, TextAtom & TreeNode>>[]> = Statics<ErasedNode<Members<FormatSchema, ExtraAtomsSchema>, FormattedTextSchemaIdentifier<TUserScope>>, FormatSchema> & ErasedSchemaSubclassable<Members<FormatSchema, ExtraAtomsSchema>, FormattedTextSchemaIdentifier<TUserScope>>;
733
+ const // @sealed
734
+ StringTextAtom: StringTextAtomStatics & TreeNodeSchema<"com.fluidframework.text.formatted.StringTextAtom", NodeKind, TextAtom & TreeNode & WithType<"com.fluidframework.text.formatted.StringTextAtom", NodeKind, unknown>, never, false>;
735
+ export type FormattedTextSchemaIdentifier<TUserScope extends string> = ScopedSchemaName<`com.fluidframework.text.formatted<${TUserScope}>`, "Text">;
736
+ // @sealed
737
+ export interface Members<FormatSchema extends ImplicitAllowedTypes, ExtraAtomsSchema extends readonly LazyItem<TreeNodeSchema<string, NodeKind, TextAtom & TreeNode>>[]> extends PlainText.Members {
738
+ charactersWithFormatting(): readonly FormattedAtom<TreeNodeFromImplicitAllowedTypes<FormatSchema>, TreeNodeFromImplicitAllowedTypes<TextAtomSchemas<ExtraAtomsSchema>>>[];
739
+ formatRange(startIndex: number | undefined, endIndex: number | undefined, format: Partial<TreeNodeFromImplicitAllowedTypes<FormatSchema>>): void;
740
+ getString(startIndex: number, endIndex?: number): string;
741
+ getUniformRun(startIndex: number, endIndex?: number): number;
742
+ // @override
743
+ insertAt(index: number, additionalCharacters: string | Iterable<TreeNodeFromImplicitAllowedTypes<TextAtomSchemas<ExtraAtomsSchema>>>, format?: InsertableTreeFieldFromImplicitField<FormatSchema>): void;
744
+ insertWithFormattingAt(index: number, additionalCharacters: Iterable<FormattedAtomInsertable<InsertableTreeNodeFromImplicitAllowedTypes<FormatSchema>, InsertableTreeNodeFromImplicitAllowedTypes<TextAtomSchemas<ExtraAtomsSchema>>>>): void;
745
+ onContentChanged(callback: (ops: readonly PlainText.TextOp[] | undefined) => void): () => void;
746
+ reformat(startIndex?: number | undefined, endIndex?: number | undefined, format?: InsertableTreeFieldFromImplicitField<FormatSchema>): void;
747
+ }
748
+ // @sealed
749
+ export interface Statics<TTree, FormatSchema extends ImplicitAllowedTypes> {
750
+ fromString(value: string, format?: InsertableTreeFieldFromImplicitField<FormatSchema>): TTree;
751
+ }
752
+ // @sealed
753
+ export type StringTextAtom = ErasedNode<TextAtom, "com.fluidframework.text.formatted.StringTextAtom">;
754
+ // @sealed
755
+ export interface StringTextAtomStatics {
756
+ fromCharacter(value: string): StringTextAtom;
757
+ fromString(value: string): StringTextAtom[];
758
+ }
759
+ export interface TextAtom {
760
+ readonly content: string;
761
+ }
762
+ // @sealed
763
+ export type TextAtomSchemas<ExtraAtomsSchema extends readonly LazyItem<TreeNodeSchema<string, NodeKind, TextAtom & TreeNode>>[]> = readonly [typeof StringTextAtom, ...ExtraAtomsSchema];
764
+ }
765
+
708
766
  // @alpha @sealed
709
767
  export interface FormatValidator extends ErasedType<"FormatValidator"> {
710
768
  }
@@ -1348,6 +1406,7 @@ export type Listeners<T extends object> = {
1348
1406
 
1349
1407
  // @alpha @sealed
1350
1408
  export interface LocalChangeMetadata extends CommitMetadata {
1409
+ readonly events: Listenable<LocalCommitEvents>;
1351
1410
  getChange(): JsonCompatibleReadOnly;
1352
1411
  getRevertible(onDisposed?: (revertible: RevertibleAlpha) => void): RevertibleAlpha | undefined;
1353
1412
  readonly isLocal: true;
@@ -1355,6 +1414,11 @@ export interface LocalChangeMetadata extends CommitMetadata {
1355
1414
  readonly labels: TransactionLabels;
1356
1415
  }
1357
1416
 
1417
+ // @alpha @sealed
1418
+ export interface LocalCommitEvents {
1419
+ settled(outcome: CommitOutcome): void;
1420
+ }
1421
+
1358
1422
  // @public
1359
1423
  export const LogLevel: LogLevelConst;
1360
1424
 
@@ -1546,6 +1610,42 @@ export function onAssertionFailure(handler: (error: Error) => void): () => void;
1546
1610
  // @alpha
1547
1611
  export function persistedToSimpleSchema(persisted: JsonCompatible, options: ICodecOptions): SimpleTreeSchema;
1548
1612
 
1613
+ // @alpha
1614
+ export namespace PlainText {
1615
+ // @sealed
1616
+ export interface Members {
1617
+ characterCount(): number;
1618
+ characters(): Iterable<string>;
1619
+ charactersCopy(): string[];
1620
+ fullString(): string;
1621
+ insertAt(index: number, additionalCharacters: string): void;
1622
+ onCharactersChanged(callback: (ops: readonly TextOp[] | undefined) => void): () => void;
1623
+ removeRange(startIndex: number | undefined, endIndex: number | undefined): void;
1624
+ }
1625
+ export interface Statics {
1626
+ fromString(value: string): Tree;
1627
+ }
1628
+ // @sealed
1629
+ export interface TextInsertOp {
1630
+ readonly text: string;
1631
+ readonly type: "insert";
1632
+ }
1633
+ export type TextOp = TextRetainOp | TextInsertOp | TextRemoveOp;
1634
+ // @sealed
1635
+ export interface TextRemoveOp {
1636
+ readonly count: number;
1637
+ readonly type: "remove";
1638
+ }
1639
+ // @sealed
1640
+ export interface TextRetainOp {
1641
+ readonly count: number;
1642
+ readonly formattingChanged?: boolean;
1643
+ readonly type: "retain";
1644
+ }
1645
+ const Tree: Statics & TreeNodeSchema<"com.fluidframework.text.Text", NodeKind, Members & TreeNode & WithType<"com.fluidframework.text.Text", NodeKind, unknown>, never, false>;
1646
+ export type Tree = Members & TreeNode & WithType<"com.fluidframework.text.Text">;
1647
+ }
1648
+
1549
1649
  // @beta @system
1550
1650
  export type PopUnion<Union, AsOverloadedFunction = UnionToIntersection<Union extends unknown ? (f: Union) => void : never>> = AsOverloadedFunction extends (a: infer First) => void ? First : never;
1551
1651
 
@@ -1721,9 +1821,9 @@ export const SchemaFactory_base: SchemaStatics & (new () => SchemaStatics);
1721
1821
  export class SchemaFactoryAlpha<out TScope extends string | undefined = string | undefined, TName extends number | string = string> extends SchemaFactoryBeta<TScope, TName> {
1722
1822
  arrayAlpha<const Name extends TName, const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptionsAlpha<TCustomMetadata>): ArrayNodeCustomizableSchemaAlpha<ScopedSchemaName<TScope, Name>, T, true, TCustomMetadata>;
1723
1823
  arrayRecursive<const Name extends TName, const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptionsAlpha<TCustomMetadata>): ArrayNodeCustomizableSchemaUnsafe<ScopedSchemaName<TScope, Name>, T, TCustomMetadata>;
1724
- static readonly identifier: <const TCustomMetadata = unknown>(props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Identifier, LeafSchema<"string", string> & SimpleLeafNodeSchema<SchemaType>, TCustomMetadata, FieldPropsAlpha<TCustomMetadata>>;
1725
- static readonly leaves: readonly [LeafSchema<"string", string> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"number", number> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"boolean", boolean> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"null", null> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"handle", IFluidHandle<unknown>> & SimpleLeafNodeSchema<SchemaType>];
1726
- readonly leaves: readonly [LeafSchema<"string", string> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"number", number> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"boolean", boolean> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"null", null> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"handle", IFluidHandle<unknown>> & SimpleLeafNodeSchema<SchemaType>];
1824
+ static readonly identifier: <const TCustomMetadata = unknown>(props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Identifier, StringSchema, TCustomMetadata, FieldPropsAlpha<TCustomMetadata>>;
1825
+ static readonly leaves: readonly [StringSchema, LeafSchema<"number", number> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"boolean", boolean> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"null", null> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"handle", IFluidHandle<unknown>> & SimpleLeafNodeSchema<SchemaType>];
1826
+ readonly leaves: readonly [StringSchema, LeafSchema<"number", number> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"boolean", boolean> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"null", null> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"handle", IFluidHandle<unknown>> & SimpleLeafNodeSchema<SchemaType>];
1727
1827
  mapAlpha<Name extends TName, const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptionsAlpha<TCustomMetadata>): MapNodeCustomizableSchema<ScopedSchemaName<TScope, Name>, T, true, TCustomMetadata>;
1728
1828
  mapRecursive<Name extends TName, const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptionsAlpha<TCustomMetadata>): MapNodeCustomizableSchemaUnsafe<ScopedSchemaName<TScope, Name>, T, TCustomMetadata>;
1729
1829
  objectAlpha<const Name extends TName, const T extends RestrictiveStringRecord<ImplicitFieldSchema>, const TCustomMetadata = unknown>(name: Name, fields: T, options?: ObjectSchemaOptionsAlpha<TCustomMetadata>): ObjectNodeSchemaWorkaround<ScopedSchemaName<TScope, Name>, T, true, TCustomMetadata>;
@@ -1838,6 +1938,8 @@ type ScopedSchemaName<TScope extends string | undefined, TName extends number |
1838
1938
 
1839
1939
  // @alpha @sealed
1840
1940
  export interface ServiceClient {
1941
+ createAttachedContainer<T>(root: DataStoreKind<T>): Promise<FluidContainerAttached<T>>;
1942
+ createAttachedContainer<T>(root: DataStoreKey<T>, registry: DataStoreRegistry): Promise<FluidContainerAttached<T>>;
1841
1943
  createContainer<T>(root: DataStoreKind<T>): Promise<FluidContainerWithService<T>>;
1842
1944
  createContainer<T>(root: DataStoreKey<T>, registry: DataStoreRegistry): Promise<FluidContainerWithService<T>>;
1843
1945
  loadContainer<T>(id: string, root: DataStoreKind<T> | DataStoreRegistry<T>): Promise<FluidContainerAttached<T>>;
@@ -2022,6 +2124,9 @@ export interface StagedSchemaUpgradePolicyFactory {
2022
2124
  readonly restrictive: StagedSchemaUpgradePolicy;
2023
2125
  }
2024
2126
 
2127
+ // @alpha @sealed @system
2128
+ export type StringSchema = LeafSchema<"string", string> & SimpleLeafNodeSchema;
2129
+
2025
2130
  // @beta @system
2026
2131
  export namespace System_TableSchema {
2027
2132
  // @sealed @system
@@ -2267,42 +2372,6 @@ export interface Tagged<V, T extends string = string> {
2267
2372
  // @public
2268
2373
  export type TelemetryBaseEventPropertyType = string | number | boolean | undefined;
2269
2374
 
2270
- // @alpha
2271
- export namespace TextAsTree {
2272
- // @sealed
2273
- export interface Members {
2274
- characterCount(): number;
2275
- characters(): Iterable<string>;
2276
- charactersCopy(): string[];
2277
- fullString(): string;
2278
- insertAt(index: number, additionalCharacters: string): void;
2279
- onCharactersChanged(callback: (ops: readonly TextOp[] | undefined) => void): () => void;
2280
- removeRange(startIndex: number | undefined, endIndex: number | undefined): void;
2281
- }
2282
- export interface Statics {
2283
- fromString(value: string): Tree;
2284
- }
2285
- // @sealed
2286
- export interface TextInsertOp {
2287
- readonly text: string;
2288
- readonly type: "insert";
2289
- }
2290
- export type TextOp = TextRetainOp | TextInsertOp | TextRemoveOp;
2291
- // @sealed
2292
- export interface TextRemoveOp {
2293
- readonly count: number;
2294
- readonly type: "remove";
2295
- }
2296
- // @sealed
2297
- export interface TextRetainOp {
2298
- readonly count: number;
2299
- readonly formattingChanged?: boolean;
2300
- readonly type: "retain";
2301
- }
2302
- const Tree: Statics & TreeNodeSchema<"com.fluidframework.text.Text", NodeKind, Members & TreeNode & WithType<"com.fluidframework.text.Text", NodeKind, unknown>, never, false>;
2303
- export type Tree = Members & TreeNode & WithType<"com.fluidframework.text.Text">;
2304
- }
2305
-
2306
2375
  // @alpha
2307
2376
  export function trackDirtyNodes(view: TreeViewAlpha<ImplicitFieldSchema>, dirty: DirtyTreeMap): () => void;
2308
2377
 
@@ -2558,6 +2627,8 @@ export interface TreeMapNode<T extends ImplicitAllowedTypes = ImplicitAllowedTyp
2558
2627
  // @alpha @sealed
2559
2628
  export interface TreeMapNodeAlpha<T extends ImplicitAllowedTypes = ImplicitAllowedTypes> extends FluidReadonlyMap<string, TreeNodeFromImplicitAllowedTypes<T>>, TreeNode, Pick<TreeMapNode<T>, "set" | "delete"> {
2560
2629
  clear(): void;
2630
+ getOrInsert(key: string, fallbackValue: InsertableTreeNodeFromImplicitAllowedTypes<T>): TreeNodeFromImplicitAllowedTypes<T>;
2631
+ getOrInsertComputed(key: string, callback: (key: string) => InsertableTreeNodeFromImplicitAllowedTypes<T>): TreeNodeFromImplicitAllowedTypes<T>;
2561
2632
  }
2562
2633
 
2563
2634
  // @public @sealed
package/dist/alpha.d.ts CHANGED
@@ -237,6 +237,7 @@ export {
237
237
  ChangeMetadata,
238
238
  CodecName,
239
239
  CodecWriteOptions,
240
+ CommitOutcome,
240
241
  Component,
241
242
  CreateIndependentTreeAlphaOptions,
242
243
  DataStoreContext,
@@ -265,6 +266,7 @@ export {
265
266
  FormatValidatorBasic,
266
267
  FormatValidatorNoOp,
267
268
  FormatVersion,
269
+ FormattedText,
268
270
  HandleConverter,
269
271
  ICodecOptions,
270
272
  ITreeAlpha,
@@ -297,6 +299,7 @@ export {
297
299
  JsonTreeSchema,
298
300
  LabelTree,
299
301
  LocalChangeMetadata,
302
+ LocalCommitEvents,
300
303
  MapNodeCustomizableSchema,
301
304
  MapNodeCustomizableSchemaUnsafe,
302
305
  MapNodePojoEmulationSchema,
@@ -313,6 +316,7 @@ export {
313
316
  ObjectNodeSchemaWorkaround,
314
317
  ObjectSchemaOptionsAlpha,
315
318
  ObservationResults,
319
+ PlainText,
316
320
  ReadSchema,
317
321
  ReadableField,
318
322
  RecordNodeCustomizableSchema,
@@ -349,7 +353,7 @@ export {
349
353
  SimpleTreeSchema,
350
354
  StagedSchemaUpgradePolicy,
351
355
  StagedSchemaUpgradePolicyFactory,
352
- TextAsTree,
356
+ StringSchema,
353
357
  TransactionCallbackStatusAlpha,
354
358
  TransactionConstraintAlpha,
355
359
  TransactionLabels,
package/lib/alpha.d.ts CHANGED
@@ -237,6 +237,7 @@ export {
237
237
  ChangeMetadata,
238
238
  CodecName,
239
239
  CodecWriteOptions,
240
+ CommitOutcome,
240
241
  Component,
241
242
  CreateIndependentTreeAlphaOptions,
242
243
  DataStoreContext,
@@ -265,6 +266,7 @@ export {
265
266
  FormatValidatorBasic,
266
267
  FormatValidatorNoOp,
267
268
  FormatVersion,
269
+ FormattedText,
268
270
  HandleConverter,
269
271
  ICodecOptions,
270
272
  ITreeAlpha,
@@ -297,6 +299,7 @@ export {
297
299
  JsonTreeSchema,
298
300
  LabelTree,
299
301
  LocalChangeMetadata,
302
+ LocalCommitEvents,
300
303
  MapNodeCustomizableSchema,
301
304
  MapNodeCustomizableSchemaUnsafe,
302
305
  MapNodePojoEmulationSchema,
@@ -313,6 +316,7 @@ export {
313
316
  ObjectNodeSchemaWorkaround,
314
317
  ObjectSchemaOptionsAlpha,
315
318
  ObservationResults,
319
+ PlainText,
316
320
  ReadSchema,
317
321
  ReadableField,
318
322
  RecordNodeCustomizableSchema,
@@ -349,7 +353,7 @@ export {
349
353
  SimpleTreeSchema,
350
354
  StagedSchemaUpgradePolicy,
351
355
  StagedSchemaUpgradePolicyFactory,
352
- TextAsTree,
356
+ StringSchema,
353
357
  TransactionCallbackStatusAlpha,
354
358
  TransactionConstraintAlpha,
355
359
  TransactionLabels,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluid-framework",
3
- "version": "2.114.0",
3
+ "version": "2.115.0",
4
4
  "description": "The main entry point into Fluid Framework public packages",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -57,17 +57,17 @@
57
57
  "main": "lib/index.js",
58
58
  "types": "lib/public.d.ts",
59
59
  "dependencies": {
60
- "@fluidframework/container-definitions": "~2.114.0",
61
- "@fluidframework/container-loader": "~2.114.0",
62
- "@fluidframework/core-interfaces": "~2.114.0",
63
- "@fluidframework/core-utils": "~2.114.0",
64
- "@fluidframework/driver-definitions": "~2.114.0",
65
- "@fluidframework/fluid-static": "~2.114.0",
66
- "@fluidframework/map": "~2.114.0",
67
- "@fluidframework/runtime-utils": "~2.114.0",
68
- "@fluidframework/sequence": "~2.114.0",
69
- "@fluidframework/shared-object-base": "~2.114.0",
70
- "@fluidframework/tree": "~2.114.0"
60
+ "@fluidframework/container-definitions": "~2.115.0",
61
+ "@fluidframework/container-loader": "~2.115.0",
62
+ "@fluidframework/core-interfaces": "~2.115.0",
63
+ "@fluidframework/core-utils": "~2.115.0",
64
+ "@fluidframework/driver-definitions": "~2.115.0",
65
+ "@fluidframework/fluid-static": "~2.115.0",
66
+ "@fluidframework/map": "~2.115.0",
67
+ "@fluidframework/runtime-utils": "~2.115.0",
68
+ "@fluidframework/sequence": "~2.115.0",
69
+ "@fluidframework/shared-object-base": "~2.115.0",
70
+ "@fluidframework/tree": "~2.115.0"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@arethetypeswrong/cli": "^0.18.2",