@fluidframework/odsp-client 2.0.0-dev-rc.5.0.0.270401

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 (65) hide show
  1. package/.eslintrc.cjs +23 -0
  2. package/.mocharc.cjs +12 -0
  3. package/CHANGELOG.md +81 -0
  4. package/LICENSE +21 -0
  5. package/README.md +109 -0
  6. package/api-extractor-lint.json +4 -0
  7. package/api-extractor.json +4 -0
  8. package/api-report/odsp-client.alpha.api.md +68 -0
  9. package/api-report/odsp-client.beta.api.md +68 -0
  10. package/api-report/odsp-client.public.api.md +17 -0
  11. package/beta.d.ts +11 -0
  12. package/dist/beta.d.ts +21 -0
  13. package/dist/index.d.ts +18 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +10 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/interfaces.d.ts +102 -0
  18. package/dist/interfaces.d.ts.map +1 -0
  19. package/dist/interfaces.js +7 -0
  20. package/dist/interfaces.js.map +1 -0
  21. package/dist/odspAudience.d.ts +8 -0
  22. package/dist/odspAudience.d.ts.map +1 -0
  23. package/dist/odspAudience.js +20 -0
  24. package/dist/odspAudience.js.map +1 -0
  25. package/dist/odspClient.d.ts +31 -0
  26. package/dist/odspClient.d.ts.map +1 -0
  27. package/dist/odspClient.js +165 -0
  28. package/dist/odspClient.js.map +1 -0
  29. package/dist/package.json +3 -0
  30. package/dist/token.d.ts +35 -0
  31. package/dist/token.d.ts.map +1 -0
  32. package/dist/token.js +7 -0
  33. package/dist/token.js.map +1 -0
  34. package/internal.d.ts +11 -0
  35. package/lib/beta.d.ts +21 -0
  36. package/lib/index.d.ts +18 -0
  37. package/lib/index.d.ts.map +1 -0
  38. package/lib/index.js +6 -0
  39. package/lib/index.js.map +1 -0
  40. package/lib/interfaces.d.ts +102 -0
  41. package/lib/interfaces.d.ts.map +1 -0
  42. package/lib/interfaces.js +6 -0
  43. package/lib/interfaces.js.map +1 -0
  44. package/lib/odspAudience.d.ts +8 -0
  45. package/lib/odspAudience.d.ts.map +1 -0
  46. package/lib/odspAudience.js +16 -0
  47. package/lib/odspAudience.js.map +1 -0
  48. package/lib/odspClient.d.ts +31 -0
  49. package/lib/odspClient.d.ts.map +1 -0
  50. package/lib/odspClient.js +161 -0
  51. package/lib/odspClient.js.map +1 -0
  52. package/lib/token.d.ts +35 -0
  53. package/lib/token.d.ts.map +1 -0
  54. package/lib/token.js +6 -0
  55. package/lib/token.js.map +1 -0
  56. package/lib/tsdoc-metadata.json +11 -0
  57. package/package.json +138 -0
  58. package/prettier.config.cjs +8 -0
  59. package/src/index.ts +25 -0
  60. package/src/interfaces.ts +114 -0
  61. package/src/odspAudience.ts +44 -0
  62. package/src/odspClient.ts +265 -0
  63. package/src/token.ts +37 -0
  64. package/tsconfig.cjs.json +7 -0
  65. package/tsconfig.json +11 -0
@@ -0,0 +1,265 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { AttachState } from "@fluidframework/container-definitions";
7
+ import {
8
+ IContainer,
9
+ IFluidModuleWithDetails,
10
+ } from "@fluidframework/container-definitions/internal";
11
+ import { Loader } from "@fluidframework/container-loader/internal";
12
+ import {
13
+ type FluidObject,
14
+ type IConfigProviderBase,
15
+ type IRequest,
16
+ } from "@fluidframework/core-interfaces";
17
+ import { assert } from "@fluidframework/core-utils/internal";
18
+ import { IClient } from "@fluidframework/driver-definitions";
19
+ import { IDocumentServiceFactory } from "@fluidframework/driver-definitions/internal";
20
+ import {
21
+ ContainerAttachProps,
22
+ type ContainerSchema,
23
+ IFluidContainer,
24
+ } from "@fluidframework/fluid-static";
25
+ import {
26
+ IRootDataObject,
27
+ createDOProviderContainerRuntimeFactory,
28
+ createFluidContainer,
29
+ createServiceAudience,
30
+ } from "@fluidframework/fluid-static/internal";
31
+ import {
32
+ OdspDocumentServiceFactory,
33
+ OdspDriverUrlResolver,
34
+ createOdspCreateContainerRequest,
35
+ createOdspUrl,
36
+ isOdspResolvedUrl,
37
+ } from "@fluidframework/odsp-driver/internal";
38
+ import type {
39
+ OdspResourceTokenFetchOptions,
40
+ TokenResponse,
41
+ } from "@fluidframework/odsp-driver-definitions/internal";
42
+ import { wrapConfigProviderWithDefaults } from "@fluidframework/telemetry-utils/internal";
43
+ import { v4 as uuid } from "uuid";
44
+
45
+ import {
46
+ OdspClientProps,
47
+ OdspConnectionConfig,
48
+ OdspContainerAttachProps,
49
+ OdspContainerServices,
50
+ } from "./interfaces.js";
51
+ import { createOdspAudienceMember } from "./odspAudience.js";
52
+ import { type IOdspTokenProvider } from "./token.js";
53
+
54
+ async function getStorageToken(
55
+ options: OdspResourceTokenFetchOptions,
56
+ tokenProvider: IOdspTokenProvider,
57
+ ): Promise<TokenResponse> {
58
+ const tokenResponse: TokenResponse = await tokenProvider.fetchStorageToken(
59
+ options.siteUrl,
60
+ options.refresh,
61
+ );
62
+ return tokenResponse;
63
+ }
64
+
65
+ async function getWebsocketToken(
66
+ options: OdspResourceTokenFetchOptions,
67
+ tokenProvider: IOdspTokenProvider,
68
+ ): Promise<TokenResponse> {
69
+ const tokenResponse: TokenResponse = await tokenProvider.fetchWebsocketToken(
70
+ options.siteUrl,
71
+ options.refresh,
72
+ );
73
+ return tokenResponse;
74
+ }
75
+
76
+ /**
77
+ * Default feature gates.
78
+ * These values will only be used if the feature gate is not already set by the supplied config provider.
79
+ */
80
+ const odspClientFeatureGates = {
81
+ // None yet
82
+ };
83
+
84
+ /**
85
+ * Feature gates required to support runtime compatibility when V1 and V2 clients are collaborating
86
+ */
87
+ const odspClientV1CompatFeatureGates = {
88
+ // Disable Garbage Collection
89
+ "Fluid.GarbageCollection.RunSweep": false, // To prevent the GC op
90
+ "Fluid.GarbageCollection.DisableAutoRecovery": true, // To prevent the GC op
91
+ "Fluid.GarbageCollection.ThrowOnTombstoneLoadOverride": false, // For a consistent story of "GC is disabled"
92
+ };
93
+
94
+ /**
95
+ * Wrap the config provider to fall back on the appropriate defaults for ODSP Client.
96
+ * @param baseConfigProvider - The base config provider to wrap
97
+ * @returns A new config provider with the appropriate defaults applied underneath the given provider
98
+ */
99
+ function wrapConfigProvider(baseConfigProvider?: IConfigProviderBase): IConfigProviderBase {
100
+ const defaults = {
101
+ ...odspClientFeatureGates,
102
+ ...odspClientV1CompatFeatureGates,
103
+ };
104
+ return wrapConfigProviderWithDefaults(baseConfigProvider, defaults);
105
+ }
106
+
107
+ /**
108
+ * OdspClient provides the ability to have a Fluid object backed by the ODSP service within the context of Microsoft 365 (M365) tenants.
109
+ * @sealed
110
+ * @beta
111
+ */
112
+ export class OdspClient {
113
+ private readonly documentServiceFactory: IDocumentServiceFactory;
114
+ private readonly urlResolver: OdspDriverUrlResolver;
115
+ private readonly configProvider: IConfigProviderBase | undefined;
116
+
117
+ public constructor(private readonly properties: OdspClientProps) {
118
+ this.documentServiceFactory = new OdspDocumentServiceFactory(
119
+ async (options) => getStorageToken(options, this.properties.connection.tokenProvider),
120
+ async (options) => getWebsocketToken(options, this.properties.connection.tokenProvider),
121
+ );
122
+
123
+ this.urlResolver = new OdspDriverUrlResolver();
124
+ this.configProvider = wrapConfigProvider(properties.configProvider);
125
+ }
126
+
127
+ public async createContainer<T extends ContainerSchema>(
128
+ containerSchema: T,
129
+ ): Promise<{
130
+ container: IFluidContainer<T>;
131
+ services: OdspContainerServices;
132
+ }> {
133
+ const loader = this.createLoader(containerSchema);
134
+
135
+ const container = await loader.createDetachedContainer({
136
+ package: "no-dynamic-package",
137
+ config: {},
138
+ });
139
+
140
+ const fluidContainer = await this.createFluidContainer(
141
+ container,
142
+ this.properties.connection,
143
+ );
144
+
145
+ const services = await this.getContainerServices(container);
146
+
147
+ return { container: fluidContainer as IFluidContainer<T>, services };
148
+ }
149
+
150
+ public async getContainer<T extends ContainerSchema>(
151
+ id: string,
152
+ containerSchema: T,
153
+ ): Promise<{
154
+ container: IFluidContainer<T>;
155
+ services: OdspContainerServices;
156
+ }> {
157
+ const loader = this.createLoader(containerSchema);
158
+ const url = createOdspUrl({
159
+ siteUrl: this.properties.connection.siteUrl,
160
+ driveId: this.properties.connection.driveId,
161
+ itemId: id,
162
+ dataStorePath: "",
163
+ });
164
+ const container = await loader.resolve({ url });
165
+
166
+ const fluidContainer = createFluidContainer({
167
+ container,
168
+ rootDataObject: await this.getContainerEntryPoint(container),
169
+ });
170
+ const services = await this.getContainerServices(container);
171
+ return { container: fluidContainer as IFluidContainer<T>, services };
172
+ }
173
+
174
+ private createLoader(schema: ContainerSchema): Loader {
175
+ const runtimeFactory = createDOProviderContainerRuntimeFactory({
176
+ schema,
177
+ compatibilityMode: "2",
178
+ });
179
+ const load = async (): Promise<IFluidModuleWithDetails> => {
180
+ return {
181
+ module: { fluidExport: runtimeFactory },
182
+ details: { package: "no-dynamic-package", config: {} },
183
+ };
184
+ };
185
+
186
+ const codeLoader = { load };
187
+ const client: IClient = {
188
+ details: {
189
+ capabilities: { interactive: true },
190
+ },
191
+ permission: [],
192
+ scopes: [],
193
+ user: { id: "" },
194
+ mode: "write",
195
+ };
196
+
197
+ return new Loader({
198
+ urlResolver: this.urlResolver,
199
+ documentServiceFactory: this.documentServiceFactory,
200
+ codeLoader,
201
+ logger: this.properties.logger,
202
+ options: { client },
203
+ configProvider: this.configProvider,
204
+ });
205
+ }
206
+
207
+ private async createFluidContainer(
208
+ container: IContainer,
209
+ connection: OdspConnectionConfig,
210
+ ): Promise<IFluidContainer> {
211
+ const rootDataObject = await this.getContainerEntryPoint(container);
212
+
213
+ /**
214
+ * See {@link FluidContainer.attach}
215
+ */
216
+ const attach = async (
217
+ odspProps?: ContainerAttachProps<OdspContainerAttachProps>,
218
+ ): Promise<string> => {
219
+ const createNewRequest: IRequest = createOdspCreateContainerRequest(
220
+ connection.siteUrl,
221
+ connection.driveId,
222
+ odspProps?.filePath ?? "",
223
+ odspProps?.fileName ?? uuid(),
224
+ );
225
+ if (container.attachState !== AttachState.Detached) {
226
+ throw new Error("Cannot attach container. Container is not in detached state");
227
+ }
228
+ await container.attach(createNewRequest);
229
+
230
+ const resolvedUrl = container.resolvedUrl;
231
+
232
+ if (resolvedUrl === undefined || !isOdspResolvedUrl(resolvedUrl)) {
233
+ throw new Error("Resolved Url not available on attached container");
234
+ }
235
+
236
+ /**
237
+ * A unique identifier for the file within the provided SharePoint Embedded container ID. When you attach a container,
238
+ * a new `itemId` is created in the user's drive, which developers can use for various operations
239
+ * like updating, renaming, moving the Fluid file, changing permissions, and more. `itemId` is used to load the container.
240
+ */
241
+ return resolvedUrl.itemId;
242
+ };
243
+ const fluidContainer = createFluidContainer({ container, rootDataObject });
244
+ fluidContainer.attach = attach;
245
+ return fluidContainer;
246
+ }
247
+
248
+ private async getContainerServices(container: IContainer): Promise<OdspContainerServices> {
249
+ return {
250
+ audience: createServiceAudience({
251
+ container,
252
+ createServiceMember: createOdspAudienceMember,
253
+ }),
254
+ };
255
+ }
256
+
257
+ private async getContainerEntryPoint(container: IContainer): Promise<IRootDataObject> {
258
+ const rootDataObject: FluidObject<IRootDataObject> = await container.getEntryPoint();
259
+ assert(
260
+ rootDataObject.IRootDataObject !== undefined,
261
+ 0x878 /* entryPoint must be of type IRootDataObject */,
262
+ );
263
+ return rootDataObject.IRootDataObject;
264
+ }
265
+ }
package/src/token.ts ADDED
@@ -0,0 +1,37 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { TokenResponse } from "@fluidframework/odsp-driver-definitions/internal";
7
+
8
+ /**
9
+ * Abstracts the token fetching mechanism for a hosting application.
10
+ * The hosting application is responsible for providing an implementation.
11
+ * @beta
12
+ */
13
+ export interface IOdspTokenProvider {
14
+ /**
15
+ * Fetches the orderer token from host.
16
+ *
17
+ * @param siteUrl - Site url representing ODSP resource location. It points to the specific SharePoint site where you can store and access the containers you create.
18
+ * @param refresh - Optional flag indicating whether token fetch must bypass local cache.
19
+ * This likely indicates that some previous request failed authorization due to an expired token,
20
+ * and so a fresh token is required.
21
+ *
22
+ * Default: `false`.
23
+ */
24
+ fetchWebsocketToken(siteUrl: string, refresh: boolean): Promise<TokenResponse>;
25
+
26
+ /**
27
+ * Fetches the storage token from host.
28
+ *
29
+ * @param siteUrl - Site url representing ODSP resource location. It points to the specific SharePoint site where you can store and access the containers you create.
30
+ * @param refresh - Optional flag indicating whether token fetch must bypass local cache.
31
+ * This likely indicates that some previous request failed authorization due to an expired token,
32
+ * and so a fresh token is required.
33
+ *
34
+ * Default: `false`.
35
+ */
36
+ fetchStorageToken(siteUrl: string, refresh: boolean): Promise<TokenResponse>;
37
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ // This config must be used in a "type": "commonjs" environment. (Use fluid-tsc commonjs.)
3
+ "extends": "./tsconfig.json",
4
+ "compilerOptions": {
5
+ "outDir": "./dist",
6
+ },
7
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../../../common/build/build-common/tsconfig.node16.json",
3
+ "include": ["src/**/*"],
4
+ "exclude": ["src/test/**/*"],
5
+ "compilerOptions": {
6
+ "rootDir": "./src",
7
+ "outDir": "./lib",
8
+ "noImplicitOverride": true,
9
+ "exactOptionalPropertyTypes": false,
10
+ },
11
+ }