@fluidframework/fluid-static 2.50.0-345060 → 2.51.0-347100

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 (53) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/api-report/fluid-static.alpha.api.md +17 -0
  3. package/dist/fluidContainer.d.ts +1 -1
  4. package/dist/fluidContainer.d.ts.map +1 -1
  5. package/dist/fluidContainer.js.map +1 -1
  6. package/dist/index.d.ts +3 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +5 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/rootDataObject.d.ts +6 -3
  11. package/dist/rootDataObject.d.ts.map +1 -1
  12. package/dist/rootDataObject.js +27 -44
  13. package/dist/rootDataObject.js.map +1 -1
  14. package/dist/treeRootDataObject.d.ts +47 -0
  15. package/dist/treeRootDataObject.d.ts.map +1 -0
  16. package/dist/treeRootDataObject.js +157 -0
  17. package/dist/treeRootDataObject.js.map +1 -0
  18. package/dist/types.d.ts +23 -8
  19. package/dist/types.d.ts.map +1 -1
  20. package/dist/types.js.map +1 -1
  21. package/dist/utils.d.ts +29 -4
  22. package/dist/utils.d.ts.map +1 -1
  23. package/dist/utils.js +62 -3
  24. package/dist/utils.js.map +1 -1
  25. package/lib/fluidContainer.d.ts +1 -1
  26. package/lib/fluidContainer.d.ts.map +1 -1
  27. package/lib/fluidContainer.js.map +1 -1
  28. package/lib/index.d.ts +3 -1
  29. package/lib/index.d.ts.map +1 -1
  30. package/lib/index.js +2 -0
  31. package/lib/index.js.map +1 -1
  32. package/lib/rootDataObject.d.ts +6 -3
  33. package/lib/rootDataObject.d.ts.map +1 -1
  34. package/lib/rootDataObject.js +25 -42
  35. package/lib/rootDataObject.js.map +1 -1
  36. package/lib/treeRootDataObject.d.ts +47 -0
  37. package/lib/treeRootDataObject.d.ts.map +1 -0
  38. package/lib/treeRootDataObject.js +153 -0
  39. package/lib/treeRootDataObject.js.map +1 -0
  40. package/lib/types.d.ts +23 -8
  41. package/lib/types.d.ts.map +1 -1
  42. package/lib/types.js.map +1 -1
  43. package/lib/utils.d.ts +29 -4
  44. package/lib/utils.d.ts.map +1 -1
  45. package/lib/utils.js +55 -0
  46. package/lib/utils.js.map +1 -1
  47. package/package.json +21 -20
  48. package/src/fluidContainer.ts +1 -1
  49. package/src/index.ts +3 -0
  50. package/src/rootDataObject.ts +46 -69
  51. package/src/treeRootDataObject.ts +249 -0
  52. package/src/types.ts +30 -9
  53. package/src/utils.ts +90 -4
@@ -0,0 +1,249 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import {
7
+ BaseContainerRuntimeFactory,
8
+ TreeDataObject,
9
+ TreeDataObjectFactory,
10
+ } from "@fluidframework/aqueduct/internal";
11
+ import type { IDataObjectProps } from "@fluidframework/aqueduct/internal";
12
+ import type { IRuntimeFactory } from "@fluidframework/container-definitions/internal";
13
+ import {
14
+ FluidDataStoreRegistry,
15
+ type IContainerRuntimeOptions,
16
+ type MinimumVersionForCollab,
17
+ } from "@fluidframework/container-runtime/internal";
18
+ import type {
19
+ IContainerRuntime,
20
+ IContainerRuntimeInternal,
21
+ } from "@fluidframework/container-runtime-definitions/internal";
22
+ import type {
23
+ FluidObject,
24
+ IFluidHandle,
25
+ IFluidLoadable,
26
+ } from "@fluidframework/core-interfaces";
27
+ import { assert } from "@fluidframework/core-utils/internal";
28
+ import type { IChannelFactory } from "@fluidframework/datastore-definitions/internal";
29
+ import type { IFluidDataStoreRegistry } from "@fluidframework/runtime-definitions/internal";
30
+ import type { SharedObjectKind } from "@fluidframework/shared-object-base/internal";
31
+
32
+ import { compatibilityModeRuntimeOptions } from "./compatibilityConfiguration.js";
33
+ import type {
34
+ CompatibilityMode,
35
+ IRootDataObject,
36
+ IStaticEntryPoint,
37
+ LoadableObjectKind,
38
+ LoadableObjectRecord,
39
+ TreeContainerSchema,
40
+ } from "./types.js";
41
+ import {
42
+ compatibilityModeToMinVersionForCollab,
43
+ createDataObject,
44
+ createSharedObject,
45
+ isDataObjectKind,
46
+ isSharedObjectKind,
47
+ makeFluidObject,
48
+ parseDataObjectsFromSharedObjects,
49
+ } from "./utils.js";
50
+
51
+ /**
52
+ * This module contains types and factories for creating tree-based root data objects.
53
+ * They exist as an alternative to the APIs in `rootDataObject.ts`.
54
+ *
55
+ * These APIs are currently shaped to parallel `RootDataObject`, but this is not intended as the long-term design.
56
+ * The current shape is a short-term solution to allow for easier migration from the old APIs.
57
+ */
58
+
59
+ /**
60
+ * The entry-point/root collaborative object of the {@link IFluidContainer | Fluid Container}.
61
+ *
62
+ * @remarks
63
+ * Abstracts the dynamic code required to build a Fluid Container into a static representation for end customers.
64
+ */
65
+ class TreeRootDataObject extends TreeDataObject implements IRootDataObject {
66
+ public constructor(props: IDataObjectProps) {
67
+ super(props);
68
+ }
69
+
70
+ public get TreeRootDataObject(): TreeRootDataObject {
71
+ return this;
72
+ }
73
+
74
+ // TODO: longer term, it would be better to not have to fit into the `initialObjects` model for tree-based containers.
75
+ // But in the short term, fitting into this model makes migration easier.
76
+ public get initialObjects(): LoadableObjectRecord {
77
+ return {
78
+ tree: this.tree,
79
+ };
80
+ }
81
+
82
+ public async create<T>(objectClass: SharedObjectKind<T>): Promise<T> {
83
+ const internal = objectClass as unknown as LoadableObjectKind<T & IFluidLoadable>;
84
+ if (isDataObjectKind(internal)) {
85
+ return createDataObject(internal, this.context);
86
+ } else if (isSharedObjectKind(internal)) {
87
+ return createSharedObject(internal, this.runtime);
88
+ }
89
+ throw new Error("Could not create new Fluid object because an unknown object was passed");
90
+ }
91
+
92
+ public async uploadBlob(blob: ArrayBufferLike): Promise<IFluidHandle<ArrayBufferLike>> {
93
+ return this.runtime.uploadBlob(blob);
94
+ }
95
+ }
96
+
97
+ const treeRootDataStoreId = "treeRootDOId";
98
+
99
+ /**
100
+ * Type of the {@link TreeRootDataObject}.
101
+ * @remarks Used in the PureDataObjectFactory to create the root data object.
102
+ */
103
+ const treeRootDataObjectType = "treeRootDO";
104
+
105
+ async function provideEntryPoint(
106
+ containerRuntime: IContainerRuntime,
107
+ ): Promise<IStaticEntryPoint> {
108
+ const entryPoint = await containerRuntime.getAliasedDataStoreEntryPoint(treeRootDataStoreId);
109
+ if (entryPoint === undefined) {
110
+ throw new Error(`default dataStore [${treeRootDataStoreId}] must exist`);
111
+ }
112
+ const treeRootDataObject = ((await entryPoint.get()) as FluidObject<TreeRootDataObject>)
113
+ .TreeRootDataObject;
114
+ assert(treeRootDataObject !== undefined, "entryPoint must be of type TreeRootDataObject");
115
+ return makeFluidObject<IStaticEntryPoint>(
116
+ {
117
+ rootDataObject: treeRootDataObject,
118
+ extensionStore: containerRuntime as IContainerRuntimeInternal,
119
+ },
120
+ "IStaticEntryPoint",
121
+ );
122
+ }
123
+
124
+ /**
125
+ * Factory for Container Runtime instances that provide a {@link IStaticEntryPoint}
126
+ * (containing single {@link IRootDataObject}) as their entry point.
127
+ */
128
+ class TreeContainerRuntimeFactory extends BaseContainerRuntimeFactory {
129
+ // TODO: use for runtime factory.
130
+ readonly #treeRootDataObjectFactory: TreeDataObjectFactory<TreeRootDataObject>;
131
+
132
+ public constructor(
133
+ compatibilityMode: CompatibilityMode,
134
+ treeRootDataObjectFactory: TreeDataObjectFactory<TreeRootDataObject>,
135
+ overrides?: Partial<{
136
+ runtimeOptions: Partial<IContainerRuntimeOptions>;
137
+ minVersionForCollab: MinimumVersionForCollab;
138
+ }>,
139
+ ) {
140
+ super({
141
+ registryEntries: [treeRootDataObjectFactory.registryEntry],
142
+ runtimeOptions: {
143
+ ...compatibilityModeRuntimeOptions[compatibilityMode],
144
+ ...overrides?.runtimeOptions,
145
+ },
146
+ provideEntryPoint,
147
+ minVersionForCollab:
148
+ overrides?.minVersionForCollab ??
149
+ compatibilityModeToMinVersionForCollab[compatibilityMode],
150
+ });
151
+ this.#treeRootDataObjectFactory = treeRootDataObjectFactory;
152
+ }
153
+
154
+ protected async containerInitializingFirstTime(runtime: IContainerRuntime): Promise<void> {
155
+ // The first time we create the container we create the RootDataObject
156
+ await this.#treeRootDataObjectFactory.createRootInstance(treeRootDataStoreId, runtime);
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Factory that creates instances of a tree-based root data object.
162
+ */
163
+ class TreeRootDataObjectFactory extends TreeDataObjectFactory<TreeRootDataObject> {
164
+ public constructor(
165
+ sharedObjects: readonly IChannelFactory[] = [],
166
+ private readonly dataStoreRegistry: IFluidDataStoreRegistry,
167
+ ) {
168
+ type Ctor = new (props: IDataObjectProps) => TreeRootDataObject;
169
+ const ctor: Ctor = function (_props) {
170
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
171
+ return new TreeRootDataObject({
172
+ ..._props,
173
+ // Add any additional injected properties here
174
+ });
175
+ } as unknown as Ctor;
176
+
177
+ // Note: we're not specifying registry entries to the base class, so it won't create a registry itself,
178
+ // and instead we override the necessary methods in this class to use the registry received in the constructor.
179
+ super({
180
+ type: treeRootDataObjectType,
181
+ ctor,
182
+ sharedObjects,
183
+ });
184
+ }
185
+
186
+ public get IFluidDataStoreRegistry(): IFluidDataStoreRegistry {
187
+ return this.dataStoreRegistry;
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Creates an {@link @fluidframework/aqueduct#IRuntimeFactory} which constructs containers
193
+ * with an entry point containing single tree-based root data object.
194
+ *
195
+ * @remarks
196
+ * The entry point is opaque to caller.
197
+ * The root data object's registry and shared objects are configured based on the provided
198
+ * SharedTree and optionally data store registry.
199
+ *
200
+ * @legacy @alpha
201
+ */
202
+ export function createTreeContainerRuntimeFactory(props: {
203
+ /**
204
+ * The schema for the container.
205
+ */
206
+ readonly schema: TreeContainerSchema;
207
+
208
+ /**
209
+ * See {@link CompatibilityMode} and compatibilityModeRuntimeOptions for more details.
210
+ */
211
+ readonly compatibilityMode: CompatibilityMode;
212
+ /**
213
+ * Optional registry of data stores to pass to the DataObject factory.
214
+ * If not provided, one will be created based on the schema.
215
+ */
216
+ readonly rootDataStoreRegistry?: IFluidDataStoreRegistry;
217
+ /**
218
+ * Optional overrides for the container runtime options.
219
+ * If not provided, only the default options for the given compatibilityMode will be used.
220
+ */
221
+ readonly runtimeOptionOverrides?: Partial<IContainerRuntimeOptions>;
222
+ /**
223
+ * Optional override for minimum version for collab.
224
+ * If not provided, the default for the given compatibilityMode will be used.
225
+ * @remarks
226
+ * This is useful when runtime options are overridden and change the minimum version for collab.
227
+ */
228
+ readonly minVersionForCollabOverride?: MinimumVersionForCollab;
229
+ }): IRuntimeFactory {
230
+ const {
231
+ compatibilityMode,
232
+ minVersionForCollabOverride,
233
+ rootDataStoreRegistry,
234
+ runtimeOptionOverrides,
235
+ schema,
236
+ } = props;
237
+
238
+ const [registryEntries, sharedObjects] = parseDataObjectsFromSharedObjects(schema);
239
+ const registry = rootDataStoreRegistry ?? new FluidDataStoreRegistry(registryEntries);
240
+
241
+ return new TreeContainerRuntimeFactory(
242
+ compatibilityMode,
243
+ new TreeRootDataObjectFactory(sharedObjects, registry),
244
+ {
245
+ runtimeOptions: runtimeOptionOverrides,
246
+ minVersionForCollab: minVersionForCollabOverride,
247
+ },
248
+ );
249
+ }
package/src/types.ts CHANGED
@@ -11,8 +11,11 @@ import type {
11
11
  IFluidHandle,
12
12
  IFluidLoadable,
13
13
  } from "@fluidframework/core-interfaces";
14
- import type { SharedObjectKind } from "@fluidframework/shared-object-base";
15
- import type { ISharedObjectKind } from "@fluidframework/shared-object-base/internal";
14
+ import type {
15
+ ISharedObjectKind,
16
+ SharedObjectKind,
17
+ } from "@fluidframework/shared-object-base/internal";
18
+ import type { ITree } from "@fluidframework/tree";
16
19
 
17
20
  /**
18
21
  * Determines the set of runtime options that Fluid Framework will use when running.
@@ -100,15 +103,28 @@ export interface ContainerSchema {
100
103
  }
101
104
 
102
105
  /**
103
- * Holds the collection of objects that the container was initially created with, as well as provides the ability
104
- * to dynamically create further objects during usage.
106
+ * Declares the Fluid objects that will be available in the {@link IFluidContainer | Container}.
107
+ *
108
+ * @remarks
109
+ *
110
+ * It includes both the kind of `SharedTree` that will be initially available upon `Container` creation, as well
111
+ * as the types of objects that may be dynamically created throughout the lifetime of the `Container`.
112
+ *
113
+ * @legacy @alpha
105
114
  */
106
- export interface IRootDataObject {
107
- /**
108
- * Provides a record of the initial objects defined on creation.
109
- */
110
- readonly initialObjects: LoadableObjectRecord;
115
+ export interface TreeContainerSchema extends ContainerSchema {
116
+ // TODO: longer term, it would be better to not have to fit into the `initialObjects` model for tree-based containers.
117
+ // But in the short term, fitting into this model makes migration easier.
118
+ readonly initialObjects: {
119
+ readonly tree: SharedObjectKind<ITree>;
120
+ };
121
+ }
111
122
 
123
+ /**
124
+ * Holds the collection of objects that the container was initially created with.
125
+ * Additionally provides the ability to dynamically create further objects during usage.
126
+ */
127
+ export interface IRootDataObject {
112
128
  /**
113
129
  * Dynamically creates a new detached collaborative object (DDS/DataObject).
114
130
  *
@@ -127,6 +143,11 @@ export interface IRootDataObject {
127
143
  * @remarks This method is used to expose uploadBlob to the IFluidContainer level. UploadBlob will upload data to server side (as of now, ODSP only). There is no downloadBlob provided as it is not needed(blob lifetime managed by server).
128
144
  */
129
145
  uploadBlob(blob: ArrayBufferLike): Promise<IFluidHandle<ArrayBufferLike>>;
146
+
147
+ /**
148
+ * Provides a record of the initial objects defined on creation.
149
+ */
150
+ readonly initialObjects: LoadableObjectRecord;
130
151
  }
131
152
 
132
153
  interface IProvideStaticEntryPoint {
package/src/utils.ts CHANGED
@@ -4,13 +4,27 @@
4
4
  */
5
5
 
6
6
  import type { DataObjectKind } from "@fluidframework/aqueduct/internal";
7
- import type { IFluidLoadable } from "@fluidframework/core-interfaces";
8
- import type { IChannelFactory } from "@fluidframework/datastore-definitions/internal";
9
- import type { NamedFluidDataStoreRegistryEntry } from "@fluidframework/runtime-definitions/internal";
7
+ import type { MinimumVersionForCollab } from "@fluidframework/container-runtime/internal";
8
+ import type { FluidObjectKeys, IFluidLoadable } from "@fluidframework/core-interfaces";
9
+ import { oob } from "@fluidframework/core-utils/internal";
10
+ import type {
11
+ IChannelFactory,
12
+ IFluidDataStoreRuntime,
13
+ } from "@fluidframework/datastore-definitions/internal";
14
+ import type {
15
+ IFluidDataStoreContext,
16
+ NamedFluidDataStoreRegistryEntry,
17
+ } from "@fluidframework/runtime-definitions/internal";
10
18
  import type { ISharedObjectKind } from "@fluidframework/shared-object-base/internal";
11
19
  import { UsageError } from "@fluidframework/telemetry-utils/internal";
20
+ import { SharedTreeFactoryType } from "@fluidframework/tree/internal";
12
21
 
13
- import type { ContainerSchema, LoadableObjectKind } from "./types.js";
22
+ import type {
23
+ CompatibilityMode,
24
+ ContainerSchema,
25
+ LoadableObjectKind,
26
+ TreeContainerSchema,
27
+ } from "./types.js";
14
28
 
15
29
  /**
16
30
  * Runtime check to determine if an object is a {@link DataObjectKind}.
@@ -94,3 +108,75 @@ export const parseDataObjectsFromSharedObjects = (
94
108
 
95
109
  return [[...registryEntries], [...sharedObjects]];
96
110
  };
111
+
112
+ /**
113
+ * Creates a new data object of the specified type.
114
+ */
115
+ export async function createDataObject<T extends IFluidLoadable>(
116
+ dataObjectClass: DataObjectKind<T>,
117
+ context: IFluidDataStoreContext,
118
+ ): Promise<T> {
119
+ const factory = dataObjectClass.factory;
120
+ const packagePath = [...context.packagePath, factory.type];
121
+ const dataStore = await context.containerRuntime.createDataStore(packagePath);
122
+ const entryPoint = await dataStore.entryPoint.get();
123
+ return entryPoint as T;
124
+ }
125
+
126
+ /**
127
+ * Creates a new shared object of the specified type.
128
+ */
129
+ export function createSharedObject<T extends IFluidLoadable>(
130
+ sharedObjectClass: ISharedObjectKind<T>,
131
+ runtime: IFluidDataStoreRuntime,
132
+ ): T {
133
+ const factory = sharedObjectClass.getFactory();
134
+ const obj = runtime.createChannel(undefined, factory.type);
135
+ return obj as unknown as T;
136
+ }
137
+
138
+ /**
139
+ * Creates a Fluid object that has a property with the key `providerKey` that points to itself.
140
+ * @remarks This is useful for creating objects that need to reference themselves, such as DataObjects.
141
+ */
142
+ export function makeFluidObject<
143
+ T extends object,
144
+ K extends FluidObjectKeys<T> = FluidObjectKeys<T>,
145
+ >(object: Omit<T, K>, providerKey: K): T {
146
+ return Object.defineProperty(object, providerKey, { value: object }) as T;
147
+ }
148
+
149
+ /**
150
+ * Maps CompatibilityMode to a semver valid string that can be passed to the container runtime.
151
+ */
152
+ export const compatibilityModeToMinVersionForCollab = {
153
+ "1": "1.0.0",
154
+ "2": "2.0.0",
155
+ } as const satisfies Record<CompatibilityMode, MinimumVersionForCollab>;
156
+
157
+ /**
158
+ * Determines if the provided schema is a valid tree-based container schema.
159
+ * @internal
160
+ */
161
+ export function isTreeContainerSchema(schema: ContainerSchema): schema is TreeContainerSchema {
162
+ const schemaEntries = Object.entries(schema.initialObjects);
163
+ if (schemaEntries.length !== 1) {
164
+ return false;
165
+ }
166
+
167
+ const entry = schemaEntries[0] ?? oob();
168
+ const key = entry[0];
169
+ if (key !== "tree") {
170
+ return false;
171
+ }
172
+
173
+ const objectKind = entry[1] as unknown as LoadableObjectKind;
174
+ if (
175
+ isSharedObjectKind(objectKind) &&
176
+ objectKind.getFactory().type === SharedTreeFactoryType
177
+ ) {
178
+ return true;
179
+ }
180
+
181
+ return false;
182
+ }