@fluidframework/odsp-driver 0.51.3 → 0.53.0-46105
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/dist/contractsPublic.d.ts +0 -4
- package/dist/contractsPublic.d.ts.map +1 -1
- package/dist/contractsPublic.js.map +1 -1
- package/dist/createFile.d.ts.map +1 -1
- package/dist/createFile.js +11 -9
- package/dist/createFile.js.map +1 -1
- package/dist/createNewUtils.js +5 -4
- package/dist/createNewUtils.js.map +1 -1
- package/dist/epochTracker.d.ts +2 -1
- package/dist/epochTracker.d.ts.map +1 -1
- package/dist/epochTracker.js +51 -25
- package/dist/epochTracker.js.map +1 -1
- package/dist/fetchSnapshot.d.ts.map +1 -1
- package/dist/fetchSnapshot.js +1 -1
- package/dist/fetchSnapshot.js.map +1 -1
- package/dist/getFileLink.d.ts +1 -1
- package/dist/getFileLink.d.ts.map +1 -1
- package/dist/getFileLink.js +32 -22
- package/dist/getFileLink.js.map +1 -1
- package/dist/odspDeltaStorageService.d.ts +3 -3
- package/dist/odspDeltaStorageService.d.ts.map +1 -1
- package/dist/odspDeltaStorageService.js +7 -4
- package/dist/odspDeltaStorageService.js.map +1 -1
- package/dist/odspDocumentDeltaConnection.d.ts.map +1 -1
- package/dist/odspDocumentDeltaConnection.js +2 -0
- package/dist/odspDocumentDeltaConnection.js.map +1 -1
- package/dist/odspDocumentService.d.ts.map +1 -1
- package/dist/odspDocumentService.js +3 -3
- package/dist/odspDocumentService.js.map +1 -1
- package/dist/odspDocumentStorageManager.d.ts.map +1 -1
- package/dist/odspDocumentStorageManager.js +30 -34
- package/dist/odspDocumentStorageManager.js.map +1 -1
- package/dist/odspDriverUrlResolver.d.ts +0 -4
- package/dist/odspDriverUrlResolver.d.ts.map +1 -1
- package/dist/odspDriverUrlResolver.js +0 -7
- package/dist/odspDriverUrlResolver.js.map +1 -1
- package/dist/odspDriverUrlResolverForShareLink.d.ts +2 -6
- package/dist/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
- package/dist/odspDriverUrlResolverForShareLink.js +4 -15
- package/dist/odspDriverUrlResolverForShareLink.js.map +1 -1
- package/dist/odspError.d.ts.map +1 -1
- package/dist/odspError.js +3 -1
- package/dist/odspError.js.map +1 -1
- package/dist/odspSummaryUploadManager.js +24 -4
- package/dist/odspSummaryUploadManager.js.map +1 -1
- package/dist/odspUtils.d.ts.map +1 -1
- package/dist/odspUtils.js +31 -23
- package/dist/odspUtils.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/zipItDataRepresentationUtils.d.ts.map +1 -1
- package/dist/zipItDataRepresentationUtils.js +3 -4
- package/dist/zipItDataRepresentationUtils.js.map +1 -1
- package/lib/contractsPublic.d.ts +0 -4
- package/lib/contractsPublic.d.ts.map +1 -1
- package/lib/contractsPublic.js.map +1 -1
- package/lib/createFile.d.ts.map +1 -1
- package/lib/createFile.js +12 -10
- package/lib/createFile.js.map +1 -1
- package/lib/createNewUtils.js +5 -4
- package/lib/createNewUtils.js.map +1 -1
- package/lib/epochTracker.d.ts +2 -1
- package/lib/epochTracker.d.ts.map +1 -1
- package/lib/epochTracker.js +52 -26
- package/lib/epochTracker.js.map +1 -1
- package/lib/fetchSnapshot.d.ts.map +1 -1
- package/lib/fetchSnapshot.js +1 -1
- package/lib/fetchSnapshot.js.map +1 -1
- package/lib/getFileLink.d.ts +1 -1
- package/lib/getFileLink.d.ts.map +1 -1
- package/lib/getFileLink.js +34 -24
- package/lib/getFileLink.js.map +1 -1
- package/lib/odspDeltaStorageService.d.ts +3 -3
- package/lib/odspDeltaStorageService.d.ts.map +1 -1
- package/lib/odspDeltaStorageService.js +7 -4
- package/lib/odspDeltaStorageService.js.map +1 -1
- package/lib/odspDocumentDeltaConnection.d.ts.map +1 -1
- package/lib/odspDocumentDeltaConnection.js +2 -0
- package/lib/odspDocumentDeltaConnection.js.map +1 -1
- package/lib/odspDocumentService.d.ts.map +1 -1
- package/lib/odspDocumentService.js +4 -4
- package/lib/odspDocumentService.js.map +1 -1
- package/lib/odspDocumentStorageManager.d.ts.map +1 -1
- package/lib/odspDocumentStorageManager.js +33 -37
- package/lib/odspDocumentStorageManager.js.map +1 -1
- package/lib/odspDriverUrlResolver.d.ts +0 -4
- package/lib/odspDriverUrlResolver.d.ts.map +1 -1
- package/lib/odspDriverUrlResolver.js +0 -7
- package/lib/odspDriverUrlResolver.js.map +1 -1
- package/lib/odspDriverUrlResolverForShareLink.d.ts +2 -6
- package/lib/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
- package/lib/odspDriverUrlResolverForShareLink.js +5 -16
- package/lib/odspDriverUrlResolverForShareLink.js.map +1 -1
- package/lib/odspError.d.ts.map +1 -1
- package/lib/odspError.js +3 -1
- package/lib/odspError.js.map +1 -1
- package/lib/odspSummaryUploadManager.js +5 -4
- package/lib/odspSummaryUploadManager.js.map +1 -1
- package/lib/odspUtils.d.ts.map +1 -1
- package/lib/odspUtils.js +33 -25
- package/lib/odspUtils.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/zipItDataRepresentationUtils.d.ts.map +1 -1
- package/lib/zipItDataRepresentationUtils.js +3 -4
- package/lib/zipItDataRepresentationUtils.js.map +1 -1
- package/package.json +12 -12
- package/src/contractsPublic.ts +0 -5
- package/src/createFile.ts +13 -9
- package/src/epochTracker.ts +52 -25
- package/src/fetchSnapshot.ts +2 -1
- package/src/getFileLink.ts +47 -27
- package/src/odspDeltaStorageService.ts +10 -3
- package/src/odspDocumentDeltaConnection.ts +2 -0
- package/src/odspDocumentService.ts +8 -4
- package/src/odspDocumentStorageManager.ts +49 -38
- package/src/odspDriverUrlResolver.ts +0 -13
- package/src/odspDriverUrlResolverForShareLink.ts +10 -23
- package/src/odspError.ts +5 -1
- package/src/odspUtils.ts +43 -35
- package/src/packageVersion.ts +1 -1
- package/src/zipItDataRepresentationUtils.ts +4 -8
|
@@ -7,8 +7,6 @@ import { default as AbortController } from "abort-controller";
|
|
|
7
7
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
8
8
|
import {
|
|
9
9
|
assert,
|
|
10
|
-
stringToBuffer,
|
|
11
|
-
bufferToString,
|
|
12
10
|
delay,
|
|
13
11
|
} from "@fluidframework/common-utils";
|
|
14
12
|
import {
|
|
@@ -19,9 +17,9 @@ import {
|
|
|
19
17
|
ISummaryContext,
|
|
20
18
|
IDocumentStorageService,
|
|
21
19
|
LoaderCachingPolicy,
|
|
20
|
+
DriverErrorType,
|
|
22
21
|
} from "@fluidframework/driver-definitions";
|
|
23
|
-
import { RateLimiter } from "@fluidframework/driver-utils";
|
|
24
|
-
import { throwOdspNetworkError } from "@fluidframework/odsp-doclib-utils";
|
|
22
|
+
import { RateLimiter, NonRetryableError } from "@fluidframework/driver-utils";
|
|
25
23
|
import {
|
|
26
24
|
IOdspResolvedUrl,
|
|
27
25
|
ISnapshotOptions,
|
|
@@ -315,17 +313,7 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
|
|
|
315
313
|
this.blobCache.setBlob(blobId, blob);
|
|
316
314
|
}
|
|
317
315
|
|
|
318
|
-
|
|
319
|
-
return blob;
|
|
320
|
-
}
|
|
321
|
-
// ODSP document ids are random guids (different per session)
|
|
322
|
-
// fix the branch name in attributes
|
|
323
|
-
// this prevents issues when generating summaries
|
|
324
|
-
const documentAttributes: api.IDocumentAttributes = JSON.parse(bufferToString(blob, "utf8"));
|
|
325
|
-
documentAttributes.branch = this.documentId;
|
|
326
|
-
const content = JSON.stringify(documentAttributes);
|
|
327
|
-
const patchedBlob = stringToBuffer(content, "utf8");
|
|
328
|
-
return patchedBlob;
|
|
316
|
+
return blob;
|
|
329
317
|
}
|
|
330
318
|
|
|
331
319
|
public async readBlob(blobId: string): Promise<ArrayBufferLike> {
|
|
@@ -415,22 +403,31 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
|
|
|
415
403
|
{ eventName: "ObtainSnapshot" },
|
|
416
404
|
async (event: PerformanceEvent) => {
|
|
417
405
|
const props = {};
|
|
418
|
-
let
|
|
406
|
+
let retrievedSnapshot: ISnapshotContents | undefined;
|
|
407
|
+
// Here's the logic to grab the persistent cache snapshot implemented by the host
|
|
408
|
+
// Epoch tracker is responsible for communicating with the persistent cache, handling epochs and cache versions
|
|
419
409
|
const cachedSnapshotP: Promise<ISnapshotContents | undefined> =
|
|
420
410
|
this.epochTracker.get(createCacheSnapshotKey(this.odspResolvedUrl))
|
|
421
|
-
.then((snapshotCachedEntry: ISnapshotCachedEntry) => {
|
|
411
|
+
.then(async (snapshotCachedEntry: ISnapshotCachedEntry) => {
|
|
422
412
|
if (snapshotCachedEntry !== undefined) {
|
|
423
413
|
// If the cached entry does not contain the entry time, then assign it a default of 30 days old.
|
|
424
|
-
|
|
425
|
-
props["cacheEntryAge"] = Date.now() - (snapshotCachedEntry.cacheEntryTime ??
|
|
414
|
+
const age = Date.now() - (snapshotCachedEntry.cacheEntryTime ??
|
|
426
415
|
(Date.now() - 30 * 24 * 60 * 60 * 1000));
|
|
416
|
+
|
|
417
|
+
// Record the cache age
|
|
418
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
419
|
+
props["cacheEntryAge"] = age;
|
|
427
420
|
}
|
|
421
|
+
|
|
428
422
|
return snapshotCachedEntry;
|
|
429
423
|
});
|
|
430
424
|
|
|
425
|
+
// Based on the concurrentSnapshotFetch policy:
|
|
426
|
+
// Either retrieve both the network and cache snapshots concurrently and pick the first to return,
|
|
427
|
+
// or grab the cache value and then the network value if the cache value returns undefined.
|
|
431
428
|
let method: string;
|
|
432
429
|
if (this.hostPolicy.concurrentSnapshotFetch && !this.hostPolicy.summarizerClient) {
|
|
433
|
-
const
|
|
430
|
+
const networkSnapshotP = this.fetchSnapshot(hostSnapshotOptions);
|
|
434
431
|
|
|
435
432
|
// Ensure that failures on both paths are ignored initially.
|
|
436
433
|
// I.e. if cache fails for some reason, we will proceed with network result.
|
|
@@ -438,20 +435,20 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
|
|
|
438
435
|
// do want to attempt to succeed with cached data!
|
|
439
436
|
const promiseRaceWinner = await promiseRaceWithWinner([
|
|
440
437
|
cachedSnapshotP.catch(() => undefined),
|
|
441
|
-
|
|
438
|
+
networkSnapshotP.catch(() => undefined),
|
|
442
439
|
]);
|
|
443
|
-
|
|
440
|
+
retrievedSnapshot = promiseRaceWinner.value;
|
|
444
441
|
method = promiseRaceWinner.index === 0 ? "cache" : "network";
|
|
445
442
|
|
|
446
|
-
if (
|
|
443
|
+
if (retrievedSnapshot === undefined) {
|
|
447
444
|
// if network failed -> wait for cache ( then return network failure)
|
|
448
445
|
// If cache returned empty or failed -> wait for network (success of failure)
|
|
449
446
|
if (promiseRaceWinner.index === 1) {
|
|
450
|
-
|
|
447
|
+
retrievedSnapshot = await cachedSnapshotP;
|
|
451
448
|
method = "cache";
|
|
452
449
|
}
|
|
453
|
-
if (
|
|
454
|
-
|
|
450
|
+
if (retrievedSnapshot === undefined) {
|
|
451
|
+
retrievedSnapshot = await networkSnapshotP;
|
|
455
452
|
method = "network";
|
|
456
453
|
}
|
|
457
454
|
}
|
|
@@ -459,12 +456,12 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
|
|
|
459
456
|
// Note: There's a race condition here - another caller may come past the undefined check
|
|
460
457
|
// while the first caller is awaiting later async code in this block.
|
|
461
458
|
|
|
462
|
-
|
|
459
|
+
retrievedSnapshot = await cachedSnapshotP;
|
|
463
460
|
|
|
464
|
-
method =
|
|
461
|
+
method = retrievedSnapshot !== undefined ? "cache" : "network";
|
|
465
462
|
|
|
466
|
-
if (
|
|
467
|
-
|
|
463
|
+
if (retrievedSnapshot === undefined) {
|
|
464
|
+
retrievedSnapshot = await this.fetchSnapshot(hostSnapshotOptions);
|
|
468
465
|
}
|
|
469
466
|
}
|
|
470
467
|
if (method === "network") {
|
|
@@ -472,12 +469,11 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
|
|
|
472
469
|
props["cacheEntryAge"] = undefined;
|
|
473
470
|
}
|
|
474
471
|
event.end({ ...props, method });
|
|
475
|
-
return
|
|
472
|
+
return retrievedSnapshot;
|
|
476
473
|
},
|
|
477
|
-
{end: true, cancel: "error"},
|
|
478
474
|
);
|
|
479
475
|
|
|
480
|
-
// Successful call,
|
|
476
|
+
// Successful call, make network calls only
|
|
481
477
|
this.firstVersionCall = false;
|
|
482
478
|
|
|
483
479
|
this._snapshotSequenceNumber = odspSnapshotCacheValue.sequenceNumber;
|
|
@@ -512,10 +508,16 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
|
|
|
512
508
|
);
|
|
513
509
|
const versionsResponse = response.content;
|
|
514
510
|
if (!versionsResponse) {
|
|
515
|
-
|
|
511
|
+
throw new NonRetryableError(
|
|
512
|
+
"getVersionsReturnedNoResponse",
|
|
513
|
+
"No response from /versions endpoint",
|
|
514
|
+
DriverErrorType.genericNetworkError);
|
|
516
515
|
}
|
|
517
516
|
if (!Array.isArray(versionsResponse.value)) {
|
|
518
|
-
|
|
517
|
+
throw new NonRetryableError(
|
|
518
|
+
"getVersionsReturnedNonArrayResponse",
|
|
519
|
+
"Incorrect response from /versions endpoint",
|
|
520
|
+
DriverErrorType.genericNetworkError);
|
|
519
521
|
}
|
|
520
522
|
return versionsResponse.value.map((version) => {
|
|
521
523
|
// Parse the date from the message
|
|
@@ -687,19 +689,28 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
|
|
|
687
689
|
|
|
688
690
|
private checkSnapshotUrl() {
|
|
689
691
|
if (!this.snapshotUrl) {
|
|
690
|
-
|
|
692
|
+
throw new NonRetryableError(
|
|
693
|
+
"noSnapshotUrlProvided",
|
|
694
|
+
"Method failed because no snapshot url was available",
|
|
695
|
+
DriverErrorType.genericError);
|
|
691
696
|
}
|
|
692
697
|
}
|
|
693
698
|
|
|
694
699
|
private checkAttachmentPOSTUrl() {
|
|
695
700
|
if (!this.attachmentPOSTUrl) {
|
|
696
|
-
|
|
701
|
+
throw new NonRetryableError(
|
|
702
|
+
"noAttachmentPOSTUrlProvided",
|
|
703
|
+
"Method failed because no attachment POST url was available",
|
|
704
|
+
DriverErrorType.genericError);
|
|
697
705
|
}
|
|
698
706
|
}
|
|
699
707
|
|
|
700
708
|
private checkAttachmentGETUrl() {
|
|
701
709
|
if (!this.attachmentGETUrl) {
|
|
702
|
-
|
|
710
|
+
throw new NonRetryableError(
|
|
711
|
+
"noAttachmentGETUrlWasProvided",
|
|
712
|
+
"Method failed because no attachment GET url was available",
|
|
713
|
+
DriverErrorType.genericError);
|
|
703
714
|
}
|
|
704
715
|
}
|
|
705
716
|
|
|
@@ -7,7 +7,6 @@ import { assert } from "@fluidframework/common-utils";
|
|
|
7
7
|
import { IFluidCodeDetails, IRequest, isFluidPackage } from "@fluidframework/core-interfaces";
|
|
8
8
|
import { DriverHeader, IResolvedUrl, IUrlResolver } from "@fluidframework/driver-definitions";
|
|
9
9
|
import { IOdspResolvedUrl, ShareLinkTypes, ShareLinkInfoType } from "@fluidframework/odsp-driver-definitions";
|
|
10
|
-
import { createOdspCreateContainerRequest } from "./createOdspCreateContainerRequest";
|
|
11
10
|
import { createOdspUrl } from "./createOdspUrl";
|
|
12
11
|
import { getApiRoot } from "./odspUrlHelper";
|
|
13
12
|
import { getOdspResolvedUrl } from "./odspUtils";
|
|
@@ -166,18 +165,6 @@ export class OdspDriverUrlResolver implements IUrlResolver {
|
|
|
166
165
|
dataStorePath,
|
|
167
166
|
});
|
|
168
167
|
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* @deprecated - use createOdspCreateContainerRequest
|
|
172
|
-
*/
|
|
173
|
-
public createCreateNewRequest(
|
|
174
|
-
siteUrl: string,
|
|
175
|
-
driveId: string,
|
|
176
|
-
filePath: string,
|
|
177
|
-
fileName: string,
|
|
178
|
-
): IRequest {
|
|
179
|
-
return createOdspCreateContainerRequest(siteUrl, driveId, filePath, fileName);
|
|
180
|
-
}
|
|
181
168
|
}
|
|
182
169
|
|
|
183
170
|
function decodeOdspUrl(url: string): {
|
|
@@ -7,7 +7,7 @@ import { PromiseCache } from "@fluidframework/common-utils";
|
|
|
7
7
|
import { IFluidCodeDetails, IRequest, isFluidPackage } from "@fluidframework/core-interfaces";
|
|
8
8
|
import { IResolvedUrl, IUrlResolver } from "@fluidframework/driver-definitions";
|
|
9
9
|
import { ITelemetryBaseLogger, ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
10
|
-
import {
|
|
10
|
+
import { NonRetryableError } from "@fluidframework/driver-utils";
|
|
11
11
|
import { PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
12
12
|
import {
|
|
13
13
|
IOdspResolvedUrl,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
isTokenFromCache,
|
|
16
16
|
OdspResourceTokenFetchOptions,
|
|
17
17
|
TokenFetcher,
|
|
18
|
+
OdspErrorType,
|
|
18
19
|
} from "@fluidframework/odsp-driver-definitions";
|
|
19
20
|
import {
|
|
20
21
|
getLocatorFromOdspUrl,
|
|
@@ -22,8 +23,7 @@ import {
|
|
|
22
23
|
encodeOdspFluidDataStoreLocator,
|
|
23
24
|
locatorQueryParamName,
|
|
24
25
|
} from "./odspFluidFileLink";
|
|
25
|
-
import {
|
|
26
|
-
import { createOdspCreateContainerRequest } from "./createOdspCreateContainerRequest";
|
|
26
|
+
import { OdspFluidDataStoreLocator, SharingLinkHeader } from "./contractsPublic";
|
|
27
27
|
import { createOdspUrl } from "./createOdspUrl";
|
|
28
28
|
import { OdspDriverUrlResolver } from "./odspDriverUrlResolver";
|
|
29
29
|
import { getOdspResolvedUrl, createOdspLogger } from "./odspUtils";
|
|
@@ -77,18 +77,6 @@ export class OdspDriverUrlResolverForShareLink implements IUrlResolver {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
/**
|
|
81
|
-
* @deprecated - use createOdspCreateContainerRequest
|
|
82
|
-
*/
|
|
83
|
-
public createCreateNewRequest(
|
|
84
|
-
siteUrl: string,
|
|
85
|
-
driveId: string,
|
|
86
|
-
filePath: string,
|
|
87
|
-
fileName: string,
|
|
88
|
-
) {
|
|
89
|
-
return createOdspCreateContainerRequest(siteUrl, driveId, filePath, fileName);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
80
|
/**
|
|
93
81
|
* Takes an already generated data store url (from requestUrl) and appends a path to the
|
|
94
82
|
* existing data store information.
|
|
@@ -175,7 +163,10 @@ export class OdspDriverUrlResolverForShareLink implements IUrlResolver {
|
|
|
175
163
|
{ eventName: "GetSharingLinkToken" },
|
|
176
164
|
async (event) => tokenFetcher(options).then((tokenResponse) => {
|
|
177
165
|
if (tokenResponse === null) {
|
|
178
|
-
|
|
166
|
+
throw new NonRetryableError(
|
|
167
|
+
"shareLinkTokenIsNull",
|
|
168
|
+
"Token callback returned null",
|
|
169
|
+
OdspErrorType.fetchTokenError);
|
|
179
170
|
}
|
|
180
171
|
event.end({ fromCache: isTokenFromCache(tokenResponse) });
|
|
181
172
|
return tokenResponse;
|
|
@@ -203,12 +194,8 @@ export class OdspDriverUrlResolverForShareLink implements IUrlResolver {
|
|
|
203
194
|
resolvedUrl,
|
|
204
195
|
this.shareLinkFetcherProps.identityType,
|
|
205
196
|
this.logger,
|
|
206
|
-
).
|
|
207
|
-
|
|
208
|
-
throw new Error("Failed to get share link");
|
|
209
|
-
}
|
|
210
|
-
return fileLink;
|
|
211
|
-
}).catch((error) => {
|
|
197
|
+
).catch((error) => {
|
|
198
|
+
// This should imply that error is a non-retriable error.
|
|
212
199
|
this.logger.sendErrorEvent({ eventName: "FluidFileUrlError" }, error);
|
|
213
200
|
this.sharingLinkCache.remove(key);
|
|
214
201
|
throw error;
|
|
@@ -254,7 +241,7 @@ export class OdspDriverUrlResolverForShareLink implements IUrlResolver {
|
|
|
254
241
|
/**
|
|
255
242
|
* Crafts a supported document/driver URL
|
|
256
243
|
*/
|
|
257
|
-
public static createDocumentUrl(baseUrl: string, driverInfo:
|
|
244
|
+
public static createDocumentUrl(baseUrl: string, driverInfo: OdspFluidDataStoreLocator) {
|
|
258
245
|
const url = new URL(baseUrl);
|
|
259
246
|
|
|
260
247
|
storeLocatorInOdspUrl(url, driverInfo);
|
package/src/odspError.ts
CHANGED
|
@@ -11,9 +11,13 @@ import { IOdspSocketError } from "./contracts";
|
|
|
11
11
|
*/
|
|
12
12
|
export function errorObjectFromSocketError(socketError: IOdspSocketError, handler: string) {
|
|
13
13
|
const message = `OdspSocketError (${handler}): ${socketError.message}`;
|
|
14
|
-
|
|
14
|
+
const error = createOdspNetworkError(
|
|
15
15
|
`odspSocketError [${handler}]`,
|
|
16
16
|
message,
|
|
17
17
|
socketError.code,
|
|
18
18
|
socketError.retryAfter);
|
|
19
|
+
|
|
20
|
+
error.addTelemetryProperties({ odspError: true, relayServiceError: true });
|
|
21
|
+
|
|
22
|
+
return error;
|
|
19
23
|
}
|
package/src/odspUtils.ts
CHANGED
|
@@ -5,19 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
import { ITelemetryProperties, ITelemetryBaseLogger, ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
7
7
|
import { IResolvedUrl, DriverErrorType } from "@fluidframework/driver-definitions";
|
|
8
|
-
import { isOnline, OnlineStatus } from "@fluidframework/driver-utils";
|
|
8
|
+
import { isOnline, OnlineStatus, RetryableError, NonRetryableError } from "@fluidframework/driver-utils";
|
|
9
9
|
import { assert, performance } from "@fluidframework/common-utils";
|
|
10
10
|
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions";
|
|
11
11
|
import { ChildLogger, PerformanceEvent, wrapError } from "@fluidframework/telemetry-utils";
|
|
12
12
|
import {
|
|
13
13
|
fetchIncorrectResponse,
|
|
14
|
-
offlineFetchFailureStatusCode,
|
|
15
|
-
fetchFailureStatusCode,
|
|
16
|
-
fetchTimeoutStatusCode,
|
|
17
14
|
throwOdspNetworkError,
|
|
18
15
|
getSPOAndGraphRequestIdsFromResponse,
|
|
19
|
-
fetchTokenErrorCode,
|
|
20
|
-
createOdspNetworkError,
|
|
21
16
|
} from "@fluidframework/odsp-doclib-utils";
|
|
22
17
|
import {
|
|
23
18
|
IOdspResolvedUrl,
|
|
@@ -82,7 +77,7 @@ export async function getWithRetryForTokenRefresh<T>(get: (options: TokenFetchOp
|
|
|
82
77
|
case DriverErrorType.authorizationError:
|
|
83
78
|
return get({ ...options, claims: e.claims, tenantId: e.tenantId });
|
|
84
79
|
|
|
85
|
-
case DriverErrorType.incorrectServerResponse: //
|
|
80
|
+
case DriverErrorType.incorrectServerResponse: // some error on the wire, retry once
|
|
86
81
|
case OdspErrorType.fetchTokenError: // If the token was null, then retry once.
|
|
87
82
|
return get(options);
|
|
88
83
|
|
|
@@ -107,7 +102,10 @@ export async function fetchHelper(
|
|
|
107
102
|
const response = fetchResponse as any as Response;
|
|
108
103
|
// Let's assume we can retry.
|
|
109
104
|
if (!response) {
|
|
110
|
-
|
|
105
|
+
throw new NonRetryableError(
|
|
106
|
+
"odspFetchErrorNoResponse",
|
|
107
|
+
"No response from fetch call",
|
|
108
|
+
DriverErrorType.incorrectServerResponse);
|
|
111
109
|
}
|
|
112
110
|
if (!response.ok || response.status < 200 || response.status >= 300) {
|
|
113
111
|
throwOdspNetworkError(
|
|
@@ -130,11 +128,13 @@ export async function fetchHelper(
|
|
|
130
128
|
if (errorText === "TypeError: Failed to fetch") {
|
|
131
129
|
online = OnlineStatus.Offline;
|
|
132
130
|
}
|
|
131
|
+
// This error is thrown by fetch() when AbortSignal is provided and it gets cancelled
|
|
133
132
|
if (error.name === "AbortError") {
|
|
134
|
-
|
|
133
|
+
throw new RetryableError("fetchAbort", "Fetch Timeout (AbortError)", OdspErrorType.fetchTimeout);
|
|
135
134
|
}
|
|
135
|
+
// TCP/IP timeout
|
|
136
136
|
if (errorText.indexOf("ETIMEDOUT") !== -1) {
|
|
137
|
-
|
|
137
|
+
throw new RetryableError("fetchETimedout", "Fetch Timeout (ETIMEDOUT)", OdspErrorType.fetchTimeout);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
//
|
|
@@ -142,11 +142,11 @@ export async function fetchHelper(
|
|
|
142
142
|
// It could container PII, like URI in message itself, or token in properties.
|
|
143
143
|
// It is also non-serializable object due to circular references.
|
|
144
144
|
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
145
|
+
if (online === OnlineStatus.Offline) {
|
|
146
|
+
throw new RetryableError("OdspFetchOffline", `Offline: ${errorText}`, DriverErrorType.offlineError);
|
|
147
|
+
} else {
|
|
148
|
+
throw new RetryableError("OdspFetchError", `Fetch error: ${errorText}`, DriverErrorType.fetchFailure);
|
|
149
|
+
}
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -181,30 +181,31 @@ export async function fetchAndParseAsJSONHelper<T>(
|
|
|
181
181
|
requestInit: RequestInit | undefined,
|
|
182
182
|
): Promise<IOdspResponse<T>> {
|
|
183
183
|
const { content, headers, commonSpoHeaders, duration } = await fetchHelper(requestInfo, requestInit);
|
|
184
|
-
|
|
185
|
-
// tokens... It fails for me with "Unexpected end of JSON input" quite often - an attempt to download big file
|
|
186
|
-
// (many ops) almost always ends up with this error - I'd guess 1% of op request end up here... It always
|
|
187
|
-
// succeeds on retry.
|
|
184
|
+
let text: string | undefined;
|
|
188
185
|
try {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
commonSpoHeaders.bodySize = text.length;
|
|
192
|
-
const res = {
|
|
193
|
-
headers,
|
|
194
|
-
content: JSON.parse(text),
|
|
195
|
-
commonSpoHeaders,
|
|
196
|
-
duration,
|
|
197
|
-
};
|
|
198
|
-
return res;
|
|
186
|
+
text = await content.text();
|
|
199
187
|
} catch (e) {
|
|
188
|
+
// JSON.parse() can fail and message would container full request URI, including
|
|
189
|
+
// tokens... It fails for me with "Unexpected end of JSON input" quite often - an attempt to download big file
|
|
190
|
+
// (many ops) almost always ends up with this error - I'd guess 1% of op request end up here... It always
|
|
191
|
+
// succeeds on retry.
|
|
192
|
+
// So do not log error object itself.
|
|
200
193
|
throwOdspNetworkError(
|
|
201
194
|
"errorWhileParsingFetchResponse",
|
|
202
195
|
fetchIncorrectResponse,
|
|
203
|
-
content,
|
|
204
|
-
|
|
205
|
-
{ error: Object(e) },
|
|
196
|
+
content, // response
|
|
197
|
+
text,
|
|
206
198
|
);
|
|
207
199
|
}
|
|
200
|
+
|
|
201
|
+
commonSpoHeaders.bodySize = text.length;
|
|
202
|
+
const res = {
|
|
203
|
+
headers,
|
|
204
|
+
content: JSON.parse(text),
|
|
205
|
+
commonSpoHeaders,
|
|
206
|
+
duration,
|
|
207
|
+
};
|
|
208
|
+
return res;
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
export interface INewFileInfo {
|
|
@@ -293,14 +294,21 @@ export function toInstrumentedOdspTokenFetcher(
|
|
|
293
294
|
event.end({ fromCache: isTokenFromCache(tokenResponse), isNull: token === null });
|
|
294
295
|
}
|
|
295
296
|
if (token === null && throwOnNullToken) {
|
|
296
|
-
|
|
297
|
+
throw new NonRetryableError(
|
|
298
|
+
"storageTokenIsNull",
|
|
299
|
+
`Token is null for ${name} call`,
|
|
300
|
+
OdspErrorType.fetchTokenError,
|
|
301
|
+
{ method: name });
|
|
297
302
|
}
|
|
298
303
|
return token;
|
|
299
304
|
}, (error) => {
|
|
300
305
|
const tokenError = wrapError(
|
|
301
306
|
error,
|
|
302
|
-
(errorMessage) =>
|
|
303
|
-
|
|
307
|
+
(errorMessage) => new NonRetryableError(
|
|
308
|
+
"tokenFetcherFailed",
|
|
309
|
+
errorMessage,
|
|
310
|
+
OdspErrorType.fetchTokenError,
|
|
311
|
+
{ method: name }));
|
|
304
312
|
throw tokenError;
|
|
305
313
|
}),
|
|
306
314
|
{ cancel: "generic" });
|
package/src/packageVersion.ts
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { assert, IsoBuffer, Uint8ArrayToArrayBuffer, Uint8ArrayToString } from "@fluidframework/common-utils";
|
|
12
|
-
import {
|
|
12
|
+
import { NonRetryableError } from "@fluidframework/driver-utils";
|
|
13
|
+
import { DriverErrorType } from "@fluidframework/driver-definitions";
|
|
13
14
|
import { ReadBuffer } from "./ReadBufferUtils";
|
|
14
15
|
|
|
15
16
|
// eslint-disable-next-line max-len
|
|
@@ -477,19 +478,14 @@ function throwBufferParseException(
|
|
|
477
478
|
expectedNodeType: NodeType,
|
|
478
479
|
message: string,
|
|
479
480
|
): never {
|
|
480
|
-
|
|
481
|
+
throw new NonRetryableError(
|
|
481
482
|
"bufferParsingException",
|
|
482
483
|
message,
|
|
483
|
-
|
|
484
|
-
undefined,
|
|
485
|
-
undefined,
|
|
486
|
-
undefined,
|
|
484
|
+
DriverErrorType.incorrectServerResponse,
|
|
487
485
|
{
|
|
488
486
|
nodeType: getNodeType(node),
|
|
489
487
|
expectedNodeType,
|
|
490
488
|
});
|
|
491
|
-
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
|
492
|
-
throw error;
|
|
493
489
|
}
|
|
494
490
|
|
|
495
491
|
function getNodeType(value: NodeTypes): NodeType {
|