@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.
- package/.eslintrc.cjs +23 -0
- package/.mocharc.cjs +12 -0
- package/CHANGELOG.md +81 -0
- package/LICENSE +21 -0
- package/README.md +109 -0
- package/api-extractor-lint.json +4 -0
- package/api-extractor.json +4 -0
- package/api-report/odsp-client.alpha.api.md +68 -0
- package/api-report/odsp-client.beta.api.md +68 -0
- package/api-report/odsp-client.public.api.md +17 -0
- package/beta.d.ts +11 -0
- package/dist/beta.d.ts +21 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.d.ts +102 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +7 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/odspAudience.d.ts +8 -0
- package/dist/odspAudience.d.ts.map +1 -0
- package/dist/odspAudience.js +20 -0
- package/dist/odspAudience.js.map +1 -0
- package/dist/odspClient.d.ts +31 -0
- package/dist/odspClient.d.ts.map +1 -0
- package/dist/odspClient.js +165 -0
- package/dist/odspClient.js.map +1 -0
- package/dist/package.json +3 -0
- package/dist/token.d.ts +35 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +7 -0
- package/dist/token.js.map +1 -0
- package/internal.d.ts +11 -0
- package/lib/beta.d.ts +21 -0
- package/lib/index.d.ts +18 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +6 -0
- package/lib/index.js.map +1 -0
- package/lib/interfaces.d.ts +102 -0
- package/lib/interfaces.d.ts.map +1 -0
- package/lib/interfaces.js +6 -0
- package/lib/interfaces.js.map +1 -0
- package/lib/odspAudience.d.ts +8 -0
- package/lib/odspAudience.d.ts.map +1 -0
- package/lib/odspAudience.js +16 -0
- package/lib/odspAudience.js.map +1 -0
- package/lib/odspClient.d.ts +31 -0
- package/lib/odspClient.d.ts.map +1 -0
- package/lib/odspClient.js +161 -0
- package/lib/odspClient.js.map +1 -0
- package/lib/token.d.ts +35 -0
- package/lib/token.d.ts.map +1 -0
- package/lib/token.js +6 -0
- package/lib/token.js.map +1 -0
- package/lib/tsdoc-metadata.json +11 -0
- package/package.json +138 -0
- package/prettier.config.cjs +8 -0
- package/src/index.ts +25 -0
- package/src/interfaces.ts +114 -0
- package/src/odspAudience.ts +44 -0
- package/src/odspClient.ts +265 -0
- package/src/token.ts +37 -0
- package/tsconfig.cjs.json +7 -0
- 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
|
+
}
|
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
|
+
}
|