@fluidframework/driver-utils 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 +17 -19
- package/.mocharc.js +2 -2
- package/api-extractor.json +2 -2
- package/dist/buildSnapshotTree.d.ts.map +1 -1
- package/dist/buildSnapshotTree.js.map +1 -1
- package/dist/documentStorageServiceProxy.d.ts.map +1 -1
- package/dist/documentStorageServiceProxy.js.map +1 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js.map +1 -1
- package/dist/fluidResolvedUrl.d.ts +8 -0
- package/dist/fluidResolvedUrl.d.ts.map +1 -1
- package/dist/fluidResolvedUrl.js +8 -0
- package/dist/fluidResolvedUrl.js.map +1 -1
- package/dist/index.d.ts +4 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -19
- package/dist/index.js.map +1 -1
- package/dist/insecureUrlResolver.d.ts.map +1 -1
- package/dist/insecureUrlResolver.js +2 -1
- package/dist/insecureUrlResolver.js.map +1 -1
- package/dist/messageRecognition.d.ts +0 -20
- package/dist/messageRecognition.d.ts.map +1 -1
- package/dist/messageRecognition.js +1 -37
- package/dist/messageRecognition.js.map +1 -1
- package/dist/network.d.ts +0 -15
- package/dist/network.d.ts.map +1 -1
- package/dist/network.js +4 -3
- package/dist/network.js.map +1 -1
- package/dist/networkUtils.d.ts +0 -10
- package/dist/networkUtils.d.ts.map +1 -1
- package/dist/networkUtils.js +3 -35
- package/dist/networkUtils.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/parallelRequests.d.ts.map +1 -1
- package/dist/parallelRequests.js +52 -23
- package/dist/parallelRequests.js.map +1 -1
- package/dist/prefetchDocumentStorageService.d.ts.map +1 -1
- package/dist/prefetchDocumentStorageService.js.map +1 -1
- package/dist/rateLimiter.d.ts.map +1 -1
- package/dist/rateLimiter.js.map +1 -1
- package/dist/readAndParse.d.ts.map +1 -1
- package/dist/readAndParse.js.map +1 -1
- package/dist/runWithRetry.d.ts.map +1 -1
- package/dist/runWithRetry.js +10 -0
- package/dist/runWithRetry.js.map +1 -1
- package/dist/summaryForCreateNew.d.ts +21 -1
- package/dist/summaryForCreateNew.d.ts.map +1 -1
- package/dist/summaryForCreateNew.js +26 -1
- package/dist/summaryForCreateNew.js.map +1 -1
- package/dist/treeConversions.d.ts.map +1 -1
- package/dist/treeConversions.js +6 -10
- package/dist/treeConversions.js.map +1 -1
- package/lib/buildSnapshotTree.d.ts.map +1 -1
- package/lib/buildSnapshotTree.js.map +1 -1
- package/lib/documentStorageServiceProxy.d.ts.map +1 -1
- package/lib/documentStorageServiceProxy.js.map +1 -1
- package/lib/error.d.ts.map +1 -1
- package/lib/error.js.map +1 -1
- package/lib/fluidResolvedUrl.d.ts +8 -0
- package/lib/fluidResolvedUrl.d.ts.map +1 -1
- package/lib/fluidResolvedUrl.js +8 -0
- package/lib/fluidResolvedUrl.js.map +1 -1
- package/lib/index.d.ts +4 -10
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -9
- package/lib/index.js.map +1 -1
- package/lib/insecureUrlResolver.d.ts.map +1 -1
- package/lib/insecureUrlResolver.js +2 -1
- package/lib/insecureUrlResolver.js.map +1 -1
- package/lib/messageRecognition.d.ts +0 -20
- package/lib/messageRecognition.d.ts.map +1 -1
- package/lib/messageRecognition.js +1 -36
- package/lib/messageRecognition.js.map +1 -1
- package/lib/network.d.ts +0 -15
- package/lib/network.d.ts.map +1 -1
- package/lib/network.js +4 -3
- package/lib/network.js.map +1 -1
- package/lib/networkUtils.d.ts +0 -10
- package/lib/networkUtils.d.ts.map +1 -1
- package/lib/networkUtils.js +2 -33
- package/lib/networkUtils.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/parallelRequests.d.ts.map +1 -1
- package/lib/parallelRequests.js +53 -24
- package/lib/parallelRequests.js.map +1 -1
- package/lib/prefetchDocumentStorageService.d.ts.map +1 -1
- package/lib/prefetchDocumentStorageService.js.map +1 -1
- package/lib/rateLimiter.d.ts.map +1 -1
- package/lib/rateLimiter.js.map +1 -1
- package/lib/readAndParse.d.ts.map +1 -1
- package/lib/readAndParse.js.map +1 -1
- package/lib/runWithRetry.d.ts.map +1 -1
- package/lib/runWithRetry.js +10 -0
- package/lib/runWithRetry.js.map +1 -1
- package/lib/summaryForCreateNew.d.ts +21 -1
- package/lib/summaryForCreateNew.d.ts.map +1 -1
- package/lib/summaryForCreateNew.js +24 -0
- package/lib/summaryForCreateNew.js.map +1 -1
- package/lib/treeConversions.d.ts.map +1 -1
- package/lib/treeConversions.js +9 -13
- package/lib/treeConversions.js.map +1 -1
- package/package.json +54 -52
- package/prettier.config.cjs +1 -1
- package/src/buildSnapshotTree.ts +54 -51
- package/src/documentStorageServiceProxy.ts +49 -43
- package/src/error.ts +5 -7
- package/src/fluidResolvedUrl.ts +17 -6
- package/src/index.ts +4 -14
- package/src/insecureUrlResolver.ts +127 -116
- package/src/messageRecognition.ts +14 -44
- package/src/network.ts +112 -126
- package/src/networkUtils.ts +19 -48
- package/src/packageVersion.ts +1 -1
- package/src/parallelRequests.ts +591 -510
- package/src/prefetchDocumentStorageService.ts +76 -74
- package/src/rateLimiter.ts +29 -29
- package/src/readAndParse.ts +7 -4
- package/src/runWithRetry.ts +106 -84
- package/src/summaryForCreateNew.ts +74 -25
- package/src/treeConversions.ts +47 -70
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +8 -12
- package/dist/blobAggregationStorage.d.ts +0 -43
- package/dist/blobAggregationStorage.d.ts.map +0 -1
- package/dist/blobAggregationStorage.js +0 -318
- package/dist/blobAggregationStorage.js.map +0 -1
- package/dist/blobCacheStorageService.d.ts +0 -16
- package/dist/blobCacheStorageService.d.ts.map +0 -1
- package/dist/blobCacheStorageService.js +0 -29
- package/dist/blobCacheStorageService.js.map +0 -1
- package/dist/emptyDocumentDeltaStorageService.d.ts +0 -13
- package/dist/emptyDocumentDeltaStorageService.d.ts.map +0 -1
- package/dist/emptyDocumentDeltaStorageService.js +0 -20
- package/dist/emptyDocumentDeltaStorageService.js.map +0 -1
- package/dist/multiDocumentServiceFactory.d.ts +0 -16
- package/dist/multiDocumentServiceFactory.d.ts.map +0 -1
- package/dist/multiDocumentServiceFactory.js +0 -63
- package/dist/multiDocumentServiceFactory.js.map +0 -1
- package/dist/multiUrlResolver.d.ts +0 -20
- package/dist/multiUrlResolver.d.ts.map +0 -1
- package/dist/multiUrlResolver.js +0 -45
- package/dist/multiUrlResolver.js.map +0 -1
- package/dist/treeUtils.d.ts +0 -51
- package/dist/treeUtils.d.ts.map +0 -1
- package/dist/treeUtils.js +0 -85
- package/dist/treeUtils.js.map +0 -1
- package/lib/blobAggregationStorage.d.ts +0 -43
- package/lib/blobAggregationStorage.d.ts.map +0 -1
- package/lib/blobAggregationStorage.js +0 -313
- package/lib/blobAggregationStorage.js.map +0 -1
- package/lib/blobCacheStorageService.d.ts +0 -16
- package/lib/blobCacheStorageService.d.ts.map +0 -1
- package/lib/blobCacheStorageService.js +0 -25
- package/lib/blobCacheStorageService.js.map +0 -1
- package/lib/emptyDocumentDeltaStorageService.d.ts +0 -13
- package/lib/emptyDocumentDeltaStorageService.d.ts.map +0 -1
- package/lib/emptyDocumentDeltaStorageService.js +0 -16
- package/lib/emptyDocumentDeltaStorageService.js.map +0 -1
- package/lib/multiDocumentServiceFactory.d.ts +0 -16
- package/lib/multiDocumentServiceFactory.d.ts.map +0 -1
- package/lib/multiDocumentServiceFactory.js +0 -59
- package/lib/multiDocumentServiceFactory.js.map +0 -1
- package/lib/multiUrlResolver.d.ts +0 -20
- package/lib/multiUrlResolver.d.ts.map +0 -1
- package/lib/multiUrlResolver.js +0 -40
- package/lib/multiUrlResolver.js.map +0 -1
- package/lib/treeUtils.d.ts +0 -51
- package/lib/treeUtils.d.ts.map +0 -1
- package/lib/treeUtils.js +0 -80
- package/lib/treeUtils.js.map +0 -1
- package/src/blobAggregationStorage.ts +0 -374
- package/src/blobCacheStorageService.ts +0 -32
- package/src/emptyDocumentDeltaStorageService.ts +0 -24
- package/src/multiDocumentServiceFactory.ts +0 -80
- package/src/multiUrlResolver.ts +0 -51
- package/src/treeUtils.ts +0 -111
|
@@ -7,10 +7,10 @@ import { parse } from "url";
|
|
|
7
7
|
import { assert } from "@fluidframework/common-utils";
|
|
8
8
|
import { IRequest } from "@fluidframework/core-interfaces";
|
|
9
9
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
IFluidResolvedUrl,
|
|
11
|
+
IResolvedUrl,
|
|
12
|
+
IUrlResolver,
|
|
13
|
+
DriverHeader,
|
|
14
14
|
} from "@fluidframework/driver-definitions";
|
|
15
15
|
import Axios from "axios";
|
|
16
16
|
|
|
@@ -29,128 +29,139 @@ import Axios from "axios";
|
|
|
29
29
|
* works or a router inside of a single page app framework.
|
|
30
30
|
*/
|
|
31
31
|
export class InsecureUrlResolver implements IUrlResolver {
|
|
32
|
-
|
|
32
|
+
private readonly cache = new Map<string, Promise<IResolvedUrl>>();
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
constructor(
|
|
35
|
+
private readonly hostUrl: string,
|
|
36
|
+
private readonly ordererUrl: string,
|
|
37
|
+
private readonly storageUrl: string,
|
|
38
|
+
private readonly tenantId: string,
|
|
39
|
+
private readonly bearer: string,
|
|
40
|
+
private readonly isForNodeTest: boolean = false,
|
|
41
|
+
) {}
|
|
42
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
|
-
|
|
43
|
+
public async resolve(request: IRequest): Promise<IResolvedUrl | undefined> {
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
45
|
+
if (request.headers?.[DriverHeader.createNew]) {
|
|
46
|
+
const [, queryString] = request.url.split("?");
|
|
47
|
+
const searchParams = new URLSearchParams(queryString);
|
|
48
|
+
const fileName = searchParams.get("fileName");
|
|
49
|
+
return this.resolveHelper(fileName);
|
|
50
|
+
}
|
|
51
|
+
const parsedUrl = new URL(request.url);
|
|
52
|
+
// If hosts match then we use the local tenant information. Otherwise we make a REST call out to the hosting
|
|
53
|
+
// service using our bearer token.
|
|
54
|
+
if (this.isForNodeTest) {
|
|
55
|
+
const [, documentId, tmpRelativePath] = parsedUrl.pathname.substr(1).split("/");
|
|
56
|
+
const relativePath = tmpRelativePath === undefined ? "" : tmpRelativePath;
|
|
57
|
+
return this.resolveHelper(documentId, relativePath, parsedUrl.search);
|
|
58
|
+
} else if (parsedUrl.host === window.location.host) {
|
|
59
|
+
const fullPath = parsedUrl.pathname.substr(1);
|
|
60
|
+
const documentId = fullPath.split("/")[0];
|
|
61
|
+
const documentRelativePath = fullPath.slice(documentId.length);
|
|
62
|
+
return this.resolveHelper(documentId, documentRelativePath);
|
|
63
|
+
} else {
|
|
64
|
+
const maybeResolvedUrl = this.cache.get(request.url);
|
|
65
|
+
if (maybeResolvedUrl) {
|
|
66
|
+
return maybeResolvedUrl;
|
|
67
|
+
}
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
69
|
+
const headers = {
|
|
70
|
+
Authorization: `Bearer ${this.bearer}`,
|
|
71
|
+
};
|
|
72
|
+
const resolvedP = Axios.post<IResolvedUrl>(
|
|
73
|
+
`${this.hostUrl}/api/v1/load`,
|
|
74
|
+
{
|
|
75
|
+
url: request.url,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
headers,
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
this.cache.set(
|
|
82
|
+
request.url,
|
|
83
|
+
resolvedP.then((resolved) => resolved.data),
|
|
84
|
+
);
|
|
81
85
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
86
|
+
return this.cache.get(request.url);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
90
|
+
private resolveHelper(
|
|
91
|
+
documentId: string | null,
|
|
92
|
+
documentRelativePath: string = "",
|
|
93
|
+
queryParams: string = "",
|
|
94
|
+
) {
|
|
95
|
+
const encodedTenantId = encodeURIComponent(this.tenantId);
|
|
96
|
+
const host = new URL(this.ordererUrl).host;
|
|
97
|
+
// when the document ID is not provided we need to resolve a special create new document URL.
|
|
98
|
+
// the actual container ID will be generated by the driver.
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
100
|
+
if (!documentId) {
|
|
101
|
+
const createNewResponse: IFluidResolvedUrl = {
|
|
102
|
+
endpoints: {
|
|
103
|
+
deltaStorageUrl: `${this.ordererUrl}/deltas/${encodedTenantId}/new`,
|
|
104
|
+
ordererUrl: this.ordererUrl,
|
|
105
|
+
storageUrl: `${this.storageUrl}/repos/${encodedTenantId}`,
|
|
106
|
+
},
|
|
107
|
+
// document ID is ignored by the driver for new container requests
|
|
108
|
+
id: "",
|
|
109
|
+
tokens: {},
|
|
110
|
+
type: "fluid",
|
|
111
|
+
url: `fluid://${host}/${encodedTenantId}/new`,
|
|
112
|
+
};
|
|
113
|
+
return createNewResponse;
|
|
114
|
+
}
|
|
115
|
+
const encodedDocId = encodeURIComponent(documentId);
|
|
116
|
+
const relativePath =
|
|
117
|
+
!documentRelativePath || documentRelativePath.startsWith("/")
|
|
118
|
+
? documentRelativePath
|
|
119
|
+
: `/${documentRelativePath}`;
|
|
120
|
+
const documentUrl = `fluid://${host}/${encodedTenantId}/${encodedDocId}${relativePath}${queryParams}`;
|
|
111
121
|
|
|
112
|
-
|
|
113
|
-
|
|
122
|
+
const deltaStorageUrl = `${this.ordererUrl}/deltas/${encodedTenantId}/${encodedDocId}`;
|
|
123
|
+
const storageUrl = `${this.storageUrl}/repos/${encodedTenantId}`;
|
|
114
124
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
const response: IFluidResolvedUrl = {
|
|
126
|
+
endpoints: {
|
|
127
|
+
deltaStorageUrl,
|
|
128
|
+
ordererUrl: this.ordererUrl,
|
|
129
|
+
storageUrl,
|
|
130
|
+
},
|
|
131
|
+
id: documentId,
|
|
132
|
+
tokens: {},
|
|
133
|
+
type: "fluid",
|
|
134
|
+
url: documentUrl,
|
|
135
|
+
};
|
|
136
|
+
return response;
|
|
137
|
+
}
|
|
128
138
|
|
|
129
|
-
|
|
130
|
-
|
|
139
|
+
public async getAbsoluteUrl(resolvedUrl: IResolvedUrl, relativeUrl: string): Promise<string> {
|
|
140
|
+
const fluidResolvedUrl = resolvedUrl as IFluidResolvedUrl;
|
|
131
141
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
142
|
+
const parsedUrl = parse(fluidResolvedUrl.url);
|
|
143
|
+
const [, , documentId] = parsedUrl.pathname?.split("/") ?? [];
|
|
144
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
145
|
+
assert(!!documentId, 0x273 /* "Invalid document id from parsed URL" */);
|
|
136
146
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
147
|
+
let url = relativeUrl;
|
|
148
|
+
if (url.startsWith("/")) {
|
|
149
|
+
url = url.substr(1);
|
|
150
|
+
}
|
|
141
151
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
152
|
+
return `${this.hostUrl}/${encodeURIComponent(this.tenantId)}/${encodeURIComponent(
|
|
153
|
+
documentId,
|
|
154
|
+
)}/${url}`;
|
|
155
|
+
}
|
|
145
156
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
157
|
+
public createCreateNewRequest(fileName?: string): IRequest {
|
|
158
|
+
const createNewRequest: IRequest = {
|
|
159
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
160
|
+
url: fileName ? `${this.hostUrl}?fileName=${fileName}` : this.hostUrl,
|
|
161
|
+
headers: {
|
|
162
|
+
[DriverHeader.createNew]: true,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
return createNewRequest;
|
|
166
|
+
}
|
|
156
167
|
}
|
|
@@ -2,62 +2,32 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
IDocumentMessage,
|
|
7
|
+
ISequencedDocumentMessage,
|
|
8
|
+
MessageType,
|
|
9
|
+
} from "@fluidframework/protocol-definitions";
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* Tells if message was sent by container runtime
|
|
9
13
|
* @privateRemarks ADO #1385: To be moved to container-definitions
|
|
10
14
|
* @returns whether the message is a runtime message
|
|
11
15
|
*/
|
|
12
|
-
export function isRuntimeMessage(message: { type: string
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
enum RuntimeMessage {
|
|
17
|
-
FluidDataStoreOp = "component",
|
|
18
|
-
Attach = "attach",
|
|
19
|
-
ChunkedOp = "chunkedOp",
|
|
20
|
-
BlobAttach = "blobAttach",
|
|
21
|
-
Rejoin = "rejoin",
|
|
22
|
-
Alias = "alias",
|
|
23
|
-
Operation = "op",
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Determines whether or not the message type is one of the following: (legacy)
|
|
28
|
-
*
|
|
29
|
-
* - "component"
|
|
30
|
-
*
|
|
31
|
-
* - "attach"
|
|
32
|
-
*
|
|
33
|
-
* - "chunkedOp"
|
|
34
|
-
*
|
|
35
|
-
* - "blobAttach"
|
|
36
|
-
*
|
|
37
|
-
* - "rejoin"
|
|
38
|
-
*
|
|
39
|
-
* - "alias"
|
|
40
|
-
*
|
|
41
|
-
* - "op"
|
|
42
|
-
*
|
|
43
|
-
* @deprecated This API should not be used.
|
|
44
|
-
*/
|
|
45
|
-
export function isUnpackedRuntimeMessage(message: ISequencedDocumentMessage): boolean {
|
|
46
|
-
if ((Object.values(RuntimeMessage) as string[]).includes(message.type)) {
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
return false;
|
|
16
|
+
export function isRuntimeMessage(message: { type: string }): boolean {
|
|
17
|
+
return message.type === MessageType.Operation;
|
|
50
18
|
}
|
|
51
19
|
|
|
52
20
|
// ADO #1385: staging code changes across layers.
|
|
53
21
|
// Eventually to be replaced by MessageType.accept
|
|
54
22
|
export enum MessageType2 {
|
|
55
|
-
|
|
23
|
+
Accept = "accept",
|
|
56
24
|
}
|
|
57
25
|
|
|
58
26
|
// ADO #1385: To be moved to packages/protocol-base/src/protocol.ts
|
|
59
|
-
export function canBeCoalescedByService(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
27
|
+
export function canBeCoalescedByService(
|
|
28
|
+
message: ISequencedDocumentMessage | IDocumentMessage,
|
|
29
|
+
): boolean {
|
|
30
|
+
// This assumes that in the future relay service may implement coalescing of accept messages,
|
|
31
|
+
// same way it was doing coalescing of immediate noops in the past.
|
|
32
|
+
return message.type === MessageType.NoOp || message.type === MessageType2.Accept;
|
|
63
33
|
}
|
package/src/network.ts
CHANGED
|
@@ -4,180 +4,166 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
IThrottlingWarning,
|
|
8
|
+
IDriverErrorBase,
|
|
9
|
+
IAuthorizationError,
|
|
10
|
+
DriverErrorType,
|
|
11
|
+
ILocationRedirectionError,
|
|
12
|
+
IResolvedUrl,
|
|
13
13
|
} from "@fluidframework/driver-definitions";
|
|
14
14
|
import { ITelemetryProperties } from "@fluidframework/common-definitions";
|
|
15
15
|
import { IFluidErrorBase, LoggingError } from "@fluidframework/telemetry-utils";
|
|
16
16
|
|
|
17
17
|
export enum OnlineStatus {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
Offline,
|
|
19
|
+
Online,
|
|
20
|
+
Unknown,
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// It tells if we have local connection only - we might not have connection to web.
|
|
24
24
|
// No solution for node.js (other than resolve dns names / ping specific sites)
|
|
25
25
|
// Can also use window.addEventListener("online" / "offline")
|
|
26
26
|
export function isOnline(): OnlineStatus {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
* Not expected to be implemented by a class or an object literal, but rather used in place of
|
|
36
|
-
* any or unknown in various function signatures that pass errors around.
|
|
37
|
-
*
|
|
38
|
-
* "Any" in the interface name is a nod to the fact that errorType has lost its type constraint.
|
|
39
|
-
* It will be either DriverErrorType or the specific driver's specialized error type enum,
|
|
40
|
-
* but we can't reference a specific driver's error type enum in this code.
|
|
41
|
-
*
|
|
42
|
-
* @deprecated - In favour of {@link @fluidframework/driver-definitions#IAnyDriverError} so that
|
|
43
|
-
* it can used from the base to upper layers.
|
|
44
|
-
*/
|
|
45
|
-
export interface IAnyDriverError extends Omit<IDriverErrorBase, "errorType"> {
|
|
46
|
-
readonly errorType: string;
|
|
27
|
+
if (
|
|
28
|
+
typeof navigator === "object" &&
|
|
29
|
+
navigator !== null &&
|
|
30
|
+
typeof navigator.onLine === "boolean"
|
|
31
|
+
) {
|
|
32
|
+
return navigator.onLine ? OnlineStatus.Online : OnlineStatus.Offline;
|
|
33
|
+
}
|
|
34
|
+
return OnlineStatus.Unknown;
|
|
47
35
|
}
|
|
48
36
|
|
|
49
37
|
/** Telemetry props with driver-specific required properties */
|
|
50
|
-
export type DriverErrorTelemetryProps = ITelemetryProperties & {
|
|
38
|
+
export type DriverErrorTelemetryProps = ITelemetryProperties & {
|
|
39
|
+
driverVersion: string | undefined;
|
|
40
|
+
};
|
|
51
41
|
|
|
52
42
|
/**
|
|
53
43
|
* Generic network error class.
|
|
54
44
|
*/
|
|
55
45
|
export class GenericNetworkError extends LoggingError implements IDriverErrorBase, IFluidErrorBase {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
props: DriverErrorTelemetryProps,
|
|
62
|
-
) {
|
|
63
|
-
super(message, props);
|
|
64
|
-
}
|
|
46
|
+
readonly errorType = DriverErrorType.genericNetworkError;
|
|
47
|
+
|
|
48
|
+
constructor(message: string, readonly canRetry: boolean, props: DriverErrorTelemetryProps) {
|
|
49
|
+
super(message, props);
|
|
50
|
+
}
|
|
65
51
|
}
|
|
66
52
|
|
|
67
53
|
/**
|
|
68
54
|
* FluidInvalidSchema error class.
|
|
69
55
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
56
|
+
export class FluidInvalidSchemaError
|
|
57
|
+
extends LoggingError
|
|
58
|
+
implements IDriverErrorBase, IFluidErrorBase
|
|
59
|
+
{
|
|
60
|
+
readonly errorType = DriverErrorType.fluidInvalidSchema;
|
|
61
|
+
readonly canRetry = false;
|
|
62
|
+
|
|
63
|
+
constructor(message: string, props: DriverErrorTelemetryProps) {
|
|
64
|
+
super(message, props);
|
|
65
|
+
}
|
|
80
66
|
}
|
|
81
67
|
|
|
82
|
-
export class DeltaStreamConnectionForbiddenError
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
68
|
+
export class DeltaStreamConnectionForbiddenError
|
|
69
|
+
extends LoggingError
|
|
70
|
+
implements IDriverErrorBase, IFluidErrorBase
|
|
71
|
+
{
|
|
72
|
+
static readonly errorType = DriverErrorType.deltaStreamConnectionForbidden;
|
|
73
|
+
readonly errorType = DeltaStreamConnectionForbiddenError.errorType;
|
|
74
|
+
readonly canRetry = false;
|
|
75
|
+
|
|
76
|
+
constructor(message: string, props: DriverErrorTelemetryProps) {
|
|
77
|
+
super(message, { ...props, statusCode: 400 });
|
|
78
|
+
}
|
|
90
79
|
}
|
|
91
80
|
|
|
92
|
-
export class AuthorizationError
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
81
|
+
export class AuthorizationError
|
|
82
|
+
extends LoggingError
|
|
83
|
+
implements IAuthorizationError, IFluidErrorBase
|
|
84
|
+
{
|
|
85
|
+
readonly errorType = DriverErrorType.authorizationError;
|
|
86
|
+
readonly canRetry = false;
|
|
87
|
+
|
|
88
|
+
constructor(
|
|
89
|
+
message: string,
|
|
90
|
+
readonly claims: string | undefined,
|
|
91
|
+
readonly tenantId: string | undefined,
|
|
92
|
+
props: DriverErrorTelemetryProps,
|
|
93
|
+
) {
|
|
94
|
+
// don't log claims or tenantId
|
|
95
|
+
super(message, props, new Set(["claims", "tenantId"]));
|
|
96
|
+
}
|
|
105
97
|
}
|
|
106
98
|
|
|
107
|
-
export class LocationRedirectionError
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
99
|
+
export class LocationRedirectionError
|
|
100
|
+
extends LoggingError
|
|
101
|
+
implements ILocationRedirectionError, IFluidErrorBase
|
|
102
|
+
{
|
|
103
|
+
readonly errorType = DriverErrorType.locationRedirection;
|
|
104
|
+
readonly canRetry = false;
|
|
105
|
+
|
|
106
|
+
constructor(
|
|
107
|
+
message: string,
|
|
108
|
+
readonly redirectUrl: IResolvedUrl,
|
|
109
|
+
props: DriverErrorTelemetryProps,
|
|
110
|
+
) {
|
|
111
|
+
// do not log redirectURL
|
|
112
|
+
super(message, props, new Set(["redirectUrl"]));
|
|
113
|
+
}
|
|
119
114
|
}
|
|
120
115
|
|
|
121
116
|
export class NetworkErrorBasic<T extends string> extends LoggingError implements IFluidErrorBase {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
117
|
+
constructor(
|
|
118
|
+
message: string,
|
|
119
|
+
readonly errorType: T,
|
|
120
|
+
readonly canRetry: boolean,
|
|
121
|
+
props: DriverErrorTelemetryProps,
|
|
122
|
+
) {
|
|
123
|
+
super(message, props);
|
|
124
|
+
}
|
|
130
125
|
}
|
|
131
126
|
|
|
132
127
|
export class NonRetryableError<T extends string> extends NetworkErrorBasic<T> {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
props: DriverErrorTelemetryProps,
|
|
137
|
-
) {
|
|
138
|
-
super(message, errorType, false, props);
|
|
139
|
-
}
|
|
128
|
+
constructor(message: string, readonly errorType: T, props: DriverErrorTelemetryProps) {
|
|
129
|
+
super(message, errorType, false, props);
|
|
130
|
+
}
|
|
140
131
|
}
|
|
141
132
|
|
|
142
133
|
export class RetryableError<T extends string> extends NetworkErrorBasic<T> {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
props: DriverErrorTelemetryProps,
|
|
147
|
-
) {
|
|
148
|
-
super(message, errorType, true, props);
|
|
149
|
-
}
|
|
134
|
+
constructor(message: string, readonly errorType: T, props: DriverErrorTelemetryProps) {
|
|
135
|
+
super(message, errorType, true, props);
|
|
136
|
+
}
|
|
150
137
|
}
|
|
151
138
|
|
|
152
139
|
/**
|
|
153
140
|
* Throttling error class - used to communicate all throttling errors
|
|
154
141
|
*/
|
|
155
142
|
export class ThrottlingError extends LoggingError implements IThrottlingWarning, IFluidErrorBase {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
143
|
+
readonly errorType = DriverErrorType.throttlingError;
|
|
144
|
+
readonly canRetry = true;
|
|
145
|
+
|
|
146
|
+
constructor(
|
|
147
|
+
message: string,
|
|
148
|
+
readonly retryAfterSeconds: number,
|
|
149
|
+
props: DriverErrorTelemetryProps,
|
|
150
|
+
) {
|
|
151
|
+
super(message, props);
|
|
152
|
+
}
|
|
166
153
|
}
|
|
167
154
|
|
|
168
155
|
export const createWriteError = (message: string, props: DriverErrorTelemetryProps) =>
|
|
169
|
-
|
|
156
|
+
new NonRetryableError(message, DriverErrorType.writeError, props);
|
|
170
157
|
|
|
171
158
|
export function createGenericNetworkError(
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
159
|
+
message: string,
|
|
160
|
+
retryInfo: { canRetry: boolean; retryAfterMs?: number },
|
|
161
|
+
props: DriverErrorTelemetryProps,
|
|
175
162
|
): ThrottlingError | GenericNetworkError {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return new GenericNetworkError(message, retryInfo.canRetry, props);
|
|
163
|
+
if (retryInfo.retryAfterMs !== undefined && retryInfo.canRetry) {
|
|
164
|
+
return new ThrottlingError(message, retryInfo.retryAfterMs / 1000, props);
|
|
165
|
+
}
|
|
166
|
+
return new GenericNetworkError(message, retryInfo.canRetry, props);
|
|
181
167
|
}
|
|
182
168
|
|
|
183
169
|
/**
|
|
@@ -189,8 +175,8 @@ export const canRetryOnError = (error: any): boolean => error?.canRetry === true
|
|
|
189
175
|
|
|
190
176
|
/** Check retryAfterSeconds property on error */
|
|
191
177
|
export const getRetryDelaySecondsFromError = (error: any): number | undefined =>
|
|
192
|
-
|
|
178
|
+
error?.retryAfterSeconds as number | undefined;
|
|
193
179
|
|
|
194
180
|
/** Check retryAfterSeconds property on error and convert to ms */
|
|
195
|
-
export const getRetryDelayFromError = (error: any): number | undefined =>
|
|
196
|
-
|
|
181
|
+
export const getRetryDelayFromError = (error: any): number | undefined =>
|
|
182
|
+
error?.retryAfterSeconds !== undefined ? error.retryAfterSeconds * 1000 : undefined;
|