@fluidframework/routerlicious-driver 2.0.0-dev.3.1.0.125672 → 2.0.0-dev.4.2.0.153917

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.
Files changed (184) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +38 -0
  3. package/dist/cache.js +2 -2
  4. package/dist/cache.js.map +1 -1
  5. package/dist/deltaStorageService.d.ts +1 -1
  6. package/dist/deltaStorageService.d.ts.map +1 -1
  7. package/dist/deltaStorageService.js +7 -4
  8. package/dist/deltaStorageService.js.map +1 -1
  9. package/dist/documentService.d.ts +4 -2
  10. package/dist/documentService.d.ts.map +1 -1
  11. package/dist/documentService.js +20 -12
  12. package/dist/documentService.js.map +1 -1
  13. package/dist/documentServiceFactory.d.ts +2 -2
  14. package/dist/documentServiceFactory.d.ts.map +1 -1
  15. package/dist/documentServiceFactory.js +21 -12
  16. package/dist/documentServiceFactory.js.map +1 -1
  17. package/dist/documentStorageService.d.ts +3 -2
  18. package/dist/documentStorageService.d.ts.map +1 -1
  19. package/dist/documentStorageService.js +4 -4
  20. package/dist/documentStorageService.js.map +1 -1
  21. package/dist/errorUtils.d.ts +9 -2
  22. package/dist/errorUtils.d.ts.map +1 -1
  23. package/dist/errorUtils.js +15 -8
  24. package/dist/errorUtils.js.map +1 -1
  25. package/dist/gitManager.d.ts +30 -0
  26. package/dist/gitManager.d.ts.map +1 -0
  27. package/dist/gitManager.js +89 -0
  28. package/dist/gitManager.js.map +1 -0
  29. package/dist/historian.d.ts +33 -0
  30. package/dist/historian.d.ts.map +1 -0
  31. package/dist/historian.js +65 -0
  32. package/dist/historian.js.map +1 -0
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +4 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/mapWithExpiration.d.ts +34 -0
  38. package/dist/mapWithExpiration.d.ts.map +1 -0
  39. package/dist/mapWithExpiration.js +105 -0
  40. package/dist/mapWithExpiration.js.map +1 -0
  41. package/dist/packageVersion.d.ts +1 -1
  42. package/dist/packageVersion.js +1 -1
  43. package/dist/packageVersion.js.map +1 -1
  44. package/dist/restWrapper.d.ts +21 -8
  45. package/dist/restWrapper.d.ts.map +1 -1
  46. package/dist/restWrapper.js +93 -25
  47. package/dist/restWrapper.js.map +1 -1
  48. package/dist/restWrapperBase.d.ts +26 -0
  49. package/dist/restWrapperBase.d.ts.map +1 -0
  50. package/dist/restWrapperBase.js +55 -0
  51. package/dist/restWrapperBase.js.map +1 -0
  52. package/dist/retriableGitManager.d.ts +10 -21
  53. package/dist/retriableGitManager.d.ts.map +1 -1
  54. package/dist/retriableGitManager.js +0 -36
  55. package/dist/retriableGitManager.js.map +1 -1
  56. package/dist/shreddedSummaryDocumentStorageService.d.ts +1 -1
  57. package/dist/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
  58. package/dist/shreddedSummaryDocumentStorageService.js +6 -6
  59. package/dist/shreddedSummaryDocumentStorageService.js.map +1 -1
  60. package/dist/storageContracts.d.ts +44 -0
  61. package/dist/storageContracts.d.ts.map +1 -0
  62. package/dist/storageContracts.js +7 -0
  63. package/dist/storageContracts.js.map +1 -0
  64. package/dist/summaryTreeUploadManager.d.ts +23 -0
  65. package/dist/summaryTreeUploadManager.d.ts.map +1 -0
  66. package/dist/summaryTreeUploadManager.js +110 -0
  67. package/dist/summaryTreeUploadManager.js.map +1 -0
  68. package/dist/tokens.d.ts +24 -7
  69. package/dist/tokens.d.ts.map +1 -1
  70. package/dist/tokens.js.map +1 -1
  71. package/dist/treeUtils.d.ts +58 -0
  72. package/dist/treeUtils.d.ts.map +1 -0
  73. package/dist/treeUtils.js +107 -0
  74. package/dist/treeUtils.js.map +1 -0
  75. package/dist/wholeSummaryDocumentStorageService.d.ts +5 -4
  76. package/dist/wholeSummaryDocumentStorageService.d.ts.map +1 -1
  77. package/dist/wholeSummaryDocumentStorageService.js +70 -38
  78. package/dist/wholeSummaryDocumentStorageService.js.map +1 -1
  79. package/dist/wholeSummaryUploadManager.d.ts +16 -0
  80. package/dist/wholeSummaryUploadManager.d.ts.map +1 -0
  81. package/dist/wholeSummaryUploadManager.js +38 -0
  82. package/dist/wholeSummaryUploadManager.js.map +1 -0
  83. package/lib/cache.js +1 -1
  84. package/lib/cache.js.map +1 -1
  85. package/lib/deltaStorageService.d.ts +1 -1
  86. package/lib/deltaStorageService.d.ts.map +1 -1
  87. package/lib/deltaStorageService.js +7 -4
  88. package/lib/deltaStorageService.js.map +1 -1
  89. package/lib/documentService.d.ts +4 -2
  90. package/lib/documentService.d.ts.map +1 -1
  91. package/lib/documentService.js +20 -12
  92. package/lib/documentService.js.map +1 -1
  93. package/lib/documentServiceFactory.d.ts +2 -2
  94. package/lib/documentServiceFactory.d.ts.map +1 -1
  95. package/lib/documentServiceFactory.js +22 -13
  96. package/lib/documentServiceFactory.js.map +1 -1
  97. package/lib/documentStorageService.d.ts +3 -2
  98. package/lib/documentStorageService.d.ts.map +1 -1
  99. package/lib/documentStorageService.js +4 -4
  100. package/lib/documentStorageService.js.map +1 -1
  101. package/lib/errorUtils.d.ts +9 -2
  102. package/lib/errorUtils.d.ts.map +1 -1
  103. package/lib/errorUtils.js +14 -7
  104. package/lib/errorUtils.js.map +1 -1
  105. package/lib/gitManager.d.ts +30 -0
  106. package/lib/gitManager.d.ts.map +1 -0
  107. package/lib/gitManager.js +85 -0
  108. package/lib/gitManager.js.map +1 -0
  109. package/lib/historian.d.ts +33 -0
  110. package/lib/historian.d.ts.map +1 -0
  111. package/lib/historian.js +60 -0
  112. package/lib/historian.js.map +1 -0
  113. package/lib/index.d.ts +1 -0
  114. package/lib/index.d.ts.map +1 -1
  115. package/lib/index.js +2 -0
  116. package/lib/index.js.map +1 -1
  117. package/lib/mapWithExpiration.d.ts +34 -0
  118. package/lib/mapWithExpiration.d.ts.map +1 -0
  119. package/lib/mapWithExpiration.js +101 -0
  120. package/lib/mapWithExpiration.js.map +1 -0
  121. package/lib/packageVersion.d.ts +1 -1
  122. package/lib/packageVersion.js +1 -1
  123. package/lib/packageVersion.js.map +1 -1
  124. package/lib/restWrapper.d.ts +21 -8
  125. package/lib/restWrapper.d.ts.map +1 -1
  126. package/lib/restWrapper.js +92 -26
  127. package/lib/restWrapper.js.map +1 -1
  128. package/lib/restWrapperBase.d.ts +26 -0
  129. package/lib/restWrapperBase.d.ts.map +1 -0
  130. package/lib/restWrapperBase.js +50 -0
  131. package/lib/restWrapperBase.js.map +1 -0
  132. package/lib/retriableGitManager.d.ts +10 -21
  133. package/lib/retriableGitManager.d.ts.map +1 -1
  134. package/lib/retriableGitManager.js +0 -36
  135. package/lib/retriableGitManager.js.map +1 -1
  136. package/lib/shreddedSummaryDocumentStorageService.d.ts +1 -1
  137. package/lib/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
  138. package/lib/shreddedSummaryDocumentStorageService.js +5 -5
  139. package/lib/shreddedSummaryDocumentStorageService.js.map +1 -1
  140. package/lib/storageContracts.d.ts +44 -0
  141. package/lib/storageContracts.d.ts.map +1 -0
  142. package/lib/storageContracts.js +6 -0
  143. package/lib/storageContracts.js.map +1 -0
  144. package/lib/summaryTreeUploadManager.d.ts +23 -0
  145. package/lib/summaryTreeUploadManager.d.ts.map +1 -0
  146. package/lib/summaryTreeUploadManager.js +106 -0
  147. package/lib/summaryTreeUploadManager.js.map +1 -0
  148. package/lib/tokens.d.ts +24 -7
  149. package/lib/tokens.d.ts.map +1 -1
  150. package/lib/tokens.js.map +1 -1
  151. package/lib/treeUtils.d.ts +58 -0
  152. package/lib/treeUtils.d.ts.map +1 -0
  153. package/lib/treeUtils.js +100 -0
  154. package/lib/treeUtils.js.map +1 -0
  155. package/lib/wholeSummaryDocumentStorageService.d.ts +5 -4
  156. package/lib/wholeSummaryDocumentStorageService.d.ts.map +1 -1
  157. package/lib/wholeSummaryDocumentStorageService.js +70 -38
  158. package/lib/wholeSummaryDocumentStorageService.js.map +1 -1
  159. package/lib/wholeSummaryUploadManager.d.ts +16 -0
  160. package/lib/wholeSummaryUploadManager.d.ts.map +1 -0
  161. package/lib/wholeSummaryUploadManager.js +34 -0
  162. package/lib/wholeSummaryUploadManager.js.map +1 -0
  163. package/package.json +52 -54
  164. package/src/cache.ts +1 -1
  165. package/src/deltaStorageService.ts +11 -3
  166. package/src/documentService.ts +37 -22
  167. package/src/documentServiceFactory.ts +40 -21
  168. package/src/documentStorageService.ts +8 -4
  169. package/src/errorUtils.ts +16 -4
  170. package/src/gitManager.ts +116 -0
  171. package/src/historian.ts +121 -0
  172. package/src/index.ts +3 -0
  173. package/src/mapWithExpiration.ts +124 -0
  174. package/src/packageVersion.ts +1 -1
  175. package/src/restWrapper.ts +114 -38
  176. package/src/restWrapperBase.ts +146 -0
  177. package/src/retriableGitManager.ts +17 -95
  178. package/src/shreddedSummaryDocumentStorageService.ts +7 -9
  179. package/src/storageContracts.ts +63 -0
  180. package/src/summaryTreeUploadManager.ts +160 -0
  181. package/src/tokens.ts +24 -7
  182. package/src/treeUtils.ts +137 -0
  183. package/src/wholeSummaryDocumentStorageService.ts +118 -46
  184. package/src/wholeSummaryUploadManager.ts +64 -0
@@ -5,11 +5,12 @@
5
5
 
6
6
  import { assert } from "@fluidframework/common-utils";
7
7
  import * as api from "@fluidframework/driver-definitions";
8
- import { RateLimiter } from "@fluidframework/driver-utils";
8
+ import { DriverErrorType } from "@fluidframework/driver-definitions";
9
+ import { RateLimiter, NetworkErrorBasic, canRetryOnError } from "@fluidframework/driver-utils";
9
10
  import { IClient } from "@fluidframework/protocol-definitions";
10
- import { GitManager, Historian, RestWrapper } from "@fluidframework/server-services-client";
11
+ import { INormalizedWholeSummary } from "@fluidframework/server-services-client";
11
12
  import io from "socket.io-client";
12
- import { PerformanceEvent } from "@fluidframework/telemetry-utils";
13
+ import { PerformanceEvent, wrapError } from "@fluidframework/telemetry-utils";
13
14
  import { ITelemetryLogger } from "@fluidframework/common-definitions";
14
15
  import { DeltaStorageService, DocumentDeltaStorageService } from "./deltaStorageService";
15
16
  import { DocumentStorageService } from "./documentStorageService";
@@ -20,6 +21,10 @@ import { RouterliciousOrdererRestWrapper, RouterliciousStorageRestWrapper } from
20
21
  import { IRouterliciousDriverPolicies } from "./policies";
21
22
  import { ICache } from "./cache";
22
23
  import { ISnapshotTreeVersion } from "./definitions";
24
+ import { pkgVersion as driverVersion } from "./packageVersion";
25
+ import { GitManager } from "./gitManager";
26
+ import { Historian } from "./historian";
27
+ import { RestWrapper } from "./restWrapperBase";
23
28
 
24
29
  /**
25
30
  * Amount of time between discoveries within which we don't need to rediscover on re-connect.
@@ -59,7 +64,8 @@ export class DocumentService implements api.IDocumentService {
59
64
  private readonly documentStorageServicePolicies: api.IDocumentStorageServicePolicies,
60
65
  private readonly driverPolicies: IRouterliciousDriverPolicies,
61
66
  private readonly blobCache: ICache<ArrayBufferLike>,
62
- private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion>,
67
+ private readonly wholeSnapshotTreeCache: ICache<INormalizedWholeSummary>,
68
+ private readonly shreddedSummaryTreeCache: ICache<ISnapshotTreeVersion>,
63
69
  private readonly discoverFluidResolvedUrl: () => Promise<api.IFluidResolvedUrl>,
64
70
  ) {}
65
71
 
@@ -103,14 +109,9 @@ export class DocumentService implements api.IDocumentService {
103
109
  this.driverPolicies.enableRestLess,
104
110
  this.storageUrl,
105
111
  );
106
- const historian = new Historian(this.storageUrl, true, false, storageRestWrapper);
112
+ const historian = new Historian(true, false, storageRestWrapper);
107
113
  this.storageManager = new GitManager(historian);
108
- const noCacheHistorian = new Historian(
109
- this.storageUrl,
110
- true,
111
- true,
112
- storageRestWrapper,
113
- );
114
+ const noCacheHistorian = new Historian(true, true, storageRestWrapper);
114
115
  this.noCacheStorageManager = new GitManager(noCacheHistorian);
115
116
  }
116
117
 
@@ -126,7 +127,8 @@ export class DocumentService implements api.IDocumentService {
126
127
  this.documentStorageServicePolicies,
127
128
  this.driverPolicies,
128
129
  this.blobCache,
129
- this.snapshotTreeCache,
130
+ this.wholeSnapshotTreeCache,
131
+ this.shreddedSummaryTreeCache,
130
132
  noCacheStorageManager,
131
133
  getStorageManager,
132
134
  );
@@ -185,7 +187,7 @@ export class DocumentService implements api.IDocumentService {
185
187
  */
186
188
  public async connectToDeltaStream(client: IClient): Promise<api.IDocumentDeltaConnection> {
187
189
  const connect = async (refreshToken?: boolean) => {
188
- let ordererToken = this.ordererRestWrapper.getToken();
190
+ let ordererToken = await this.ordererRestWrapper.getToken();
189
191
  if (this.shouldUpdateDiscoveredSessionInfo()) {
190
192
  await this.refreshDiscovery();
191
193
  }
@@ -200,15 +202,28 @@ export class DocumentService implements api.IDocumentService {
200
202
  refreshToken,
201
203
  }),
202
204
  },
203
- async () => {
204
- const newOrdererToken = await this.tokenProvider.fetchOrdererToken(
205
- this.tenantId,
206
- this.documentId,
207
- refreshToken,
208
- );
209
- this.ordererRestWrapper.setToken(newOrdererToken);
210
- return newOrdererToken;
211
- },
205
+ async () =>
206
+ this.tokenProvider
207
+ .fetchOrdererToken(this.tenantId, this.documentId, refreshToken)
208
+ .then(
209
+ (newOrdererToken) => {
210
+ this.ordererRestWrapper.setToken(newOrdererToken);
211
+ return newOrdererToken;
212
+ },
213
+ (error) => {
214
+ const tokenError = wrapError(
215
+ error,
216
+ (errorMessage) =>
217
+ new NetworkErrorBasic(
218
+ `The Host-provided token fetcher threw an error`,
219
+ DriverErrorType.fetchTokenError,
220
+ canRetryOnError(error),
221
+ { errorMessage, driverVersion },
222
+ ),
223
+ );
224
+ throw tokenError;
225
+ },
226
+ ),
212
227
  );
213
228
  }
214
229
 
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { assert } from "@fluidframework/common-utils";
7
+ import { getW3CData } from "@fluidframework/driver-base";
7
8
  import {
8
9
  FiveDaysMs,
9
10
  IDocumentService,
@@ -19,10 +20,11 @@ import {
19
20
  ensureFluidResolvedUrl,
20
21
  getDocAttributesFromProtocolSummary,
21
22
  getQuorumValuesFromProtocolSummary,
23
+ isCombinedAppAndProtocolSummary,
22
24
  RateLimiter,
23
25
  } from "@fluidframework/driver-utils";
24
26
  import { ChildLogger, PerformanceEvent } from "@fluidframework/telemetry-utils";
25
- import { ISession } from "@fluidframework/server-services-client";
27
+ import { INormalizedWholeSummary, ISession } from "@fluidframework/server-services-client";
26
28
  import { DocumentService } from "./documentService";
27
29
  import { IRouterliciousDriverPolicies } from "./policies";
28
30
  import { ITokenProvider } from "./tokens";
@@ -51,10 +53,10 @@ const defaultRouterliciousDriverPolicies: IRouterliciousDriverPolicies = {
51
53
  * use the routerlicious implementation.
52
54
  */
53
55
  export class RouterliciousDocumentServiceFactory implements IDocumentServiceFactory {
54
- public readonly protocolName = "fluid:";
55
56
  private readonly driverPolicies: IRouterliciousDriverPolicies;
56
57
  private readonly blobCache: ICache<ArrayBufferLike>;
57
- private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion>;
58
+ private readonly wholeSnapshotTreeCache: ICache<INormalizedWholeSummary> = new NullCache();
59
+ private readonly shreddedSummaryTreeCache: ICache<ISnapshotTreeVersion> = new NullCache();
58
60
 
59
61
  constructor(
60
62
  private readonly tokenProvider: ITokenProvider,
@@ -68,9 +70,17 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
68
70
  ...driverPolicies,
69
71
  };
70
72
  this.blobCache = new InMemoryCache<ArrayBufferLike>();
71
- this.snapshotTreeCache = this.driverPolicies.enableInternalSummaryCaching
72
- ? new InMemoryCache<ISnapshotTreeVersion>(snapshotCacheExpiryMs)
73
- : new NullCache<ISnapshotTreeVersion>();
73
+ if (this.driverPolicies.enableInternalSummaryCaching) {
74
+ if (this.driverPolicies.enableWholeSummaryUpload) {
75
+ this.wholeSnapshotTreeCache = new InMemoryCache<INormalizedWholeSummary>(
76
+ snapshotCacheExpiryMs,
77
+ );
78
+ } else {
79
+ this.shreddedSummaryTreeCache = new InMemoryCache<ISnapshotTreeVersion>(
80
+ snapshotCacheExpiryMs,
81
+ );
82
+ }
83
+ }
74
84
  }
75
85
 
76
86
  /**
@@ -96,11 +106,12 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
96
106
  }
97
107
  const [, tenantId] = parsedUrl.pathname.split("/");
98
108
 
99
- const protocolSummary = createNewSummary.tree[".protocol"] as ISummaryTree;
100
- const appSummary = createNewSummary.tree[".app"] as ISummaryTree;
101
- if (!(protocolSummary && appSummary)) {
109
+ if (!isCombinedAppAndProtocolSummary(createNewSummary)) {
102
110
  throw new Error("Protocol and App Summary required in the full summary");
103
111
  }
112
+ const protocolSummary = createNewSummary.tree[".protocol"];
113
+ const appSummary = createNewSummary.tree[".app"];
114
+
104
115
  const documentAttributes = getDocAttributesFromProtocolSummary(protocolSummary);
105
116
  const quorumValues = getQuorumValuesFromProtocolSummary(protocolSummary);
106
117
 
@@ -127,15 +138,17 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
127
138
  },
128
139
  async (event) => {
129
140
  // @TODO: Remove returned "string" type when removing back-compat code
130
- const postRes = await ordererRestWrapper.post<
131
- { id: string; token?: string; session?: ISession } | string
132
- >(`/documents/${tenantId}`, {
133
- summary: convertSummaryToCreateNewSummary(appSummary),
134
- sequenceNumber: documentAttributes.sequenceNumber,
135
- values: quorumValues,
136
- enableDiscovery: this.driverPolicies.enableDiscovery,
137
- generateToken: this.tokenProvider.documentPostCreateCallback !== undefined,
138
- });
141
+ const postRes = (
142
+ await ordererRestWrapper.post<
143
+ { id: string; token?: string; session?: ISession } | string
144
+ >(`/documents/${tenantId}`, {
145
+ summary: convertSummaryToCreateNewSummary(appSummary),
146
+ sequenceNumber: documentAttributes.sequenceNumber,
147
+ values: quorumValues,
148
+ enableDiscovery: this.driverPolicies.enableDiscovery,
149
+ generateToken: this.tokenProvider.documentPostCreateCallback !== undefined,
150
+ })
151
+ ).content;
139
152
 
140
153
  event.end({
141
154
  docId: typeof postRes === "string" ? postRes : postRes.id,
@@ -252,11 +265,16 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
252
265
  eventName: "DiscoverSession",
253
266
  docId: documentId,
254
267
  },
255
- async () => {
268
+ async (event) => {
256
269
  // The service responds with the current document session associated with the container.
257
- return ordererRestWrapper.get<ISession>(
270
+ const response = await ordererRestWrapper.get<ISession>(
258
271
  `${resolvedUrl.endpoints.ordererUrl}/documents/${tenantId}/session/${documentId}`,
259
272
  );
273
+ event.end({
274
+ ...response.propsToLog,
275
+ ...getW3CData(response.requestUrl, "xmlhttprequest"),
276
+ });
277
+ return response.content;
260
278
  },
261
279
  );
262
280
  return getDiscoveredFluidResolvedUrl(resolvedUrl, discoveredSession);
@@ -298,7 +316,8 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
298
316
  documentStorageServicePolicies,
299
317
  this.driverPolicies,
300
318
  this.blobCache,
301
- this.snapshotTreeCache,
319
+ this.wholeSnapshotTreeCache,
320
+ this.shreddedSummaryTreeCache,
302
321
  discoverFluidResolvedUrl,
303
322
  );
304
323
  }
@@ -10,15 +10,16 @@ import {
10
10
  LoaderCachingPolicy,
11
11
  } from "@fluidframework/driver-definitions";
12
12
  import { ISnapshotTree, IVersion } from "@fluidframework/protocol-definitions";
13
- import { GitManager } from "@fluidframework/server-services-client";
14
13
  import {
15
14
  DocumentStorageServiceProxy,
16
15
  PrefetchDocumentStorageService,
17
16
  } from "@fluidframework/driver-utils";
17
+ import { INormalizedWholeSummary } from "@fluidframework/server-services-client";
18
18
  import { IRouterliciousDriverPolicies } from "./policies";
19
19
  import { ICache } from "./cache";
20
20
  import { WholeSummaryDocumentStorageService } from "./wholeSummaryDocumentStorageService";
21
21
  import { ShreddedSummaryDocumentStorageService } from "./shreddedSummaryDocumentStorageService";
22
+ import { GitManager } from "./gitManager";
22
23
  import { ISnapshotTreeVersion } from "./definitions";
23
24
 
24
25
  export class DocumentStorageService extends DocumentStorageServiceProxy {
@@ -35,7 +36,8 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
35
36
  policies: IDocumentStorageServicePolicies,
36
37
  driverPolicies?: IRouterliciousDriverPolicies,
37
38
  blobCache?: ICache<ArrayBufferLike>,
38
- snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
39
+ snapshotTreeCache?: ICache<INormalizedWholeSummary>,
40
+ shreddedSummaryTreeCache?: ICache<ISnapshotTreeVersion>,
39
41
  noCacheGitManager?: GitManager,
40
42
  getStorageManager?: (disableCache?: boolean) => Promise<GitManager>,
41
43
  ): IDocumentStorageService {
@@ -58,7 +60,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
58
60
  policies,
59
61
  driverPolicies,
60
62
  blobCache,
61
- snapshotTreeCache,
63
+ shreddedSummaryTreeCache,
62
64
  getStorageManager,
63
65
  );
64
66
  // TODO: worth prefetching latest summary making version + snapshot call with WholeSummary storage?
@@ -78,7 +80,8 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
78
80
  policies: IDocumentStorageServicePolicies,
79
81
  driverPolicies?: IRouterliciousDriverPolicies,
80
82
  blobCache?: ICache<ArrayBufferLike>,
81
- snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
83
+ snapshotTreeCache?: ICache<INormalizedWholeSummary>,
84
+ shreddedSummaryTreeCache?: ICache<ISnapshotTreeVersion>,
82
85
  public noCacheGitManager?: GitManager,
83
86
  getStorageManager?: (disableCache?: boolean) => Promise<GitManager>,
84
87
  ) {
@@ -91,6 +94,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
91
94
  driverPolicies,
92
95
  blobCache,
93
96
  snapshotTreeCache,
97
+ shreddedSummaryTreeCache,
94
98
  noCacheGitManager,
95
99
  getStorageManager,
96
100
  ),
package/src/errorUtils.ts CHANGED
@@ -12,8 +12,16 @@ import {
12
12
  } from "@fluidframework/driver-utils";
13
13
  import { pkgVersion as driverVersion } from "./packageVersion";
14
14
 
15
- export enum R11sErrorType {
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
+ */
16
23
  fileNotFoundOrAccessDeniedError = "fileNotFoundOrAccessDeniedError",
24
+
17
25
  sslCertError = "sslCertError",
18
26
  }
19
27
 
@@ -48,7 +56,7 @@ export interface IR11sSocketError {
48
56
  }
49
57
 
50
58
  export interface IR11sError {
51
- readonly errorType: R11sErrorType;
59
+ readonly errorType: RouterliciousErrorType;
52
60
  readonly message: string;
53
61
  canRetry: boolean;
54
62
  }
@@ -69,7 +77,11 @@ export function createR11sNetworkError(
69
77
  // If there exists a self-signed SSL certificates error, throw a NonRetryableError
70
78
  // TODO: instead of relying on string matching, filter error based on the error code like we do for websocket connections
71
79
  if (errorMessage.includes("failed, reason: self signed certificate")) {
72
- return new NonRetryableError(errorMessage, R11sErrorType.sslCertError, props);
80
+ return new NonRetryableError(
81
+ errorMessage,
82
+ RouterliciousErrorType.sslCertError,
83
+ props,
84
+ );
73
85
  }
74
86
  return new GenericNetworkError(
75
87
  errorMessage,
@@ -82,7 +94,7 @@ export function createR11sNetworkError(
82
94
  case 403:
83
95
  return new AuthorizationError(errorMessage, undefined, undefined, props);
84
96
  case 404:
85
- const errorType = R11sErrorType.fileNotFoundOrAccessDeniedError;
97
+ const errorType = RouterliciousErrorType.fileNotFoundOrAccessDeniedError;
86
98
  return new NonRetryableError(errorMessage, errorType, props);
87
99
  case 429:
88
100
  return createGenericNetworkError(errorMessage, { canRetry: true, retryAfterMs }, props);
@@ -0,0 +1,116 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import * as resources from "@fluidframework/gitresources";
7
+ import {
8
+ IWholeFlatSummary,
9
+ IWholeSummaryPayload,
10
+ IWriteSummaryResponse,
11
+ } from "@fluidframework/server-services-client";
12
+ import { IGitManager, IHistorian } from "./storageContracts";
13
+ import { IR11sResponse, createR11sResponseFromContent } from "./restWrapper";
14
+
15
+ export class GitManager implements IGitManager {
16
+ private readonly blobCache = new Map<string, resources.IBlob>();
17
+ private readonly commitCache = new Map<string, resources.ICommit>();
18
+ private readonly treeCache = new Map<string, resources.ITree>();
19
+ private readonly refCache = new Map<string, string>();
20
+
21
+ constructor(private readonly historian: IHistorian) {}
22
+
23
+ /**
24
+ * Reads the object with the given ID. We defer to the client implementation to do the actual read.
25
+ */
26
+ public async getCommits(
27
+ shaOrRef: string,
28
+ count: number,
29
+ ): Promise<IR11sResponse<resources.ICommitDetails[]>> {
30
+ let sha: string | undefined = shaOrRef;
31
+
32
+ // See if the sha is really a ref and convert
33
+ if (this.refCache.has(shaOrRef)) {
34
+ sha = this.refCache.get(shaOrRef);
35
+
36
+ // Delete refcache after first use
37
+ this.refCache.delete(shaOrRef);
38
+
39
+ // If null is stored for the ref then there are no commits - return an empty array
40
+ if (!sha) {
41
+ return createR11sResponseFromContent([]);
42
+ }
43
+ }
44
+
45
+ // See if the commit sha is hashed and return it if so
46
+ const commit = this.commitCache.get(sha);
47
+ if (commit !== undefined) {
48
+ return createR11sResponseFromContent([
49
+ {
50
+ commit: {
51
+ author: commit.author,
52
+ committer: commit.committer,
53
+ message: commit.message,
54
+ tree: commit.tree,
55
+ url: commit.url,
56
+ },
57
+ parents: commit.parents,
58
+ sha: commit.sha,
59
+ url: commit.url,
60
+ },
61
+ ]);
62
+ }
63
+
64
+ // Otherwise fall back to the historian
65
+ return this.historian.getCommits(sha, count);
66
+ }
67
+
68
+ /**
69
+ * Reads the object with the given ID. We defer to the client implementation to do the actual read.
70
+ */
71
+ public async getTree(root: string, recursive = true): Promise<IR11sResponse<resources.ITree>> {
72
+ const tree = this.treeCache.get(root);
73
+ if (tree !== undefined) {
74
+ return createR11sResponseFromContent(tree);
75
+ }
76
+
77
+ return this.historian.getTree(root, recursive);
78
+ }
79
+
80
+ public async getBlob(sha: string): Promise<IR11sResponse<resources.IBlob>> {
81
+ const blob = this.blobCache.get(sha);
82
+ if (blob !== undefined) {
83
+ return createR11sResponseFromContent(blob);
84
+ }
85
+ return this.historian.getBlob(sha);
86
+ }
87
+
88
+ public async createBlob(
89
+ content: string,
90
+ encoding: "utf-8" | "base64",
91
+ ): Promise<IR11sResponse<resources.ICreateBlobResponse>> {
92
+ const blob: resources.ICreateBlobParams = {
93
+ content,
94
+ encoding,
95
+ };
96
+ return this.historian.createBlob(blob);
97
+ }
98
+
99
+ public async createGitTree(
100
+ params: resources.ICreateTreeParams,
101
+ ): Promise<IR11sResponse<resources.ITree>> {
102
+ const treeP = this.historian.createTree(params);
103
+ return treeP;
104
+ }
105
+
106
+ public async createSummary(
107
+ summary: IWholeSummaryPayload,
108
+ initial: boolean = false,
109
+ ): Promise<IR11sResponse<IWriteSummaryResponse>> {
110
+ return this.historian.createSummary(summary, initial);
111
+ }
112
+
113
+ public async getSummary(sha: string): Promise<IR11sResponse<IWholeFlatSummary>> {
114
+ return this.historian.getSummary(sha);
115
+ }
116
+ }
@@ -0,0 +1,121 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { fromUtf8ToBase64 } from "@fluidframework/common-utils";
7
+ import * as git from "@fluidframework/gitresources";
8
+ import {
9
+ IWholeFlatSummary,
10
+ IWholeSummaryPayload,
11
+ IWriteSummaryResponse,
12
+ } from "@fluidframework/server-services-client";
13
+ import { QueryStringType, RestWrapper } from "./restWrapperBase";
14
+ import { IR11sResponse } from "./restWrapper";
15
+ import { IHistorian } from "./storageContracts";
16
+
17
+ export interface ICredentials {
18
+ user: string;
19
+ password: string;
20
+ }
21
+
22
+ export const getAuthorizationTokenFromCredentials = (credentials: ICredentials): string =>
23
+ `Basic ${fromUtf8ToBase64(`${credentials.user}:${credentials.password}`)}`;
24
+
25
+ /**
26
+ * Implementation of the IHistorian interface that calls out to a REST interface
27
+ */
28
+ export class Historian implements IHistorian {
29
+ private readonly defaultQueryString: QueryStringType = {};
30
+ private readonly cacheBust: boolean;
31
+
32
+ constructor(
33
+ private readonly historianApi: boolean,
34
+ disableCache: boolean,
35
+ private readonly restWrapper: RestWrapper,
36
+ ) {
37
+ if (disableCache && this.historianApi) {
38
+ this.defaultQueryString.disableCache = disableCache;
39
+ this.cacheBust = false;
40
+ } else {
41
+ this.cacheBust = disableCache;
42
+ }
43
+ }
44
+
45
+ public async getBlob(sha: string): Promise<IR11sResponse<git.IBlob>> {
46
+ return this.restWrapper.get<git.IBlob>(
47
+ `/git/blobs/${encodeURIComponent(sha)}`,
48
+ this.getQueryString(),
49
+ );
50
+ }
51
+
52
+ public async createBlob(
53
+ blob: git.ICreateBlobParams,
54
+ ): Promise<IR11sResponse<git.ICreateBlobResponse>> {
55
+ return this.restWrapper.post<git.ICreateBlobResponse>(
56
+ `/git/blobs`,
57
+ blob,
58
+ this.getQueryString(),
59
+ );
60
+ }
61
+
62
+ public async getCommits(
63
+ sha: string,
64
+ count: number,
65
+ ): Promise<IR11sResponse<git.ICommitDetails[]>> {
66
+ return this.restWrapper
67
+ .get<git.ICommitDetails[]>(`/commits`, this.getQueryString({ count, sha }))
68
+ .catch((error) =>
69
+ error.statusCode === 400 || error.statusCode === 404
70
+ ? {
71
+ content: [],
72
+ headers: new Map(),
73
+ propsToLog: {},
74
+ requestUrl: "",
75
+ }
76
+ : Promise.reject<IR11sResponse<git.ICommitDetails[]>>(error),
77
+ );
78
+ }
79
+
80
+ public async createTree(tree: git.ICreateTreeParams): Promise<IR11sResponse<git.ITree>> {
81
+ return this.restWrapper.post<git.ITree>(`/git/trees`, tree, this.getQueryString());
82
+ }
83
+
84
+ public async getTree(sha: string, recursive: boolean): Promise<IR11sResponse<git.ITree>> {
85
+ return this.restWrapper.get<git.ITree>(
86
+ `/git/trees/${encodeURIComponent(sha)}`,
87
+ this.getQueryString({ recursive: recursive ? 1 : 0 }),
88
+ );
89
+ }
90
+ public async createSummary(
91
+ summary: IWholeSummaryPayload,
92
+ initial?: boolean,
93
+ ): Promise<IR11sResponse<IWriteSummaryResponse>> {
94
+ return this.restWrapper.post<IWriteSummaryResponse>(
95
+ `/git/summaries`,
96
+ summary,
97
+ this.getQueryString(initial !== undefined ? { initial } : undefined),
98
+ );
99
+ }
100
+
101
+ public async getSummary(sha: string): Promise<IR11sResponse<IWholeFlatSummary>> {
102
+ return this.restWrapper.get<IWholeFlatSummary>(
103
+ `/git/summaries/${sha}`,
104
+ this.getQueryString(),
105
+ );
106
+ }
107
+
108
+ private getQueryString(queryString?: QueryStringType): QueryStringType {
109
+ if (this.cacheBust) {
110
+ return {
111
+ cacheBust: Date.now(),
112
+ ...this.defaultQueryString,
113
+ ...queryString,
114
+ };
115
+ }
116
+ return {
117
+ ...this.defaultQueryString,
118
+ ...queryString,
119
+ };
120
+ }
121
+ }
package/src/index.ts CHANGED
@@ -7,6 +7,9 @@
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
14
  export {
12
15
  DocumentPostCreateError,