@fluidframework/odsp-driver 2.13.0 → 2.20.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 +4 -0
- package/dist/WriteBufferUtils.js.map +1 -1
- package/dist/compactSnapshotParser.js +5 -5
- package/dist/compactSnapshotParser.js.map +1 -1
- package/dist/fetchSnapshot.d.ts.map +1 -1
- package/dist/fetchSnapshot.js +8 -3
- package/dist/fetchSnapshot.js.map +1 -1
- package/dist/getFileLink.js +3 -3
- package/dist/getFileLink.js.map +1 -1
- package/dist/odspDelayLoadedDeltaStream.d.ts +2 -1
- package/dist/odspDelayLoadedDeltaStream.d.ts.map +1 -1
- package/dist/odspDelayLoadedDeltaStream.js +10 -9
- package/dist/odspDelayLoadedDeltaStream.js.map +1 -1
- package/dist/odspDocumentStorageServiceBase.d.ts.map +1 -1
- package/dist/odspDocumentStorageServiceBase.js.map +1 -1
- package/dist/odspDriverUrlResolver.js +1 -1
- package/dist/odspDriverUrlResolver.js.map +1 -1
- package/dist/package.json +2 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/vroom.d.ts +4 -3
- package/dist/vroom.d.ts.map +1 -1
- package/dist/vroom.js +12 -7
- package/dist/vroom.js.map +1 -1
- package/lib/WriteBufferUtils.js.map +1 -1
- package/lib/compactSnapshotParser.js +5 -5
- package/lib/compactSnapshotParser.js.map +1 -1
- package/lib/fetchSnapshot.d.ts.map +1 -1
- package/lib/fetchSnapshot.js +8 -3
- package/lib/fetchSnapshot.js.map +1 -1
- package/lib/getFileLink.js +3 -3
- package/lib/getFileLink.js.map +1 -1
- package/lib/odspDelayLoadedDeltaStream.d.ts +2 -1
- package/lib/odspDelayLoadedDeltaStream.d.ts.map +1 -1
- package/lib/odspDelayLoadedDeltaStream.js +10 -9
- package/lib/odspDelayLoadedDeltaStream.js.map +1 -1
- package/lib/odspDocumentStorageServiceBase.d.ts.map +1 -1
- package/lib/odspDocumentStorageServiceBase.js.map +1 -1
- package/lib/odspDriverUrlResolver.js +1 -1
- package/lib/odspDriverUrlResolver.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/vroom.d.ts +4 -3
- package/lib/vroom.d.ts.map +1 -1
- package/lib/vroom.js +12 -7
- package/lib/vroom.js.map +1 -1
- package/package.json +12 -12
- package/src/WriteBufferUtils.ts +2 -2
- package/src/compactSnapshotParser.ts +5 -5
- package/src/fetchSnapshot.ts +7 -8
- package/src/getFileLink.ts +2 -3
- package/src/odspDelayLoadedDeltaStream.ts +11 -2
- package/src/odspDocumentStorageServiceBase.ts +2 -3
- package/src/odspDriverUrlResolver.ts +1 -1
- package/src/packageVersion.ts +1 -1
- package/src/vroom.ts +14 -8
package/src/fetchSnapshot.ts
CHANGED
|
@@ -150,13 +150,8 @@ export async function fetchSnapshotWithRedeem(
|
|
|
150
150
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
151
151
|
if (enableRedeemFallback && isRedeemSharingLinkError(odspResolvedUrl, error)) {
|
|
152
152
|
// Execute the redeem fallback
|
|
153
|
+
await redeemSharingLink(odspResolvedUrl, storageTokenFetcher, logger);
|
|
153
154
|
|
|
154
|
-
await redeemSharingLink(
|
|
155
|
-
odspResolvedUrl,
|
|
156
|
-
storageTokenFetcher,
|
|
157
|
-
logger,
|
|
158
|
-
forceAccessTokenViaAuthorizationHeader,
|
|
159
|
-
);
|
|
160
155
|
const odspResolvedUrlWithoutShareLink: IOdspResolvedUrl = {
|
|
161
156
|
...odspResolvedUrl,
|
|
162
157
|
shareLinkInfo: {
|
|
@@ -213,7 +208,6 @@ async function redeemSharingLink(
|
|
|
213
208
|
odspResolvedUrl: IOdspResolvedUrl,
|
|
214
209
|
getAuthHeader: InstrumentedStorageTokenFetcher,
|
|
215
210
|
logger: ITelemetryLoggerExt,
|
|
216
|
-
forceAccessTokenViaAuthorizationHeader: boolean,
|
|
217
211
|
): Promise<void> {
|
|
218
212
|
await PerformanceEvent.timedExecAsync(
|
|
219
213
|
logger,
|
|
@@ -233,7 +227,12 @@ async function redeemSharingLink(
|
|
|
233
227
|
let redeemUrl: string | undefined;
|
|
234
228
|
async function callSharesAPI(baseUrl: string): Promise<void> {
|
|
235
229
|
await getWithRetryForTokenRefresh(async (tokenFetchOptions) => {
|
|
236
|
-
redeemUrl
|
|
230
|
+
// IMPORTANT: Note that redeemUrl has '/driveItem' in it. Technically it is not required for executing redeem operation.
|
|
231
|
+
// However, we have other cases that use '/shares' API and do require to specify '/driveItem' in order to get specific
|
|
232
|
+
// drive item properties. The reason this matters is when caller of this API must possess logical permissions to call
|
|
233
|
+
// this API (for instance, this will be the case when call is made with app-only token) then two separate logical
|
|
234
|
+
// permissions are needed for the '/shares' call with and without '/driveItem'.
|
|
235
|
+
redeemUrl = `${baseUrl}/_api/v2.0/shares/${encodedShareUrl}/driveItem`;
|
|
237
236
|
const url = redeemUrl;
|
|
238
237
|
const method = "GET";
|
|
239
238
|
const authHeader = await getAuthHeader(
|
package/src/getFileLink.ts
CHANGED
|
@@ -102,7 +102,7 @@ export async function getFileLink(
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
|
-
* Handles location redirection while fulfilling the
|
|
105
|
+
* Handles location redirection while fulfilling the getFileLink call. We don't want browser to handle
|
|
106
106
|
* the redirection as the browser will retry with same auth token which will not work as we need app
|
|
107
107
|
* to regenerate tokens for the new site domain. So when we will make the network calls below we will set
|
|
108
108
|
* the redirect:manual header to manually handle these redirects.
|
|
@@ -125,7 +125,7 @@ async function getFileLinkWithLocationRedirectionHandling(
|
|
|
125
125
|
let locationRedirected = false;
|
|
126
126
|
for (let count = 1; count <= 5; count++) {
|
|
127
127
|
try {
|
|
128
|
-
const fileItem = await getFileItemLite(getToken, resolvedUrl, logger
|
|
128
|
+
const fileItem = await getFileItemLite(getToken, resolvedUrl, logger);
|
|
129
129
|
// Sometimes the siteUrl in the actual file is different from the siteUrl in the resolvedUrl due to location
|
|
130
130
|
// redirection. This creates issues in the getSharingInformation call. So we need to update the siteUrl in the
|
|
131
131
|
// resolvedUrl to the siteUrl in the fileItem which is the updated siteUrl.
|
|
@@ -260,7 +260,6 @@ async function getFileItemLite(
|
|
|
260
260
|
getToken: TokenFetcher<OdspResourceTokenFetchOptions>,
|
|
261
261
|
odspUrlParts: IOdspUrlParts,
|
|
262
262
|
logger: ITelemetryLoggerExt,
|
|
263
|
-
forceAccessTokenViaAuthorizationHeader: boolean,
|
|
264
263
|
): Promise<FileItemLite> {
|
|
265
264
|
return PerformanceEvent.timedExecAsync(
|
|
266
265
|
logger,
|
|
@@ -91,7 +91,7 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
91
91
|
| undefined,
|
|
92
92
|
private readonly mc: MonitoringContext,
|
|
93
93
|
private readonly cache: IOdspCache,
|
|
94
|
-
|
|
94
|
+
private readonly hostPolicy: HostStoragePolicy,
|
|
95
95
|
private readonly epochTracker: EpochTracker,
|
|
96
96
|
private readonly opsReceived: (ops: ISequencedDocumentMessage[]) => void,
|
|
97
97
|
private readonly metadataUpdateHandler: (metadata: Record<string, string>) => void,
|
|
@@ -156,6 +156,8 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
156
156
|
requestWebsocketTokenFromJoinSession,
|
|
157
157
|
options,
|
|
158
158
|
false /* isRefreshingJoinSession */,
|
|
159
|
+
undefined /* clientId */,
|
|
160
|
+
this.hostPolicy.sessionOptions?.displayName,
|
|
159
161
|
);
|
|
160
162
|
const [websocketEndpoint, websocketToken] = await Promise.all([
|
|
161
163
|
joinSessionPromise.catch(annotateAndRethrowConnectionError("joinSession")),
|
|
@@ -273,6 +275,7 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
273
275
|
delta: number,
|
|
274
276
|
requestSocketToken: boolean,
|
|
275
277
|
clientId: string | undefined,
|
|
278
|
+
displayName: string | undefined,
|
|
276
279
|
): Promise<void> {
|
|
277
280
|
if (this.joinSessionRefreshTimer !== undefined) {
|
|
278
281
|
this.clearJoinSessionTimer();
|
|
@@ -301,6 +304,7 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
301
304
|
options,
|
|
302
305
|
true /* isRefreshingJoinSession */,
|
|
303
306
|
clientId,
|
|
307
|
+
displayName,
|
|
304
308
|
);
|
|
305
309
|
resolve();
|
|
306
310
|
}).catch((error) => {
|
|
@@ -314,7 +318,8 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
314
318
|
requestSocketToken: boolean,
|
|
315
319
|
options: TokenFetchOptionsEx,
|
|
316
320
|
isRefreshingJoinSession: boolean,
|
|
317
|
-
clientId
|
|
321
|
+
clientId: string | undefined,
|
|
322
|
+
displayName: string | undefined,
|
|
318
323
|
): Promise<ISocketStorageDiscovery> {
|
|
319
324
|
// If this call is to refresh the join session for the current connection but we are already disconnected in
|
|
320
325
|
// the meantime or disconnected and then reconnected then do not make the call. However, we should not have
|
|
@@ -342,6 +347,7 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
342
347
|
requestSocketToken,
|
|
343
348
|
options,
|
|
344
349
|
isRefreshingJoinSession,
|
|
350
|
+
displayName,
|
|
345
351
|
).catch((error) => {
|
|
346
352
|
if (hasFacetCodes(error) && error.facetCodes !== undefined) {
|
|
347
353
|
for (const code of error.facetCodes) {
|
|
@@ -378,6 +384,7 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
378
384
|
requestSocketToken: boolean,
|
|
379
385
|
options: TokenFetchOptionsEx,
|
|
380
386
|
isRefreshingJoinSession: boolean,
|
|
387
|
+
displayName: string | undefined,
|
|
381
388
|
): Promise<ISocketStorageDiscovery> {
|
|
382
389
|
const disableJoinSessionRefresh = this.mc.config.getBoolean(
|
|
383
390
|
"Fluid.Driver.Odsp.disableJoinSessionRefresh",
|
|
@@ -397,6 +404,7 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
397
404
|
options,
|
|
398
405
|
disableJoinSessionRefresh,
|
|
399
406
|
isRefreshingJoinSession,
|
|
407
|
+
displayName,
|
|
400
408
|
);
|
|
401
409
|
// Emit event only in case it is fetched from the network.
|
|
402
410
|
if (joinSessionResponse.sensitivityLabelsInfo !== undefined) {
|
|
@@ -450,6 +458,7 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
450
458
|
response.refreshAfterDeltaMs,
|
|
451
459
|
requestSocketToken,
|
|
452
460
|
this.currentConnection?.clientId,
|
|
461
|
+
displayName,
|
|
453
462
|
).catch((error) => {
|
|
454
463
|
// Log the error and do nothing as the reconnection would fetch the join session.
|
|
455
464
|
this.mc.logger.sendTelemetryEvent(
|
|
@@ -257,9 +257,8 @@ export abstract class OdspDocumentStorageServiceBase implements IDocumentStorage
|
|
|
257
257
|
protected combineProtocolAndAppSnapshotTree(snapshotTree: ISnapshotTree): ISnapshotTree {
|
|
258
258
|
// When we upload the container snapshot, we upload appTree in ".app" and protocol tree in ".protocol"
|
|
259
259
|
// So when we request the snapshot we get ".app" as tree and not as commit node as in the case just above.
|
|
260
|
-
const hierarchicalAppTree
|
|
261
|
-
const hierarchicalProtocolTree
|
|
262
|
-
snapshotTree.trees[".protocol"];
|
|
260
|
+
const hierarchicalAppTree = snapshotTree.trees[".app"];
|
|
261
|
+
const hierarchicalProtocolTree = snapshotTree.trees[".protocol"];
|
|
263
262
|
const summarySnapshotTree: ISnapshotTree = {
|
|
264
263
|
blobs: {
|
|
265
264
|
...hierarchicalAppTree.blobs,
|
|
@@ -108,7 +108,7 @@ export class OdspDriverUrlResolver implements IUrlResolver {
|
|
|
108
108
|
|
|
109
109
|
const searchParams = new URLSearchParams(queryString);
|
|
110
110
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
111
|
-
const fileName: string = request.headers[DriverHeader.createNew]
|
|
111
|
+
const fileName: string = request.headers[DriverHeader.createNew].fileName;
|
|
112
112
|
const driveID = searchParams.get("driveId");
|
|
113
113
|
const filePath = searchParams.get("path");
|
|
114
114
|
const packageName = searchParams.get("containerPackageName");
|
package/src/packageVersion.ts
CHANGED
package/src/vroom.ts
CHANGED
|
@@ -21,8 +21,8 @@ import { TokenFetchOptionsEx } from "./odspUtils.js";
|
|
|
21
21
|
import { runWithRetry } from "./retryUtils.js";
|
|
22
22
|
|
|
23
23
|
interface IJoinSessionBody {
|
|
24
|
-
requestSocketToken
|
|
25
|
-
|
|
24
|
+
requestSocketToken?: boolean;
|
|
25
|
+
displayName?: string;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
@@ -38,8 +38,9 @@ interface IJoinSessionBody {
|
|
|
38
38
|
* @param options - Options to fetch the token.
|
|
39
39
|
* @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.
|
|
40
40
|
* @param isRefreshingJoinSession - whether call is to refresh the session before expiry.
|
|
41
|
-
* @param
|
|
42
|
-
* This is optional and used only when collab session is being joined
|
|
41
|
+
* @param displayName - display name used to identify client joining a session.
|
|
42
|
+
* This is optional and used only when collab session is being joined by client acting in app-only mode (i.e. without user context).
|
|
43
|
+
* If not specified client display name is extracted from the access token that is used to join session.
|
|
43
44
|
*/
|
|
44
45
|
export async function fetchJoinSession(
|
|
45
46
|
urlParts: IOdspUrlParts,
|
|
@@ -52,6 +53,7 @@ export async function fetchJoinSession(
|
|
|
52
53
|
options: TokenFetchOptionsEx,
|
|
53
54
|
disableJoinSessionRefresh: boolean | undefined,
|
|
54
55
|
isRefreshingJoinSession: boolean,
|
|
56
|
+
displayName: string | undefined,
|
|
55
57
|
): Promise<ISocketStorageDiscovery> {
|
|
56
58
|
const apiRoot = getApiRoot(new URL(urlParts.siteUrl));
|
|
57
59
|
const url = `${apiRoot}/drives/${urlParts.driveId}/items/${urlParts.itemId}/${path}?ump=1`;
|
|
@@ -89,11 +91,15 @@ export async function fetchJoinSession(
|
|
|
89
91
|
}
|
|
90
92
|
postBody += `_post: 1\r\n`;
|
|
91
93
|
|
|
94
|
+
let requestBody: IJoinSessionBody | undefined;
|
|
92
95
|
if (requestSocketToken) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
requestBody = { ...requestBody, requestSocketToken: true };
|
|
97
|
+
}
|
|
98
|
+
if (displayName) {
|
|
99
|
+
requestBody = { ...requestBody, displayName };
|
|
100
|
+
}
|
|
101
|
+
if (requestBody) {
|
|
102
|
+
postBody += `\r\n${JSON.stringify(requestBody)}\r\n`;
|
|
97
103
|
}
|
|
98
104
|
postBody += `\r\n--${formBoundary}--`;
|
|
99
105
|
const headers: { [index: string]: string } = {
|