@fluidframework/odsp-driver 0.58.2002 → 0.59.1000

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 (99) hide show
  1. package/dist/compactSnapshotParser.d.ts +1 -0
  2. package/dist/compactSnapshotParser.d.ts.map +1 -1
  3. package/dist/compactSnapshotParser.js +8 -7
  4. package/dist/compactSnapshotParser.js.map +1 -1
  5. package/dist/createNewUtils.js +0 -1
  6. package/dist/createNewUtils.js.map +1 -1
  7. package/dist/epochTracker.d.ts +12 -0
  8. package/dist/epochTracker.d.ts.map +1 -1
  9. package/dist/epochTracker.js +18 -22
  10. package/dist/epochTracker.js.map +1 -1
  11. package/dist/fetchSnapshot.d.ts +11 -0
  12. package/dist/fetchSnapshot.d.ts.map +1 -1
  13. package/dist/fetchSnapshot.js +53 -68
  14. package/dist/fetchSnapshot.js.map +1 -1
  15. package/dist/odspDocumentService.d.ts +2 -1
  16. package/dist/odspDocumentService.d.ts.map +1 -1
  17. package/dist/odspDocumentService.js +14 -7
  18. package/dist/odspDocumentService.js.map +1 -1
  19. package/dist/odspDocumentServiceFactoryCore.d.ts +2 -2
  20. package/dist/odspDocumentServiceFactoryCore.d.ts.map +1 -1
  21. package/dist/odspDocumentServiceFactoryCore.js +6 -6
  22. package/dist/odspDocumentServiceFactoryCore.js.map +1 -1
  23. package/dist/odspDocumentStorageManager.d.ts +0 -6
  24. package/dist/odspDocumentStorageManager.d.ts.map +1 -1
  25. package/dist/odspDocumentStorageManager.js +9 -58
  26. package/dist/odspDocumentStorageManager.js.map +1 -1
  27. package/dist/odspDriverUrlResolver.d.ts +2 -6
  28. package/dist/odspDriverUrlResolver.d.ts.map +1 -1
  29. package/dist/odspDriverUrlResolver.js +15 -10
  30. package/dist/odspDriverUrlResolver.js.map +1 -1
  31. package/dist/odspDriverUrlResolverForShareLink.d.ts +2 -6
  32. package/dist/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
  33. package/dist/odspDriverUrlResolverForShareLink.js +12 -9
  34. package/dist/odspDriverUrlResolverForShareLink.js.map +1 -1
  35. package/dist/odspSnapshotParser.d.ts.map +1 -1
  36. package/dist/odspSnapshotParser.js +1 -5
  37. package/dist/odspSnapshotParser.js.map +1 -1
  38. package/dist/odspSummaryUploadManager.d.ts.map +1 -1
  39. package/dist/odspSummaryUploadManager.js +9 -6
  40. package/dist/odspSummaryUploadManager.js.map +1 -1
  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/lib/compactSnapshotParser.d.ts +1 -0
  45. package/lib/compactSnapshotParser.d.ts.map +1 -1
  46. package/lib/compactSnapshotParser.js +7 -6
  47. package/lib/compactSnapshotParser.js.map +1 -1
  48. package/lib/createNewUtils.js +0 -1
  49. package/lib/createNewUtils.js.map +1 -1
  50. package/lib/epochTracker.d.ts +12 -0
  51. package/lib/epochTracker.d.ts.map +1 -1
  52. package/lib/epochTracker.js +19 -23
  53. package/lib/epochTracker.js.map +1 -1
  54. package/lib/fetchSnapshot.d.ts +11 -0
  55. package/lib/fetchSnapshot.d.ts.map +1 -1
  56. package/lib/fetchSnapshot.js +55 -70
  57. package/lib/fetchSnapshot.js.map +1 -1
  58. package/lib/odspDocumentService.d.ts +2 -1
  59. package/lib/odspDocumentService.d.ts.map +1 -1
  60. package/lib/odspDocumentService.js +14 -7
  61. package/lib/odspDocumentService.js.map +1 -1
  62. package/lib/odspDocumentServiceFactoryCore.d.ts +2 -2
  63. package/lib/odspDocumentServiceFactoryCore.d.ts.map +1 -1
  64. package/lib/odspDocumentServiceFactoryCore.js +6 -6
  65. package/lib/odspDocumentServiceFactoryCore.js.map +1 -1
  66. package/lib/odspDocumentStorageManager.d.ts +0 -6
  67. package/lib/odspDocumentStorageManager.d.ts.map +1 -1
  68. package/lib/odspDocumentStorageManager.js +9 -58
  69. package/lib/odspDocumentStorageManager.js.map +1 -1
  70. package/lib/odspDriverUrlResolver.d.ts +2 -6
  71. package/lib/odspDriverUrlResolver.d.ts.map +1 -1
  72. package/lib/odspDriverUrlResolver.js +14 -9
  73. package/lib/odspDriverUrlResolver.js.map +1 -1
  74. package/lib/odspDriverUrlResolverForShareLink.d.ts +2 -6
  75. package/lib/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
  76. package/lib/odspDriverUrlResolverForShareLink.js +10 -7
  77. package/lib/odspDriverUrlResolverForShareLink.js.map +1 -1
  78. package/lib/odspSnapshotParser.d.ts.map +1 -1
  79. package/lib/odspSnapshotParser.js +1 -5
  80. package/lib/odspSnapshotParser.js.map +1 -1
  81. package/lib/odspSummaryUploadManager.d.ts.map +1 -1
  82. package/lib/odspSummaryUploadManager.js +9 -6
  83. package/lib/odspSummaryUploadManager.js.map +1 -1
  84. package/lib/packageVersion.d.ts +1 -1
  85. package/lib/packageVersion.js +1 -1
  86. package/lib/packageVersion.js.map +1 -1
  87. package/package.json +19 -14
  88. package/src/compactSnapshotParser.ts +14 -12
  89. package/src/createNewUtils.ts +0 -1
  90. package/src/epochTracker.ts +34 -25
  91. package/src/fetchSnapshot.ts +57 -89
  92. package/src/odspDocumentService.ts +8 -5
  93. package/src/odspDocumentServiceFactoryCore.ts +7 -2
  94. package/src/odspDocumentStorageManager.ts +10 -64
  95. package/src/odspDriverUrlResolver.ts +18 -9
  96. package/src/odspDriverUrlResolverForShareLink.ts +11 -8
  97. package/src/odspSnapshotParser.ts +1 -4
  98. package/src/odspSummaryUploadManager.ts +7 -6
  99. package/src/packageVersion.ts +1 -1
@@ -36,7 +36,6 @@ function convertCreateNewSummaryTreeToTreeAndBlobsCore(
36
36
  const treeNode: ISnapshotTree = {
37
37
  blobs: {},
38
38
  trees: {},
39
- commits: {},
40
39
  unreferenced: summary.unreferenced,
41
40
  };
42
41
  const keys = Object.keys(summary.tree);
@@ -18,7 +18,7 @@ import {
18
18
  } from "@fluidframework/odsp-driver-definitions";
19
19
  import { DriverErrorType } from "@fluidframework/driver-definitions";
20
20
  import { PerformanceEvent, isFluidError, normalizeError } from "@fluidframework/telemetry-utils";
21
- import { fetchAndParseAsJSONHelper, fetchArray, getOdspResolvedUrl, IOdspResponse } from "./odspUtils";
21
+ import { fetchAndParseAsJSONHelper, fetchArray, fetchHelper, getOdspResolvedUrl, IOdspResponse } from "./odspUtils";
22
22
  import {
23
23
  IOdspCache,
24
24
  INonPersistentCache,
@@ -166,6 +166,7 @@ export class EpochTracker implements IPersistedFileCache {
166
166
  * @param fetchOptions - fetch options for request containing body, headers etc.
167
167
  * @param fetchType - method for which fetch is called.
168
168
  * @param addInBody - Pass True if caller wants to add epoch in post body.
169
+ * @param fetchReason - fetch reason to add to the request.
169
170
  */
170
171
  public async fetchAndParseAsJSON<T>(
171
172
  url: string,
@@ -174,12 +175,41 @@ export class EpochTracker implements IPersistedFileCache {
174
175
  addInBody: boolean = false,
175
176
  fetchReason?: string,
176
177
  ): Promise<IOdspResponse<T>> {
178
+ return this.fetchCore<T>(url, fetchOptions, fetchAndParseAsJSONHelper, fetchType, addInBody, fetchReason);
179
+ }
180
+
181
+ /**
182
+ * Api to fetch the response for given request and parse it as json.
183
+ * @param url - url of the request
184
+ * @param fetchOptions - fetch options for request containing body, headers etc.
185
+ * @param fetchType - method for which fetch is called.
186
+ * @param addInBody - Pass True if caller wants to add epoch in post body.
187
+ * @param fetchReason - fetch reason to add to the request.
188
+ */
189
+ public async fetch(
190
+ url: string,
191
+ fetchOptions: RequestInit,
192
+ fetchType: FetchType,
193
+ addInBody: boolean = false,
194
+ fetchReason?: string,
195
+ ) {
196
+ return this.fetchCore<Response>(url, fetchOptions, fetchHelper, fetchType, addInBody, fetchReason);
197
+ }
198
+
199
+ private async fetchCore<T>(
200
+ url: string,
201
+ fetchOptions: {[index: string]: any},
202
+ fetcher: (url: string, fetchOptions: {[index: string]: any}) => Promise<IOdspResponse<T>>,
203
+ fetchType: FetchType,
204
+ addInBody: boolean = false,
205
+ fetchReason?: string,
206
+ ) {
177
207
  const clientCorrelationId = this.formatClientCorrelationId(fetchReason);
178
208
  // Add epoch in fetch request.
179
209
  this.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);
180
210
  let epochFromResponse: string | undefined;
181
211
  return this.rateLimiter.schedule(
182
- async () => fetchAndParseAsJSONHelper<T>(url, fetchOptions),
212
+ async () => fetcher(url, fetchOptions),
183
213
  ).then((response) => {
184
214
  epochFromResponse = response.headers.get("x-fluid-epoch");
185
215
  this.validateEpochFromResponse(epochFromResponse, fetchType);
@@ -205,6 +235,7 @@ export class EpochTracker implements IPersistedFileCache {
205
235
  * @param fetchOptions - fetch options for request containing body, headers etc.
206
236
  * @param fetchType - method for which fetch is called.
207
237
  * @param addInBody - Pass True if caller wants to add epoch in post body.
238
+ * @param fetchReason - fetch reason to add to the request.
208
239
  */
209
240
  public async fetchArray(
210
241
  url: string,
@@ -213,29 +244,7 @@ export class EpochTracker implements IPersistedFileCache {
213
244
  addInBody: boolean = false,
214
245
  fetchReason?: string,
215
246
  ) {
216
- const clientCorrelationId = this.formatClientCorrelationId(fetchReason);
217
- // Add epoch in fetch request.
218
- this.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);
219
- let epochFromResponse: string | undefined;
220
- return this.rateLimiter.schedule(
221
- async () => fetchArray(url, fetchOptions),
222
- ).then((response) => {
223
- epochFromResponse = response.headers.get("x-fluid-epoch");
224
- this.validateEpochFromResponse(epochFromResponse, fetchType);
225
- response.propsToLog.XRequestStatsHeader = clientCorrelationId;
226
- return response;
227
- }).catch(async (error) => {
228
- // Get the server epoch from error in case we don't have it as if undefined we won't be able
229
- // to mark it as epoch error.
230
- if (epochFromResponse === undefined) {
231
- epochFromResponse = (error as IOdspError).serverEpoch;
232
- }
233
- await this.checkForEpochError(error, epochFromResponse, fetchType);
234
- throw error;
235
- }).catch((error) => {
236
- const fluidError = normalizeError(error, { props: { XRequestStatsHeader: clientCorrelationId }});
237
- throw fluidError;
238
- });
247
+ return this.fetchCore<ArrayBuffer>(url, fetchOptions, fetchArray, fetchType, addInBody, fetchReason);
239
248
  }
240
249
 
241
250
  private addEpochInRequest(
@@ -22,14 +22,14 @@ import { getQueryString } from "./getQueryString";
22
22
  import { getUrlAndHeadersWithAuth } from "./getUrlAndHeadersWithAuth";
23
23
  import {
24
24
  fetchAndParseAsJSONHelper,
25
- fetchArray,
25
+ fetchHelper,
26
26
  getWithRetryForTokenRefresh,
27
27
  getWithRetryForTokenRefreshRepeat,
28
28
  IOdspResponse,
29
29
  ISnapshotContents,
30
30
  } from "./odspUtils";
31
31
  import { convertOdspSnapshotToSnapsohtTreeAndBlobs } from "./odspSnapshotParser";
32
- import { parseCompactSnapshotResponse } from "./compactSnapshotParser";
32
+ import { currentReadVersion, parseCompactSnapshotResponse } from "./compactSnapshotParser";
33
33
  import { ReadBuffer } from "./ReadBufferUtils";
34
34
  import { EpochTracker } from "./epochTracker";
35
35
 
@@ -362,89 +362,6 @@ interface ISnapshotRequestAndResponseOptions {
362
362
  requestHeaders: {[index: string]: any},
363
363
  }
364
364
 
365
- /**
366
- * This function fetches the older snapshot format which is the json format(IOdspSnapshot).
367
- * @param odspResolvedUrl - resolved odsp url.
368
- * @param storageToken - token to do the auth for network request.
369
- * @param snapshotOptions - Options used to specify how and what to fetch in the snapshot.
370
- * @param controller - abort controller if caller needs to abort the network call.
371
- * @param epochTracker - epoch tracker used to add/validate epoch in the network call.
372
- * @returns fetched snapshot.
373
- */
374
- async function fetchSnapshotContentsCoreV1(
375
- odspResolvedUrl: IOdspResolvedUrl,
376
- storageToken: string,
377
- snapshotOptions: ISnapshotOptions | undefined,
378
- controller?: AbortController,
379
- epochTracker?: EpochTracker,
380
- ): Promise<ISnapshotRequestAndResponseOptions> {
381
- const snapshotUrl = odspResolvedUrl.endpoints.snapshotStorageUrl;
382
- const url = `${snapshotUrl}/trees/latest?ump=1`;
383
- // The location of file can move on Spo in which case server returns 308(Permanent Redirect) error.
384
- // Adding below header will make VROOM API return 404 instead of 308 and browser can intercept it.
385
- // This error thrown by server will contain the new redirect location. Look at the 404 error parsing
386
- // for futher reference here: \packages\utils\odsp-doclib-utils\src\odspErrorUtils.ts
387
- const header = { prefer: "manualredirect" };
388
- const { body, headers } = getFormBodyAndHeaders(
389
- odspResolvedUrl, storageToken, snapshotOptions, header);
390
- headers.accept = "application/json";
391
- const fetchOptions = {
392
- body,
393
- headers,
394
- signal: controller?.signal,
395
- method: "POST",
396
- };
397
- const response = await (epochTracker?.fetchAndParseAsJSON<IOdspSnapshot>(url, fetchOptions, "treesLatest", true) ??
398
- fetchAndParseAsJSONHelper<IOdspSnapshot>(url, fetchOptions));
399
- const snapshotContents: ISnapshotContents = convertOdspSnapshotToSnapsohtTreeAndBlobs(response.content);
400
- const finalSnapshotContents: IOdspResponse<ISnapshotContents> = { ...response, content: snapshotContents };
401
- return {
402
- odspSnapshotResponse: finalSnapshotContents,
403
- requestHeaders: headers,
404
- requestUrl: url,
405
- };
406
- }
407
-
408
- /**
409
- * This function fetches the binary compact snapshot format. This is an experimental feature
410
- * and is behind a feature flag.
411
- * @param odspResolvedUrl - resolved odsp url.
412
- * @param storageToken - token to do the auth for network request.
413
- * @param snapshotOptions - Options used to specify how and what to fetch in the snapshot.
414
- * @param controller - abort controller if caller needs to abort the network call.
415
- * @param epochTracker - epoch tracker used to add/validate epoch in the network call.
416
- * @returns fetched snapshot.
417
- */
418
- async function fetchSnapshotContentsCoreV2(
419
- odspResolvedUrl: IOdspResolvedUrl,
420
- storageToken: string,
421
- snapshotOptions: ISnapshotOptions | undefined,
422
- controller?: AbortController,
423
- epochTracker?: EpochTracker,
424
- ): Promise<ISnapshotRequestAndResponseOptions> {
425
- const fullUrl = `${odspResolvedUrl.siteUrl}/_api/v2.1/drives/${odspResolvedUrl.driveId}/items/${
426
- odspResolvedUrl.itemId}/opStream/attachments/latest/content?ump=1`;
427
-
428
- const { body, headers } = getFormBodyAndHeaders(odspResolvedUrl, storageToken, snapshotOptions);
429
- const fetchOptions = {
430
- body,
431
- headers,
432
- signal: controller?.signal,
433
- method: "POST",
434
- };
435
-
436
- const response = await (epochTracker?.fetchArray(fullUrl, fetchOptions, "treesLatest", true) ??
437
- fetchArray(fullUrl, fetchOptions));
438
- const snapshotContents: ISnapshotContents = parseCompactSnapshotResponse(
439
- new ReadBuffer(new Uint8Array(response.content)));
440
- const finalSnapshotContents: IOdspResponse<ISnapshotContents> = { ...response, content: snapshotContents };
441
- return {
442
- odspSnapshotResponse: finalSnapshotContents,
443
- requestHeaders: headers,
444
- requestUrl: fullUrl,
445
- };
446
- }
447
-
448
365
  function getFormBodyAndHeaders(
449
366
  odspResolvedUrl: IOdspResolvedUrl,
450
367
  storageToken: string,
@@ -505,6 +422,17 @@ function countTreesInSnapshotTree(snapshotTree: ISnapshotTree): number {
505
422
  return numTrees;
506
423
  }
507
424
 
425
+ /**
426
+ * This function fetches the snapshot and parse it according to what is mentioned in response headers.
427
+ * @param odspResolvedUrl - resolved odsp url.
428
+ * @param storageToken - token to do the auth for network request.
429
+ * @param snapshotOptions - Options used to specify how and what to fetch in the snapshot.
430
+ * @param logger - logger
431
+ * @param fetchBinarySnapshotFormat - whether to fetch binary snapshot or not.
432
+ * @param controller - abort controller if caller needs to abort the network call.
433
+ * @param epochTracker - epoch tracker used to add/validate epoch in the network call.
434
+ * @returns fetched snapshot.
435
+ */
508
436
  export async function downloadSnapshot(
509
437
  odspResolvedUrl: IOdspResolvedUrl,
510
438
  storageToken: string,
@@ -520,13 +448,53 @@ export async function downloadSnapshot(
520
448
  odspResolvedUrl.shareLinkInfo = { ...odspResolvedUrl.shareLinkInfo, sharingLinkToRedeem };
521
449
  }
522
450
 
451
+ const snapshotUrl = odspResolvedUrl.endpoints.snapshotStorageUrl;
452
+ const url = `${snapshotUrl}/trees/latest?ump=1`;
453
+ // The location of file can move on Spo in which case server returns 308(Permanent Redirect) error.
454
+ // Adding below header will make VROOM API return 404 instead of 308 and browser can intercept it.
455
+ // This error thrown by server will contain the new redirect location. Look at the 404 error parsing
456
+ // for futher reference here: \packages\utils\odsp-doclib-utils\src\odspErrorUtils.ts
457
+ const header = {prefer: "manualredirect"};
458
+ const { body, headers } = getFormBodyAndHeaders(
459
+ odspResolvedUrl, storageToken, snapshotOptions, header);
460
+ const fetchOptions = {
461
+ body,
462
+ headers,
463
+ signal: controller?.signal,
464
+ method: "POST",
465
+ };
466
+ // For now we are keeping both json and ms-fluid values in accept header while fetching as we want to let
467
+ // the server decide what format it wants to send to the client as we roll it out slowly.
523
468
  if (fetchBinarySnapshotFormat) {
524
- // Logging an event here as it is not supposed to be used in production yet and only in experimental mode.
525
- logger.sendTelemetryEvent({ eventName: "BinarySnapshotFetched" });
526
- return fetchSnapshotContentsCoreV2(odspResolvedUrl, storageToken, snapshotOptions, controller, epochTracker);
469
+ headers.accept = `application/json, application/ms-fluid; v=${currentReadVersion}`;
470
+ } else {
471
+ headers.accept = "application/json";
472
+ }
473
+ const response = await (epochTracker?.fetch(url, fetchOptions, "treesLatest", true) ??
474
+ fetchHelper(url, fetchOptions));
475
+
476
+ let finalSnapshotContents: IOdspResponse<ISnapshotContents>;
477
+ const contentType = response.headers.get("content-type");
478
+ if (contentType === "application/json") {
479
+ const text = await response.content.text();
480
+ const content: IOdspSnapshot = JSON.parse(text);
481
+ response.propsToLog.bodySize = text.length;
482
+ const snapshotContents: ISnapshotContents = convertOdspSnapshotToSnapsohtTreeAndBlobs(content);
483
+ finalSnapshotContents = { ...response, content: snapshotContents };
527
484
  } else {
528
- return fetchSnapshotContentsCoreV1(odspResolvedUrl, storageToken, snapshotOptions, controller, epochTracker);
485
+ assert(contentType === "application/ms-fluid", 0x2c3 /* "Content type should be application/ms-fluid" */);
486
+ const content = await response.content.arrayBuffer();
487
+ response.propsToLog.bodySize = content.byteLength;
488
+ const snapshotContents: ISnapshotContents = parseCompactSnapshotResponse(
489
+ new ReadBuffer(new Uint8Array(content)));
490
+ finalSnapshotContents = { ...response, content: snapshotContents };
529
491
  }
492
+ response.propsToLog.contentType = contentType;
493
+ return {
494
+ odspSnapshotResponse: finalSnapshotContents,
495
+ requestHeaders: headers,
496
+ requestUrl: url,
497
+ };
530
498
  }
531
499
 
532
500
  function isRedeemSharingLinkError(odspResolvedUrl: IOdspResolvedUrl, error: any) {
@@ -81,6 +81,7 @@ export class OdspDocumentService implements IDocumentService {
81
81
  hostPolicy: HostStoragePolicy,
82
82
  epochTracker: EpochTracker,
83
83
  socketReferenceKeyPrefix?: string,
84
+ clientIsSummarizer?: boolean,
84
85
  ): Promise<IDocumentService> {
85
86
  return new OdspDocumentService(
86
87
  getOdspResolvedUrl(resolvedUrl),
@@ -92,6 +93,7 @@ export class OdspDocumentService implements IDocumentService {
92
93
  hostPolicy,
93
94
  epochTracker,
94
95
  socketReferenceKeyPrefix,
96
+ clientIsSummarizer,
95
97
  );
96
98
  }
97
99
 
@@ -131,6 +133,7 @@ export class OdspDocumentService implements IDocumentService {
131
133
  hostPolicy: HostStoragePolicy,
132
134
  private readonly epochTracker: EpochTracker,
133
135
  private readonly socketReferenceKeyPrefix?: string,
136
+ private readonly clientIsSummarizer?: boolean,
134
137
  ) {
135
138
  this._policies = {
136
139
  // load in storage-only mode if a file version is specified
@@ -150,7 +153,7 @@ export class OdspDocumentService implements IDocumentService {
150
153
  this.hostPolicy = hostPolicy;
151
154
  this.hostPolicy.fetchBinarySnapshotFormat ??=
152
155
  this.mc.config.getBoolean("Fluid.Driver.Odsp.binaryFormatSnapshot");
153
- if (this.odspResolvedUrl.summarizer) {
156
+ if (this.clientIsSummarizer) {
154
157
  this.hostPolicy = { ...this.hostPolicy, summarizerClient: true };
155
158
  }
156
159
  }
@@ -385,7 +388,7 @@ export class OdspDocumentService implements IDocumentService {
385
388
  };
386
389
 
387
390
  const getResponseAndRefreshAfterDeltaMs = async () => {
388
- let _response = await this.cache.sessionJoinCache.addOrGet(this.joinSessionKey, executeFetch);
391
+ const _response = await this.cache.sessionJoinCache.addOrGet(this.joinSessionKey, executeFetch);
389
392
  // If the response does not contain refreshSessionDurationSeconds, then treat it as old flow and let the
390
393
  // cache entry to be treated as expired after 1 hour.
391
394
  _response.joinSessionResponse.refreshSessionDurationSeconds =
@@ -415,16 +418,16 @@ export class OdspDocumentService implements IDocumentService {
415
418
  .catch((error) => {
416
419
  this.mc.logger.sendErrorEvent({
417
420
  eventName: "JoinSessionRefreshError",
418
- ...props,
421
+ details: JSON.stringify(props),
419
422
  },
420
423
  error,
421
424
  );
422
425
  });
423
426
  } else {
424
427
  // Logging just for informational purposes to help with debugging as this is a new feature.
425
- this.mc.logger.sendErrorEvent({
428
+ this.mc.logger.sendTelemetryEvent({
426
429
  eventName: "JoinSessionRefreshNotScheduled",
427
- ...props,
430
+ details: JSON.stringify(props),
428
431
  });
429
432
  }
430
433
  }
@@ -55,6 +55,7 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
55
55
  createNewSummary: ISummaryTree | undefined,
56
56
  createNewResolvedUrl: IResolvedUrl,
57
57
  logger?: ITelemetryBaseLogger,
58
+ clientIsSummarizer?: boolean,
58
59
  ): Promise<IDocumentService> {
59
60
  ensureFluidResolvedUrl(createNewResolvedUrl);
60
61
 
@@ -113,7 +114,8 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
113
114
  this.hostPolicy.cacheCreateNewSummary ?? true,
114
115
  !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,
115
116
  );
116
- const docService = this.createDocumentServiceCore(odspResolvedUrl, odspLogger, cacheAndTracker);
117
+ const docService = this.createDocumentServiceCore(odspResolvedUrl, odspLogger,
118
+ cacheAndTracker, clientIsSummarizer);
117
119
  event.end({
118
120
  docId: odspResolvedUrl.hashedDocumentId,
119
121
  });
@@ -147,14 +149,16 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
147
149
  public async createDocumentService(
148
150
  resolvedUrl: IResolvedUrl,
149
151
  logger?: ITelemetryBaseLogger,
152
+ clientIsSummarizer?: boolean,
150
153
  ): Promise<IDocumentService> {
151
- return this.createDocumentServiceCore(resolvedUrl, createOdspLogger(logger));
154
+ return this.createDocumentServiceCore(resolvedUrl, createOdspLogger(logger), undefined, clientIsSummarizer);
152
155
  }
153
156
 
154
157
  private async createDocumentServiceCore(
155
158
  resolvedUrl: IResolvedUrl,
156
159
  odspLogger: TelemetryLogger,
157
160
  cacheAndTrackerArg?: ICacheAndTracker,
161
+ clientIsSummarizer?: boolean,
158
162
  ): Promise<IDocumentService> {
159
163
  const odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);
160
164
  const resolvedUrlData: IOdspUrlParts = {
@@ -194,6 +198,7 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
194
198
  this.hostPolicy,
195
199
  cacheAndTracker.epochTracker,
196
200
  this.socketReferenceKeyPrefix,
201
+ clientIsSummarizer,
197
202
  );
198
203
  }
199
204
  }
@@ -356,38 +356,20 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
356
356
  if (!snapshotTree) {
357
357
  return null;
358
358
  }
359
- // Decode commit paths
360
- const commits = {};
361
359
 
362
- for (const key of Object.keys(snapshotTree.commits)) {
363
- commits[decodeURIComponent(key)] = snapshotTree.commits[key];
364
- }
365
-
366
- let finalTree: api.ISnapshotTree;
367
- // For container loaded from detach new summary, we will not have a commit for ".app" in downloaded summary as the client uploaded both
368
- // ".app" and ".protocol" trees by itself. For other summaries, we will have ".app" as commit because client previously only uploaded the
369
- // app summary.
370
- if (commits && commits[".app"]) {
371
- // The latest snapshot is a summary
372
- // attempt to read .protocol from commits for backwards compat
373
- finalTree = await this.readSummaryTree(commits[".protocol"] || snapshotTree.trees[".protocol"], commits[".app"] as string);
374
- } else {
375
- if (snapshotTree.blobs) {
376
- const attributesBlob = snapshotTree.blobs.attributes;
377
- if (attributesBlob) {
378
- this.attributesBlobHandles.add(attributesBlob);
379
- }
360
+ if (snapshotTree.blobs) {
361
+ const attributesBlob = snapshotTree.blobs.attributes;
362
+ if (attributesBlob) {
363
+ this.attributesBlobHandles.add(attributesBlob);
380
364
  }
365
+ }
381
366
 
382
- snapshotTree.commits = commits;
367
+ // When we upload the container snapshot, we upload appTree in ".app" and protocol tree in ".protocol"
368
+ // So when we request the snapshot we get ".app" as tree and not as commit node as in the case just above.
369
+ const appTree = snapshotTree.trees[".app"];
370
+ const protocolTree = snapshotTree.trees[".protocol"];
383
371
 
384
- // When we upload the container snapshot, we upload appTree in ".app" and protocol tree in ".protocol"
385
- // So when we request the snapshot we get ".app" as tree and not as commit node as in the case just above.
386
- const appTree = snapshotTree.trees[".app"];
387
- const protocolTree = snapshotTree.trees[".protocol"];
388
- finalTree = this.combineProtocolAndAppSnapshotTree(appTree, protocolTree);
389
- }
390
- return finalTree;
372
+ return this.combineProtocolAndAppSnapshotTree(appTree, protocolTree);
391
373
  }
392
374
 
393
375
  public async getVersions(blobid: string | null, count: number): Promise<api.IVersion[]> {
@@ -782,39 +764,6 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
782
764
  return tree;
783
765
  }
784
766
 
785
- /**
786
- * Reads a summary tree
787
- * @param protocolTreeOrId - Protocol snapshot tree or id of the protocol tree
788
- * @param appTreeId - Id of the app tree
789
- */
790
- private async readSummaryTree(protocolTreeOrId: api.ISnapshotTree | string, appTreeId: string): Promise<api.ISnapshotTree> {
791
- // Load the app and protocol trees and return them
792
- let hierarchicalProtocolTree: api.ISnapshotTree | null;
793
- if (typeof (protocolTreeOrId) === "string") {
794
- // Backwards compat for older summaries
795
- hierarchicalProtocolTree = await this.readTree(protocolTreeOrId);
796
- } else {
797
- hierarchicalProtocolTree = protocolTreeOrId;
798
- }
799
-
800
- const hierarchicalAppTree = await this.readTree(appTreeId);
801
- if (!hierarchicalProtocolTree) {
802
- throw new Error("Invalid protocol tree");
803
- }
804
-
805
- if (!hierarchicalAppTree) {
806
- throw new Error("Invalid app tree");
807
- }
808
-
809
- if (hierarchicalProtocolTree.blobs) {
810
- const attributesBlob = hierarchicalProtocolTree.blobs.attributes;
811
- if (attributesBlob) {
812
- this.attributesBlobHandles.add(attributesBlob);
813
- }
814
- }
815
- return this.combineProtocolAndAppSnapshotTree(hierarchicalAppTree, hierarchicalProtocolTree);
816
- }
817
-
818
767
  private combineProtocolAndAppSnapshotTree(
819
768
  hierarchicalAppTree: api.ISnapshotTree,
820
769
  hierarchicalProtocolTree: api.ISnapshotTree,
@@ -823,9 +772,6 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
823
772
  blobs: {
824
773
  ...hierarchicalAppTree.blobs,
825
774
  },
826
- commits: {
827
- ...hierarchicalAppTree.commits,
828
- },
829
775
  trees: {
830
776
  ...hierarchicalAppTree.trees,
831
777
  // the app tree could have a .protocol
@@ -2,21 +2,23 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
-
6
5
  import { assert } from "@fluidframework/common-utils";
7
- import { IFluidCodeDetails, IRequest, isFluidPackage } from "@fluidframework/core-interfaces";
6
+ import { IRequest } from "@fluidframework/core-interfaces";
8
7
  import {
8
+ DriverErrorType,
9
9
  DriverHeader,
10
10
  IContainerPackageInfo,
11
11
  IResolvedUrl,
12
12
  IUrlResolver,
13
13
  } from "@fluidframework/driver-definitions";
14
14
  import { IOdspResolvedUrl, ShareLinkTypes, ShareLinkInfoType } from "@fluidframework/odsp-driver-definitions";
15
+ import { NonRetryableError } from "@fluidframework/driver-utils";
15
16
  import { createOdspUrl } from "./createOdspUrl";
16
17
  import { getApiRoot } from "./odspUrlHelper";
17
18
  import { getOdspResolvedUrl } from "./odspUtils";
18
19
  import { getHashedDocumentId } from "./odspPublicUtils";
19
20
  import { ClpCompliantAppHeader } from "./contractsPublic";
21
+ import { pkgVersion } from "./packageVersion";
20
22
 
21
23
  function getUrlBase(siteUrl: string, driveId: string, itemId: string, fileVersion?: string) {
22
24
  const siteOrigin = new URL(siteUrl).origin;
@@ -74,7 +76,10 @@ export class OdspDriverUrlResolver implements IUrlResolver {
74
76
  const packageName = searchParams.get("containerPackageName");
75
77
  const createLinkType = searchParams.get("createLinkType");
76
78
  if (!(fileName && siteURL && driveID && filePath !== null && filePath !== undefined)) {
77
- throw new Error("Proper new file params should be there!!");
79
+ throw new NonRetryableError(
80
+ "Proper new file params should be there!!",
81
+ DriverErrorType.genericError,
82
+ { driverVersion: pkgVersion });
78
83
  }
79
84
  let shareLinkInfo: ShareLinkInfoType | undefined;
80
85
  if(createLinkType && createLinkType in ShareLinkTypes) {
@@ -156,22 +161,26 @@ export class OdspDriverUrlResolver implements IUrlResolver {
156
161
  public async getAbsoluteUrl(
157
162
  resolvedUrl: IResolvedUrl,
158
163
  relativeUrl: string,
159
- packageInfoSource?: IContainerPackageInfo | IFluidCodeDetails,
164
+ packageInfoSource?: IContainerPackageInfo,
160
165
  ): Promise<string> {
161
166
  let dataStorePath = relativeUrl;
162
167
  if (dataStorePath.startsWith("/")) {
163
168
  dataStorePath = dataStorePath.substr(1);
164
169
  }
165
170
  const odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);
166
-
167
- // back-compat: IFluidCodeDetails usage to be removed in 0.58.0
171
+ // back-compat: GitHub #9653
172
+ const isFluidPackage = (pkg: any) =>
173
+ typeof pkg === "object"
174
+ && typeof pkg?.name === "string"
175
+ && typeof pkg?.fluid === "object";
168
176
  let containerPackageName;
169
177
  if (packageInfoSource && "name" in packageInfoSource) {
170
178
  containerPackageName = packageInfoSource.name;
171
- } else if (isFluidPackage(packageInfoSource?.package)) {
172
- containerPackageName = packageInfoSource?.package.name;
179
+ // packageInfoSource is cast to any as it is typed to IContainerPackageInfo instead of IFluidCodeDetails
180
+ } else if (isFluidPackage((packageInfoSource as any)?.package)) {
181
+ containerPackageName = (packageInfoSource as any)?.package.name;
173
182
  } else {
174
- containerPackageName = packageInfoSource?.package;
183
+ containerPackageName = (packageInfoSource as any)?.package;
175
184
  }
176
185
  containerPackageName = containerPackageName ?? odspResolvedUrl.codeHint?.containerPackageName;
177
186
 
@@ -2,9 +2,8 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
-
6
5
  import { PromiseCache } from "@fluidframework/common-utils";
7
- import { IFluidCodeDetails, IRequest, isFluidPackage } from "@fluidframework/core-interfaces";
6
+ import { IRequest } from "@fluidframework/core-interfaces";
8
7
  import {
9
8
  IContainerPackageInfo,
10
9
  IResolvedUrl,
@@ -191,20 +190,24 @@ export class OdspDriverUrlResolverForShareLink implements IUrlResolver {
191
190
  public async getAbsoluteUrl(
192
191
  resolvedUrl: IResolvedUrl,
193
192
  dataStorePath: string,
194
- packageInfoSource?: IContainerPackageInfo | IFluidCodeDetails,
193
+ packageInfoSource?: IContainerPackageInfo,
195
194
  ): Promise<string> {
196
195
  const odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);
197
196
  const shareLink = await this.getShareLinkPromise(odspResolvedUrl);
198
197
  const shareLinkUrl = new URL(shareLink);
199
-
200
- // back-compat: IFluidCodeDetails usage to be removed in 0.58.0
198
+ // back-compat: GitHub #9653
199
+ const isFluidPackage = (pkg: any) =>
200
+ typeof pkg === "object"
201
+ && typeof pkg?.name === "string"
202
+ && typeof pkg?.fluid === "object";
201
203
  let containerPackageName;
202
204
  if (packageInfoSource && "name" in packageInfoSource) {
203
205
  containerPackageName = packageInfoSource.name;
204
- } else if (isFluidPackage(packageInfoSource?.package)) {
205
- containerPackageName = packageInfoSource?.package.name;
206
+ // packageInfoSource is cast to any as it is typed to IContainerPackageInfo instead of IFluidCodeDetails
207
+ } else if (isFluidPackage((packageInfoSource as any)?.package)) {
208
+ containerPackageName = (packageInfoSource as any)?.package.name;
206
209
  } else {
207
- containerPackageName = packageInfoSource?.package;
210
+ containerPackageName = (packageInfoSource as any)?.package;
208
211
  }
209
212
  containerPackageName = containerPackageName ?? odspResolvedUrl.codeHint?.containerPackageName;
210
213
 
@@ -18,7 +18,7 @@ import { ISnapshotContents } from "./odspUtils";
18
18
  function buildHierarchy(flatTree: IOdspSnapshotCommit): api.ISnapshotTree {
19
19
  const lookup: { [path: string]: api.ISnapshotTree } = {};
20
20
  // id is required for root tree as it will be used to determine the version we loaded from.
21
- const root: api.ISnapshotTree = { id: flatTree.id, blobs: {}, commits: {}, trees: {} };
21
+ const root: api.ISnapshotTree = { id: flatTree.id, blobs: {}, trees: {} };
22
22
  lookup[""] = root;
23
23
 
24
24
  for (const entry of flatTree.entries) {
@@ -33,7 +33,6 @@ function buildHierarchy(flatTree: IOdspSnapshotCommit): api.ISnapshotTree {
33
33
  if (entry.type === "tree") {
34
34
  const newTree: api.ISnapshotTree = {
35
35
  blobs: {},
36
- commits: {},
37
36
  trees: {},
38
37
  unreferenced: entry.unreferenced,
39
38
  };
@@ -41,8 +40,6 @@ function buildHierarchy(flatTree: IOdspSnapshotCommit): api.ISnapshotTree {
41
40
  lookup[entry.path] = newTree;
42
41
  } else if (entry.type === "blob") {
43
42
  node.blobs[decodeURIComponent(entryPathBase)] = entry.id;
44
- } else if (entry.type === "commit") {
45
- node.commits[decodeURIComponent(entryPathBase)] = entry.id;
46
43
  }
47
44
  }
48
45