@fluidframework/routerlicious-driver 2.0.0-dev.5.2.0.169897 → 2.0.0-dev.6.4.0.191258
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 +71 -0
- package/README.md +4 -3
- package/dist/contracts.d.ts +28 -1
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/createNewUtils.d.ts +1 -1
- package/dist/createNewUtils.js +3 -3
- package/dist/createNewUtils.js.map +1 -1
- package/dist/deltaStorageService.d.ts.map +1 -1
- package/dist/deltaStorageService.js +21 -10
- package/dist/deltaStorageService.js.map +1 -1
- package/dist/documentDeltaConnection.js +1 -1
- package/dist/documentDeltaConnection.js.map +1 -1
- package/dist/documentService.d.ts +3 -3
- package/dist/documentService.d.ts.map +1 -1
- package/dist/documentService.js +4 -4
- package/dist/documentService.js.map +1 -1
- package/dist/documentServiceFactory.d.ts +1 -1
- package/dist/documentServiceFactory.d.ts.map +1 -1
- package/dist/documentServiceFactory.js +32 -10
- package/dist/documentServiceFactory.js.map +1 -1
- package/dist/documentStorageService.d.ts +2 -2
- package/dist/documentStorageService.d.ts.map +1 -1
- package/dist/documentStorageService.js +2 -2
- package/dist/documentStorageService.js.map +1 -1
- package/dist/errorUtils.d.ts +38 -6
- package/dist/errorUtils.d.ts.map +1 -1
- package/dist/errorUtils.js +32 -16
- package/dist/errorUtils.js.map +1 -1
- package/dist/gitManager.d.ts +3 -2
- package/dist/gitManager.d.ts.map +1 -1
- package/dist/gitManager.js +2 -2
- package/dist/gitManager.js.map +1 -1
- package/dist/historian.d.ts +3 -2
- package/dist/historian.d.ts.map +1 -1
- package/dist/historian.js +13 -6
- package/dist/historian.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/mapWithExpiration.js +2 -2
- package/dist/mapWithExpiration.js.map +1 -1
- package/dist/nullBlobStorageService.js +4 -4
- 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 +7 -1
- package/dist/policies.d.ts.map +1 -1
- package/dist/policies.js.map +1 -1
- package/dist/r11sSnapshotParser.d.ts +4 -5
- package/dist/r11sSnapshotParser.d.ts.map +1 -1
- package/dist/r11sSnapshotParser.js +14 -16
- package/dist/r11sSnapshotParser.js.map +1 -1
- package/dist/restWrapper.d.ts +4 -4
- package/dist/restWrapper.d.ts.map +1 -1
- package/dist/restWrapper.js +53 -36
- package/dist/restWrapper.js.map +1 -1
- package/dist/restWrapperBase.js +39 -5
- package/dist/restWrapperBase.js.map +1 -1
- package/dist/retriableGitManager.d.ts +3 -2
- package/dist/retriableGitManager.d.ts.map +1 -1
- package/dist/retriableGitManager.js +2 -2
- package/dist/retriableGitManager.js.map +1 -1
- package/dist/shreddedSummaryDocumentStorageService.js +13 -16
- package/dist/shreddedSummaryDocumentStorageService.js.map +1 -1
- package/dist/storageContracts.d.ts +4 -3
- package/dist/storageContracts.d.ts.map +1 -1
- package/dist/storageContracts.js.map +1 -1
- package/dist/summaryTreeUploadManager.d.ts.map +1 -1
- package/dist/summaryTreeUploadManager.js +11 -11
- package/dist/summaryTreeUploadManager.js.map +1 -1
- package/dist/treeUtils.d.ts +2 -2
- package/dist/treeUtils.d.ts.map +1 -1
- package/dist/treeUtils.js +8 -8
- package/dist/treeUtils.js.map +1 -1
- package/dist/wholeSummaryDocumentStorageService.d.ts +2 -2
- package/dist/wholeSummaryDocumentStorageService.d.ts.map +1 -1
- package/dist/wholeSummaryDocumentStorageService.js +27 -22
- package/dist/wholeSummaryDocumentStorageService.js.map +1 -1
- package/dist/wholeSummaryUploadManager.js +1 -2
- package/dist/wholeSummaryUploadManager.js.map +1 -1
- package/lib/contracts.d.ts +28 -1
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/createNewUtils.d.ts +1 -1
- package/lib/createNewUtils.js +2 -2
- package/lib/createNewUtils.js.map +1 -1
- package/lib/deltaStorageService.d.ts.map +1 -1
- package/lib/deltaStorageService.js +22 -11
- package/lib/deltaStorageService.js.map +1 -1
- package/lib/documentDeltaConnection.js +1 -1
- package/lib/documentDeltaConnection.js.map +1 -1
- package/lib/documentService.d.ts +3 -3
- package/lib/documentService.d.ts.map +1 -1
- package/lib/documentService.js +4 -4
- package/lib/documentService.js.map +1 -1
- package/lib/documentServiceFactory.d.ts +1 -1
- package/lib/documentServiceFactory.d.ts.map +1 -1
- package/lib/documentServiceFactory.js +32 -10
- package/lib/documentServiceFactory.js.map +1 -1
- package/lib/documentStorageService.d.ts +2 -2
- package/lib/documentStorageService.d.ts.map +1 -1
- package/lib/documentStorageService.js +2 -2
- package/lib/documentStorageService.js.map +1 -1
- package/lib/errorUtils.d.ts +38 -6
- package/lib/errorUtils.d.ts.map +1 -1
- package/lib/errorUtils.js +31 -15
- package/lib/errorUtils.js.map +1 -1
- package/lib/gitManager.d.ts +3 -2
- package/lib/gitManager.d.ts.map +1 -1
- package/lib/gitManager.js +2 -2
- package/lib/gitManager.js.map +1 -1
- package/lib/historian.d.ts +3 -2
- package/lib/historian.d.ts.map +1 -1
- package/lib/historian.js +12 -5
- package/lib/historian.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/mapWithExpiration.js +1 -1
- package/lib/mapWithExpiration.js.map +1 -1
- package/lib/nullBlobStorageService.js +4 -4
- 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 +7 -1
- package/lib/policies.d.ts.map +1 -1
- package/lib/policies.js.map +1 -1
- package/lib/r11sSnapshotParser.d.ts +4 -5
- package/lib/r11sSnapshotParser.d.ts.map +1 -1
- package/lib/r11sSnapshotParser.js +12 -14
- package/lib/r11sSnapshotParser.js.map +1 -1
- package/lib/restWrapper.d.ts +4 -4
- package/lib/restWrapper.d.ts.map +1 -1
- package/lib/restWrapper.js +48 -31
- package/lib/restWrapper.js.map +1 -1
- package/lib/restWrapperBase.js +39 -5
- package/lib/restWrapperBase.js.map +1 -1
- package/lib/retriableGitManager.d.ts +3 -2
- package/lib/retriableGitManager.d.ts.map +1 -1
- package/lib/retriableGitManager.js +2 -2
- package/lib/retriableGitManager.js.map +1 -1
- package/lib/shreddedSummaryDocumentStorageService.js +12 -15
- package/lib/shreddedSummaryDocumentStorageService.js.map +1 -1
- package/lib/storageContracts.d.ts +4 -3
- package/lib/storageContracts.d.ts.map +1 -1
- package/lib/storageContracts.js.map +1 -1
- package/lib/summaryTreeUploadManager.d.ts.map +1 -1
- package/lib/summaryTreeUploadManager.js +4 -4
- package/lib/summaryTreeUploadManager.js.map +1 -1
- package/lib/treeUtils.d.ts +2 -2
- package/lib/treeUtils.d.ts.map +1 -1
- package/lib/treeUtils.js +4 -4
- package/lib/treeUtils.js.map +1 -1
- package/lib/wholeSummaryDocumentStorageService.d.ts +2 -2
- package/lib/wholeSummaryDocumentStorageService.d.ts.map +1 -1
- package/lib/wholeSummaryDocumentStorageService.js +23 -18
- package/lib/wholeSummaryDocumentStorageService.js.map +1 -1
- package/lib/wholeSummaryUploadManager.js +1 -2
- package/lib/wholeSummaryUploadManager.js.map +1 -1
- package/package.json +28 -33
- package/src/contracts.ts +45 -1
- package/src/createNewUtils.ts +2 -2
- package/src/deltaStorageService.ts +14 -11
- package/src/documentService.ts +5 -5
- package/src/documentServiceFactory.ts +22 -12
- package/src/documentStorageService.ts +3 -3
- package/src/errorUtils.ts +48 -30
- package/src/gitManager.ts +3 -3
- package/src/historian.ts +5 -5
- package/src/index.ts +1 -1
- package/src/mapWithExpiration.ts +1 -1
- package/src/nullBlobStorageService.ts +4 -4
- package/src/packageVersion.ts +1 -1
- package/src/policies.ts +7 -1
- package/src/r11sSnapshotParser.ts +15 -16
- package/src/restWrapper.ts +35 -22
- package/src/retriableGitManager.ts +3 -3
- package/src/shreddedSummaryDocumentStorageService.ts +3 -3
- package/src/storageContracts.ts +3 -3
- package/src/summaryTreeUploadManager.ts +2 -7
- package/src/treeUtils.ts +4 -3
- package/src/wholeSummaryDocumentStorageService.ts +14 -19
package/src/errorUtils.ts
CHANGED
|
@@ -3,25 +3,51 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
DriverError,
|
|
8
|
+
IDriverErrorBase,
|
|
9
|
+
DriverErrorTypes,
|
|
10
|
+
} from "@fluidframework/driver-definitions";
|
|
7
11
|
import {
|
|
8
12
|
NonRetryableError,
|
|
9
13
|
GenericNetworkError,
|
|
10
14
|
createGenericNetworkError,
|
|
11
15
|
AuthorizationError,
|
|
12
16
|
} from "@fluidframework/driver-utils";
|
|
17
|
+
import { IFluidErrorBase } from "@fluidframework/telemetry-utils";
|
|
13
18
|
import { pkgVersion as driverVersion } from "./packageVersion";
|
|
14
19
|
|
|
15
20
|
/**
|
|
16
21
|
* Routerlicious Error types
|
|
17
22
|
* Different error types that may be thrown by the routerlicious driver
|
|
18
23
|
*/
|
|
24
|
+
export const RouterliciousErrorTypes = {
|
|
25
|
+
// Inherit base driver error types
|
|
26
|
+
...DriverErrorTypes,
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* SSL Certificate Error.
|
|
30
|
+
*/
|
|
31
|
+
sslCertError: "sslCertError",
|
|
32
|
+
} as const;
|
|
33
|
+
export type RouterliciousErrorTypes =
|
|
34
|
+
typeof RouterliciousErrorTypes[keyof typeof RouterliciousErrorTypes];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Routerlicious Error types
|
|
38
|
+
* Different error types that may be thrown by the routerlicious driver
|
|
39
|
+
*
|
|
40
|
+
* @deprecated Use {@link (RouterliciousErrorTypes:variable)} instead.
|
|
41
|
+
*/
|
|
19
42
|
export enum RouterliciousErrorType {
|
|
20
43
|
/**
|
|
21
44
|
* File not found, or file deleted during session
|
|
22
45
|
*/
|
|
23
46
|
fileNotFoundOrAccessDeniedError = "fileNotFoundOrAccessDeniedError",
|
|
24
47
|
|
|
48
|
+
/**
|
|
49
|
+
* SSL Certificate Error.
|
|
50
|
+
*/
|
|
25
51
|
sslCertError = "sslCertError",
|
|
26
52
|
}
|
|
27
53
|
|
|
@@ -55,61 +81,53 @@ export interface IR11sSocketError {
|
|
|
55
81
|
retryAfterMs?: number;
|
|
56
82
|
}
|
|
57
83
|
|
|
58
|
-
export interface IR11sError {
|
|
84
|
+
export interface IR11sError extends Omit<IDriverErrorBase, "errorType"> {
|
|
59
85
|
readonly errorType: RouterliciousErrorType;
|
|
60
|
-
readonly message: string;
|
|
61
|
-
canRetry: boolean;
|
|
62
86
|
}
|
|
63
87
|
|
|
64
88
|
export type R11sError = DriverError | IR11sError;
|
|
65
89
|
|
|
66
90
|
export function createR11sNetworkError(
|
|
67
91
|
errorMessage: string,
|
|
68
|
-
statusCode
|
|
92
|
+
statusCode: number,
|
|
69
93
|
retryAfterMs?: number,
|
|
70
|
-
): R11sError {
|
|
94
|
+
): IFluidErrorBase & R11sError {
|
|
95
|
+
let error: IFluidErrorBase & R11sError;
|
|
71
96
|
const props = { statusCode, driverVersion };
|
|
72
97
|
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
98
|
case 401:
|
|
92
99
|
// The first 401 is manually retried in RouterliciousRestWrapper with a refreshed token,
|
|
93
100
|
// so we treat repeat 401s the same as 403.
|
|
94
101
|
case 403:
|
|
95
|
-
|
|
102
|
+
error = new AuthorizationError(errorMessage, undefined, undefined, props);
|
|
103
|
+
break;
|
|
96
104
|
case 404:
|
|
97
105
|
const errorType = RouterliciousErrorType.fileNotFoundOrAccessDeniedError;
|
|
98
|
-
|
|
106
|
+
error = new NonRetryableError(errorMessage, errorType, props);
|
|
107
|
+
break;
|
|
99
108
|
case 429:
|
|
100
|
-
|
|
109
|
+
error = createGenericNetworkError(
|
|
110
|
+
errorMessage,
|
|
111
|
+
{ canRetry: true, retryAfterMs },
|
|
112
|
+
props,
|
|
113
|
+
);
|
|
114
|
+
break;
|
|
101
115
|
case 500:
|
|
102
116
|
case 502:
|
|
103
|
-
|
|
117
|
+
error = new GenericNetworkError(errorMessage, true, props);
|
|
118
|
+
break;
|
|
104
119
|
default:
|
|
105
120
|
const retryInfo = { canRetry: retryAfterMs !== undefined, retryAfterMs };
|
|
106
|
-
|
|
121
|
+
error = createGenericNetworkError(errorMessage, retryInfo, props);
|
|
122
|
+
break;
|
|
107
123
|
}
|
|
124
|
+
error.addTelemetryProperties({ endpointReached: true });
|
|
125
|
+
return error;
|
|
108
126
|
}
|
|
109
127
|
|
|
110
128
|
export function throwR11sNetworkError(
|
|
111
129
|
errorMessage: string,
|
|
112
|
-
statusCode
|
|
130
|
+
statusCode: number,
|
|
113
131
|
retryAfterMs?: number,
|
|
114
132
|
): never {
|
|
115
133
|
const networkError = createR11sNetworkError(errorMessage, statusCode, retryAfterMs);
|
package/src/gitManager.ts
CHANGED
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
import * as resources from "@fluidframework/gitresources";
|
|
7
7
|
import {
|
|
8
|
-
IWholeFlatSummary,
|
|
9
8
|
IWholeSummaryPayload,
|
|
10
9
|
IWriteSummaryResponse,
|
|
11
10
|
} from "@fluidframework/server-services-client";
|
|
12
11
|
import { IGitManager, IHistorian } from "./storageContracts";
|
|
13
12
|
import { IR11sResponse, createR11sResponseFromContent } from "./restWrapper";
|
|
13
|
+
import { IWholeFlatSnapshot } from "./contracts";
|
|
14
14
|
|
|
15
15
|
export class GitManager implements IGitManager {
|
|
16
16
|
private readonly blobCache = new Map<string, resources.IBlob>();
|
|
@@ -110,7 +110,7 @@ export class GitManager implements IGitManager {
|
|
|
110
110
|
return this.historian.createSummary(summary, initial);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
public async
|
|
114
|
-
return this.historian.
|
|
113
|
+
public async getSnapshot(sha: string): Promise<IR11sResponse<IWholeFlatSnapshot>> {
|
|
114
|
+
return this.historian.getSnapshot(sha);
|
|
115
115
|
}
|
|
116
116
|
}
|
package/src/historian.ts
CHANGED
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { fromUtf8ToBase64 } from "@
|
|
6
|
+
import { fromUtf8ToBase64 } from "@fluid-internal/client-utils";
|
|
7
7
|
import * as git from "@fluidframework/gitresources";
|
|
8
8
|
import {
|
|
9
|
-
IWholeFlatSummary,
|
|
10
9
|
IWholeSummaryPayload,
|
|
11
10
|
IWriteSummaryResponse,
|
|
12
11
|
} from "@fluidframework/server-services-client";
|
|
13
12
|
import { QueryStringType, RestWrapper } from "./restWrapperBase";
|
|
14
13
|
import { IR11sResponse } from "./restWrapper";
|
|
15
14
|
import { IHistorian } from "./storageContracts";
|
|
15
|
+
import { IWholeFlatSnapshot } from "./contracts";
|
|
16
16
|
|
|
17
17
|
export interface ICredentials {
|
|
18
18
|
user: string;
|
|
@@ -65,7 +65,7 @@ export class Historian implements IHistorian {
|
|
|
65
65
|
): Promise<IR11sResponse<git.ICommitDetails[]>> {
|
|
66
66
|
return this.restWrapper
|
|
67
67
|
.get<git.ICommitDetails[]>(`/commits`, this.getQueryString({ count, sha }))
|
|
68
|
-
.catch((error) =>
|
|
68
|
+
.catch(async (error) =>
|
|
69
69
|
error.statusCode === 400 || error.statusCode === 404
|
|
70
70
|
? {
|
|
71
71
|
content: [],
|
|
@@ -98,8 +98,8 @@ export class Historian implements IHistorian {
|
|
|
98
98
|
);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
public async
|
|
102
|
-
return this.restWrapper.get<
|
|
101
|
+
public async getSnapshot(sha: string): Promise<IR11sResponse<IWholeFlatSnapshot>> {
|
|
102
|
+
return this.restWrapper.get<IWholeFlatSnapshot>(
|
|
103
103
|
`/git/summaries/${sha}`,
|
|
104
104
|
this.getQueryString(),
|
|
105
105
|
);
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { DefaultTokenProvider } from "./defaultTokenProvider";
|
|
|
8
8
|
export { ITokenProvider, ITokenResponse, ITokenService } from "./tokens";
|
|
9
9
|
|
|
10
10
|
// Errors
|
|
11
|
-
export { RouterliciousErrorType } from "./errorUtils";
|
|
11
|
+
export { RouterliciousErrorType, RouterliciousErrorTypes } from "./errorUtils";
|
|
12
12
|
|
|
13
13
|
// Factory
|
|
14
14
|
export {
|
package/src/mapWithExpiration.ts
CHANGED
|
@@ -27,17 +27,17 @@ export class NullBlobStorageService implements IDocumentStorageService {
|
|
|
27
27
|
summary: api.ISummaryTree,
|
|
28
28
|
context: ISummaryContext,
|
|
29
29
|
): Promise<string> {
|
|
30
|
-
|
|
30
|
+
throw new Error("Invalid operation");
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
public async downloadSummary(handle: api.ISummaryHandle): Promise<api.ISummaryTree> {
|
|
34
|
-
|
|
34
|
+
throw new Error("Invalid operation");
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
public async createBlob(file: ArrayBufferLike): Promise<api.ICreateBlobResponse> {
|
|
38
|
-
|
|
38
|
+
throw new Error("Null blob storage can not create blob");
|
|
39
39
|
}
|
|
40
40
|
public async readBlob(blobId: string): Promise<ArrayBufferLike> {
|
|
41
|
-
|
|
41
|
+
throw new Error("Null blob storage can not read blob");
|
|
42
42
|
}
|
|
43
43
|
}
|
package/src/packageVersion.ts
CHANGED
package/src/policies.ts
CHANGED
|
@@ -36,7 +36,7 @@ export interface IRouterliciousDriverPolicies {
|
|
|
36
36
|
* Enable service endpoint discovery when creating or joining a session.
|
|
37
37
|
* Default: false
|
|
38
38
|
*/
|
|
39
|
-
enableDiscovery
|
|
39
|
+
enableDiscovery: boolean;
|
|
40
40
|
/**
|
|
41
41
|
* Enable using RestLess which avoids CORS preflight requests.
|
|
42
42
|
* Default: true
|
|
@@ -54,4 +54,10 @@ export interface IRouterliciousDriverPolicies {
|
|
|
54
54
|
* Default: true
|
|
55
55
|
*/
|
|
56
56
|
enableLongPollingDowngrade: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Indicates that the container is ephemeral.
|
|
59
|
+
* Artifacts relates to the container are limited to container lifetime.
|
|
60
|
+
* Default: false
|
|
61
|
+
*/
|
|
62
|
+
isEphemeralContainer: boolean;
|
|
57
63
|
}
|
|
@@ -4,19 +4,18 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { ISnapshotTree } from "@fluidframework/protocol-definitions";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { INormalizedWholeSummary } from "./contracts";
|
|
7
|
+
import { stringToBuffer } from "@fluid-internal/client-utils";
|
|
8
|
+
import { INormalizedWholeSnapshot, IWholeFlatSnapshot, IWholeFlatSnapshotTree } from "./contracts";
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
|
-
* Build a tree
|
|
11
|
+
* Build a tree hierarchy from a flat tree.
|
|
13
12
|
*
|
|
14
13
|
* @param flatTree - a flat tree
|
|
15
14
|
* @param treePrefixToRemove - tree prefix to strip
|
|
16
15
|
* @returns the heirarchical tree
|
|
17
16
|
*/
|
|
18
17
|
function buildHierarchy(
|
|
19
|
-
flatTree:
|
|
18
|
+
flatTree: IWholeFlatSnapshotTree,
|
|
20
19
|
treePrefixToRemove: string,
|
|
21
20
|
): ISnapshotTree {
|
|
22
21
|
const lookup: { [path: string]: ISnapshotTree } = {};
|
|
@@ -54,30 +53,30 @@ function buildHierarchy(
|
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
/**
|
|
57
|
-
* Converts existing
|
|
56
|
+
* Converts existing IWholeFlatSnapshot to snapshot tree, blob array, and sequence number.
|
|
58
57
|
*
|
|
59
|
-
* @param
|
|
58
|
+
* @param flatSnapshot - flat snapshot
|
|
60
59
|
* @param treePrefixToRemove - tree prefix to strip. By default we are stripping ".app" prefix
|
|
61
60
|
* @returns snapshot tree, blob array, and sequence number
|
|
62
61
|
*/
|
|
63
|
-
export function
|
|
64
|
-
|
|
62
|
+
export function convertWholeFlatSnapshotToSnapshotTreeAndBlobs(
|
|
63
|
+
flatSnapshot: IWholeFlatSnapshot,
|
|
65
64
|
treePrefixToRemove: string = ".app",
|
|
66
|
-
):
|
|
65
|
+
): INormalizedWholeSnapshot {
|
|
67
66
|
const blobs = new Map<string, ArrayBuffer>();
|
|
68
|
-
if (
|
|
69
|
-
|
|
67
|
+
if (flatSnapshot.blobs) {
|
|
68
|
+
flatSnapshot.blobs.forEach((blob) => {
|
|
70
69
|
blobs.set(blob.id, stringToBuffer(blob.content, blob.encoding ?? "utf-8"));
|
|
71
70
|
});
|
|
72
71
|
}
|
|
73
|
-
const
|
|
74
|
-
const sequenceNumber =
|
|
75
|
-
const snapshotTree = buildHierarchy(
|
|
72
|
+
const flatSnapshotTree = flatSnapshot.trees?.[0];
|
|
73
|
+
const sequenceNumber = flatSnapshotTree?.sequenceNumber;
|
|
74
|
+
const snapshotTree = buildHierarchy(flatSnapshotTree, treePrefixToRemove);
|
|
76
75
|
|
|
77
76
|
return {
|
|
78
77
|
blobs,
|
|
79
78
|
snapshotTree,
|
|
80
79
|
sequenceNumber,
|
|
81
|
-
id:
|
|
80
|
+
id: flatSnapshot.id,
|
|
82
81
|
};
|
|
83
82
|
}
|
package/src/restWrapper.ts
CHANGED
|
@@ -3,23 +3,25 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { ITelemetryProperties } from "@fluidframework/
|
|
6
|
+
import { ITelemetryProperties } from "@fluidframework/core-interfaces";
|
|
7
7
|
import {
|
|
8
8
|
ITelemetryLoggerExt,
|
|
9
9
|
PerformanceEvent,
|
|
10
|
-
|
|
10
|
+
numberFromString,
|
|
11
11
|
} from "@fluidframework/telemetry-utils";
|
|
12
|
-
import { assert
|
|
13
|
-
import {
|
|
12
|
+
import { assert } from "@fluidframework/core-utils";
|
|
13
|
+
import { fromUtf8ToBase64, performance } from "@fluid-internal/client-utils";
|
|
14
|
+
import { GenericNetworkError, NonRetryableError, RateLimiter } from "@fluidframework/driver-utils";
|
|
14
15
|
import {
|
|
16
|
+
CorrelationIdHeaderName,
|
|
17
|
+
DriverVersionHeaderName,
|
|
15
18
|
getAuthorizationTokenFromCredentials,
|
|
16
19
|
RestLessClient,
|
|
17
20
|
} from "@fluidframework/server-services-client";
|
|
18
21
|
import fetch from "cross-fetch";
|
|
19
22
|
import type { AxiosRequestConfig, AxiosRequestHeaders } from "axios";
|
|
20
23
|
import safeStringify from "json-stringify-safe";
|
|
21
|
-
import {
|
|
22
|
-
import { throwR11sNetworkError } from "./errorUtils";
|
|
24
|
+
import { RouterliciousErrorTypes, throwR11sNetworkError } from "./errorUtils";
|
|
23
25
|
import { ITokenProvider, ITokenResponse } from "./tokens";
|
|
24
26
|
import { pkgVersion as driverVersion } from "./packageVersion";
|
|
25
27
|
import { QueryStringType, RestWrapper } from "./restWrapperBase";
|
|
@@ -52,9 +54,9 @@ export interface IR11sResponse<T> {
|
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/**
|
|
55
|
-
* A utility function to create a
|
|
56
|
-
* @param content -
|
|
57
|
-
* @returns
|
|
57
|
+
* A utility function to create a Routerlicious response without any additional props as we might not have them always.
|
|
58
|
+
* @param content - Response which is equivalent to content.
|
|
59
|
+
* @returns A Routerlicious response without any extra props.
|
|
58
60
|
*/
|
|
59
61
|
export function createR11sResponseFromContent<T>(content: T): IR11sResponse<T> {
|
|
60
62
|
return {
|
|
@@ -84,12 +86,12 @@ export function getPropsToLogFromResponse(headers: {
|
|
|
84
86
|
// We rename headers so that otel doesn't scrub them away. Otel doesn't allow
|
|
85
87
|
// certain characters in headers including '-'
|
|
86
88
|
const headersToLog: LoggingHeader[] = [
|
|
87
|
-
{ headerName:
|
|
89
|
+
{ headerName: CorrelationIdHeaderName, logName: "requestCorrelationId" },
|
|
88
90
|
{ headerName: "content-encoding", logName: "contentEncoding" },
|
|
89
91
|
{ headerName: "content-type", logName: "contentType" },
|
|
90
92
|
];
|
|
91
93
|
const additionalProps: ITelemetryProperties = {
|
|
92
|
-
contentsize:
|
|
94
|
+
contentsize: numberFromString(headers.get("content-length")),
|
|
93
95
|
};
|
|
94
96
|
headersToLog.forEach((header) => {
|
|
95
97
|
const headerValue = headers.get(header.headerName);
|
|
@@ -136,9 +138,24 @@ export class RouterliciousRestWrapper extends RestWrapper {
|
|
|
136
138
|
const result = await fetch(...fetchRequestConfig).catch(async (error) => {
|
|
137
139
|
// Browser Fetch throws a TypeError on network error, `node-fetch` throws a FetchError
|
|
138
140
|
const isNetworkError = ["TypeError", "FetchError"].includes(error?.name);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
const errorMessage = isNetworkError
|
|
142
|
+
? `NetworkError: ${error.message}`
|
|
143
|
+
: safeStringify(error);
|
|
144
|
+
// If a service is temporarily down or a browser resource limit is reached, RestWrapper will throw
|
|
145
|
+
// a network error with no status code (e.g. err:ERR_CONN_REFUSED or err:ERR_FAILED) and
|
|
146
|
+
// the error message will start with NetworkError as defined in restWrapper.ts
|
|
147
|
+
// If there exists a self-signed SSL certificates error, throw a NonRetryableError
|
|
148
|
+
// TODO: instead of relying on string matching, filter error based on the error code like we do for websocket connections
|
|
149
|
+
const err = errorMessage.includes("failed, reason: self signed certificate")
|
|
150
|
+
? new NonRetryableError(errorMessage, RouterliciousErrorTypes.sslCertError, {
|
|
151
|
+
driverVersion,
|
|
152
|
+
})
|
|
153
|
+
: new GenericNetworkError(
|
|
154
|
+
errorMessage,
|
|
155
|
+
errorMessage.startsWith("NetworkError"),
|
|
156
|
+
{ driverVersion },
|
|
157
|
+
);
|
|
158
|
+
throw err;
|
|
142
159
|
});
|
|
143
160
|
return {
|
|
144
161
|
response: result,
|
|
@@ -209,17 +226,13 @@ export class RouterliciousRestWrapper extends RestWrapper {
|
|
|
209
226
|
): Promise<Record<string, string>> {
|
|
210
227
|
const token = await this.getToken();
|
|
211
228
|
assert(token !== undefined, 0x679 /* token should be present */);
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
return {
|
|
229
|
+
const headers: Record<string, string> = {
|
|
215
230
|
...requestHeaders,
|
|
216
|
-
|
|
217
|
-
// NOTE: Can correlationId actually be number | true?
|
|
218
|
-
"x-correlation-id": correlationId as string,
|
|
219
|
-
"x-driver-version": driverVersion,
|
|
231
|
+
[DriverVersionHeaderName]: driverVersion,
|
|
220
232
|
// NOTE: If this.authorizationHeader is undefined, should "Authorization" be removed entirely?
|
|
221
|
-
|
|
233
|
+
Authorization: this.getAuthorizationHeader(token),
|
|
222
234
|
};
|
|
235
|
+
return headers;
|
|
223
236
|
}
|
|
224
237
|
|
|
225
238
|
public async getToken(): Promise<ITokenResponse> {
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
import type * as git from "@fluidframework/gitresources";
|
|
7
7
|
import {
|
|
8
|
-
IWholeFlatSummary,
|
|
9
8
|
IWholeSummaryPayload,
|
|
10
9
|
IWriteSummaryResponse,
|
|
11
10
|
} from "@fluidframework/server-services-client";
|
|
@@ -13,6 +12,7 @@ import { runWithRetry } from "@fluidframework/driver-utils";
|
|
|
13
12
|
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
|
|
14
13
|
import { IGitManager } from "./storageContracts";
|
|
15
14
|
import { IR11sResponse } from "./restWrapper";
|
|
15
|
+
import { IWholeFlatSnapshot } from "./contracts";
|
|
16
16
|
|
|
17
17
|
export class RetriableGitManager implements IGitManager {
|
|
18
18
|
constructor(
|
|
@@ -70,9 +70,9 @@ export class RetriableGitManager implements IGitManager {
|
|
|
70
70
|
);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
public async
|
|
73
|
+
public async getSnapshot(sha: string): Promise<IR11sResponse<IWholeFlatSnapshot>> {
|
|
74
74
|
return this.runWithRetry(
|
|
75
|
-
async () => this.internalGitManager.
|
|
75
|
+
async () => this.internalGitManager.getSnapshot(sha),
|
|
76
76
|
"gitManager_getSummary",
|
|
77
77
|
);
|
|
78
78
|
}
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { ITelemetryLoggerExt, PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
7
|
-
import { stringToBuffer, Uint8ArrayToString } from "@
|
|
7
|
+
import { stringToBuffer, Uint8ArrayToString } from "@fluid-internal/client-utils";
|
|
8
8
|
import {
|
|
9
9
|
IDocumentStorageService,
|
|
10
10
|
ISummaryContext,
|
|
11
11
|
IDocumentStorageServicePolicies,
|
|
12
12
|
} from "@fluidframework/driver-definitions";
|
|
13
|
-
import {
|
|
13
|
+
import { buildGitTreeHierarchy } from "@fluidframework/protocol-base";
|
|
14
14
|
import {
|
|
15
15
|
ICreateBlobResponse,
|
|
16
16
|
ISnapshotTreeEx,
|
|
@@ -125,7 +125,7 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
125
125
|
return response;
|
|
126
126
|
},
|
|
127
127
|
);
|
|
128
|
-
const tree =
|
|
128
|
+
const tree = buildGitTreeHierarchy(rawTree, this.blobsShaCache, true);
|
|
129
129
|
await this.snapshotTreeCache?.put(this.getCacheKey(tree.id), {
|
|
130
130
|
id: requestVersion.id,
|
|
131
131
|
snapshotTree: tree,
|
package/src/storageContracts.ts
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
import * as git from "@fluidframework/gitresources";
|
|
7
7
|
import * as api from "@fluidframework/protocol-definitions";
|
|
8
8
|
import {
|
|
9
|
-
IWholeFlatSummary,
|
|
10
9
|
IWholeSummaryPayload,
|
|
11
10
|
IWholeSummaryPayloadType,
|
|
12
11
|
IWriteSummaryResponse,
|
|
13
12
|
} from "@fluidframework/server-services-client";
|
|
14
13
|
import { IR11sResponse } from "./restWrapper";
|
|
14
|
+
import { IWholeFlatSnapshot } from "./contracts";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Interface to a generic Git provider
|
|
@@ -26,7 +26,7 @@ export interface IHistorian {
|
|
|
26
26
|
summary: IWholeSummaryPayload,
|
|
27
27
|
initial?: boolean,
|
|
28
28
|
): Promise<IR11sResponse<IWriteSummaryResponse>>;
|
|
29
|
-
|
|
29
|
+
getSnapshot(sha: string): Promise<IR11sResponse<IWholeFlatSnapshot>>;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export interface IGitManager {
|
|
@@ -39,7 +39,7 @@ export interface IGitManager {
|
|
|
39
39
|
summary: IWholeSummaryPayload,
|
|
40
40
|
initial?: boolean,
|
|
41
41
|
): Promise<IR11sResponse<IWriteSummaryResponse>>;
|
|
42
|
-
|
|
42
|
+
getSnapshot(sha: string): Promise<IR11sResponse<IWholeFlatSnapshot>>;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -3,13 +3,8 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
gitHashFile,
|
|
9
|
-
IsoBuffer,
|
|
10
|
-
Uint8ArrayToString,
|
|
11
|
-
unreachableCase,
|
|
12
|
-
} from "@fluidframework/common-utils";
|
|
6
|
+
import { gitHashFile, IsoBuffer, Uint8ArrayToString } from "@fluid-internal/client-utils";
|
|
7
|
+
import { assert, unreachableCase } from "@fluidframework/core-utils";
|
|
13
8
|
import { ICreateTreeEntry } from "@fluidframework/gitresources";
|
|
14
9
|
import { getGitMode, getGitType } from "@fluidframework/protocol-base";
|
|
15
10
|
import {
|
package/src/treeUtils.ts
CHANGED
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { IsoBuffer } from "@fluid-internal/client-utils";
|
|
7
|
+
import { assert } from "@fluidframework/core-utils";
|
|
7
8
|
import {
|
|
8
9
|
SummaryType,
|
|
9
10
|
ISnapshotTree,
|
|
10
11
|
ISummaryTree,
|
|
11
12
|
SummaryObject,
|
|
12
13
|
} from "@fluidframework/protocol-definitions";
|
|
13
|
-
import {
|
|
14
|
+
import { INormalizedWholeSnapshot } from "./contracts";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Summary tree assembler props
|
|
@@ -107,7 +108,7 @@ export function convertSnapshotAndBlobsToSummaryTree(
|
|
|
107
108
|
return assembler.summary;
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
export function evalBlobsAndTrees(snapshot:
|
|
111
|
+
export function evalBlobsAndTrees(snapshot: INormalizedWholeSnapshot) {
|
|
111
112
|
const trees = countTreesInSnapshotTree(snapshot.snapshotTree);
|
|
112
113
|
const numBlobs = snapshot.blobs.size;
|
|
113
114
|
let encodedBlobsSize = 0;
|