@fluidframework/odsp-driver 0.59.2001 → 0.59.3000

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 (165) hide show
  1. package/.eslintrc.js +0 -1
  2. package/dist/ReadBufferUtils.js +2 -2
  3. package/dist/ReadBufferUtils.js.map +1 -1
  4. package/dist/WriteBufferUtils.js +14 -14
  5. package/dist/WriteBufferUtils.js.map +1 -1
  6. package/dist/checkUrl.js +1 -1
  7. package/dist/checkUrl.js.map +1 -1
  8. package/dist/compactSnapshotParser.js +27 -27
  9. package/dist/compactSnapshotParser.js.map +1 -1
  10. package/dist/compactSnapshotWriter.js +15 -15
  11. package/dist/compactSnapshotWriter.js.map +1 -1
  12. package/dist/contracts.d.ts +0 -1
  13. package/dist/contracts.d.ts.map +1 -1
  14. package/dist/contracts.js.map +1 -1
  15. package/dist/createFile.js +15 -15
  16. package/dist/createFile.js.map +1 -1
  17. package/dist/createNewUtils.js +4 -4
  18. package/dist/createNewUtils.js.map +1 -1
  19. package/dist/epochTracker.d.ts.map +1 -1
  20. package/dist/epochTracker.js +11 -11
  21. package/dist/epochTracker.js.map +1 -1
  22. package/dist/fetch.js +1 -1
  23. package/dist/fetch.js.map +1 -1
  24. package/dist/fetchSnapshot.d.ts.map +1 -1
  25. package/dist/fetchSnapshot.js +19 -19
  26. package/dist/fetchSnapshot.js.map +1 -1
  27. package/dist/getFileLink.js +19 -19
  28. package/dist/getFileLink.js.map +1 -1
  29. package/dist/getQueryString.d.ts.map +1 -1
  30. package/dist/getQueryString.js.map +1 -1
  31. package/dist/getUrlAndHeadersWithAuth.d.ts.map +1 -1
  32. package/dist/getUrlAndHeadersWithAuth.js.map +1 -1
  33. package/dist/odspCache.d.ts.map +1 -1
  34. package/dist/odspCache.js.map +1 -1
  35. package/dist/odspDeltaStorageService.d.ts.map +1 -1
  36. package/dist/odspDeltaStorageService.js +5 -5
  37. package/dist/odspDeltaStorageService.js.map +1 -1
  38. package/dist/odspDocumentDeltaConnection.d.ts.map +1 -1
  39. package/dist/odspDocumentDeltaConnection.js +12 -12
  40. package/dist/odspDocumentDeltaConnection.js.map +1 -1
  41. package/dist/odspDocumentService.js +9 -8
  42. package/dist/odspDocumentService.js.map +1 -1
  43. package/dist/odspDocumentServiceFactory.js +1 -1
  44. package/dist/odspDocumentServiceFactory.js.map +1 -1
  45. package/dist/odspDocumentServiceFactoryCore.d.ts.map +1 -1
  46. package/dist/odspDocumentServiceFactoryCore.js +20 -12
  47. package/dist/odspDocumentServiceFactoryCore.js.map +1 -1
  48. package/dist/odspDocumentStorageManager.d.ts +1 -0
  49. package/dist/odspDocumentStorageManager.d.ts.map +1 -1
  50. package/dist/odspDocumentStorageManager.js +34 -32
  51. package/dist/odspDocumentStorageManager.js.map +1 -1
  52. package/dist/odspDriverUrlResolver.js +10 -10
  53. package/dist/odspDriverUrlResolver.js.map +1 -1
  54. package/dist/odspDriverUrlResolverForShareLink.js +10 -10
  55. package/dist/odspDriverUrlResolverForShareLink.js.map +1 -1
  56. package/dist/odspError.d.ts +1 -1
  57. package/dist/odspError.d.ts.map +1 -1
  58. package/dist/odspError.js +1 -1
  59. package/dist/odspError.js.map +1 -1
  60. package/dist/odspFluidFileLink.js +2 -2
  61. package/dist/odspFluidFileLink.js.map +1 -1
  62. package/dist/odspPublicUtils.js +1 -1
  63. package/dist/odspPublicUtils.js.map +1 -1
  64. package/dist/odspSnapshotParser.js +3 -3
  65. package/dist/odspSnapshotParser.js.map +1 -1
  66. package/dist/odspSummaryUploadManager.js +7 -7
  67. package/dist/odspSummaryUploadManager.js.map +1 -1
  68. package/dist/odspUtils.js +9 -9
  69. package/dist/odspUtils.js.map +1 -1
  70. package/dist/opsCaching.js.map +1 -1
  71. package/dist/packageVersion.d.ts +1 -1
  72. package/dist/packageVersion.js +1 -1
  73. package/dist/packageVersion.js.map +1 -1
  74. package/dist/prefetchLatestSnapshot.js +7 -7
  75. package/dist/prefetchLatestSnapshot.js.map +1 -1
  76. package/dist/retryErrorsStorageAdapter.d.ts.map +1 -1
  77. package/dist/retryErrorsStorageAdapter.js +1 -1
  78. package/dist/retryErrorsStorageAdapter.js.map +1 -1
  79. package/dist/retryUtils.js +4 -4
  80. package/dist/retryUtils.js.map +1 -1
  81. package/dist/vroom.js +3 -3
  82. package/dist/vroom.js.map +1 -1
  83. package/dist/zipItDataRepresentationUtils.d.ts.map +1 -1
  84. package/dist/zipItDataRepresentationUtils.js +21 -12
  85. package/dist/zipItDataRepresentationUtils.js.map +1 -1
  86. package/lib/WriteBufferUtils.js +1 -1
  87. package/lib/WriteBufferUtils.js.map +1 -1
  88. package/lib/compactSnapshotParser.js.map +1 -1
  89. package/lib/compactSnapshotWriter.js.map +1 -1
  90. package/lib/contracts.d.ts +0 -1
  91. package/lib/contracts.d.ts.map +1 -1
  92. package/lib/contracts.js.map +1 -1
  93. package/lib/createFile.js.map +1 -1
  94. package/lib/epochTracker.d.ts.map +1 -1
  95. package/lib/epochTracker.js +1 -1
  96. package/lib/epochTracker.js.map +1 -1
  97. package/lib/fetchSnapshot.d.ts.map +1 -1
  98. package/lib/fetchSnapshot.js.map +1 -1
  99. package/lib/getFileLink.js +6 -6
  100. package/lib/getFileLink.js.map +1 -1
  101. package/lib/getQueryString.d.ts.map +1 -1
  102. package/lib/getQueryString.js.map +1 -1
  103. package/lib/getUrlAndHeadersWithAuth.d.ts.map +1 -1
  104. package/lib/getUrlAndHeadersWithAuth.js.map +1 -1
  105. package/lib/odspCache.d.ts.map +1 -1
  106. package/lib/odspCache.js.map +1 -1
  107. package/lib/odspDeltaStorageService.d.ts.map +1 -1
  108. package/lib/odspDeltaStorageService.js.map +1 -1
  109. package/lib/odspDocumentDeltaConnection.d.ts.map +1 -1
  110. package/lib/odspDocumentDeltaConnection.js +1 -1
  111. package/lib/odspDocumentDeltaConnection.js.map +1 -1
  112. package/lib/odspDocumentService.js +2 -1
  113. package/lib/odspDocumentService.js.map +1 -1
  114. package/lib/odspDocumentServiceFactoryCore.d.ts.map +1 -1
  115. package/lib/odspDocumentServiceFactoryCore.js +10 -2
  116. package/lib/odspDocumentServiceFactoryCore.js.map +1 -1
  117. package/lib/odspDocumentStorageManager.d.ts +1 -0
  118. package/lib/odspDocumentStorageManager.d.ts.map +1 -1
  119. package/lib/odspDocumentStorageManager.js +17 -15
  120. package/lib/odspDocumentStorageManager.js.map +1 -1
  121. package/lib/odspDriverUrlResolver.js +5 -5
  122. package/lib/odspDriverUrlResolver.js.map +1 -1
  123. package/lib/odspDriverUrlResolverForShareLink.js.map +1 -1
  124. package/lib/odspError.d.ts +1 -1
  125. package/lib/odspError.d.ts.map +1 -1
  126. package/lib/odspFluidFileLink.js.map +1 -1
  127. package/lib/odspSnapshotParser.js +1 -1
  128. package/lib/odspSnapshotParser.js.map +1 -1
  129. package/lib/odspUtils.js.map +1 -1
  130. package/lib/opsCaching.js.map +1 -1
  131. package/lib/packageVersion.d.ts +1 -1
  132. package/lib/packageVersion.js +1 -1
  133. package/lib/packageVersion.js.map +1 -1
  134. package/lib/retryErrorsStorageAdapter.d.ts.map +1 -1
  135. package/lib/retryErrorsStorageAdapter.js.map +1 -1
  136. package/lib/retryUtils.js +1 -1
  137. package/lib/retryUtils.js.map +1 -1
  138. package/lib/vroom.js.map +1 -1
  139. package/lib/zipItDataRepresentationUtils.d.ts.map +1 -1
  140. package/lib/zipItDataRepresentationUtils.js +12 -3
  141. package/lib/zipItDataRepresentationUtils.js.map +1 -1
  142. package/package.json +14 -13
  143. package/src/compactSnapshotParser.ts +2 -2
  144. package/src/contracts.ts +4 -5
  145. package/src/createFile.ts +2 -2
  146. package/src/epochTracker.ts +9 -10
  147. package/src/fetchSnapshot.ts +10 -10
  148. package/src/getFileLink.ts +10 -10
  149. package/src/getQueryString.ts +1 -1
  150. package/src/getUrlAndHeadersWithAuth.ts +1 -1
  151. package/src/odspCache.ts +2 -2
  152. package/src/odspDeltaStorageService.ts +4 -5
  153. package/src/odspDocumentDeltaConnection.ts +2 -2
  154. package/src/odspDocumentService.ts +5 -5
  155. package/src/odspDocumentServiceFactoryCore.ts +13 -1
  156. package/src/odspDocumentStorageManager.ts +25 -18
  157. package/src/odspDriverUrlResolver.ts +2 -2
  158. package/src/odspDriverUrlResolverForShareLink.ts +1 -1
  159. package/src/odspSnapshotParser.ts +2 -2
  160. package/src/odspUtils.ts +6 -6
  161. package/src/opsCaching.ts +2 -2
  162. package/src/packageVersion.ts +1 -1
  163. package/src/retryErrorsStorageAdapter.ts +1 -1
  164. package/src/vroom.ts +1 -1
  165. package/src/zipItDataRepresentationUtils.ts +15 -13
package/src/createFile.ts CHANGED
@@ -87,13 +87,13 @@ export async function createNewFluidFile(
87
87
  sharingLinkErrorReason = content.sharingLinkErrorReason;
88
88
  }
89
89
 
90
- const odspUrl = createOdspUrl({... newFileInfo, itemId, dataStorePath: "/"});
90
+ const odspUrl = createOdspUrl({ ... newFileInfo, itemId, dataStorePath: "/" });
91
91
  const resolver = new OdspDriverUrlResolver();
92
92
  const odspResolvedUrl = await resolver.resolve({ url: odspUrl });
93
93
  fileEntry.docId = odspResolvedUrl.hashedDocumentId;
94
94
  fileEntry.resolvedUrl = odspResolvedUrl;
95
95
 
96
- if(sharingLink || sharingLinkErrorReason) {
96
+ if (sharingLink || sharingLinkErrorReason) {
97
97
  odspResolvedUrl.shareLinkInfo = {
98
98
  createLink: {
99
99
  type: newFileInfo.createLinkType,
@@ -198,8 +198,8 @@ export class EpochTracker implements IPersistedFileCache {
198
198
 
199
199
  private async fetchCore<T>(
200
200
  url: string,
201
- fetchOptions: {[index: string]: any},
202
- fetcher: (url: string, fetchOptions: {[index: string]: any}) => Promise<IOdspResponse<T>>,
201
+ fetchOptions: { [index: string]: any; },
202
+ fetcher: (url: string, fetchOptions: { [index: string]: any; }) => Promise<IOdspResponse<T>>,
203
203
  fetchType: FetchType,
204
204
  addInBody: boolean = false,
205
205
  fetchReason?: string,
@@ -224,7 +224,7 @@ export class EpochTracker implements IPersistedFileCache {
224
224
  await this.checkForEpochError(error, epochFromResponse, fetchType);
225
225
  throw error;
226
226
  }).catch((error) => {
227
- const fluidError = normalizeError(error, { props: { XRequestStatsHeader: clientCorrelationId }});
227
+ const fluidError = normalizeError(error, { props: { XRequestStatsHeader: clientCorrelationId } });
228
228
  throw fluidError;
229
229
  });
230
230
  }
@@ -239,7 +239,7 @@ export class EpochTracker implements IPersistedFileCache {
239
239
  */
240
240
  public async fetchArray(
241
241
  url: string,
242
- fetchOptions: {[index: string]: any},
242
+ fetchOptions: { [index: string]: any; },
243
243
  fetchType: FetchType,
244
244
  addInBody: boolean = false,
245
245
  fetchReason?: string,
@@ -254,7 +254,7 @@ export class EpochTracker implements IPersistedFileCache {
254
254
  ) {
255
255
  const isClpCompliantApp = getOdspResolvedUrl(this.fileEntry.resolvedUrl).isClpCompliantApp;
256
256
  if (addInBody) {
257
- const headers: {[key: string]: string} = {};
257
+ const headers: { [key: string]: string; } = {};
258
258
  headers["X-RequestStats"] = clientCorrelationId;
259
259
  if (this.fluidEpoch !== undefined) {
260
260
  headers["x-fluid-epoch"] = this.fluidEpoch;
@@ -281,14 +281,14 @@ export class EpochTracker implements IPersistedFileCache {
281
281
  }
282
282
  }
283
283
 
284
- private addParamInBody(fetchOptions: RequestInit, headers: {[key: string]: string}) {
284
+ private addParamInBody(fetchOptions: RequestInit, headers: { [key: string]: string; }) {
285
285
  // We use multi part form request for post body where we want to use this.
286
286
  // So extract the form boundary to mark the end of form.
287
287
  const body = fetchOptions.body;
288
288
  assert(typeof body === "string", 0x21d /* "body is not string" */);
289
289
  const splitBody = body.split("\r\n");
290
290
  const firstLine = splitBody.shift();
291
- assert(firstLine !== undefined && firstLine.startsWith("--"), 0x21e /* "improper boundary format" */);
291
+ assert(firstLine?.startsWith("--") === true, 0x21e /* "improper boundary format" */);
292
292
  const formParams = [firstLine];
293
293
  Object.entries(headers).forEach(([key, value]) => {
294
294
  formParams.push(`${key}: ${value}`);
@@ -412,7 +412,7 @@ export class EpochTrackerWithRedemption extends EpochTracker {
412
412
 
413
413
  public async fetchAndParseAsJSON<T>(
414
414
  url: string,
415
- fetchOptions: {[index: string]: any},
415
+ fetchOptions: { [index: string]: any; },
416
416
  fetchType: FetchType,
417
417
  addInBody: boolean = false,
418
418
  fetchReason?: string,
@@ -475,8 +475,7 @@ export function createOdspCacheAndTracker(
475
475
  persistedCacheArg: IPersistedCache,
476
476
  nonpersistentCache: INonPersistentCache,
477
477
  fileEntry: IFileEntry,
478
- logger: ITelemetryLogger): ICacheAndTracker
479
- {
478
+ logger: ITelemetryLogger): ICacheAndTracker {
480
479
  const epochTracker = new EpochTrackerWithRedemption(persistedCacheArg, fileEntry, logger);
481
480
  return {
482
481
  cache: {
@@ -59,7 +59,7 @@ export async function fetchSnapshot(
59
59
  fetchFullSnapshot: boolean,
60
60
  forceAccessTokenViaAuthorizationHeader: boolean,
61
61
  logger: ITelemetryLogger,
62
- snapshotDownloader: (url: string, fetchOptions: {[index: string]: any}) => Promise<IOdspResponse<unknown>>,
62
+ snapshotDownloader: (url: string, fetchOptions: { [index: string]: any; }) => Promise<IOdspResponse<unknown>>,
63
63
  ): Promise<ISnapshotContents> {
64
64
  const path = `/trees/${versionId}`;
65
65
  let queryParams: ISnapshotOptions = {};
@@ -104,7 +104,7 @@ export async function fetchSnapshotWithRedeem(
104
104
  ): Promise<ISnapshotContents> {
105
105
  // back-compat: This block to be removed with #8784 when we only consume/consider odsp resolvers that are >= 0.51
106
106
  const sharingLinkToRedeem = (odspResolvedUrl as any).sharingLinkToRedeem;
107
- if(sharingLinkToRedeem) {
107
+ if (sharingLinkToRedeem) {
108
108
  odspResolvedUrl.shareLinkInfo = { ...odspResolvedUrl.shareLinkInfo, sharingLinkToRedeem };
109
109
  }
110
110
 
@@ -323,7 +323,7 @@ async function fetchLatestSnapshotCore(
323
323
  encodedBlobsSize,
324
324
  sequenceNumber,
325
325
  ops: snapshot.ops?.length ?? 0,
326
- nonSysOps: snapshot.ops?.filter((op) => !isSystemMessage(op)).length ?? 0,
326
+ nonSysOps: snapshot.ops?.filter((op) => !isSystemMessage(op)).length ?? 0,
327
327
  headers: Object.keys(response.requestHeaders).length !== 0 ? true : undefined,
328
328
  // Interval between the first fetch until the last byte of the last redirect.
329
329
  redirectTime,
@@ -366,16 +366,16 @@ async function fetchLatestSnapshotCore(
366
366
  }
367
367
 
368
368
  interface ISnapshotRequestAndResponseOptions {
369
- odspSnapshotResponse: IOdspResponse<ISnapshotContents>,
370
- requestUrl: string,
371
- requestHeaders: {[index: string]: any},
369
+ odspSnapshotResponse: IOdspResponse<ISnapshotContents>;
370
+ requestUrl: string;
371
+ requestHeaders: { [index: string]: any; };
372
372
  }
373
373
 
374
374
  function getFormBodyAndHeaders(
375
375
  odspResolvedUrl: IOdspResolvedUrl,
376
376
  storageToken: string,
377
377
  snapshotOptions: ISnapshotOptions | undefined,
378
- headers?: {[index: string]: string},
378
+ headers?: { [index: string]: string; },
379
379
  ) {
380
380
  const formBoundary = uuid();
381
381
  const formParams: string[] = [];
@@ -402,7 +402,7 @@ function getFormBodyAndHeaders(
402
402
  formParams.push(`_post: 1`);
403
403
  formParams.push(`\r\n--${formBoundary}--`);
404
404
  const postBody = formParams.join("\r\n");
405
- const header: {[index: string]: any} = {
405
+ const header: { [index: string]: any; } = {
406
406
  "Content-Type": `multipart/form-data;boundary=${formBoundary}`,
407
407
  };
408
408
  return { body: postBody, headers: header };
@@ -453,7 +453,7 @@ export async function downloadSnapshot(
453
453
  ): Promise<ISnapshotRequestAndResponseOptions> {
454
454
  // back-compat: This block to be removed with #8784 when we only consume/consider odsp resolvers that are >= 0.51
455
455
  const sharingLinkToRedeem = (odspResolvedUrl as any).sharingLinkToRedeem;
456
- if(sharingLinkToRedeem) {
456
+ if (sharingLinkToRedeem) {
457
457
  odspResolvedUrl.shareLinkInfo = { ...odspResolvedUrl.shareLinkInfo, sharingLinkToRedeem };
458
458
  }
459
459
 
@@ -463,7 +463,7 @@ export async function downloadSnapshot(
463
463
  // Adding below header will make VROOM API return 404 instead of 308 and browser can intercept it.
464
464
  // This error thrown by server will contain the new redirect location. Look at the 404 error parsing
465
465
  // for futher reference here: \packages\utils\odsp-doclib-utils\src\odspErrorUtils.ts
466
- const header = {prefer: "manualredirect"};
466
+ const header = { prefer: "manualredirect" };
467
467
  const { body, headers } = getFormBodyAndHeaders(
468
468
  odspResolvedUrl, storageToken, snapshotOptions, header);
469
469
  const fetchOptions = {
@@ -94,7 +94,7 @@ async function getFileLinkCore(
94
94
  // ODSP link requires extra call to return link that is resistant to file being renamed or moved to different folder
95
95
  return PerformanceEvent.timedExecAsync(
96
96
  logger,
97
- { eventName: "odspFileLink", requestName: "getSharingInformation" },
97
+ { eventName: "odspFileLink", requestName: "getSharingLink" },
98
98
  async (event) => {
99
99
  let attempts = 0;
100
100
  let additionalProps;
@@ -106,13 +106,13 @@ async function getFileLinkCore(
106
106
  getToken,
107
107
  true /* throwOnNullToken */,
108
108
  );
109
- const storageToken = await storageTokenFetcher(options,"GetFileLinkCore");
109
+ const storageToken = await storageTokenFetcher(options, "GetFileLinkCore");
110
110
  assert(storageToken !== null,
111
111
  0x2bb /* "Instrumented token fetcher with throwOnNullToken = true should never return null" */);
112
112
 
113
113
  const { url, headers } = getUrlAndHeadersWithAuth(
114
- `${odspUrlParts.siteUrl}/_api/web/GetFileByUrl(@a1)/ListItemAllFields/GetSharingInformation?@a1=${
115
- encodeURIComponent(`'${fileItem.webDavUrl}'`)
114
+ `${odspUrlParts.siteUrl}/_api/web/GetFileByServerRelativeUrl(@a1)/Linkingurl?@a1=${
115
+ encodeURIComponent(`'${new URL(fileItem.webDavUrl).pathname}'`)
116
116
  }`,
117
117
  storageToken,
118
118
  false,
@@ -129,15 +129,15 @@ async function getFileLinkCore(
129
129
  additionalProps = response.propsToLog;
130
130
 
131
131
  const sharingInfo = await response.content.json();
132
- const directUrl = sharingInfo?.d?.directUrl;
133
- if (typeof directUrl !== "string") {
132
+ const linkingUrl = sharingInfo?.d?.LinkingUrl;
133
+ if (typeof linkingUrl !== "string") {
134
134
  // This will retry once in getWithRetryForTokenRefresh
135
135
  throw new NonRetryableError(
136
- "Malformed GetSharingInformation response",
136
+ "Malformed GetSharingLink response",
137
137
  DriverErrorType.incorrectServerResponse,
138
138
  { driverVersion });
139
139
  }
140
- return directUrl;
140
+ return linkingUrl;
141
141
  });
142
142
  event.end({ ...additionalProps, attempts });
143
143
  return fileLink;
@@ -174,14 +174,14 @@ async function getFileItemLite(
174
174
  let additionalProps;
175
175
  const fileItem = await getWithRetryForTokenRefresh(async (options) => {
176
176
  attempts++;
177
- const {siteUrl, driveId, itemId} = odspUrlParts;
177
+ const { siteUrl, driveId, itemId } = odspUrlParts;
178
178
  const storageTokenFetcher = toInstrumentedOdspTokenFetcher(
179
179
  logger,
180
180
  odspUrlParts,
181
181
  getToken,
182
182
  true /* throwOnNullToken */,
183
183
  );
184
- const storageToken = await storageTokenFetcher(options,"GetFileItemLite");
184
+ const storageToken = await storageTokenFetcher(options, "GetFileItemLite");
185
185
  assert(storageToken !== null,
186
186
  0x2bc /* "Instrumented token fetcher with throwOnNullToken =true should never return null" */);
187
187
 
@@ -8,7 +8,7 @@ import { ISnapshotOptions } from "@fluidframework/odsp-driver-definitions";
8
8
  * Generates query string from the given query parameters.
9
9
  * @param queryParams - Query parameters from which to create a query.
10
10
  */
11
- export function getQueryString(queryParams: { [key: string]: string | number } | ISnapshotOptions): string {
11
+ export function getQueryString(queryParams: { [key: string]: string | number; } | ISnapshotOptions): string {
12
12
  let queryString = "";
13
13
  for (const key of Object.keys(queryParams)) {
14
14
  if (queryParams[key] !== undefined) {
@@ -7,7 +7,7 @@ export function getUrlAndHeadersWithAuth(
7
7
  url: string,
8
8
  token: string | null,
9
9
  forceAccessTokenViaAuthorizationHeader: boolean,
10
- ): { url: string, headers: { [index: string]: string } } {
10
+ ): { url: string; headers: { [index: string]: string; }; } {
11
11
  if (!token || token.length === 0) {
12
12
  return { url, headers: {} };
13
13
  }
package/src/odspCache.ts CHANGED
@@ -100,7 +100,7 @@ export interface INonPersistentCache {
100
100
  * Cache of joined/joining session info
101
101
  */
102
102
  readonly sessionJoinCache: PromiseCache<string,
103
- { entryTime: number, joinSessionResponse: ISocketStorageDiscovery }>;
103
+ { entryTime: number; joinSessionResponse: ISocketStorageDiscovery; }>;
104
104
 
105
105
  /**
106
106
  * Cache of resolved/resolving file URLs
@@ -120,7 +120,7 @@ export interface IOdspCache extends INonPersistentCache {
120
120
 
121
121
  export class NonPersistentCache implements INonPersistentCache {
122
122
  public readonly sessionJoinCache =
123
- new PromiseCache<string, { entryTime: number, joinSessionResponse: ISocketStorageDiscovery }>();
123
+ new PromiseCache<string, { entryTime: number; joinSessionResponse: ISocketStorageDiscovery; }>();
124
124
 
125
125
  public readonly fileUrlCache = new PromiseCache<string, IOdspResolvedUrl>();
126
126
  }
@@ -56,7 +56,7 @@ export class OdspDeltaStorageService {
56
56
 
57
57
  postBody += `_post: 1\r\n`;
58
58
  postBody += `\r\n--${formBoundary}--`;
59
- const headers: {[index: string]: any} = {
59
+ const headers: { [index: string]: any; } = {
60
60
  "Content-Type": `multipart/form-data;boundary=${formBoundary}`,
61
61
  };
62
62
 
@@ -139,11 +139,11 @@ export class OdspDeltaStorageWithCache implements IDocumentDeltaStorageService {
139
139
  const length = messages.length;
140
140
  const last = messages[length - 1].sequenceNumber;
141
141
  if (start !== from) {
142
- this.logger.sendErrorEvent({ eventName: "OpsFetchViolation", reason, from, start, last, length});
142
+ this.logger.sendErrorEvent({ eventName: "OpsFetchViolation", reason, from, start, last, length });
143
143
  messages.length = 0;
144
144
  }
145
145
  if (last + 1 !== from + length) {
146
- this.logger.sendErrorEvent({ eventName: "OpsFetchViolation", reason, from, start, last, length});
146
+ this.logger.sendErrorEvent({ eventName: "OpsFetchViolation", reason, from, start, last, length });
147
147
  // we can do better here by finding consecutive sub-block and return it
148
148
  messages.length = 0;
149
149
  }
@@ -155,8 +155,7 @@ export class OdspDeltaStorageWithCache implements IDocumentDeltaStorageService {
155
155
  toTotal: number | undefined,
156
156
  abortSignal?: AbortSignal,
157
157
  cachedOnly?: boolean,
158
- fetchReason?: string)
159
- {
158
+ fetchReason?: string) {
160
159
  // We do not control what's in the cache. Current API assumes that fetchMessages() keeps banging on
161
160
  // storage / cache until it gets ops it needs. This would result in deadlock if fixed range is asked from
162
161
  // cache and it's not there.
@@ -58,7 +58,7 @@ class SocketReference extends TypedEventEmitter<ISocketEvents> {
58
58
  const socketReference = SocketReference.socketIoSockets.get(key);
59
59
 
60
60
  // Verify the socket is healthy before reusing it
61
- if (socketReference && socketReference.disconnected) {
61
+ if (socketReference?.disconnected) {
62
62
  // The socket is in a bad state. fully remove the reference
63
63
  socketReference.closeSocket();
64
64
  return undefined;
@@ -279,7 +279,7 @@ export class OdspDocumentDeltaConnection extends DocumentDeltaConnection {
279
279
 
280
280
  private readonly requestOpsNoncePrefix: string;
281
281
  private pushCallCounter = 0;
282
- private readonly getOpsMap: Map<string, { start: number, from: number, to: number }> = new Map();
282
+ private readonly getOpsMap: Map<string, { start: number; from: number; to: number; }> = new Map();
283
283
  private flushOpNonce: string | undefined;
284
284
  private flushDeferred: Deferred<FlushResult> | undefined;
285
285
 
@@ -237,7 +237,7 @@ export class OdspDocumentService implements IDocumentService {
237
237
  return normalizeError(error, { props: {
238
238
  failedConnectionStep,
239
239
  separateTokenRequest,
240
- }});
240
+ } });
241
241
  }
242
242
 
243
243
  /**
@@ -309,7 +309,7 @@ export class OdspDocumentService implements IDocumentService {
309
309
  "createDeltaConnection",
310
310
  !requestWebsocketTokenFromJoinSession);
311
311
  if (typeof error === "object" && error !== null) {
312
- normalizedError.addTelemetryProperties({socketDocumentId: websocketEndpoint.id});
312
+ normalizedError.addTelemetryProperties({ socketDocumentId: websocketEndpoint.id });
313
313
  }
314
314
  throw normalizedError;
315
315
  }
@@ -351,7 +351,7 @@ export class OdspDocumentService implements IDocumentService {
351
351
  // This document can only be opened in storage-only mode.
352
352
  // DeltaManager will recognize this error
353
353
  // and load without a delta stream connection.
354
- this._policies = {...this._policies,storageOnly: true};
354
+ this._policies = { ...this._policies, storageOnly: true };
355
355
  throw new DeltaStreamConnectionForbiddenError(code, { driverVersion });
356
356
  default:
357
357
  continue;
@@ -515,9 +515,9 @@ export class OdspDocumentService implements IDocumentService {
515
515
  // ICache
516
516
  {
517
517
  write: async (key: string, opsData: string) => {
518
- return this.cache.persistedCache.put({...opsKey, key}, opsData);
518
+ return this.cache.persistedCache.put({ ...opsKey, key }, opsData);
519
519
  },
520
- read: async (key: string) => this.cache.persistedCache.get({...opsKey, key}),
520
+ read: async (key: string) => this.cache.persistedCache.get({ ...opsKey, key }),
521
521
  remove: () => { this.cache.persistedCache.removeEntries().catch(() => {}); },
522
522
  },
523
523
  batchSize,
@@ -14,7 +14,10 @@ import {
14
14
  TelemetryLogger,
15
15
  PerformanceEvent,
16
16
  } from "@fluidframework/telemetry-utils";
17
- import { ensureFluidResolvedUrl } from "@fluidframework/driver-utils";
17
+ import {
18
+ getDocAttributesFromProtocolSummary,
19
+ ensureFluidResolvedUrl,
20
+ } from "@fluidframework/driver-utils";
18
21
  import {
19
22
  TokenFetchOptions,
20
23
  OdspResourceTokenFetchOptions,
@@ -72,6 +75,15 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
72
75
  if (filePath === undefined || filePath === null) {
73
76
  throw new Error("File path should be provided!!");
74
77
  }
78
+
79
+ const protocolSummary = createNewSummary?.tree[".protocol"];
80
+ if (protocolSummary) {
81
+ const documentAttributes = getDocAttributesFromProtocolSummary(protocolSummary as ISummaryTree);
82
+ if (documentAttributes?.sequenceNumber !== 0) {
83
+ throw new Error("Seq number in detached ODSP container should be 0");
84
+ }
85
+ }
86
+
75
87
  const newFileInfo: INewFileInfo = {
76
88
  driveId: odspResolvedUrl.driveId,
77
89
  siteUrl: odspResolvedUrl.siteUrl,
@@ -45,10 +45,12 @@ import { OdspSummaryUploadManager } from "./odspSummaryUploadManager";
45
45
  import { FlushResult } from "./odspDocumentDeltaConnection";
46
46
  import { pkgVersion as driverVersion } from "./packageVersion";
47
47
 
48
+ export const defaultSummarizerCacheExpiryTimeout: number = 60 * 1000; // 60 seconds.
49
+
48
50
  /* eslint-disable max-len */
49
51
 
50
52
  // An implementation of Promise.race that gives you the winner of the promise race
51
- async function promiseRaceWithWinner<T>(promises: Promise<T>[]): Promise<{ index: number, value: T }> {
53
+ async function promiseRaceWithWinner<T>(promises: Promise<T>[]): Promise<{ index: number; value: T; }> {
52
54
  return new Promise((resolve, reject) => {
53
55
  promises.forEach((p, index) => {
54
56
  p.then((v) => resolve({ index, value: v })).catch(reject);
@@ -152,6 +154,10 @@ class BlobCache {
152
154
  }
153
155
  }
154
156
 
157
+ interface GetVersionsTelemetryProps {
158
+ cacheEntryAge?: number;
159
+ cacheSummarizerExpired?: boolean;
160
+ }
155
161
  export class OdspDocumentStorageService implements IDocumentStorageService {
156
162
  readonly policies = {
157
163
  // By default, ODSP tells the container not to prefetch/cache.
@@ -401,7 +407,7 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
401
407
  this.logger,
402
408
  { eventName: "ObtainSnapshot" },
403
409
  async (event: PerformanceEvent) => {
404
- const props = {};
410
+ const props: GetVersionsTelemetryProps = {};
405
411
  let retrievedSnapshot: ISnapshotContents | undefined;
406
412
  // Here's the logic to grab the persistent cache snapshot implemented by the host
407
413
  // Epoch tracker is responsible for communicating with the persistent cache, handling epochs and cache versions
@@ -413,9 +419,21 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
413
419
  const age = Date.now() - (snapshotCachedEntry.cacheEntryTime ??
414
420
  (Date.now() - 30 * 24 * 60 * 60 * 1000));
415
421
 
422
+ // In order to decrease the number of times we have to execute a snapshot refresh,
423
+ // if this is the summarizer and we have a cache entry but it is past the defaultSummarizerCacheExpiryTimeout,
424
+ // force the network retrieval instead as there might be a more recent snapshot available.
425
+ // See: https://github.com/microsoft/FluidFramework/issues/8995 for additional information.
426
+ if (this.hostPolicy.summarizerClient) {
427
+ if (age > defaultSummarizerCacheExpiryTimeout) {
428
+ props.cacheSummarizerExpired = true;
429
+ return undefined;
430
+ } else {
431
+ props.cacheSummarizerExpired = false;
432
+ }
433
+ }
434
+
416
435
  // Record the cache age
417
- // eslint-disable-next-line @typescript-eslint/dot-notation
418
- props["cacheEntryAge"] = age;
436
+ props.cacheEntryAge = age;
419
437
  }
420
438
 
421
439
  return snapshotCachedEntry;
@@ -464,8 +482,7 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
464
482
  }
465
483
  }
466
484
  if (method === "network") {
467
- // eslint-disable-next-line @typescript-eslint/dot-notation
468
- props["cacheEntryAge"] = undefined;
485
+ props.cacheEntryAge = undefined;
469
486
  }
470
487
  event.end({ ...props, method });
471
488
  return retrievedSnapshot;
@@ -495,7 +512,7 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
495
512
  return getWithRetryForTokenRefresh(async (options) => {
496
513
  const storageToken = await this.getStorageToken(options, "GetVersions");
497
514
  const { url, headers } = getUrlAndHeadersWithAuth(
498
- `${this.snapshotUrl}/versions?count=${count}`,
515
+ `${this.snapshotUrl}/versions?top=${count}`,
499
516
  storageToken,
500
517
  !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,
501
518
  );
@@ -523,17 +540,7 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
523
540
  { driverVersion });
524
541
  }
525
542
  return versionsResponse.value.map((version) => {
526
- // Parse the date from the message
527
- let date: string | undefined;
528
- for (const rec of version.message.split("\n")) {
529
- const index = rec.indexOf(":");
530
- if (index !== -1 && rec.substr(0, index) === "Date") {
531
- date = rec.substr(index + 1).trim();
532
- break;
533
- }
534
- }
535
543
  return {
536
- date,
537
544
  id: version.id,
538
545
  treeId: undefined!,
539
546
  };
@@ -727,7 +734,7 @@ export class OdspDocumentStorageService implements IDocumentStorageService {
727
734
  if (!tree) {
728
735
  tree = await getWithRetryForTokenRefresh(async (options) => {
729
736
  const storageToken = await this.getStorageToken(options, "ReadCommit");
730
- const snapshotDownloader = async (url: string, fetchOptions: {[index: string]: any}) => {
737
+ const snapshotDownloader = async (url: string, fetchOptions: { [index: string]: any; }) => {
731
738
  return this.epochTracker.fetchAndParseAsJSON(
732
739
  url,
733
740
  fetchOptions,
@@ -66,7 +66,7 @@ export class OdspDriverUrlResolver implements IUrlResolver {
66
66
  constructor() { }
67
67
 
68
68
  public async resolve(request: IRequest): Promise<IOdspResolvedUrl> {
69
- if (request.headers && request.headers[DriverHeader.createNew]) {
69
+ if (request.headers?.[DriverHeader.createNew]) {
70
70
  const [siteURL, queryString] = request.url.split("?");
71
71
 
72
72
  const searchParams = new URLSearchParams(queryString);
@@ -82,7 +82,7 @@ export class OdspDriverUrlResolver implements IUrlResolver {
82
82
  { driverVersion: pkgVersion });
83
83
  }
84
84
  let shareLinkInfo: ShareLinkInfoType | undefined;
85
- if(createLinkType && createLinkType in ShareLinkTypes) {
85
+ if (createLinkType && createLinkType in ShareLinkTypes) {
86
86
  shareLinkInfo = {
87
87
  createLink: {
88
88
  type: ShareLinkTypes[createLinkType],
@@ -133,7 +133,7 @@ export class OdspDriverUrlResolverForShareLink implements IUrlResolver {
133
133
  // when redeeming the share link during the redeem fallback for trees latest call becomes greater than
134
134
  // the eligible length.
135
135
  odspResolvedUrl.shareLinkInfo = Object.assign(odspResolvedUrl.shareLinkInfo || {},
136
- {sharingLinkToRedeem: this.removeNavParam(request.url)});
136
+ { sharingLinkToRedeem: this.removeNavParam(request.url) });
137
137
  }
138
138
  if (odspResolvedUrl.itemId) {
139
139
  // Kick start the sharing link request if we don't have it already as a performance optimization.
@@ -16,7 +16,7 @@ import { ISnapshotContents } from "./odspUtils";
16
16
  * @returns the hierarchical tree
17
17
  */
18
18
  function buildHierarchy(flatTree: IOdspSnapshotCommit): api.ISnapshotTree {
19
- const lookup: { [path: string]: api.ISnapshotTree } = {};
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
21
  const root: api.ISnapshotTree = { id: flatTree.id, blobs: {}, trees: {} };
22
22
  lookup[""] = root;
@@ -64,7 +64,7 @@ export function convertOdspSnapshotToSnapsohtTreeAndBlobs(
64
64
  const val: ISnapshotContents = {
65
65
  blobs: blobsWithBufferContent,
66
66
  ops: odspSnapshot.ops?.map((op) => op.op) ?? [],
67
- sequenceNumber: odspSnapshot.trees && (odspSnapshot.trees[0]).sequenceNumber,
67
+ sequenceNumber: odspSnapshot?.trees[0].sequenceNumber,
68
68
  snapshotTree: buildHierarchy(odspSnapshot.trees[0]),
69
69
  };
70
70
  return val;
package/src/odspUtils.ts CHANGED
@@ -44,17 +44,17 @@ export const getWithRetryForTokenRefreshRepeat = "getWithRetryForTokenRefreshRep
44
44
  export const getOrigin = (url: string) => new URL(url).origin;
45
45
 
46
46
  export interface ISnapshotContents {
47
- snapshotTree: ISnapshotTree,
48
- blobs: Map<string, ArrayBuffer>,
49
- ops: ISequencedDocumentMessage[],
50
- sequenceNumber: number | undefined,
47
+ snapshotTree: ISnapshotTree;
48
+ blobs: Map<string, ArrayBuffer>;
49
+ ops: ISequencedDocumentMessage[];
50
+ sequenceNumber: number | undefined;
51
51
  }
52
52
 
53
53
  export interface IOdspResponse<T> {
54
54
  content: T;
55
55
  headers: Map<string, string>;
56
56
  propsToLog: ITelemetryProperties;
57
- duration: number,
57
+ duration: number;
58
58
  }
59
59
 
60
60
  export interface TokenFetchOptionsEx extends TokenFetchOptions {
@@ -246,7 +246,7 @@ export const createOdspLogger = (logger?: ITelemetryBaseLogger) =>
246
246
  ChildLogger.create(
247
247
  logger,
248
248
  "OdspDriver",
249
- { all :
249
+ { all:
250
250
  {
251
251
  driverVersion,
252
252
  },
package/src/opsCaching.ts CHANGED
@@ -47,7 +47,7 @@ export class OpsCache {
47
47
  if (remainingSlots !== 0) {
48
48
  this.batches.set(this.getBatchNumber(startingSequenceNumber), {
49
49
  remainingSlots,
50
- batchData : this.initializeNewBatchDataArray(),
50
+ batchData: this.initializeNewBatchDataArray(),
51
51
  dirty: false,
52
52
  });
53
53
  }
@@ -109,7 +109,7 @@ export class OpsCache {
109
109
 
110
110
  this.totalOpsToCache--;
111
111
  if (this.totalOpsToCache === 0) {
112
- this.logger.sendPerformanceEvent({ eventName: "CacheOpsLimitHit"});
112
+ this.logger.sendPerformanceEvent({ eventName: "CacheOpsLimitHit" });
113
113
  this.cache.remove();
114
114
  this.dispose();
115
115
  break;
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/odsp-driver";
9
- export const pkgVersion = "0.59.2001";
9
+ export const pkgVersion = "0.59.3000";
@@ -31,7 +31,7 @@ export class RetryErrorsStorageAdapter implements IDocumentStorageService, IDisp
31
31
  public get policies(): IDocumentStorageServicePolicies | undefined {
32
32
  return this.internalStorageService.policies;
33
33
  }
34
- public get disposed() {return this._disposed;}
34
+ public get disposed() { return this._disposed; }
35
35
  public dispose() {
36
36
  this._disposed = true;
37
37
  }
package/src/vroom.ts CHANGED
@@ -83,7 +83,7 @@ export async function fetchJoinSession(
83
83
  postBody += `\r\n${JSON.stringify(body)}\r\n`;
84
84
  }
85
85
  postBody += `\r\n--${formBoundary}--`;
86
- const headers: {[index: string]: string} = {
86
+ const headers: { [index: string]: string; } = {
87
87
  "Content-Type": `multipart/form-data;boundary=${formBoundary}`,
88
88
  };
89
89