@fluidframework/routerlicious-driver 1.2.3-83900 → 1.2.4

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 (64) hide show
  1. package/dist/deltaStorageService.d.ts +5 -3
  2. package/dist/deltaStorageService.d.ts.map +1 -1
  3. package/dist/deltaStorageService.js +9 -5
  4. package/dist/deltaStorageService.js.map +1 -1
  5. package/dist/documentService.d.ts +21 -5
  6. package/dist/documentService.d.ts.map +1 -1
  7. package/dist/documentService.js +88 -16
  8. package/dist/documentService.js.map +1 -1
  9. package/dist/documentServiceFactory.d.ts +3 -2
  10. package/dist/documentServiceFactory.d.ts.map +1 -1
  11. package/dist/documentServiceFactory.js +18 -23
  12. package/dist/documentServiceFactory.js.map +1 -1
  13. package/dist/documentStorageService.d.ts +1 -1
  14. package/dist/documentStorageService.d.ts.map +1 -1
  15. package/dist/documentStorageService.js +5 -5
  16. package/dist/documentStorageService.js.map +1 -1
  17. package/dist/packageVersion.d.ts +1 -1
  18. package/dist/packageVersion.d.ts.map +1 -1
  19. package/dist/packageVersion.js +1 -1
  20. package/dist/packageVersion.js.map +1 -1
  21. package/dist/shreddedSummaryDocumentStorageService.d.ts +3 -2
  22. package/dist/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
  23. package/dist/shreddedSummaryDocumentStorageService.js +21 -7
  24. package/dist/shreddedSummaryDocumentStorageService.js.map +1 -1
  25. package/dist/wholeSummaryDocumentStorageService.d.ts +4 -3
  26. package/dist/wholeSummaryDocumentStorageService.d.ts.map +1 -1
  27. package/dist/wholeSummaryDocumentStorageService.js +23 -10
  28. package/dist/wholeSummaryDocumentStorageService.js.map +1 -1
  29. package/lib/deltaStorageService.d.ts +5 -3
  30. package/lib/deltaStorageService.d.ts.map +1 -1
  31. package/lib/deltaStorageService.js +9 -5
  32. package/lib/deltaStorageService.js.map +1 -1
  33. package/lib/documentService.d.ts +21 -5
  34. package/lib/documentService.d.ts.map +1 -1
  35. package/lib/documentService.js +88 -16
  36. package/lib/documentService.js.map +1 -1
  37. package/lib/documentServiceFactory.d.ts +3 -2
  38. package/lib/documentServiceFactory.d.ts.map +1 -1
  39. package/lib/documentServiceFactory.js +18 -23
  40. package/lib/documentServiceFactory.js.map +1 -1
  41. package/lib/documentStorageService.d.ts +1 -1
  42. package/lib/documentStorageService.d.ts.map +1 -1
  43. package/lib/documentStorageService.js +5 -5
  44. package/lib/documentStorageService.js.map +1 -1
  45. package/lib/packageVersion.d.ts +1 -1
  46. package/lib/packageVersion.d.ts.map +1 -1
  47. package/lib/packageVersion.js +1 -1
  48. package/lib/packageVersion.js.map +1 -1
  49. package/lib/shreddedSummaryDocumentStorageService.d.ts +3 -2
  50. package/lib/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
  51. package/lib/shreddedSummaryDocumentStorageService.js +21 -7
  52. package/lib/shreddedSummaryDocumentStorageService.js.map +1 -1
  53. package/lib/wholeSummaryDocumentStorageService.d.ts +4 -3
  54. package/lib/wholeSummaryDocumentStorageService.d.ts.map +1 -1
  55. package/lib/wholeSummaryDocumentStorageService.js +23 -10
  56. package/lib/wholeSummaryDocumentStorageService.js.map +1 -1
  57. package/package.json +6 -6
  58. package/src/deltaStorageService.ts +10 -5
  59. package/src/documentService.ts +138 -39
  60. package/src/documentServiceFactory.ts +23 -25
  61. package/src/documentStorageService.ts +10 -3
  62. package/src/packageVersion.ts +1 -1
  63. package/src/shreddedSummaryDocumentStorageService.ts +27 -13
  64. package/src/wholeSummaryDocumentStorageService.ts +26 -12
@@ -7,8 +7,9 @@ import { assert } from "@fluidframework/common-utils";
7
7
  import * as api from "@fluidframework/driver-definitions";
8
8
  import { RateLimiter } from "@fluidframework/driver-utils";
9
9
  import { IClient } from "@fluidframework/protocol-definitions";
10
- import { GitManager, Historian } from "@fluidframework/server-services-client";
10
+ import { GitManager, Historian, RestWrapper } from "@fluidframework/server-services-client";
11
11
  import io from "socket.io-client";
12
+ import { PerformanceEvent } from "@fluidframework/telemetry-utils";
12
13
  import { ITelemetryLogger } from "@fluidframework/common-definitions";
13
14
  import { DeltaStorageService, DocumentDeltaStorageService } from "./deltaStorageService";
14
15
  import { DocumentStorageService } from "./documentStorageService";
@@ -20,16 +21,35 @@ import { IRouterliciousDriverPolicies } from "./policies";
20
21
  import { ICache } from "./cache";
21
22
  import { ISnapshotTreeVersion } from "./definitions";
22
23
 
24
+ /**
25
+ * Amount of time between discoveries within which we don't need to rediscover on re-connect.
26
+ * Currently, R11s defines session length at 10 minutes. To avoid any weird unknown edge-cases though,
27
+ * we set the limit to 5 minutes here.
28
+ * In the future, we likely want to retrieve this information from service's "inactive session" definition.
29
+ */
30
+ const RediscoverAfterTimeSinceDiscoveryMs = 5 * 60000; // 5 minute
31
+
23
32
  /**
24
33
  * The DocumentService manages the Socket.IO connection and manages routing requests to connected
25
- * clients
34
+ * clients.
26
35
  */
27
36
  export class DocumentService implements api.IDocumentService {
37
+ private lastDiscoveredAt: number = Date.now();
38
+ private discoverP: Promise<void> | undefined;
39
+
40
+ private storageManager: GitManager | undefined;
41
+ private noCacheStorageManager: GitManager | undefined;
42
+ private ordererRestWrapper: RestWrapper | undefined;
43
+
44
+ public get resolvedUrl() {
45
+ return this._resolvedUrl;
46
+ }
47
+
28
48
  constructor(
29
- public readonly resolvedUrl: api.IResolvedUrl,
49
+ private _resolvedUrl: api.IResolvedUrl,
30
50
  protected ordererUrl: string,
31
- private readonly deltaStorageUrl: string,
32
- private readonly gitUrl: string,
51
+ private deltaStorageUrl: string,
52
+ private storageUrl: string,
33
53
  private readonly logger: ITelemetryLogger,
34
54
  protected tokenProvider: ITokenProvider,
35
55
  protected tenantId: string,
@@ -37,6 +57,7 @@ export class DocumentService implements api.IDocumentService {
37
57
  private readonly driverPolicies: IRouterliciousDriverPolicies,
38
58
  private readonly blobCache: ICache<ArrayBufferLike>,
39
59
  private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion>,
60
+ private readonly discoverFluidResolvedUrl: () => Promise<api.IFluidResolvedUrl>,
40
61
  ) {
41
62
  }
42
63
 
@@ -54,32 +75,45 @@ export class DocumentService implements api.IDocumentService {
54
75
  return this.documentStorageService;
55
76
  }
56
77
 
57
- if (this.gitUrl === undefined) {
78
+ if (this.storageUrl === undefined) {
58
79
  return new NullBlobStorageService();
59
80
  }
60
81
 
61
- const rateLimiter = new RateLimiter(this.driverPolicies.maxConcurrentStorageRequests);
62
- const storageRestWrapper = await RouterliciousStorageRestWrapper.load(
63
- this.tenantId,
64
- this.documentId,
65
- this.tokenProvider,
66
- this.logger,
67
- rateLimiter,
68
- this.driverPolicies.enableRestLess,
69
- this.gitUrl,
70
- );
71
- const historian = new Historian(
72
- this.gitUrl,
73
- true,
74
- false,
75
- storageRestWrapper);
76
- const gitManager = new GitManager(historian);
77
- const noCacheHistorian = new Historian(
78
- this.gitUrl,
79
- true,
80
- true,
81
- storageRestWrapper);
82
- const noCacheGitManager = new GitManager(noCacheHistorian);
82
+ const getStorageManager = async (disableCache?: boolean): Promise<GitManager> => {
83
+ const shouldUpdateDiscoveredSessionInfo = this.shouldUpdateDiscoveredSessionInfo();
84
+ if (shouldUpdateDiscoveredSessionInfo) {
85
+ await this.refreshDiscovery();
86
+ }
87
+ if (!this.storageManager || !this.noCacheStorageManager || shouldUpdateDiscoveredSessionInfo) {
88
+ const rateLimiter = new RateLimiter(this.driverPolicies.maxConcurrentStorageRequests);
89
+ const storageRestWrapper = await RouterliciousStorageRestWrapper.load(
90
+ this.tenantId,
91
+ this.documentId,
92
+ this.tokenProvider,
93
+ this.logger,
94
+ rateLimiter,
95
+ this.driverPolicies.enableRestLess,
96
+ this.storageUrl,
97
+ );
98
+ const historian = new Historian(
99
+ this.storageUrl,
100
+ true,
101
+ false,
102
+ storageRestWrapper);
103
+ this.storageManager = new GitManager(historian);
104
+ const noCacheHistorian = new Historian(
105
+ this.storageUrl,
106
+ true,
107
+ true,
108
+ storageRestWrapper);
109
+ this.noCacheStorageManager = new GitManager(noCacheHistorian);
110
+ }
111
+
112
+ return disableCache ? this.noCacheStorageManager : this.storageManager;
113
+ };
114
+ // Initialize storageManager and noCacheStorageManager
115
+ const storageManager = await getStorageManager();
116
+ const noCacheStorageManager = await getStorageManager(true);
83
117
  const documentStorageServicePolicies: api.IDocumentStorageServicePolicies = {
84
118
  caching: this.driverPolicies.enablePrefetch
85
119
  ? api.LoaderCachingPolicy.Prefetch
@@ -89,13 +123,14 @@ export class DocumentService implements api.IDocumentService {
89
123
 
90
124
  this.documentStorageService = new DocumentStorageService(
91
125
  this.documentId,
92
- gitManager,
126
+ storageManager,
93
127
  this.logger,
94
128
  documentStorageServicePolicies,
95
129
  this.driverPolicies,
96
130
  this.blobCache,
97
131
  this.snapshotTreeCache,
98
- noCacheGitManager);
132
+ noCacheStorageManager,
133
+ getStorageManager);
99
134
  return this.documentStorageService;
100
135
  }
101
136
 
@@ -108,18 +143,38 @@ export class DocumentService implements api.IDocumentService {
108
143
  await this.connectToStorage();
109
144
  assert(!!this.documentStorageService, 0x0b1 /* "Storage service not initialized" */);
110
145
 
111
- const rateLimiter = new RateLimiter(this.driverPolicies.maxConcurrentOrdererRequests);
112
- const ordererRestWrapper = await RouterliciousOrdererRestWrapper.load(
146
+ const getRestWrapper = async (): Promise<RestWrapper> => {
147
+ const shouldUpdateDiscoveredSessionInfo = this.shouldUpdateDiscoveredSessionInfo();
148
+ if (shouldUpdateDiscoveredSessionInfo) {
149
+ await this.refreshDiscovery();
150
+ }
151
+ if (!this.ordererRestWrapper || shouldUpdateDiscoveredSessionInfo) {
152
+ const rateLimiter = new RateLimiter(this.driverPolicies.maxConcurrentOrdererRequests);
153
+ this.ordererRestWrapper = await RouterliciousOrdererRestWrapper.load(
154
+ this.tenantId,
155
+ this.documentId,
156
+ this.tokenProvider,
157
+ this.logger,
158
+ rateLimiter,
159
+ this.driverPolicies.enableRestLess,
160
+ );
161
+ }
162
+ return this.ordererRestWrapper;
163
+ };
164
+ const restWrapper = await getRestWrapper();
165
+ const deltaStorageService = new DeltaStorageService(
166
+ this.deltaStorageUrl,
167
+ restWrapper,
168
+ this.logger,
169
+ getRestWrapper,
170
+ () => this.deltaStorageUrl,
171
+ );
172
+ return new DocumentDeltaStorageService(
113
173
  this.tenantId,
114
174
  this.documentId,
115
- this.tokenProvider,
116
- this.logger,
117
- rateLimiter,
118
- this.driverPolicies.enableRestLess,
175
+ deltaStorageService,
176
+ this.documentStorageService,
119
177
  );
120
- const deltaStorage = new DeltaStorageService(this.deltaStorageUrl, ordererRestWrapper, this.logger);
121
- return new DocumentDeltaStorageService(this.tenantId, this.documentId,
122
- deltaStorage, this.documentStorageService);
123
178
  }
124
179
 
125
180
  /**
@@ -129,6 +184,9 @@ export class DocumentService implements api.IDocumentService {
129
184
  */
130
185
  public async connectToDeltaStream(client: IClient): Promise<api.IDocumentDeltaConnection> {
131
186
  const connect = async (refreshToken?: boolean) => {
187
+ if (this.shouldUpdateDiscoveredSessionInfo()) {
188
+ await this.refreshDiscovery();
189
+ }
132
190
  const ordererToken = await this.tokenProvider.fetchOrdererToken(
133
191
  this.tenantId,
134
192
  this.documentId,
@@ -159,4 +217,45 @@ export class DocumentService implements api.IDocumentService {
159
217
  throw error;
160
218
  }
161
219
  }
220
+
221
+ /**
222
+ * Re-discover session URLs if necessary.
223
+ */
224
+ private async refreshDiscovery(): Promise<void> {
225
+ if (!this.discoverP) {
226
+ this.discoverP = PerformanceEvent.timedExecAsync(
227
+ this.logger,
228
+ {
229
+ eventName: "refreshSessionDiscovery",
230
+ },
231
+ async () => this.refreshDiscoveryCore(),
232
+ );
233
+ }
234
+ return this.discoverP;
235
+ }
236
+
237
+ private async refreshDiscoveryCore(): Promise<void> {
238
+ const fluidResolvedUrl = await this.discoverFluidResolvedUrl();
239
+ this._resolvedUrl = fluidResolvedUrl;
240
+ this.storageUrl = fluidResolvedUrl.endpoints.storageUrl;
241
+ this.ordererUrl = fluidResolvedUrl.endpoints.ordererUrl;
242
+ this.deltaStorageUrl = fluidResolvedUrl.endpoints.deltaStorageUrl;
243
+ this.lastDiscoveredAt = Date.now();
244
+ }
245
+
246
+ /**
247
+ * Whether enough time has passed since last disconnect to warrant a new discovery call on reconnect.
248
+ */
249
+ private shouldUpdateDiscoveredSessionInfo(): boolean {
250
+ if (!this.driverPolicies.enableDiscovery) {
251
+ return false;
252
+ }
253
+ const now = Date.now();
254
+ // When connection is disconnected, we cannot know if session has moved or document has been deleted
255
+ // without re-doing discovery on the next attempt to connect.
256
+ // Disconnect event is not so reliable in local testing. To ensure re-discovery when necessary,
257
+ // re-discover if enough time has passed since last discovery.
258
+ const pastLastDiscoveryTimeThreshold = (now - this.lastDiscoveredAt) > RediscoverAfterTimeSinceDiscoveryMs;
259
+ return pastLastDiscoveryTimeThreshold;
260
+ }
162
261
  }
@@ -7,6 +7,7 @@ import { assert } from "@fluidframework/common-utils";
7
7
  import {
8
8
  IDocumentService,
9
9
  IDocumentServiceFactory,
10
+ IFluidResolvedUrl,
10
11
  IResolvedUrl,
11
12
  } from "@fluidframework/driver-definitions";
12
13
  import { ITelemetryBaseLogger } from "@fluidframework/common-definitions";
@@ -121,20 +122,14 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
121
122
  let documentId: string;
122
123
  let token: string | undefined;
123
124
  let session: ISession | undefined;
124
- let fluidResolvedUrl: IResolvedUrl;
125
125
  if (typeof res === "string") {
126
126
  documentId = res;
127
127
  } else {
128
128
  documentId = res.id;
129
129
  token = res.token;
130
- session = res.session;
130
+ session = this.driverPolicies.enableDiscovery ? res.session : undefined;
131
131
  }
132
- if (session && this.driverPolicies.enableDiscovery) {
133
- fluidResolvedUrl = getDiscoveredFluidResolvedUrl(resolvedUrl, session);
134
- } else {
135
- fluidResolvedUrl = resolvedUrl;
136
- }
137
- parsedUrl = parseFluidUrl(fluidResolvedUrl.url);
132
+ parsedUrl = parseFluidUrl(resolvedUrl.url);
138
133
 
139
134
  // @TODO: Remove token from the condition, checking the documentPostCreateCallback !== undefined
140
135
  // is sufficient to determine if the token will be undefined or not.
@@ -147,7 +142,7 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
147
142
  }
148
143
 
149
144
  parsedUrl.set("pathname", replaceDocumentIdInPath(parsedUrl.pathname, documentId));
150
- const deltaStorageUrl = fluidResolvedUrl.endpoints.deltaStorageUrl;
145
+ const deltaStorageUrl = resolvedUrl.endpoints.deltaStorageUrl;
151
146
  if (!deltaStorageUrl) {
152
147
  throw new Error(
153
148
  `All endpoints urls must be provided. [deltaStorageUrl:${deltaStorageUrl}]`);
@@ -157,22 +152,22 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
157
152
 
158
153
  return this.createDocumentService(
159
154
  {
160
- ...fluidResolvedUrl,
155
+ ...resolvedUrl,
161
156
  url: parsedUrl.toString(),
162
157
  id: documentId,
163
158
  endpoints: {
164
- ...fluidResolvedUrl.endpoints,
159
+ ...resolvedUrl.endpoints,
165
160
  deltaStorageUrl: parsedDeltaStorageUrl.toString(),
166
161
  },
167
162
  },
168
163
  logger,
169
164
  clientIsSummarizer,
170
- true,
165
+ session,
171
166
  );
172
167
  }
173
168
 
174
169
  /**
175
- * {@inheritDoc @fluidframework/driver-definitions#IDocumentServiceFactory.createContainer}
170
+ * {@inheritDoc @fluidframework/driver-definitions#IDocumentServiceFactory.createDocumentService}
176
171
  *
177
172
  * @returns Routerlicious document service.
178
173
  */
@@ -180,7 +175,7 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
180
175
  resolvedUrl: IResolvedUrl,
181
176
  logger?: ITelemetryBaseLogger,
182
177
  clientIsSummarizer?: boolean,
183
- isCreateContainer?: boolean,
178
+ session?: ISession,
184
179
  ): Promise<IDocumentService> {
185
180
  ensureFluidResolvedUrl(resolvedUrl);
186
181
 
@@ -192,8 +187,10 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
192
187
  }
193
188
  const logger2 = ChildLogger.create(logger, "RouterliciousDriver", { all: { driverVersion } });
194
189
 
195
- let fluidResolvedUrl: IResolvedUrl;
196
- if (!isCreateContainer && this.driverPolicies.enableDiscovery) {
190
+ const discoverFluidResolvedUrl = async (): Promise<IFluidResolvedUrl> => {
191
+ if (!this.driverPolicies.enableDiscovery) {
192
+ return resolvedUrl;
193
+ }
197
194
  const rateLimiter = new RateLimiter(this.driverPolicies.maxConcurrentOrdererRequests);
198
195
  const ordererRestWrapper = await RouterliciousOrdererRestWrapper.load(
199
196
  tenantId,
@@ -204,15 +201,15 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
204
201
  this.driverPolicies.enableRestLess,
205
202
  resolvedUrl.endpoints.ordererUrl,
206
203
  );
207
-
208
- // the backend responds with the actual document session associated with the container.
209
- const session: ISession = await ordererRestWrapper.get<ISession>(
204
+ // The service responds with the current document session associated with the container.
205
+ const discoveredSession = await ordererRestWrapper.get<ISession>(
210
206
  `/documents/${tenantId}/session/${documentId}`,
211
207
  );
212
- fluidResolvedUrl = getDiscoveredFluidResolvedUrl(resolvedUrl, session);
213
- } else {
214
- fluidResolvedUrl = resolvedUrl;
215
- }
208
+ return getDiscoveredFluidResolvedUrl(resolvedUrl, discoveredSession);
209
+ };
210
+ const fluidResolvedUrl: IFluidResolvedUrl = session !== undefined
211
+ ? getDiscoveredFluidResolvedUrl(resolvedUrl, session)
212
+ : await discoverFluidResolvedUrl();
216
213
 
217
214
  const storageUrl = fluidResolvedUrl.endpoints.storageUrl;
218
215
  const ordererUrl = fluidResolvedUrl.endpoints.ordererUrl;
@@ -233,7 +230,8 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
233
230
  documentId,
234
231
  this.driverPolicies,
235
232
  this.blobCache,
236
- this.snapshotTreeCache);
233
+ this.snapshotTreeCache,
234
+ discoverFluidResolvedUrl);
237
235
  }
238
236
  }
239
237
 
@@ -248,7 +246,7 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
248
246
  * - How would a user delete the created document?
249
247
  * - What would a retry pattern look like here?
250
248
  */
251
- export class DocumentPostCreateError extends Error {
249
+ export class DocumentPostCreateError extends Error {
252
250
  public constructor(
253
251
  /**
254
252
  * Inner error being wrapped.
@@ -8,7 +8,7 @@ import {
8
8
  IDocumentStorageService,
9
9
  IDocumentStorageServicePolicies,
10
10
  LoaderCachingPolicy,
11
- } from "@fluidframework/driver-definitions";
11
+ } from "@fluidframework/driver-definitions";
12
12
  import {
13
13
  ISnapshotTree,
14
14
  IVersion,
@@ -38,7 +38,9 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
38
38
  driverPolicies?: IRouterliciousDriverPolicies,
39
39
  blobCache?: ICache<ArrayBufferLike>,
40
40
  snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
41
- noCacheGitManager?: GitManager): IDocumentStorageService {
41
+ noCacheGitManager?: GitManager,
42
+ getStorageManager?: (disableCache?: boolean) => Promise<GitManager>,
43
+ ): IDocumentStorageService {
42
44
  const storageService = driverPolicies?.enableWholeSummaryUpload ?
43
45
  new WholeSummaryDocumentStorageService(
44
46
  id,
@@ -49,6 +51,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
49
51
  blobCache,
50
52
  snapshotTreeCache,
51
53
  noCacheGitManager,
54
+ getStorageManager,
52
55
  ) :
53
56
  new ShreddedSummaryDocumentStorageService(
54
57
  id,
@@ -58,6 +61,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
58
61
  driverPolicies,
59
62
  blobCache,
60
63
  snapshotTreeCache,
64
+ getStorageManager,
61
65
  );
62
66
  // TODO: worth prefetching latest summary making version + snapshot call with WholeSummary storage?
63
67
  if (!driverPolicies?.enableWholeSummaryUpload && policies.caching === LoaderCachingPolicy.Prefetch) {
@@ -74,7 +78,9 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
74
78
  driverPolicies?: IRouterliciousDriverPolicies,
75
79
  blobCache?: ICache<ArrayBufferLike>,
76
80
  snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
77
- public noCacheGitManager?: GitManager) {
81
+ public noCacheGitManager?: GitManager,
82
+ getStorageManager?: (disableCache?: boolean) => Promise<GitManager>,
83
+ ) {
78
84
  super(DocumentStorageService.loadInternalDocumentStorageService(
79
85
  id,
80
86
  manager,
@@ -84,6 +90,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
84
90
  blobCache,
85
91
  snapshotTreeCache,
86
92
  noCacheGitManager,
93
+ getStorageManager,
87
94
  ));
88
95
  }
89
96
 
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/routerlicious-driver";
9
- export const pkgVersion = "1.2.3-83900";
9
+ export const pkgVersion = "1.2.4";
@@ -12,7 +12,7 @@ import {
12
12
  IDocumentStorageService,
13
13
  ISummaryContext,
14
14
  IDocumentStorageServicePolicies,
15
- } from "@fluidframework/driver-definitions";
15
+ } from "@fluidframework/driver-definitions";
16
16
  import { buildHierarchy } from "@fluidframework/protocol-base";
17
17
  import {
18
18
  ICreateBlobResponse,
@@ -45,12 +45,20 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
45
45
  protected readonly blobsShaCache = new Map<string, string>();
46
46
  private readonly blobCache: ICache<ArrayBufferLike> | undefined;
47
47
  private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion> | undefined;
48
- private readonly summaryUploadManager: ISummaryUploadManager;
49
48
 
50
49
  public get repositoryUrl(): string {
51
50
  return "";
52
51
  }
53
52
 
53
+ private async getSummaryUploadManager(): Promise<ISummaryUploadManager> {
54
+ const manager = await this.getStorageManager();
55
+ return new SummaryTreeUploadManager(
56
+ new RetriableGitManager(manager, this.logger),
57
+ this.blobsShaCache,
58
+ this.getPreviousFullSnapshot.bind(this),
59
+ );
60
+ }
61
+
54
62
  constructor(
55
63
  protected readonly id: string,
56
64
  protected readonly manager: GitManager,
@@ -58,12 +66,9 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
58
66
  public readonly policies: IDocumentStorageServicePolicies = {},
59
67
  driverPolicies?: IRouterliciousDriverPolicies,
60
68
  blobCache?: ICache<ArrayBufferLike>,
61
- snapshotTreeCache?: ICache<ISnapshotTreeVersion>) {
62
- this.summaryUploadManager = new SummaryTreeUploadManager(
63
- new RetriableGitManager(manager, logger),
64
- this.blobsShaCache,
65
- this.getPreviousFullSnapshot.bind(this),
66
- );
69
+ snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
70
+ private readonly getStorageManager: (disableCache?: boolean) => Promise<GitManager> = async () => this.manager,
71
+ ) {
67
72
  if (driverPolicies?.enableRestLess === true || isNode) {
68
73
  this.blobCache = blobCache ?? new InMemoryCache();
69
74
  this.snapshotTreeCache = snapshotTreeCache ?? new InMemoryCache();
@@ -79,7 +84,10 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
79
84
  versionId: id,
80
85
  count,
81
86
  },
82
- async () => this.manager.getCommits(id, count),
87
+ async () => {
88
+ const manager = await this.getStorageManager();
89
+ return manager.getCommits(id, count);
90
+ },
83
91
  );
84
92
  return commits.map((commit) => ({
85
93
  date: commit.commit.author.date,
@@ -111,7 +119,8 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
111
119
  treeId: requestVersion.treeId,
112
120
  },
113
121
  async (event) => {
114
- const response = await this.manager.getTree(requestVersion!.treeId);
122
+ const manager = await this.getStorageManager();
123
+ const response = await manager.getTree(requestVersion!.treeId);
115
124
  event.end({
116
125
  size: response.tree.length,
117
126
  });
@@ -136,7 +145,8 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
136
145
  blobId,
137
146
  },
138
147
  async (event) => {
139
- const response = await this.manager.getBlob(blobId);
148
+ const manager = await this.getStorageManager();
149
+ const response = await manager.getBlob(blobId);
140
150
  event.end({
141
151
  size: response.size,
142
152
  });
@@ -155,7 +165,10 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
155
165
  {
156
166
  eventName: "uploadSummaryWithContext",
157
167
  },
158
- async () => this.summaryUploadManager.writeSummaryTree(summary, context.ackHandle ?? "", "channel"),
168
+ async () => {
169
+ const summaryUploadManager = await this.getSummaryUploadManager();
170
+ return summaryUploadManager.writeSummaryTree(summary, context.ackHandle ?? "", "channel");
171
+ },
159
172
  );
160
173
  return summaryHandle;
161
174
  }
@@ -173,7 +186,8 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
173
186
  size: uint8ArrayFile.length,
174
187
  },
175
188
  async (event) => {
176
- const response = await this.manager.createBlob(
189
+ const manager = await this.getStorageManager();
190
+ const response = await manager.createBlob(
177
191
  Uint8ArrayToString(
178
192
  uint8ArrayFile, "base64"),
179
193
  "base64").then((r) => ({ id: r.sha, url: r.url }));
@@ -16,7 +16,7 @@ import {
16
16
  } from "@fluidframework/driver-definitions";
17
17
  import {
18
18
  convertSnapshotAndBlobsToSummaryTree,
19
- } from "@fluidframework/driver-utils";
19
+ } from "@fluidframework/driver-utils";
20
20
  import {
21
21
  ICreateBlobResponse,
22
22
  ISnapshotTree,
@@ -38,13 +38,17 @@ import { IRouterliciousDriverPolicies } from "./policies";
38
38
  const latestSnapshotId: string = "latest";
39
39
 
40
40
  export class WholeSummaryDocumentStorageService implements IDocumentStorageService {
41
- private readonly summaryUploadManager: ISummaryUploadManager;
42
41
  private firstVersionsCall: boolean = true;
43
42
 
44
43
  public get repositoryUrl(): string {
45
44
  return "";
46
45
  }
47
46
 
47
+ private async getSummaryUploadManager(): Promise<ISummaryUploadManager> {
48
+ const manager = await this.getStorageManager();
49
+ return new WholeSummaryUploadManager(manager);
50
+ }
51
+
48
52
  constructor(
49
53
  protected readonly id: string,
50
54
  protected readonly manager: GitManager,
@@ -53,8 +57,10 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
53
57
  private readonly driverPolicies?: IRouterliciousDriverPolicies,
54
58
  private readonly blobCache: ICache<ArrayBufferLike> = new InMemoryCache(),
55
59
  private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion> = new InMemoryCache(),
56
- protected readonly noCacheGitManager?: GitManager) {
57
- this.summaryUploadManager = new WholeSummaryUploadManager(manager);
60
+ private readonly noCacheGitManager?: GitManager,
61
+ private readonly getStorageManager: (disableCache?: boolean) => Promise<GitManager> = async (disableCache) =>
62
+ disableCache && this.noCacheGitManager !== undefined ? this.noCacheGitManager : this.manager,
63
+ ) {
58
64
  }
59
65
 
60
66
  public async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {
@@ -87,7 +93,10 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
87
93
  versionId: id,
88
94
  count,
89
95
  },
90
- async () => this.manager.getCommits(id, count),
96
+ async () => {
97
+ const manager = await this.getStorageManager();
98
+ return manager.getCommits(id, count);
99
+ },
91
100
  );
92
101
  return commits.map((commit) => ({
93
102
  date: commit.commit.author.date,
@@ -123,7 +132,8 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
123
132
  blobId,
124
133
  },
125
134
  async (event) => {
126
- const response = await this.manager.getBlob(blobId);
135
+ const manager = await this.getStorageManager();
136
+ const response = await manager.getBlob(blobId);
127
137
  event.end({
128
138
  size: response.size,
129
139
  });
@@ -143,7 +153,10 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
143
153
  {
144
154
  eventName: "uploadSummaryWithContext",
145
155
  },
146
- async () => this.summaryUploadManager.writeSummaryTree(summary, context.ackHandle ?? "", "channel"),
156
+ async () => {
157
+ const summaryUploadManager = await this.getSummaryUploadManager();
158
+ return summaryUploadManager.writeSummaryTree(summary, context.ackHandle ?? "", "channel");
159
+ },
147
160
  );
148
161
  return summaryHandle;
149
162
  }
@@ -156,7 +169,8 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
156
169
  treeId: summaryHandle.handle,
157
170
  },
158
171
  async (event) => {
159
- const response = await this.manager.getSummary(summaryHandle.handle);
172
+ const manager = await this.getStorageManager();
173
+ const response = await manager.getSummary(summaryHandle.handle);
160
174
  event.end({
161
175
  size: response.trees[0]?.entries.length,
162
176
  });
@@ -177,7 +191,8 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
177
191
  size: uint8ArrayFile.length,
178
192
  },
179
193
  async (event) => {
180
- const response = await this.manager.createBlob(
194
+ const manager = await this.getStorageManager();
195
+ const response = await manager.createBlob(
181
196
  Uint8ArrayToString(
182
197
  uint8ArrayFile, "base64"),
183
198
  "base64").then((r) => ({ id: r.sha, url: r.url }));
@@ -202,9 +217,8 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
202
217
  treeId: versionId,
203
218
  },
204
219
  async (event) => {
205
- const response = disableCache && this.noCacheGitManager !== undefined ?
206
- await this.noCacheGitManager.getSummary(versionId) :
207
- await this.manager.getSummary(versionId);
220
+ const manager = await this.getStorageManager(disableCache);
221
+ const response = await manager.getSummary(versionId);
208
222
  event.end({
209
223
  size: response.trees[0]?.entries.length,
210
224
  });