@fluidframework/routerlicious-driver 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.4.1.0.148229
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.js +10 -12
- package/.mocharc.js +2 -2
- package/README.md +1 -1
- package/api-extractor.json +2 -2
- package/dist/cache.d.ts +3 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +6 -4
- package/dist/cache.js.map +1 -1
- package/dist/createNewUtils.d.ts.map +1 -1
- package/dist/createNewUtils.js +4 -2
- package/dist/createNewUtils.js.map +1 -1
- package/dist/defaultTokenProvider.d.ts.map +1 -1
- package/dist/defaultTokenProvider.js.map +1 -1
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js.map +1 -1
- package/dist/deltaStorageService.d.ts.map +1 -1
- package/dist/deltaStorageService.js +4 -1
- package/dist/deltaStorageService.js.map +1 -1
- package/dist/documentDeltaConnection.d.ts.map +1 -1
- package/dist/documentDeltaConnection.js.map +1 -1
- package/dist/documentService.d.ts +4 -2
- package/dist/documentService.d.ts.map +1 -1
- package/dist/documentService.js +28 -41
- package/dist/documentService.js.map +1 -1
- package/dist/documentServiceFactory.d.ts +0 -1
- package/dist/documentServiceFactory.d.ts.map +1 -1
- package/dist/documentServiceFactory.js +26 -13
- package/dist/documentServiceFactory.js.map +1 -1
- package/dist/documentStorageService.d.ts +1 -1
- package/dist/documentStorageService.d.ts.map +1 -1
- package/dist/documentStorageService.js +8 -6
- package/dist/documentStorageService.js.map +1 -1
- package/dist/errorUtils.d.ts +11 -3
- package/dist/errorUtils.d.ts.map +1 -1
- package/dist/errorUtils.js +19 -6
- package/dist/errorUtils.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/mapWithExpiration.d.ts +34 -0
- package/dist/mapWithExpiration.d.ts.map +1 -0
- package/dist/mapWithExpiration.js +105 -0
- package/dist/mapWithExpiration.js.map +1 -0
- package/dist/nullBlobStorageService.d.ts.map +1 -1
- package/dist/nullBlobStorageService.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/policies.d.ts.map +1 -1
- package/dist/policies.js.map +1 -1
- package/dist/restWrapper.d.ts +8 -5
- package/dist/restWrapper.d.ts.map +1 -1
- package/dist/restWrapper.js +38 -44
- package/dist/restWrapper.js.map +1 -1
- package/dist/retriableGitManager.d.ts.map +1 -1
- package/dist/retriableGitManager.js.map +1 -1
- package/dist/shreddedSummaryDocumentStorageService.d.ts +1 -1
- package/dist/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
- package/dist/shreddedSummaryDocumentStorageService.js +9 -5
- package/dist/shreddedSummaryDocumentStorageService.js.map +1 -1
- package/dist/tokens.d.ts +24 -7
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js.map +1 -1
- package/dist/treeUtils.d.ts +51 -0
- package/dist/treeUtils.d.ts.map +1 -0
- package/dist/treeUtils.js +85 -0
- package/dist/treeUtils.js.map +1 -0
- package/dist/urlUtils.d.ts.map +1 -1
- package/dist/urlUtils.js.map +1 -1
- package/dist/wholeSummaryDocumentStorageService.d.ts +1 -1
- package/dist/wholeSummaryDocumentStorageService.d.ts.map +1 -1
- package/dist/wholeSummaryDocumentStorageService.js +30 -17
- package/dist/wholeSummaryDocumentStorageService.js.map +1 -1
- package/lib/cache.d.ts +3 -0
- package/lib/cache.d.ts.map +1 -1
- package/lib/cache.js +6 -4
- package/lib/cache.js.map +1 -1
- package/lib/createNewUtils.d.ts.map +1 -1
- package/lib/createNewUtils.js +4 -2
- package/lib/createNewUtils.js.map +1 -1
- package/lib/defaultTokenProvider.d.ts.map +1 -1
- package/lib/defaultTokenProvider.js.map +1 -1
- package/lib/definitions.d.ts.map +1 -1
- package/lib/definitions.js.map +1 -1
- package/lib/deltaStorageService.d.ts.map +1 -1
- package/lib/deltaStorageService.js +4 -1
- package/lib/deltaStorageService.js.map +1 -1
- package/lib/documentDeltaConnection.d.ts.map +1 -1
- package/lib/documentDeltaConnection.js.map +1 -1
- package/lib/documentService.d.ts +4 -2
- package/lib/documentService.d.ts.map +1 -1
- package/lib/documentService.js +30 -24
- package/lib/documentService.js.map +1 -1
- package/lib/documentServiceFactory.d.ts +0 -1
- package/lib/documentServiceFactory.d.ts.map +1 -1
- package/lib/documentServiceFactory.js +27 -14
- package/lib/documentServiceFactory.js.map +1 -1
- package/lib/documentStorageService.d.ts +1 -1
- package/lib/documentStorageService.d.ts.map +1 -1
- package/lib/documentStorageService.js +9 -7
- package/lib/documentStorageService.js.map +1 -1
- package/lib/errorUtils.d.ts +11 -3
- package/lib/errorUtils.d.ts.map +1 -1
- package/lib/errorUtils.js +18 -5
- package/lib/errorUtils.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/mapWithExpiration.d.ts +34 -0
- package/lib/mapWithExpiration.d.ts.map +1 -0
- package/lib/mapWithExpiration.js +101 -0
- package/lib/mapWithExpiration.js.map +1 -0
- package/lib/nullBlobStorageService.d.ts.map +1 -1
- package/lib/nullBlobStorageService.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/policies.d.ts.map +1 -1
- package/lib/policies.js.map +1 -1
- package/lib/restWrapper.d.ts +8 -5
- package/lib/restWrapper.d.ts.map +1 -1
- package/lib/restWrapper.js +38 -44
- package/lib/restWrapper.js.map +1 -1
- package/lib/retriableGitManager.d.ts.map +1 -1
- package/lib/retriableGitManager.js.map +1 -1
- package/lib/shreddedSummaryDocumentStorageService.d.ts +1 -1
- package/lib/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
- package/lib/shreddedSummaryDocumentStorageService.js +10 -6
- package/lib/shreddedSummaryDocumentStorageService.js.map +1 -1
- package/lib/tokens.d.ts +24 -7
- package/lib/tokens.d.ts.map +1 -1
- package/lib/tokens.js.map +1 -1
- package/lib/treeUtils.d.ts +51 -0
- package/lib/treeUtils.d.ts.map +1 -0
- package/lib/treeUtils.js +80 -0
- package/lib/treeUtils.js.map +1 -0
- package/lib/urlUtils.d.ts.map +1 -1
- package/lib/urlUtils.js.map +1 -1
- package/lib/wholeSummaryDocumentStorageService.d.ts +1 -1
- package/lib/wholeSummaryDocumentStorageService.d.ts.map +1 -1
- package/lib/wholeSummaryDocumentStorageService.js +30 -17
- package/lib/wholeSummaryDocumentStorageService.js.map +1 -1
- package/package.json +55 -52
- package/prettier.config.cjs +1 -1
- package/src/cache.ts +21 -14
- package/src/createNewUtils.ts +24 -22
- package/src/defaultTokenProvider.ts +13 -15
- package/src/definitions.ts +2 -2
- package/src/deltaStorageService.ts +99 -95
- package/src/documentDeltaConnection.ts +53 -47
- package/src/documentService.ts +260 -241
- package/src/documentServiceFactory.ts +268 -237
- package/src/documentStorageService.ts +87 -83
- package/src/errorUtils.ts +91 -76
- package/src/index.ts +7 -1
- package/src/mapWithExpiration.ts +124 -0
- package/src/nullBlobStorageService.ts +24 -21
- package/src/packageVersion.ts +1 -1
- package/src/policies.ts +44 -44
- package/src/restWrapper.ts +270 -208
- package/src/retriableGitManager.ts +152 -151
- package/src/shreddedSummaryDocumentStorageService.ts +202 -194
- package/src/tokens.ts +69 -44
- package/src/treeUtils.ts +107 -0
- package/src/urlUtils.ts +26 -23
- package/src/wholeSummaryDocumentStorageService.ts +248 -228
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +9 -13
|
@@ -5,18 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
import type { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
IDocumentStorageService,
|
|
9
|
+
IDocumentStorageServicePolicies,
|
|
10
|
+
LoaderCachingPolicy,
|
|
11
11
|
} from "@fluidframework/driver-definitions";
|
|
12
|
+
import { ISnapshotTree, IVersion } from "@fluidframework/protocol-definitions";
|
|
13
|
+
import { GitManager } from "@fluidframework/server-services-client";
|
|
12
14
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "@fluidframework/
|
|
16
|
-
import {
|
|
17
|
-
GitManager,
|
|
18
|
-
} from "@fluidframework/server-services-client";
|
|
19
|
-
import { DocumentStorageServiceProxy, PrefetchDocumentStorageService } from "@fluidframework/driver-utils";
|
|
15
|
+
DocumentStorageServiceProxy,
|
|
16
|
+
PrefetchDocumentStorageService,
|
|
17
|
+
} from "@fluidframework/driver-utils";
|
|
20
18
|
import { IRouterliciousDriverPolicies } from "./policies";
|
|
21
19
|
import { ICache } from "./cache";
|
|
22
20
|
import { WholeSummaryDocumentStorageService } from "./wholeSummaryDocumentStorageService";
|
|
@@ -24,81 +22,87 @@ import { ShreddedSummaryDocumentStorageService } from "./shreddedSummaryDocument
|
|
|
24
22
|
import { ISnapshotTreeVersion } from "./definitions";
|
|
25
23
|
|
|
26
24
|
export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
27
|
-
|
|
25
|
+
private _logTailSha: string | undefined = undefined;
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
public get logTailSha(): string | undefined {
|
|
28
|
+
return this._logTailSha;
|
|
29
|
+
}
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
31
|
+
private static loadInternalDocumentStorageService(
|
|
32
|
+
id: string,
|
|
33
|
+
manager: GitManager,
|
|
34
|
+
logger: ITelemetryLogger,
|
|
35
|
+
policies: IDocumentStorageServicePolicies,
|
|
36
|
+
driverPolicies?: IRouterliciousDriverPolicies,
|
|
37
|
+
blobCache?: ICache<ArrayBufferLike>,
|
|
38
|
+
snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
|
|
39
|
+
noCacheGitManager?: GitManager,
|
|
40
|
+
getStorageManager?: (disableCache?: boolean) => Promise<GitManager>,
|
|
41
|
+
): IDocumentStorageService {
|
|
42
|
+
const storageService = driverPolicies?.enableWholeSummaryUpload
|
|
43
|
+
? new WholeSummaryDocumentStorageService(
|
|
44
|
+
id,
|
|
45
|
+
manager,
|
|
46
|
+
logger,
|
|
47
|
+
policies,
|
|
48
|
+
driverPolicies,
|
|
49
|
+
blobCache,
|
|
50
|
+
snapshotTreeCache,
|
|
51
|
+
noCacheGitManager,
|
|
52
|
+
getStorageManager,
|
|
53
|
+
)
|
|
54
|
+
: new ShreddedSummaryDocumentStorageService(
|
|
55
|
+
id,
|
|
56
|
+
manager,
|
|
57
|
+
logger,
|
|
58
|
+
policies,
|
|
59
|
+
driverPolicies,
|
|
60
|
+
blobCache,
|
|
61
|
+
snapshotTreeCache,
|
|
62
|
+
getStorageManager,
|
|
63
|
+
);
|
|
64
|
+
// TODO: worth prefetching latest summary making version + snapshot call with WholeSummary storage?
|
|
65
|
+
if (
|
|
66
|
+
!driverPolicies?.enableWholeSummaryUpload &&
|
|
67
|
+
policies.caching === LoaderCachingPolicy.Prefetch
|
|
68
|
+
) {
|
|
69
|
+
return new PrefetchDocumentStorageService(storageService);
|
|
70
|
+
}
|
|
71
|
+
return storageService;
|
|
72
|
+
}
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
74
|
+
constructor(
|
|
75
|
+
public readonly id: string,
|
|
76
|
+
public manager: GitManager,
|
|
77
|
+
logger: ITelemetryLogger,
|
|
78
|
+
policies: IDocumentStorageServicePolicies,
|
|
79
|
+
driverPolicies?: IRouterliciousDriverPolicies,
|
|
80
|
+
blobCache?: ICache<ArrayBufferLike>,
|
|
81
|
+
snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
|
|
82
|
+
public noCacheGitManager?: GitManager,
|
|
83
|
+
getStorageManager?: (disableCache?: boolean) => Promise<GitManager>,
|
|
84
|
+
) {
|
|
85
|
+
super(
|
|
86
|
+
DocumentStorageService.loadInternalDocumentStorageService(
|
|
87
|
+
id,
|
|
88
|
+
manager,
|
|
89
|
+
logger,
|
|
90
|
+
policies,
|
|
91
|
+
driverPolicies,
|
|
92
|
+
blobCache,
|
|
93
|
+
snapshotTreeCache,
|
|
94
|
+
noCacheGitManager,
|
|
95
|
+
getStorageManager,
|
|
96
|
+
),
|
|
97
|
+
);
|
|
98
|
+
}
|
|
96
99
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {
|
|
101
|
+
const tree = await this.internalStorageService.getSnapshotTree(version);
|
|
102
|
+
if (tree !== null) {
|
|
103
|
+
this._logTailSha =
|
|
104
|
+
".logTail" in tree.trees ? tree.trees[".logTail"].blobs.logTail : undefined;
|
|
105
|
+
}
|
|
106
|
+
return tree;
|
|
107
|
+
}
|
|
104
108
|
}
|
package/src/errorUtils.ts
CHANGED
|
@@ -5,15 +5,24 @@
|
|
|
5
5
|
|
|
6
6
|
import { DriverError } from "@fluidframework/driver-definitions";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
NonRetryableError,
|
|
9
|
+
GenericNetworkError,
|
|
10
|
+
createGenericNetworkError,
|
|
11
|
+
AuthorizationError,
|
|
12
12
|
} from "@fluidframework/driver-utils";
|
|
13
13
|
import { pkgVersion as driverVersion } from "./packageVersion";
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Routerlicious Error types
|
|
17
|
+
* Different error types that may be thrown by the routerlicious driver
|
|
18
|
+
*/
|
|
19
|
+
export enum RouterliciousErrorType {
|
|
20
|
+
/**
|
|
21
|
+
* File not found, or file deleted during session
|
|
22
|
+
*/
|
|
23
|
+
fileNotFoundOrAccessDeniedError = "fileNotFoundOrAccessDeniedError",
|
|
24
|
+
|
|
25
|
+
sslCertError = "sslCertError",
|
|
17
26
|
}
|
|
18
27
|
|
|
19
28
|
/**
|
|
@@ -21,96 +30,102 @@ export enum R11sErrorType {
|
|
|
21
30
|
* Intended to be compatible with output from {@link NetworkError.toJSON}
|
|
22
31
|
*/
|
|
23
32
|
export interface IR11sSocketError {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
/**
|
|
34
|
+
* An error code number for the error that occurred.
|
|
35
|
+
* It will be a valid HTTP status code.
|
|
36
|
+
*/
|
|
37
|
+
code: number;
|
|
29
38
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
/**
|
|
40
|
+
* A message about the error that occurred for debugging / logging purposes.
|
|
41
|
+
* This should not be displayed to the user directly.
|
|
42
|
+
*/
|
|
43
|
+
message: string;
|
|
35
44
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Optional Retry-After time in seconds.
|
|
47
|
+
* The client should wait this many seconds before retrying its request.
|
|
48
|
+
*/
|
|
49
|
+
retryAfter?: number;
|
|
41
50
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Optional Retry-After time in milliseconds.
|
|
53
|
+
* The client should wait this many milliseconds before retrying its request.
|
|
54
|
+
*/
|
|
55
|
+
retryAfterMs?: number;
|
|
47
56
|
}
|
|
48
57
|
|
|
49
58
|
export interface IR11sError {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
readonly errorType: RouterliciousErrorType;
|
|
60
|
+
readonly message: string;
|
|
61
|
+
canRetry: boolean;
|
|
53
62
|
}
|
|
54
63
|
|
|
55
64
|
export type R11sError = DriverError | IR11sError;
|
|
56
65
|
|
|
57
66
|
export function createR11sNetworkError(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
errorMessage: string,
|
|
68
|
+
statusCode?: number,
|
|
69
|
+
retryAfterMs?: number,
|
|
61
70
|
): R11sError {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
71
|
+
const props = { statusCode, driverVersion };
|
|
72
|
+
switch (statusCode) {
|
|
73
|
+
case undefined:
|
|
74
|
+
// If a service is temporarily down or a browser resource limit is reached, RestWrapper will throw
|
|
75
|
+
// a network error with no status code (e.g. err:ERR_CONN_REFUSED or err:ERR_FAILED) and
|
|
76
|
+
// the error message will start with NetworkError as defined in restWrapper.ts
|
|
77
|
+
// If there exists a self-signed SSL certificates error, throw a NonRetryableError
|
|
78
|
+
// TODO: instead of relying on string matching, filter error based on the error code like we do for websocket connections
|
|
79
|
+
if (errorMessage.includes("failed, reason: self signed certificate")) {
|
|
80
|
+
return new NonRetryableError(
|
|
81
|
+
errorMessage,
|
|
82
|
+
RouterliciousErrorType.sslCertError,
|
|
83
|
+
props,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
return new GenericNetworkError(
|
|
87
|
+
errorMessage,
|
|
88
|
+
errorMessage.startsWith("NetworkError"),
|
|
89
|
+
props,
|
|
90
|
+
);
|
|
91
|
+
case 401:
|
|
92
|
+
// The first 401 is manually retried in RouterliciousRestWrapper with a refreshed token,
|
|
93
|
+
// so we treat repeat 401s the same as 403.
|
|
94
|
+
case 403:
|
|
95
|
+
return new AuthorizationError(errorMessage, undefined, undefined, props);
|
|
96
|
+
case 404:
|
|
97
|
+
const errorType = RouterliciousErrorType.fileNotFoundOrAccessDeniedError;
|
|
98
|
+
return new NonRetryableError(errorMessage, errorType, props);
|
|
99
|
+
case 429:
|
|
100
|
+
return createGenericNetworkError(errorMessage, { canRetry: true, retryAfterMs }, props);
|
|
101
|
+
case 500:
|
|
102
|
+
case 502:
|
|
103
|
+
return new GenericNetworkError(errorMessage, true, props);
|
|
104
|
+
default:
|
|
105
|
+
const retryInfo = { canRetry: retryAfterMs !== undefined, retryAfterMs };
|
|
106
|
+
return createGenericNetworkError(errorMessage, retryInfo, props);
|
|
107
|
+
}
|
|
89
108
|
}
|
|
90
109
|
|
|
91
110
|
export function throwR11sNetworkError(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
111
|
+
errorMessage: string,
|
|
112
|
+
statusCode?: number,
|
|
113
|
+
retryAfterMs?: number,
|
|
95
114
|
): never {
|
|
96
|
-
|
|
97
|
-
errorMessage,
|
|
98
|
-
statusCode,
|
|
99
|
-
retryAfterMs);
|
|
115
|
+
const networkError = createR11sNetworkError(errorMessage, statusCode, retryAfterMs);
|
|
100
116
|
|
|
101
|
-
|
|
102
|
-
|
|
117
|
+
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
|
118
|
+
throw networkError;
|
|
103
119
|
}
|
|
104
120
|
|
|
105
121
|
/**
|
|
106
122
|
* Returns network error based on error object from R11s socket (IR11sSocketError)
|
|
107
123
|
*/
|
|
108
|
-
export function errorObjectFromSocketError(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
);
|
|
124
|
+
export function errorObjectFromSocketError(
|
|
125
|
+
socketError: IR11sSocketError,
|
|
126
|
+
handler: string,
|
|
127
|
+
): R11sError {
|
|
128
|
+
// pre-0.58 error message prefix: R11sSocketError
|
|
129
|
+
const message = `R11s socket error (${handler}): ${socketError.message}`;
|
|
130
|
+
return createR11sNetworkError(message, socketError.code, socketError.retryAfterMs);
|
|
116
131
|
}
|
package/src/index.ts
CHANGED
|
@@ -7,8 +7,14 @@
|
|
|
7
7
|
export { DefaultTokenProvider } from "./defaultTokenProvider";
|
|
8
8
|
export { ITokenProvider, ITokenResponse, ITokenService } from "./tokens";
|
|
9
9
|
|
|
10
|
+
// Errors
|
|
11
|
+
export { RouterliciousErrorType } from "./errorUtils";
|
|
12
|
+
|
|
10
13
|
// Factory
|
|
11
|
-
export {
|
|
14
|
+
export {
|
|
15
|
+
DocumentPostCreateError,
|
|
16
|
+
RouterliciousDocumentServiceFactory,
|
|
17
|
+
} from "./documentServiceFactory";
|
|
12
18
|
|
|
13
19
|
// Configuration
|
|
14
20
|
export { IRouterliciousDriverPolicies } from "./policies";
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { assert } from "@fluidframework/common-utils";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* An extension of Map that expires (deletes) entries after a period of inactivity.
|
|
10
|
+
* The policy is based on the last time a key was written to.
|
|
11
|
+
*/
|
|
12
|
+
export class MapWithExpiration<TKey = any, TValue = any> extends Map<TKey, TValue> {
|
|
13
|
+
/** Timestamps (as epoch ms numbers) of when each key was last refreshed */
|
|
14
|
+
private readonly lastRefreshedTimes = new Map<TKey, number>();
|
|
15
|
+
|
|
16
|
+
constructor(private readonly expiryMs: number) {
|
|
17
|
+
super();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private refresh(key: TKey): void {
|
|
21
|
+
this.lastRefreshedTimes.set(key, new Date().valueOf());
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns true if the key is present and expired, false if it's not expired, and undefined if it's not found
|
|
26
|
+
* If cleanUp is passed as true, then delete any expired entry before returning.
|
|
27
|
+
*/
|
|
28
|
+
private checkExpiry(key: TKey, cleanUp: boolean = false): boolean | undefined {
|
|
29
|
+
const refreshTime = this.lastRefreshedTimes.get(key);
|
|
30
|
+
assert(
|
|
31
|
+
(refreshTime !== undefined) === super.has(key),
|
|
32
|
+
0x50c /* freshness map out of sync */,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (refreshTime === undefined) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const expired = new Date().valueOf() - refreshTime >= this.expiryMs;
|
|
39
|
+
if (expired && cleanUp) {
|
|
40
|
+
this.delete(key);
|
|
41
|
+
}
|
|
42
|
+
return expired;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private clearExpiredEntries() {
|
|
46
|
+
// forEach clears out any expired entries
|
|
47
|
+
this.forEach(() => {});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get size(): number {
|
|
51
|
+
this.clearExpiredEntries();
|
|
52
|
+
return super.size;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
has(key: TKey): boolean {
|
|
56
|
+
this.checkExpiry(key, true /* cleanUp */);
|
|
57
|
+
return super.has(key);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get(key: TKey): TValue | undefined {
|
|
61
|
+
this.checkExpiry(key, true /* cleanUp */);
|
|
62
|
+
return super.get(key);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
set(key: TKey, value: TValue): this {
|
|
66
|
+
// Sliding window expiration policy (on write)
|
|
67
|
+
this.refresh(key);
|
|
68
|
+
return super.set(key, value);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
delete(key: TKey): boolean {
|
|
72
|
+
this.lastRefreshedTimes.delete(key);
|
|
73
|
+
return super.delete(key);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
clear(): void {
|
|
77
|
+
this.lastRefreshedTimes.clear();
|
|
78
|
+
super.clear();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
forEach(
|
|
82
|
+
callbackfn: (value: TValue, key: TKey, map: Map<TKey, TValue>) => void,
|
|
83
|
+
thisArg?: any,
|
|
84
|
+
): void {
|
|
85
|
+
const expiredKeys: TKey[] = [];
|
|
86
|
+
super.forEach(
|
|
87
|
+
(v, k, m) => {
|
|
88
|
+
if (this.checkExpiry(k) === true) {
|
|
89
|
+
expiredKeys.push(k);
|
|
90
|
+
} else {
|
|
91
|
+
callbackfn.bind(thisArg)(v, k, m);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
// Note we don't pass thisArg here, since we bind it directly to callbackFn and don't need it otherwise
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// Clean up keys we know are expired now that we're done iterating
|
|
98
|
+
expiredKeys.forEach((key: TKey) => {
|
|
99
|
+
this.delete(key);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
entries(): IterableIterator<[TKey, TValue]> {
|
|
104
|
+
this.clearExpiredEntries();
|
|
105
|
+
return super.entries();
|
|
106
|
+
}
|
|
107
|
+
keys(): IterableIterator<TKey> {
|
|
108
|
+
this.clearExpiredEntries();
|
|
109
|
+
return super.keys();
|
|
110
|
+
}
|
|
111
|
+
values(): IterableIterator<TValue> {
|
|
112
|
+
this.clearExpiredEntries();
|
|
113
|
+
return super.values();
|
|
114
|
+
}
|
|
115
|
+
[Symbol.iterator](): IterableIterator<[TKey, TValue]> {
|
|
116
|
+
this.clearExpiredEntries();
|
|
117
|
+
return super[Symbol.iterator]();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
valueOf() {
|
|
121
|
+
this.clearExpiredEntries();
|
|
122
|
+
return super.valueOf();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -11,30 +11,33 @@ import * as api from "@fluidframework/protocol-definitions";
|
|
|
11
11
|
* Does not read/write anything.
|
|
12
12
|
*/
|
|
13
13
|
export class NullBlobStorageService implements IDocumentStorageService {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
public get repositoryUrl(): string {
|
|
15
|
+
throw new Error("Invalid operation");
|
|
16
|
+
}
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
public async getSnapshotTree(version?: api.IVersion): Promise<api.ISnapshotTree | null> {
|
|
19
|
+
return version ? Promise.reject(new Error("Invalid operation")) : null;
|
|
20
|
+
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
public async getVersions(versionId: string | null, count: number): Promise<api.IVersion[]> {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
public async uploadSummaryWithContext(
|
|
27
|
+
summary: api.ISummaryTree,
|
|
28
|
+
context: ISummaryContext,
|
|
29
|
+
): Promise<string> {
|
|
30
|
+
return Promise.reject(new Error("Invalid operation"));
|
|
31
|
+
}
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
public async downloadSummary(handle: api.ISummaryHandle): Promise<api.ISummaryTree> {
|
|
34
|
+
return Promise.reject(new Error("Invalid operation"));
|
|
35
|
+
}
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
public async createBlob(file: ArrayBufferLike): Promise<api.ICreateBlobResponse> {
|
|
38
|
+
return Promise.reject(new Error("Null blob storage can not create blob"));
|
|
39
|
+
}
|
|
40
|
+
public async readBlob(blobId: string): Promise<ArrayBufferLike> {
|
|
41
|
+
return Promise.reject(new Error("Null blob storage can not read blob"));
|
|
42
|
+
}
|
|
40
43
|
}
|
package/src/packageVersion.ts
CHANGED