@fluidframework/odsp-driver 1.2.7 → 2.0.0-dev.1.3.0.96595

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 (254) hide show
  1. package/.mocharc.js +12 -0
  2. package/README.md +19 -0
  3. package/dist/ReadBufferUtils.d.ts.map +1 -1
  4. package/dist/ReadBufferUtils.js +1 -0
  5. package/dist/ReadBufferUtils.js.map +1 -1
  6. package/dist/WriteBufferUtils.d.ts +3 -5
  7. package/dist/WriteBufferUtils.d.ts.map +1 -1
  8. package/dist/WriteBufferUtils.js +59 -55
  9. package/dist/WriteBufferUtils.js.map +1 -1
  10. package/dist/compactSnapshotParser.d.ts +2 -2
  11. package/dist/compactSnapshotParser.d.ts.map +1 -1
  12. package/dist/compactSnapshotParser.js +91 -34
  13. package/dist/compactSnapshotParser.js.map +1 -1
  14. package/dist/compactSnapshotWriter.d.ts +1 -2
  15. package/dist/compactSnapshotWriter.d.ts.map +1 -1
  16. package/dist/compactSnapshotWriter.js +17 -14
  17. package/dist/compactSnapshotWriter.js.map +1 -1
  18. package/dist/contracts.d.ts +1 -18
  19. package/dist/contracts.d.ts.map +1 -1
  20. package/dist/contracts.js.map +1 -1
  21. package/dist/createFile.d.ts +1 -1
  22. package/dist/createFile.d.ts.map +1 -1
  23. package/dist/createFile.js +53 -16
  24. package/dist/createFile.js.map +1 -1
  25. package/dist/createNewUtils.d.ts.map +1 -1
  26. package/dist/createNewUtils.js +0 -1
  27. package/dist/createNewUtils.js.map +1 -1
  28. package/dist/createOdspCreateContainerRequest.d.ts +4 -3
  29. package/dist/createOdspCreateContainerRequest.d.ts.map +1 -1
  30. package/dist/createOdspCreateContainerRequest.js +6 -3
  31. package/dist/createOdspCreateContainerRequest.js.map +1 -1
  32. package/dist/epochTracker.d.ts +1 -0
  33. package/dist/epochTracker.d.ts.map +1 -1
  34. package/dist/epochTracker.js +24 -5
  35. package/dist/epochTracker.js.map +1 -1
  36. package/dist/fetchSnapshot.d.ts +1 -2
  37. package/dist/fetchSnapshot.d.ts.map +1 -1
  38. package/dist/fetchSnapshot.js +22 -27
  39. package/dist/fetchSnapshot.js.map +1 -1
  40. package/dist/getFileLink.d.ts +3 -6
  41. package/dist/getFileLink.d.ts.map +1 -1
  42. package/dist/getFileLink.js +22 -33
  43. package/dist/getFileLink.js.map +1 -1
  44. package/dist/index.d.ts +1 -2
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +3 -3
  47. package/dist/index.js.map +1 -1
  48. package/dist/localOdspDriver/localOdspDocumentStorageManager.d.ts.map +1 -1
  49. package/dist/localOdspDriver/localOdspDocumentStorageManager.js +1 -2
  50. package/dist/localOdspDriver/localOdspDocumentStorageManager.js.map +1 -1
  51. package/dist/odspDeltaStorageService.d.ts +3 -2
  52. package/dist/odspDeltaStorageService.d.ts.map +1 -1
  53. package/dist/odspDeltaStorageService.js +9 -12
  54. package/dist/odspDeltaStorageService.js.map +1 -1
  55. package/dist/odspDocumentDeltaConnection.d.ts.map +1 -1
  56. package/dist/odspDocumentDeltaConnection.js +3 -6
  57. package/dist/odspDocumentDeltaConnection.js.map +1 -1
  58. package/dist/odspDocumentService.d.ts +1 -0
  59. package/dist/odspDocumentService.d.ts.map +1 -1
  60. package/dist/odspDocumentService.js +12 -6
  61. package/dist/odspDocumentService.js.map +1 -1
  62. package/dist/odspDocumentServiceFactoryCore.d.ts.map +1 -1
  63. package/dist/odspDocumentServiceFactoryCore.js +29 -6
  64. package/dist/odspDocumentServiceFactoryCore.js.map +1 -1
  65. package/dist/odspDocumentStorageManager.d.ts +4 -4
  66. package/dist/odspDocumentStorageManager.d.ts.map +1 -1
  67. package/dist/odspDocumentStorageManager.js +82 -64
  68. package/dist/odspDocumentStorageManager.js.map +1 -1
  69. package/dist/odspDocumentStorageServiceBase.d.ts +1 -1
  70. package/dist/odspDocumentStorageServiceBase.d.ts.map +1 -1
  71. package/dist/odspDocumentStorageServiceBase.js +4 -2
  72. package/dist/odspDocumentStorageServiceBase.js.map +1 -1
  73. package/dist/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
  74. package/dist/odspDriverUrlResolverForShareLink.js +4 -4
  75. package/dist/odspDriverUrlResolverForShareLink.js.map +1 -1
  76. package/dist/odspFluidFileLink.js +1 -1
  77. package/dist/odspFluidFileLink.js.map +1 -1
  78. package/dist/odspLocationRedirection.d.ts +14 -0
  79. package/dist/odspLocationRedirection.d.ts.map +1 -0
  80. package/dist/odspLocationRedirection.js +24 -0
  81. package/dist/odspLocationRedirection.js.map +1 -0
  82. package/dist/odspSnapshotParser.d.ts.map +1 -1
  83. package/dist/odspSnapshotParser.js +1 -2
  84. package/dist/odspSnapshotParser.js.map +1 -1
  85. package/dist/odspSummaryUploadManager.d.ts +6 -3
  86. package/dist/odspSummaryUploadManager.d.ts.map +1 -1
  87. package/dist/odspSummaryUploadManager.js +14 -17
  88. package/dist/odspSummaryUploadManager.js.map +1 -1
  89. package/dist/odspUrlHelper.js +2 -1
  90. package/dist/odspUrlHelper.js.map +1 -1
  91. package/dist/odspUtils.d.ts +11 -2
  92. package/dist/odspUtils.d.ts.map +1 -1
  93. package/dist/odspUtils.js +32 -5
  94. package/dist/odspUtils.js.map +1 -1
  95. package/dist/opsCaching.d.ts.map +1 -1
  96. package/dist/opsCaching.js +3 -2
  97. package/dist/opsCaching.js.map +1 -1
  98. package/dist/packageVersion.d.ts +1 -1
  99. package/dist/packageVersion.d.ts.map +1 -1
  100. package/dist/packageVersion.js +1 -1
  101. package/dist/packageVersion.js.map +1 -1
  102. package/dist/prefetchLatestSnapshot.d.ts +6 -4
  103. package/dist/prefetchLatestSnapshot.d.ts.map +1 -1
  104. package/dist/prefetchLatestSnapshot.js +6 -4
  105. package/dist/prefetchLatestSnapshot.js.map +1 -1
  106. package/dist/retryUtils.d.ts.map +1 -1
  107. package/dist/retryUtils.js +8 -4
  108. package/dist/retryUtils.js.map +1 -1
  109. package/dist/zipItDataRepresentationUtils.d.ts +30 -18
  110. package/dist/zipItDataRepresentationUtils.d.ts.map +1 -1
  111. package/dist/zipItDataRepresentationUtils.js +170 -76
  112. package/dist/zipItDataRepresentationUtils.js.map +1 -1
  113. package/lib/ReadBufferUtils.d.ts.map +1 -1
  114. package/lib/ReadBufferUtils.js +1 -0
  115. package/lib/ReadBufferUtils.js.map +1 -1
  116. package/lib/WriteBufferUtils.d.ts +3 -5
  117. package/lib/WriteBufferUtils.d.ts.map +1 -1
  118. package/lib/WriteBufferUtils.js +61 -57
  119. package/lib/WriteBufferUtils.js.map +1 -1
  120. package/lib/compactSnapshotParser.d.ts +2 -2
  121. package/lib/compactSnapshotParser.d.ts.map +1 -1
  122. package/lib/compactSnapshotParser.js +92 -35
  123. package/lib/compactSnapshotParser.js.map +1 -1
  124. package/lib/compactSnapshotWriter.d.ts +1 -2
  125. package/lib/compactSnapshotWriter.d.ts.map +1 -1
  126. package/lib/compactSnapshotWriter.js +18 -15
  127. package/lib/compactSnapshotWriter.js.map +1 -1
  128. package/lib/contracts.d.ts +1 -18
  129. package/lib/contracts.d.ts.map +1 -1
  130. package/lib/contracts.js.map +1 -1
  131. package/lib/createFile.d.ts +1 -1
  132. package/lib/createFile.d.ts.map +1 -1
  133. package/lib/createFile.js +54 -17
  134. package/lib/createFile.js.map +1 -1
  135. package/lib/createNewUtils.d.ts.map +1 -1
  136. package/lib/createNewUtils.js +0 -1
  137. package/lib/createNewUtils.js.map +1 -1
  138. package/lib/createOdspCreateContainerRequest.d.ts +4 -3
  139. package/lib/createOdspCreateContainerRequest.d.ts.map +1 -1
  140. package/lib/createOdspCreateContainerRequest.js +6 -3
  141. package/lib/createOdspCreateContainerRequest.js.map +1 -1
  142. package/lib/epochTracker.d.ts +1 -0
  143. package/lib/epochTracker.d.ts.map +1 -1
  144. package/lib/epochTracker.js +26 -7
  145. package/lib/epochTracker.js.map +1 -1
  146. package/lib/fetchSnapshot.d.ts +1 -2
  147. package/lib/fetchSnapshot.d.ts.map +1 -1
  148. package/lib/fetchSnapshot.js +22 -27
  149. package/lib/fetchSnapshot.js.map +1 -1
  150. package/lib/getFileLink.d.ts +3 -6
  151. package/lib/getFileLink.d.ts.map +1 -1
  152. package/lib/getFileLink.js +24 -35
  153. package/lib/getFileLink.js.map +1 -1
  154. package/lib/index.d.ts +1 -2
  155. package/lib/index.d.ts.map +1 -1
  156. package/lib/index.js +1 -3
  157. package/lib/index.js.map +1 -1
  158. package/lib/localOdspDriver/localOdspDocumentStorageManager.d.ts.map +1 -1
  159. package/lib/localOdspDriver/localOdspDocumentStorageManager.js +1 -2
  160. package/lib/localOdspDriver/localOdspDocumentStorageManager.js.map +1 -1
  161. package/lib/odspDeltaStorageService.d.ts +3 -2
  162. package/lib/odspDeltaStorageService.d.ts.map +1 -1
  163. package/lib/odspDeltaStorageService.js +9 -12
  164. package/lib/odspDeltaStorageService.js.map +1 -1
  165. package/lib/odspDocumentDeltaConnection.d.ts.map +1 -1
  166. package/lib/odspDocumentDeltaConnection.js +3 -6
  167. package/lib/odspDocumentDeltaConnection.js.map +1 -1
  168. package/lib/odspDocumentService.d.ts +1 -0
  169. package/lib/odspDocumentService.d.ts.map +1 -1
  170. package/lib/odspDocumentService.js +14 -8
  171. package/lib/odspDocumentService.js.map +1 -1
  172. package/lib/odspDocumentServiceFactoryCore.d.ts.map +1 -1
  173. package/lib/odspDocumentServiceFactoryCore.js +29 -6
  174. package/lib/odspDocumentServiceFactoryCore.js.map +1 -1
  175. package/lib/odspDocumentStorageManager.d.ts +4 -4
  176. package/lib/odspDocumentStorageManager.d.ts.map +1 -1
  177. package/lib/odspDocumentStorageManager.js +83 -65
  178. package/lib/odspDocumentStorageManager.js.map +1 -1
  179. package/lib/odspDocumentStorageServiceBase.d.ts +1 -1
  180. package/lib/odspDocumentStorageServiceBase.d.ts.map +1 -1
  181. package/lib/odspDocumentStorageServiceBase.js +4 -2
  182. package/lib/odspDocumentStorageServiceBase.js.map +1 -1
  183. package/lib/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
  184. package/lib/odspDriverUrlResolverForShareLink.js +4 -4
  185. package/lib/odspDriverUrlResolverForShareLink.js.map +1 -1
  186. package/lib/odspFluidFileLink.js +1 -1
  187. package/lib/odspFluidFileLink.js.map +1 -1
  188. package/lib/odspLocationRedirection.d.ts +14 -0
  189. package/lib/odspLocationRedirection.d.ts.map +1 -0
  190. package/lib/odspLocationRedirection.js +20 -0
  191. package/lib/odspLocationRedirection.js.map +1 -0
  192. package/lib/odspSnapshotParser.d.ts.map +1 -1
  193. package/lib/odspSnapshotParser.js +1 -2
  194. package/lib/odspSnapshotParser.js.map +1 -1
  195. package/lib/odspSummaryUploadManager.d.ts +6 -3
  196. package/lib/odspSummaryUploadManager.d.ts.map +1 -1
  197. package/lib/odspSummaryUploadManager.js +14 -17
  198. package/lib/odspSummaryUploadManager.js.map +1 -1
  199. package/lib/odspUrlHelper.js +2 -1
  200. package/lib/odspUrlHelper.js.map +1 -1
  201. package/lib/odspUtils.d.ts +11 -2
  202. package/lib/odspUtils.d.ts.map +1 -1
  203. package/lib/odspUtils.js +31 -5
  204. package/lib/odspUtils.js.map +1 -1
  205. package/lib/opsCaching.d.ts.map +1 -1
  206. package/lib/opsCaching.js +3 -2
  207. package/lib/opsCaching.js.map +1 -1
  208. package/lib/packageVersion.d.ts +1 -1
  209. package/lib/packageVersion.d.ts.map +1 -1
  210. package/lib/packageVersion.js +1 -1
  211. package/lib/packageVersion.js.map +1 -1
  212. package/lib/prefetchLatestSnapshot.d.ts +6 -4
  213. package/lib/prefetchLatestSnapshot.d.ts.map +1 -1
  214. package/lib/prefetchLatestSnapshot.js +6 -4
  215. package/lib/prefetchLatestSnapshot.js.map +1 -1
  216. package/lib/retryUtils.d.ts.map +1 -1
  217. package/lib/retryUtils.js +9 -5
  218. package/lib/retryUtils.js.map +1 -1
  219. package/lib/zipItDataRepresentationUtils.d.ts +30 -18
  220. package/lib/zipItDataRepresentationUtils.d.ts.map +1 -1
  221. package/lib/zipItDataRepresentationUtils.js +166 -75
  222. package/lib/zipItDataRepresentationUtils.js.map +1 -1
  223. package/package.json +33 -20
  224. package/src/ReadBufferUtils.ts +1 -0
  225. package/src/WriteBufferUtils.ts +67 -58
  226. package/src/compactSnapshotParser.ts +102 -40
  227. package/src/compactSnapshotWriter.ts +25 -17
  228. package/src/contracts.ts +2 -14
  229. package/src/createFile.ts +75 -15
  230. package/src/createNewUtils.ts +2 -4
  231. package/src/createOdspCreateContainerRequest.ts +7 -4
  232. package/src/epochTracker.ts +47 -7
  233. package/src/fetchSnapshot.ts +35 -31
  234. package/src/getFileLink.ts +26 -39
  235. package/src/index.ts +1 -3
  236. package/src/localOdspDriver/localOdspDocumentStorageManager.ts +2 -2
  237. package/src/odspDeltaStorageService.ts +8 -9
  238. package/src/odspDocumentDeltaConnection.ts +3 -5
  239. package/src/odspDocumentService.ts +16 -13
  240. package/src/odspDocumentServiceFactoryCore.ts +40 -4
  241. package/src/odspDocumentStorageManager.ts +64 -50
  242. package/src/odspDocumentStorageServiceBase.ts +4 -2
  243. package/src/odspDriverUrlResolverForShareLink.ts +2 -5
  244. package/src/odspFluidFileLink.ts +1 -1
  245. package/src/odspLocationRedirection.ts +23 -0
  246. package/src/odspSnapshotParser.ts +3 -4
  247. package/src/odspSummaryUploadManager.ts +10 -11
  248. package/src/odspUrlHelper.ts +1 -1
  249. package/src/odspUtils.ts +40 -7
  250. package/src/opsCaching.ts +3 -2
  251. package/src/packageVersion.ts +1 -1
  252. package/src/prefetchLatestSnapshot.ts +6 -4
  253. package/src/retryUtils.ts +8 -5
  254. package/src/zipItDataRepresentationUtils.ts +198 -75
@@ -1 +1 @@
1
- {"version":3,"file":"createOdspCreateContainerRequest.js","sourceRoot":"","sources":["../src/createOdspCreateContainerRequest.ts"],"names":[],"mappings":";;;AAKA,2EAAkE;AAGlE;;;;;;;GAOG;AACH,SAAgB,gCAAgC,CAC5C,OAAe,EACf,OAAe,EACf,QAAgB,EAChB,QAAgB,EAChB,cAA+B;IAE/B,MAAM,gBAAgB,GAAa;QAC/B,GAAG,EAAE,GAAG,OAAO,YAAY,kBAAkB,CACzC,OAAO,CACV,SAAS,kBAAkB,CAAC,QAAQ,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,mBAAmB,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;QACpG,OAAO,EAAE;YACL,CAAC,iCAAY,CAAC,SAAS,CAAC,EAAE;gBACtB,QAAQ;aACX;SACJ;KACJ,CAAC;IACF,OAAO,gBAAgB,CAAC;AAC5B,CAAC;AAlBD,4EAkBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport { IRequest } from \"@fluidframework/core-interfaces\";\nimport { DriverHeader } from \"@fluidframework/driver-definitions\";\nimport { ShareLinkTypes } from \"@fluidframework/odsp-driver-definitions\";\n\n/**\n * Create the request object with url and headers for creating a new file on OneDrive Sharepoint\n * @param siteUrl - Base url for OneDrive\n * @param driveId - drive identifier\n * @param filePath - path where file needs to be created\n * @param fileName - name of the new file to be created\n * @param createLinkType - type of sharing link you would like to create for this file\n */\nexport function createOdspCreateContainerRequest(\n siteUrl: string,\n driveId: string,\n filePath: string,\n fileName: string,\n createLinkType?: ShareLinkTypes,\n): IRequest {\n const createNewRequest: IRequest = {\n url: `${siteUrl}?driveId=${encodeURIComponent(\n driveId,\n )}&path=${encodeURIComponent(filePath)}${createLinkType ? `&createLinkType=${createLinkType}` : \"\"}`,\n headers: {\n [DriverHeader.createNew]: {\n fileName,\n },\n },\n };\n return createNewRequest;\n}\n"]}
1
+ {"version":3,"file":"createOdspCreateContainerRequest.js","sourceRoot":"","sources":["../src/createOdspCreateContainerRequest.ts"],"names":[],"mappings":";;;AAKA,2EAAkE;AAElE,2CAA0D;AAE1D;;;;;;;;GAQG;AACH,SAAgB,gCAAgC,CAC5C,OAAe,EACf,OAAe,EACf,QAAgB,EAChB,QAAgB,EAChB,mBAAuD;IAEvD,MAAM,sBAAsB,GAAG,IAAA,uCAA2B,EAAC,mBAAmB,CAAC,CAAC;IAChF,MAAM,gBAAgB,GAAa;QAC/B,GAAG,EAAE,GAAG,OAAO,YAAY,kBAAkB,CACzC,OAAO,CACV,SAAS,kBAAkB,CAAC,QAAQ,CAAC,GAAG,sBAAsB,CAAC,CAAC,CAAC,IAAI,sBAAsB,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;QACrG,OAAO,EAAE;YACL,CAAC,iCAAY,CAAC,SAAS,CAAC,EAAE;gBACtB,QAAQ;aACX;SACJ;KACJ,CAAC;IACF,OAAO,gBAAgB,CAAC;AAC5B,CAAC;AAnBD,4EAmBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport { IRequest } from \"@fluidframework/core-interfaces\";\nimport { DriverHeader } from \"@fluidframework/driver-definitions\";\nimport { ShareLinkTypes, ISharingLinkKind } from \"@fluidframework/odsp-driver-definitions\";\nimport { buildOdspShareLinkReqParams } from \"./odspUtils\";\n\n/**\n * Create the request object with url and headers for creating a new file on OneDrive Sharepoint\n * @param siteUrl - Base url for OneDrive\n * @param driveId - drive identifier\n * @param filePath - path where file needs to be created\n * @param fileName - name of the new file to be created\n * @param createShareLinkType - type of sharing link you would like to create for this file. ShareLinkTypes\n * will be deprecated soon, so for any new implementation please provide createShareLinkType of type ShareLink\n */\nexport function createOdspCreateContainerRequest(\n siteUrl: string,\n driveId: string,\n filePath: string,\n fileName: string,\n createShareLinkType?: ShareLinkTypes | ISharingLinkKind,\n): IRequest {\n const shareLinkRequestParams = buildOdspShareLinkReqParams(createShareLinkType);\n const createNewRequest: IRequest = {\n url: `${siteUrl}?driveId=${encodeURIComponent(\n driveId,\n )}&path=${encodeURIComponent(filePath)}${shareLinkRequestParams ? `&${shareLinkRequestParams}` : \"\"}`,\n headers: {\n [DriverHeader.createNew]: {\n fileName,\n },\n },\n };\n return createNewRequest;\n}\n"]}
@@ -24,6 +24,7 @@ export declare class EpochTracker implements IPersistedFileCache {
24
24
  protected readonly logger: ITelemetryLogger;
25
25
  protected readonly clientIsSummarizer?: boolean | undefined;
26
26
  private _fluidEpoch;
27
+ private readonly snapshotCacheExpiryTimeoutMs;
27
28
  readonly rateLimiter: RateLimiter;
28
29
  private readonly driverId;
29
30
  private networkCallNumber;
@@ -1 +1 @@
1
- {"version":3,"file":"epochTracker.d.ts","sourceRoot":"","sources":["../src/epochTracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"epochTracker.d.ts","sourceRoot":"","sources":["../src/epochTracker.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,7 @@ const odspUtils_1 = require("./odspUtils");
15
15
  const contracts_1 = require("./contracts");
16
16
  const contractsPublic_1 = require("./contractsPublic");
17
17
  const packageVersion_1 = require("./packageVersion");
18
+ const odspLocationRedirection_1 = require("./odspLocationRedirection");
18
19
  exports.Odsp409Error = "Odsp409Error";
19
20
  // Please update the README file in odsp-driver-definitions if you change the defaultCacheExpiryTimeoutMs.
20
21
  exports.defaultCacheExpiryTimeoutMs = 2 * 24 * 60 * 60 * 1000;
@@ -35,6 +36,11 @@ class EpochTracker {
35
36
  this.networkCallNumber = 1;
36
37
  // Limits the max number of concurrent requests to 24.
37
38
  this.rateLimiter = new driver_utils_1.RateLimiter(24);
39
+ // We need this for GC testing until we properly plumb through the snapshot expiration policy (see PR #11168)
40
+ this.snapshotCacheExpiryTimeoutMs =
41
+ (0, telemetry_utils_1.loggerToMonitoringContext)(logger).config.getBoolean("Fluid.Driver.Odsp.TestOverride.DisableSnapshotCache")
42
+ ? 0
43
+ : exports.defaultCacheExpiryTimeoutMs;
38
44
  }
39
45
  // public for UT purposes only!
40
46
  setEpoch(epoch, fromCache, fetchType) {
@@ -66,16 +72,16 @@ class EpochTracker {
66
72
  else if (this._fluidEpoch !== value.fluidEpoch) {
67
73
  return undefined;
68
74
  }
69
- // Expire the cached snapshot if it's older than the defaultCacheExpiryTimeoutMs and immediately
75
+ // Expire the cached snapshot if it's older than snapshotCacheExpiryTimeoutMs and immediately
70
76
  // expire all old caches that do not have cacheEntryTime
71
77
  if (entry.type === odsp_driver_definitions_1.snapshotKey) {
72
78
  const cacheTime = (_a = value.value) === null || _a === void 0 ? void 0 : _a.cacheEntryTime;
73
79
  const currentTime = Date.now();
74
- if (cacheTime === undefined || currentTime - cacheTime >= exports.defaultCacheExpiryTimeoutMs) {
80
+ if (cacheTime === undefined || currentTime - cacheTime >= this.snapshotCacheExpiryTimeoutMs) {
75
81
  this.logger.sendTelemetryEvent({
76
82
  eventName: "odspVersionsCacheExpired",
77
83
  duration: currentTime - cacheTime,
78
- maxCacheAgeMs: exports.defaultCacheExpiryTimeoutMs,
84
+ maxCacheAgeMs: this.snapshotCacheExpiryTimeoutMs,
79
85
  });
80
86
  await this.removeEntries();
81
87
  return undefined;
@@ -92,8 +98,8 @@ class EpochTracker {
92
98
  async put(entry, value) {
93
99
  var _a;
94
100
  (0, common_utils_1.assert)(this._fluidEpoch !== undefined, 0x1dd /* "no epoch" */);
95
- // For snapshots, the value should have the cacheEntryTime. This will be used to expire snapshots older
96
- // than the defaultCacheExpiryTimeoutMs.
101
+ // For snapshots, the value should have the cacheEntryTime.
102
+ // This will be used to expire snapshots older than snapshotCacheExpiryTimeoutMs.
97
103
  if (entry.type === odsp_driver_definitions_1.snapshotKey) {
98
104
  value.cacheEntryTime = (_a = value.cacheEntryTime) !== null && _a !== void 0 ? _a : Date.now();
99
105
  }
@@ -170,6 +176,19 @@ class EpochTracker {
170
176
  }
171
177
  await this.checkForEpochError(error, epochFromResponse, fetchType);
172
178
  throw error;
179
+ }).catch((error) => {
180
+ // If the error is about location redirection, then we need to generate new resolved url with correct
181
+ // location info.
182
+ if ((0, telemetry_utils_1.isFluidError)(error) && error.errorType === driver_definitions_1.DriverErrorType.fileNotFoundOrAccessDeniedError) {
183
+ const redirectLocation = error.redirectLocation;
184
+ if (redirectLocation !== undefined) {
185
+ const redirectUrl = (0, odspLocationRedirection_1.patchOdspResolvedUrl)(this.fileEntry.resolvedUrl, redirectLocation);
186
+ const locationRedirectionError = new driver_utils_1.LocationRedirectionError(error.message, redirectUrl, { driverVersion: packageVersion_1.pkgVersion, redirectLocation });
187
+ locationRedirectionError.addTelemetryProperties(error.getTelemetryProperties());
188
+ throw locationRedirectionError;
189
+ }
190
+ }
191
+ throw error;
173
192
  }).catch((error) => {
174
193
  const fluidError = (0, telemetry_utils_1.normalizeError)(error, { props: { XRequestStatsHeader: clientCorrelationId } });
175
194
  throw fluidError;
@@ -1 +1 @@
1
- {"version":3,"file":"epochTracker.js","sourceRoot":"","sources":["../src/epochTracker.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { v4 as uuid } from \"uuid\";\nimport { assert, Deferred } from \"@fluidframework/common-utils\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { ThrottlingError, RateLimiter, NonRetryableError } from \"@fluidframework/driver-utils\";\nimport { IConnected } from \"@fluidframework/protocol-definitions\";\nimport {\n snapshotKey,\n ICacheEntry,\n IEntry,\n IFileEntry,\n IPersistedCache,\n IOdspError,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport { PerformanceEvent, isFluidError, normalizeError } from \"@fluidframework/telemetry-utils\";\nimport { fetchAndParseAsJSONHelper, fetchArray, fetchHelper, getOdspResolvedUrl, IOdspResponse } from \"./odspUtils\";\nimport {\n IOdspCache,\n INonPersistentCache,\n IPersistedFileCache,\n } from \"./odspCache\";\nimport { IVersionedValueWithEpoch, persistedCacheValueVersion } from \"./contracts\";\nimport { ClpCompliantAppHeader } from \"./contractsPublic\";\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\n\nexport type FetchType = \"blob\" | \"createBlob\" | \"createFile\" | \"joinSession\" | \"ops\" | \"test\" | \"snapshotTree\" |\n \"treesLatest\" | \"uploadSummary\" | \"push\" | \"versions\";\n\nexport type FetchTypeInternal = FetchType | \"cache\";\n\nexport const Odsp409Error = \"Odsp409Error\";\n\n// Please update the README file in odsp-driver-definitions if you change the defaultCacheExpiryTimeoutMs.\nexport const defaultCacheExpiryTimeoutMs: number = 2 * 24 * 60 * 60 * 1000;\n\n/**\n * This class is a wrapper around fetch calls. It adds epoch to the request made so that the\n * server can match it with its epoch value in order to match the version.\n * It also validates the epoch value received in response of fetch calls. If the epoch does not match,\n * then it also clears all the cached entries for the given container.\n */\nexport class EpochTracker implements IPersistedFileCache {\n private _fluidEpoch: string | undefined;\n\n public readonly rateLimiter: RateLimiter;\n private readonly driverId = uuid();\n // This tracks the request number made by the driver instance.\n private networkCallNumber = 1;\n constructor(\n protected readonly cache: IPersistedCache,\n protected readonly fileEntry: IFileEntry,\n protected readonly logger: ITelemetryLogger,\n protected readonly clientIsSummarizer?: boolean,\n ) {\n // Limits the max number of concurrent requests to 24.\n this.rateLimiter = new RateLimiter(24);\n }\n\n // public for UT purposes only!\n public setEpoch(epoch: string, fromCache: boolean, fetchType: FetchTypeInternal) {\n assert(this._fluidEpoch === undefined, 0x1db /* \"epoch exists\" */);\n this._fluidEpoch = epoch;\n\n this.logger.sendTelemetryEvent(\n {\n eventName: \"EpochLearnedFirstTime\",\n epoch,\n fetchType,\n fromCache,\n },\n );\n }\n\n public async get(\n entry: IEntry,\n ): Promise<any> {\n try {\n // Return undefined so that the ops/snapshots are grabbed from the server instead of the cache\n const value: IVersionedValueWithEpoch = await this.cache.get(this.fileEntryFromEntry(entry));\n // Version mismatch between what the runtime expects and what it recieved.\n // The cached value should not be used\n if (value === undefined || value.version !== persistedCacheValueVersion) {\n return undefined;\n }\n assert(value.fluidEpoch !== undefined, 0x1dc /* \"all entries have to have epoch\" */);\n if (this._fluidEpoch === undefined) {\n this.setEpoch(value.fluidEpoch, true, \"cache\");\n // Epoch mismatch, the cached value is considerably different from what the current state of\n // the runtime and should not be used\n } else if (this._fluidEpoch !== value.fluidEpoch) {\n return undefined;\n }\n // Expire the cached snapshot if it's older than the defaultCacheExpiryTimeoutMs and immediately\n // expire all old caches that do not have cacheEntryTime\n if (entry.type === snapshotKey) {\n const cacheTime = value.value?.cacheEntryTime;\n const currentTime = Date.now();\n if (cacheTime === undefined || currentTime - cacheTime >= defaultCacheExpiryTimeoutMs) {\n this.logger.sendTelemetryEvent(\n {\n eventName: \"odspVersionsCacheExpired\",\n duration: currentTime - cacheTime,\n maxCacheAgeMs: defaultCacheExpiryTimeoutMs,\n });\n await this.removeEntries();\n return undefined;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value.value;\n } catch (error) {\n this.logger.sendErrorEvent({ eventName: \"cacheFetchError\", type: entry.type }, error);\n return undefined;\n }\n }\n\n public async put(entry: IEntry, value: any) {\n assert(this._fluidEpoch !== undefined, 0x1dd /* \"no epoch\" */);\n // For snapshots, the value should have the cacheEntryTime. This will be used to expire snapshots older\n // than the defaultCacheExpiryTimeoutMs.\n if (entry.type === snapshotKey) {\n value.cacheEntryTime = value.cacheEntryTime ?? Date.now();\n }\n const data: IVersionedValueWithEpoch = {\n value,\n version: persistedCacheValueVersion,\n fluidEpoch: this._fluidEpoch,\n };\n return this.cache.put(this.fileEntryFromEntry(entry), data)\n .catch((error) => {\n this.logger.sendErrorEvent({ eventName: \"cachePutError\", type: entry.type }, error);\n throw error;\n });\n }\n\n public async removeEntries(): Promise<void> {\n try {\n return await this.cache.removeEntries(this.fileEntry);\n } catch (error) {\n this.logger.sendErrorEvent({ eventName: \"removeCacheEntries\" }, error);\n }\n }\n\n public get fluidEpoch() {\n return this._fluidEpoch;\n }\n\n public async validateEpochFromPush(details: IConnected) {\n const epoch = details.epoch;\n assert(epoch !== undefined, 0x09d /* \"Connection details should contain epoch\" */);\n try {\n this.validateEpochFromResponse(epoch, \"push\");\n } catch (error) {\n await this.checkForEpochError(error, epoch, \"push\");\n throw error;\n }\n }\n\n /**\n * Api to fetch the response for given request and parse it as json.\n * @param url - url of the request\n * @param fetchOptions - fetch options for request containing body, headers etc.\n * @param fetchType - method for which fetch is called.\n * @param addInBody - Pass True if caller wants to add epoch in post body.\n * @param fetchReason - fetch reason to add to the request.\n */\n public async fetchAndParseAsJSON<T>(\n url: string,\n fetchOptions: RequestInit,\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ): Promise<IOdspResponse<T>> {\n return this.fetchCore<T>(url, fetchOptions, fetchAndParseAsJSONHelper, fetchType, addInBody, fetchReason);\n }\n\n /**\n * Api to fetch the response for given request and parse it as json.\n * @param url - url of the request\n * @param fetchOptions - fetch options for request containing body, headers etc.\n * @param fetchType - method for which fetch is called.\n * @param addInBody - Pass True if caller wants to add epoch in post body.\n * @param fetchReason - fetch reason to add to the request.\n */\n public async fetch(\n url: string,\n fetchOptions: RequestInit,\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ) {\n return this.fetchCore<Response>(url, fetchOptions, fetchHelper, fetchType, addInBody, fetchReason);\n }\n\n private async fetchCore<T>(\n url: string,\n fetchOptions: { [index: string]: any; },\n fetcher: (url: string, fetchOptions: { [index: string]: any; }) => Promise<IOdspResponse<T>>,\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ) {\n const clientCorrelationId = this.formatClientCorrelationId(fetchReason);\n // Add epoch in fetch request.\n this.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);\n let epochFromResponse: string | undefined;\n return this.rateLimiter.schedule(\n async () => fetcher(url, fetchOptions),\n ).then((response) => {\n epochFromResponse = response.headers.get(\"x-fluid-epoch\");\n this.validateEpochFromResponse(epochFromResponse, fetchType);\n response.propsToLog.XRequestStatsHeader = clientCorrelationId;\n return response;\n }).catch(async (error) => {\n // Get the server epoch from error in case we don't have it as if undefined we won't be able\n // to mark it as epoch error.\n if (epochFromResponse === undefined) {\n epochFromResponse = (error as IOdspError).serverEpoch;\n }\n await this.checkForEpochError(error, epochFromResponse, fetchType);\n throw error;\n }).catch((error) => {\n const fluidError = normalizeError(error, { props: { XRequestStatsHeader: clientCorrelationId } });\n throw fluidError;\n });\n }\n\n /**\n * Api to fetch the response as it is for given request.\n * @param url - url of the request\n * @param fetchOptions - fetch options for request containing body, headers etc.\n * @param fetchType - method for which fetch is called.\n * @param addInBody - Pass True if caller wants to add epoch in post body.\n * @param fetchReason - fetch reason to add to the request.\n */\n public async fetchArray(\n url: string,\n fetchOptions: { [index: string]: any; },\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ) {\n return this.fetchCore<ArrayBuffer>(url, fetchOptions, fetchArray, fetchType, addInBody, fetchReason);\n }\n\n private addEpochInRequest(\n fetchOptions: RequestInit,\n addInBody: boolean,\n clientCorrelationId: string,\n ) {\n const isClpCompliantApp = getOdspResolvedUrl(this.fileEntry.resolvedUrl).isClpCompliantApp;\n if (addInBody) {\n const headers: { [key: string]: string; } = {};\n headers[\"X-RequestStats\"] = clientCorrelationId;\n if (this.fluidEpoch !== undefined) {\n headers[\"x-fluid-epoch\"] = this.fluidEpoch;\n }\n if (isClpCompliantApp) {\n headers[ClpCompliantAppHeader.isClpCompliantApp] = isClpCompliantApp.toString();\n }\n this.addParamInBody(fetchOptions, headers);\n } else {\n const addHeader = (key: string, val: string) => {\n fetchOptions.headers = {\n ...fetchOptions.headers,\n };\n assert(fetchOptions.headers !== undefined, 0x282 /* \"Headers should be present now\" */);\n fetchOptions.headers[key] = val;\n };\n addHeader(\"X-RequestStats\", clientCorrelationId);\n if (this.fluidEpoch !== undefined) {\n addHeader(\"x-fluid-epoch\", this.fluidEpoch);\n }\n if (isClpCompliantApp) {\n addHeader(ClpCompliantAppHeader.isClpCompliantApp, isClpCompliantApp.toString());\n }\n }\n }\n\n private addParamInBody(fetchOptions: RequestInit, headers: { [key: string]: string; }) {\n // We use multi part form request for post body where we want to use this.\n // So extract the form boundary to mark the end of form.\n const body = fetchOptions.body;\n assert(typeof body === \"string\", 0x21d /* \"body is not string\" */);\n const splitBody = body.split(\"\\r\\n\");\n const firstLine = splitBody.shift();\n assert(firstLine?.startsWith(\"--\") === true, 0x21e /* \"improper boundary format\" */);\n const formParams = [firstLine];\n Object.entries(headers).forEach(([key, value]) => {\n formParams.push(`${key}: ${value}`);\n });\n splitBody.forEach((value: string) => {\n formParams.push(value);\n });\n fetchOptions.body = formParams.join(\"\\r\\n\");\n }\n\n private formatClientCorrelationId(fetchReason?: string) {\n const items: string[] = [\n `driverId=${this.driverId}`,\n `RequestNumber=${this.networkCallNumber++}`,\n `driverVersion=${driverVersion}`,\n `isSummarizer=${this.clientIsSummarizer}`,\n ];\n if (fetchReason !== undefined) {\n items.push(`fetchReason=${fetchReason}`);\n }\n return items.join(\", \");\n }\n\n protected validateEpochFromResponse(\n epochFromResponse: string | undefined,\n fetchType: FetchTypeInternal,\n fromCache: boolean = false,\n ) {\n const error = this.checkForEpochErrorCore(epochFromResponse);\n if (error !== undefined) {\n throw error;\n }\n if (epochFromResponse !== undefined) {\n if (this._fluidEpoch === undefined) {\n this.setEpoch(epochFromResponse, fromCache, fetchType);\n }\n }\n }\n\n private async checkForEpochError(\n error: unknown,\n epochFromResponse: string | null | undefined,\n fetchType: FetchTypeInternal,\n fromCache: boolean = false,\n ) {\n if (isFluidError(error) && error.errorType === DriverErrorType.fileOverwrittenInStorage) {\n const epochError = this.checkForEpochErrorCore(epochFromResponse);\n if (epochError !== undefined) {\n epochError.addTelemetryProperties({\n fromCache,\n clientEpoch: this.fluidEpoch,\n fetchType,\n });\n this.logger.sendErrorEvent({ eventName: \"fileOverwrittenInStorage\" }, epochError);\n // If the epoch mismatches, then clear all entries for such file entry from cache.\n await this.removeEntries();\n throw epochError;\n }\n // If it was categorized as epoch error but the epoch returned in response matches with the client epoch\n // then it was coherency 409, so rethrow it as throttling error so that it can retried. Default throttling\n // time is 1s.\n throw new ThrottlingError(\n `Coherency 409: ${error.message}`,\n 1 /* retryAfterSeconds */,\n { [Odsp409Error]: true, driverVersion });\n }\n }\n\n private checkForEpochErrorCore(epochFromResponse: string | null | undefined) {\n // If epoch is undefined, then don't compare it because initially for createNew or TreesLatest\n // initializes this value. Sometimes response does not contain epoch as it is still in\n // implementation phase at server side. In that case also, don't compare it with our epoch value.\n if (this.fluidEpoch && epochFromResponse && (this.fluidEpoch !== epochFromResponse)) {\n // This is similar in nature to how fluidEpochMismatchError (409) is handled.\n // Difference - client detected mismatch, instead of server detecting it.\n return new NonRetryableError(\n \"Epoch mismatch\", DriverErrorType.fileOverwrittenInStorage, { driverVersion });\n }\n }\n\n private fileEntryFromEntry(entry: IEntry): ICacheEntry {\n return { ...entry, file: this.fileEntry };\n }\n}\n\nexport class EpochTrackerWithRedemption extends EpochTracker {\n private readonly treesLatestDeferral = new Deferred<void>();\n\n protected validateEpochFromResponse(\n epochFromResponse: string | undefined,\n fetchType: FetchType,\n fromCache: boolean = false,\n ) {\n super.validateEpochFromResponse(epochFromResponse, fetchType, fromCache);\n\n // Any successful call means we have access to a file, i.e. any redemption that was required already happened.\n // That covers cases of \"treesLatest\" as well as \"getVersions\" or \"createFile\" - all the ways we can start\n // exploring a file.\n this.treesLatestDeferral.resolve();\n }\n\n public async get(\n entry: IEntry,\n ): Promise<any> {\n let result = super.get(entry);\n\n // equivalence of what happens in fetchAndParseAsJSON()\n if (entry.type === snapshotKey) {\n result = result\n .then((value) => {\n // If there is nothing in cache, we need to wait for network call to complete (and do redemption)\n // Otherwise file was redeemed in prior session, so if joinSession failed, we should not retry\n if (value !== undefined) {\n this.treesLatestDeferral.resolve();\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n })\n .catch((error) => {\n this.treesLatestDeferral.reject(error);\n throw error;\n });\n }\n return result;\n }\n\n public async fetchAndParseAsJSON<T>(\n url: string,\n fetchOptions: { [index: string]: any; },\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ): Promise<IOdspResponse<T>> {\n // Optimize the flow if we know that treesLatestDeferral was already completed by the timer we started\n // joinSession call. If we did - there is no reason to repeat the call as it will fail with same error.\n const completed = this.treesLatestDeferral.isCompleted;\n\n try {\n return await super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody, fetchReason);\n } catch (error: any) {\n // Only handling here treesLatest. If createFile failed, we should never try to do joinSession.\n // Similar, if getVersions failed, we should not do any further storage calls.\n // So treesLatest is the only call that can have parallel joinSession request.\n if (fetchType === \"treesLatest\") {\n this.treesLatestDeferral.reject(error);\n }\n if (fetchType !== \"joinSession\" || error.statusCode < 401 || error.statusCode > 404 || completed) {\n throw error;\n }\n }\n\n // It is joinSession failing with 401..404 error\n // Repeat after waiting for treeLatest succeeding (or fail if it failed).\n // No special handling after first call - if file has been deleted, then it's game over.\n\n // Ensure we have some safety here - we do not want to deadlock if we got logic somewhere wrong.\n // If we waited too long, we will log error event and proceed with call.\n // It may result in failure for user, but refreshing document would address it.\n // Thus we use rather long timeout (not to get these failures as much as possible), but not large enough\n // to unblock the process.\n await PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"JoinSessionSyncWait\" },\n async (event) => {\n const timeoutRes = 51; // anything will work here\n let timer: ReturnType<typeof setTimeout>;\n const timeoutP = new Promise<number>((resolve) => {\n timer = setTimeout(() => { resolve(timeoutRes); }, 15000);\n });\n const res = await Promise.race([\n timeoutP,\n // cancel timeout to unblock UTs (otherwise Node process does not exit for 15 sec)\n this.treesLatestDeferral.promise.finally(() => clearTimeout(timer))]);\n if (res === timeoutRes) {\n event.cancel();\n }\n },\n { start: true, end: true, cancel: \"generic\" });\n return super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody);\n }\n}\n\nexport interface ICacheAndTracker {\n cache: IOdspCache;\n epochTracker: EpochTracker;\n}\n\nexport function createOdspCacheAndTracker(\n persistedCacheArg: IPersistedCache,\n nonpersistentCache: INonPersistentCache,\n fileEntry: IFileEntry,\n logger: ITelemetryLogger,\n clientIsSummarizer?: boolean): ICacheAndTracker {\n const epochTracker = new EpochTrackerWithRedemption(persistedCacheArg, fileEntry, logger, clientIsSummarizer);\n return {\n cache: {\n ...nonpersistentCache,\n persistedCache: epochTracker,\n },\n epochTracker,\n };\n}\n"]}
1
+ {"version":3,"file":"epochTracker.js","sourceRoot":"","sources":["../src/epochTracker.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { v4 as uuid } from \"uuid\";\nimport { assert, Deferred } from \"@fluidframework/common-utils\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport {\n ThrottlingError,\n RateLimiter,\n NonRetryableError,\n LocationRedirectionError,\n} from \"@fluidframework/driver-utils\";\nimport { IConnected } from \"@fluidframework/protocol-definitions\";\nimport {\n snapshotKey,\n ICacheEntry,\n IEntry,\n IFileEntry,\n IPersistedCache,\n IOdspError,\n IOdspErrorAugmentations,\n IOdspResolvedUrl,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport {\n PerformanceEvent,\n isFluidError,\n normalizeError,\n loggerToMonitoringContext,\n} from \"@fluidframework/telemetry-utils\";\nimport { fetchAndParseAsJSONHelper, fetchArray, fetchHelper, getOdspResolvedUrl, IOdspResponse } from \"./odspUtils\";\nimport {\n IOdspCache,\n INonPersistentCache,\n IPersistedFileCache,\n } from \"./odspCache\";\nimport { IVersionedValueWithEpoch, persistedCacheValueVersion } from \"./contracts\";\nimport { ClpCompliantAppHeader } from \"./contractsPublic\";\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\nimport { patchOdspResolvedUrl } from \"./odspLocationRedirection\";\n\nexport type FetchType = \"blob\" | \"createBlob\" | \"createFile\" | \"joinSession\" | \"ops\" | \"test\" | \"snapshotTree\" |\n \"treesLatest\" | \"uploadSummary\" | \"push\" | \"versions\";\n\nexport type FetchTypeInternal = FetchType | \"cache\";\n\nexport const Odsp409Error = \"Odsp409Error\";\n\n// Please update the README file in odsp-driver-definitions if you change the defaultCacheExpiryTimeoutMs.\nexport const defaultCacheExpiryTimeoutMs: number = 2 * 24 * 60 * 60 * 1000;\n\n/**\n * This class is a wrapper around fetch calls. It adds epoch to the request made so that the\n * server can match it with its epoch value in order to match the version.\n * It also validates the epoch value received in response of fetch calls. If the epoch does not match,\n * then it also clears all the cached entries for the given container.\n */\nexport class EpochTracker implements IPersistedFileCache {\n private _fluidEpoch: string | undefined;\n\n private readonly snapshotCacheExpiryTimeoutMs: number;\n public readonly rateLimiter: RateLimiter;\n private readonly driverId = uuid();\n // This tracks the request number made by the driver instance.\n private networkCallNumber = 1;\n constructor(\n protected readonly cache: IPersistedCache,\n protected readonly fileEntry: IFileEntry,\n protected readonly logger: ITelemetryLogger,\n protected readonly clientIsSummarizer?: boolean,\n ) {\n // Limits the max number of concurrent requests to 24.\n this.rateLimiter = new RateLimiter(24);\n\n // We need this for GC testing until we properly plumb through the snapshot expiration policy (see PR #11168)\n this.snapshotCacheExpiryTimeoutMs =\n loggerToMonitoringContext(logger).config.getBoolean(\"Fluid.Driver.Odsp.TestOverride.DisableSnapshotCache\")\n ? 0\n : defaultCacheExpiryTimeoutMs;\n }\n\n // public for UT purposes only!\n public setEpoch(epoch: string, fromCache: boolean, fetchType: FetchTypeInternal) {\n assert(this._fluidEpoch === undefined, 0x1db /* \"epoch exists\" */);\n this._fluidEpoch = epoch;\n\n this.logger.sendTelemetryEvent(\n {\n eventName: \"EpochLearnedFirstTime\",\n epoch,\n fetchType,\n fromCache,\n },\n );\n }\n\n public async get(\n entry: IEntry,\n ): Promise<any> {\n try {\n // Return undefined so that the ops/snapshots are grabbed from the server instead of the cache\n const value: IVersionedValueWithEpoch = await this.cache.get(this.fileEntryFromEntry(entry));\n // Version mismatch between what the runtime expects and what it recieved.\n // The cached value should not be used\n if (value === undefined || value.version !== persistedCacheValueVersion) {\n return undefined;\n }\n assert(value.fluidEpoch !== undefined, 0x1dc /* \"all entries have to have epoch\" */);\n if (this._fluidEpoch === undefined) {\n this.setEpoch(value.fluidEpoch, true, \"cache\");\n // Epoch mismatch, the cached value is considerably different from what the current state of\n // the runtime and should not be used\n } else if (this._fluidEpoch !== value.fluidEpoch) {\n return undefined;\n }\n // Expire the cached snapshot if it's older than snapshotCacheExpiryTimeoutMs and immediately\n // expire all old caches that do not have cacheEntryTime\n if (entry.type === snapshotKey) {\n const cacheTime = value.value?.cacheEntryTime;\n const currentTime = Date.now();\n if (cacheTime === undefined || currentTime - cacheTime >= this.snapshotCacheExpiryTimeoutMs) {\n this.logger.sendTelemetryEvent(\n {\n eventName: \"odspVersionsCacheExpired\",\n duration: currentTime - cacheTime,\n maxCacheAgeMs: this.snapshotCacheExpiryTimeoutMs,\n });\n await this.removeEntries();\n return undefined;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value.value;\n } catch (error) {\n this.logger.sendErrorEvent({ eventName: \"cacheFetchError\", type: entry.type }, error);\n return undefined;\n }\n }\n\n public async put(entry: IEntry, value: any) {\n assert(this._fluidEpoch !== undefined, 0x1dd /* \"no epoch\" */);\n // For snapshots, the value should have the cacheEntryTime.\n // This will be used to expire snapshots older than snapshotCacheExpiryTimeoutMs.\n if (entry.type === snapshotKey) {\n value.cacheEntryTime = value.cacheEntryTime ?? Date.now();\n }\n const data: IVersionedValueWithEpoch = {\n value,\n version: persistedCacheValueVersion,\n fluidEpoch: this._fluidEpoch,\n };\n return this.cache.put(this.fileEntryFromEntry(entry), data)\n .catch((error) => {\n this.logger.sendErrorEvent({ eventName: \"cachePutError\", type: entry.type }, error);\n throw error;\n });\n }\n\n public async removeEntries(): Promise<void> {\n try {\n return await this.cache.removeEntries(this.fileEntry);\n } catch (error) {\n this.logger.sendErrorEvent({ eventName: \"removeCacheEntries\" }, error);\n }\n }\n\n public get fluidEpoch() {\n return this._fluidEpoch;\n }\n\n public async validateEpochFromPush(details: IConnected) {\n const epoch = details.epoch;\n assert(epoch !== undefined, 0x09d /* \"Connection details should contain epoch\" */);\n try {\n this.validateEpochFromResponse(epoch, \"push\");\n } catch (error) {\n await this.checkForEpochError(error, epoch, \"push\");\n throw error;\n }\n }\n\n /**\n * Api to fetch the response for given request and parse it as json.\n * @param url - url of the request\n * @param fetchOptions - fetch options for request containing body, headers etc.\n * @param fetchType - method for which fetch is called.\n * @param addInBody - Pass True if caller wants to add epoch in post body.\n * @param fetchReason - fetch reason to add to the request.\n */\n public async fetchAndParseAsJSON<T>(\n url: string,\n fetchOptions: RequestInit,\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ): Promise<IOdspResponse<T>> {\n return this.fetchCore<T>(url, fetchOptions, fetchAndParseAsJSONHelper, fetchType, addInBody, fetchReason);\n }\n\n /**\n * Api to fetch the response for given request and parse it as json.\n * @param url - url of the request\n * @param fetchOptions - fetch options for request containing body, headers etc.\n * @param fetchType - method for which fetch is called.\n * @param addInBody - Pass True if caller wants to add epoch in post body.\n * @param fetchReason - fetch reason to add to the request.\n */\n public async fetch(\n url: string,\n fetchOptions: RequestInit,\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ) {\n return this.fetchCore<Response>(url, fetchOptions, fetchHelper, fetchType, addInBody, fetchReason);\n }\n\n private async fetchCore<T>(\n url: string,\n fetchOptions: { [index: string]: any; },\n fetcher: (url: string, fetchOptions: { [index: string]: any; }) => Promise<IOdspResponse<T>>,\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ) {\n const clientCorrelationId = this.formatClientCorrelationId(fetchReason);\n // Add epoch in fetch request.\n this.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);\n let epochFromResponse: string | undefined;\n return this.rateLimiter.schedule(\n async () => fetcher(url, fetchOptions),\n ).then((response) => {\n epochFromResponse = response.headers.get(\"x-fluid-epoch\");\n this.validateEpochFromResponse(epochFromResponse, fetchType);\n response.propsToLog.XRequestStatsHeader = clientCorrelationId;\n return response;\n }).catch(async (error) => {\n // Get the server epoch from error in case we don't have it as if undefined we won't be able\n // to mark it as epoch error.\n if (epochFromResponse === undefined) {\n epochFromResponse = (error as IOdspError).serverEpoch;\n }\n await this.checkForEpochError(error, epochFromResponse, fetchType);\n throw error;\n }).catch((error) => {\n // If the error is about location redirection, then we need to generate new resolved url with correct\n // location info.\n if (isFluidError(error) && error.errorType === DriverErrorType.fileNotFoundOrAccessDeniedError) {\n const redirectLocation = (error as IOdspErrorAugmentations).redirectLocation;\n if (redirectLocation !== undefined) {\n const redirectUrl: IOdspResolvedUrl = patchOdspResolvedUrl(\n this.fileEntry.resolvedUrl,\n redirectLocation,\n );\n const locationRedirectionError = new LocationRedirectionError(\n error.message,\n redirectUrl,\n { driverVersion, redirectLocation },\n );\n locationRedirectionError.addTelemetryProperties(error.getTelemetryProperties());\n throw locationRedirectionError;\n }\n }\n throw error;\n }).catch((error) => {\n const fluidError = normalizeError(error, { props: { XRequestStatsHeader: clientCorrelationId } });\n throw fluidError;\n });\n }\n\n /**\n * Api to fetch the response as it is for given request.\n * @param url - url of the request\n * @param fetchOptions - fetch options for request containing body, headers etc.\n * @param fetchType - method for which fetch is called.\n * @param addInBody - Pass True if caller wants to add epoch in post body.\n * @param fetchReason - fetch reason to add to the request.\n */\n public async fetchArray(\n url: string,\n fetchOptions: { [index: string]: any; },\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ) {\n return this.fetchCore<ArrayBuffer>(url, fetchOptions, fetchArray, fetchType, addInBody, fetchReason);\n }\n\n private addEpochInRequest(\n fetchOptions: RequestInit,\n addInBody: boolean,\n clientCorrelationId: string,\n ) {\n const isClpCompliantApp = getOdspResolvedUrl(this.fileEntry.resolvedUrl).isClpCompliantApp;\n if (addInBody) {\n const headers: { [key: string]: string; } = {};\n headers[\"X-RequestStats\"] = clientCorrelationId;\n if (this.fluidEpoch !== undefined) {\n headers[\"x-fluid-epoch\"] = this.fluidEpoch;\n }\n if (isClpCompliantApp) {\n headers[ClpCompliantAppHeader.isClpCompliantApp] = isClpCompliantApp.toString();\n }\n this.addParamInBody(fetchOptions, headers);\n } else {\n const addHeader = (key: string, val: string) => {\n fetchOptions.headers = {\n ...fetchOptions.headers,\n };\n assert(fetchOptions.headers !== undefined, 0x282 /* \"Headers should be present now\" */);\n fetchOptions.headers[key] = val;\n };\n addHeader(\"X-RequestStats\", clientCorrelationId);\n if (this.fluidEpoch !== undefined) {\n addHeader(\"x-fluid-epoch\", this.fluidEpoch);\n }\n if (isClpCompliantApp) {\n addHeader(ClpCompliantAppHeader.isClpCompliantApp, isClpCompliantApp.toString());\n }\n }\n }\n\n private addParamInBody(fetchOptions: RequestInit, headers: { [key: string]: string; }) {\n // We use multi part form request for post body where we want to use this.\n // So extract the form boundary to mark the end of form.\n const body = fetchOptions.body;\n assert(typeof body === \"string\", 0x21d /* \"body is not string\" */);\n const splitBody = body.split(\"\\r\\n\");\n const firstLine = splitBody.shift();\n assert(firstLine?.startsWith(\"--\") === true, 0x21e /* \"improper boundary format\" */);\n const formParams = [firstLine];\n Object.entries(headers).forEach(([key, value]) => {\n formParams.push(`${key}: ${value}`);\n });\n splitBody.forEach((value: string) => {\n formParams.push(value);\n });\n fetchOptions.body = formParams.join(\"\\r\\n\");\n }\n\n private formatClientCorrelationId(fetchReason?: string) {\n const items: string[] = [\n `driverId=${this.driverId}`,\n `RequestNumber=${this.networkCallNumber++}`,\n `driverVersion=${driverVersion}`,\n `isSummarizer=${this.clientIsSummarizer}`,\n ];\n if (fetchReason !== undefined) {\n items.push(`fetchReason=${fetchReason}`);\n }\n return items.join(\", \");\n }\n\n protected validateEpochFromResponse(\n epochFromResponse: string | undefined,\n fetchType: FetchTypeInternal,\n fromCache: boolean = false,\n ) {\n const error = this.checkForEpochErrorCore(epochFromResponse);\n if (error !== undefined) {\n throw error;\n }\n if (epochFromResponse !== undefined) {\n if (this._fluidEpoch === undefined) {\n this.setEpoch(epochFromResponse, fromCache, fetchType);\n }\n }\n }\n\n private async checkForEpochError(\n error: unknown,\n epochFromResponse: string | null | undefined,\n fetchType: FetchTypeInternal,\n fromCache: boolean = false,\n ) {\n if (isFluidError(error) && error.errorType === DriverErrorType.fileOverwrittenInStorage) {\n const epochError = this.checkForEpochErrorCore(epochFromResponse);\n if (epochError !== undefined) {\n epochError.addTelemetryProperties({\n fromCache,\n clientEpoch: this.fluidEpoch,\n fetchType,\n });\n this.logger.sendErrorEvent({ eventName: \"fileOverwrittenInStorage\" }, epochError);\n // If the epoch mismatches, then clear all entries for such file entry from cache.\n await this.removeEntries();\n throw epochError;\n }\n // If it was categorized as epoch error but the epoch returned in response matches with the client epoch\n // then it was coherency 409, so rethrow it as throttling error so that it can retried. Default throttling\n // time is 1s.\n throw new ThrottlingError(\n `Coherency 409: ${error.message}`,\n 1 /* retryAfterSeconds */,\n { [Odsp409Error]: true, driverVersion });\n }\n }\n\n private checkForEpochErrorCore(epochFromResponse: string | null | undefined) {\n // If epoch is undefined, then don't compare it because initially for createNew or TreesLatest\n // initializes this value. Sometimes response does not contain epoch as it is still in\n // implementation phase at server side. In that case also, don't compare it with our epoch value.\n if (this.fluidEpoch && epochFromResponse && (this.fluidEpoch !== epochFromResponse)) {\n // This is similar in nature to how fluidEpochMismatchError (409) is handled.\n // Difference - client detected mismatch, instead of server detecting it.\n return new NonRetryableError(\n \"Epoch mismatch\", DriverErrorType.fileOverwrittenInStorage, { driverVersion });\n }\n }\n\n private fileEntryFromEntry(entry: IEntry): ICacheEntry {\n return { ...entry, file: this.fileEntry };\n }\n}\n\nexport class EpochTrackerWithRedemption extends EpochTracker {\n private readonly treesLatestDeferral = new Deferred<void>();\n\n protected validateEpochFromResponse(\n epochFromResponse: string | undefined,\n fetchType: FetchType,\n fromCache: boolean = false,\n ) {\n super.validateEpochFromResponse(epochFromResponse, fetchType, fromCache);\n\n // Any successful call means we have access to a file, i.e. any redemption that was required already happened.\n // That covers cases of \"treesLatest\" as well as \"getVersions\" or \"createFile\" - all the ways we can start\n // exploring a file.\n this.treesLatestDeferral.resolve();\n }\n\n public async get(\n entry: IEntry,\n ): Promise<any> {\n let result = super.get(entry);\n\n // equivalence of what happens in fetchAndParseAsJSON()\n if (entry.type === snapshotKey) {\n result = result\n .then((value) => {\n // If there is nothing in cache, we need to wait for network call to complete (and do redemption)\n // Otherwise file was redeemed in prior session, so if joinSession failed, we should not retry\n if (value !== undefined) {\n this.treesLatestDeferral.resolve();\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n })\n .catch((error) => {\n this.treesLatestDeferral.reject(error);\n throw error;\n });\n }\n return result;\n }\n\n public async fetchAndParseAsJSON<T>(\n url: string,\n fetchOptions: { [index: string]: any; },\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ): Promise<IOdspResponse<T>> {\n // Optimize the flow if we know that treesLatestDeferral was already completed by the timer we started\n // joinSession call. If we did - there is no reason to repeat the call as it will fail with same error.\n const completed = this.treesLatestDeferral.isCompleted;\n\n try {\n return await super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody, fetchReason);\n } catch (error: any) {\n // Only handling here treesLatest. If createFile failed, we should never try to do joinSession.\n // Similar, if getVersions failed, we should not do any further storage calls.\n // So treesLatest is the only call that can have parallel joinSession request.\n if (fetchType === \"treesLatest\") {\n this.treesLatestDeferral.reject(error);\n }\n if (fetchType !== \"joinSession\" || error.statusCode < 401 || error.statusCode > 404 || completed) {\n throw error;\n }\n }\n\n // It is joinSession failing with 401..404 error\n // Repeat after waiting for treeLatest succeeding (or fail if it failed).\n // No special handling after first call - if file has been deleted, then it's game over.\n\n // Ensure we have some safety here - we do not want to deadlock if we got logic somewhere wrong.\n // If we waited too long, we will log error event and proceed with call.\n // It may result in failure for user, but refreshing document would address it.\n // Thus we use rather long timeout (not to get these failures as much as possible), but not large enough\n // to unblock the process.\n await PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"JoinSessionSyncWait\" },\n async (event) => {\n const timeoutRes = 51; // anything will work here\n let timer: ReturnType<typeof setTimeout>;\n const timeoutP = new Promise<number>((resolve) => {\n timer = setTimeout(() => { resolve(timeoutRes); }, 15000);\n });\n const res = await Promise.race([\n timeoutP,\n // cancel timeout to unblock UTs (otherwise Node process does not exit for 15 sec)\n this.treesLatestDeferral.promise.finally(() => clearTimeout(timer))]);\n if (res === timeoutRes) {\n event.cancel();\n }\n },\n { start: true, end: true, cancel: \"generic\" });\n return super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody);\n }\n}\n\nexport interface ICacheAndTracker {\n cache: IOdspCache;\n epochTracker: EpochTracker;\n}\n\nexport function createOdspCacheAndTracker(\n persistedCacheArg: IPersistedCache,\n nonpersistentCache: INonPersistentCache,\n fileEntry: IFileEntry,\n logger: ITelemetryLogger,\n clientIsSummarizer?: boolean): ICacheAndTracker {\n const epochTracker = new EpochTrackerWithRedemption(persistedCacheArg, fileEntry, logger, clientIsSummarizer);\n return {\n cache: {\n ...nonpersistentCache,\n persistedCache: epochTracker,\n },\n epochTracker,\n };\n}\n"]}
@@ -23,11 +23,10 @@ export declare enum SnapshotFormatSupportType {
23
23
  * @param token - token used for authorization in the request
24
24
  * @param storageFetchWrapper - Implementation of the get/post methods used to fetch the snapshot
25
25
  * @param versionId - id of specific snapshot to be fetched
26
- * @param fetchFullSnapshot - whether we want to fetch full snapshot(with blobs)
27
26
  * @param forceAccessTokenViaAuthorizationHeader - whether to force passing given token via authorization header
28
27
  * @returns A promise of the snapshot and the status code of the response
29
28
  */
30
- export declare function fetchSnapshot(snapshotUrl: string, token: string | null, versionId: string, fetchFullSnapshot: boolean, forceAccessTokenViaAuthorizationHeader: boolean, logger: ITelemetryLogger, snapshotDownloader: (url: string, fetchOptions: {
29
+ export declare function fetchSnapshot(snapshotUrl: string, token: string | null, versionId: string, forceAccessTokenViaAuthorizationHeader: boolean, logger: ITelemetryLogger, snapshotDownloader: (url: string, fetchOptions: {
31
30
  [index: string]: any;
32
31
  }) => Promise<IOdspResponse<unknown>>): Promise<ISnapshotContents>;
33
32
  export declare function fetchSnapshotWithRedeem(odspResolvedUrl: IOdspResolvedUrl, storageTokenFetcher: InstrumentedStorageTokenFetcher, snapshotOptions: ISnapshotOptions | undefined, forceAccessTokenViaAuthorizationHeader: boolean, logger: ITelemetryLogger, snapshotDownloader: (finalOdspResolvedUrl: IOdspResolvedUrl, storageToken: string, snapshotOptions: ISnapshotOptions | undefined, controller?: AbortController) => Promise<ISnapshotRequestAndResponseOptions>, putInCache: (valueWithEpoch: IVersionedValueWithEpoch) => Promise<void>, removeEntries: () => Promise<void>, enableRedeemFallback?: boolean): Promise<ISnapshotContents>;
@@ -1 +1 @@
1
- {"version":3,"file":"fetchSnapshot.d.ts","sourceRoot":"","sources":["../src/fetchSnapshot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAItE,OAAO,EACH,gBAAgB,EAChB,gBAAgB,EAEhB,+BAA+B,EAClC,MAAM,yCAAyC,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAwB,wBAAwB,EAA8B,MAAM,aAAa,CAAC;AAGxH,OAAO,EAKH,aAAa,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAItD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C;;GAEG;AACH,oBAAY,yBAAyB;IACjC,IAAI,IAAI;IACR,MAAM,IAAI;IACV,aAAa,IAAI;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAC/B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,OAAO,EAC1B,sCAAsC,EAAE,OAAO,EAC/C,MAAM,EAAE,gBAAgB,EACxB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE;IAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC;CAAE,KAAK,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAC9G,OAAO,CAAC,iBAAiB,CAAC,CAwB5B;AAED,wBAAsB,uBAAuB,CACzC,eAAe,EAAE,gBAAgB,EACjC,mBAAmB,EAAE,+BAA+B,EACpD,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,sCAAsC,EAAE,OAAO,EAC/C,MAAM,EAAE,gBAAgB,EACxB,kBAAkB,EAAE,CAChB,oBAAoB,EAAE,gBAAgB,EACtC,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,UAAU,CAAC,EAAE,eAAe,KAC3B,OAAO,CAAC,kCAAkC,CAAC,EAChD,UAAU,EAAE,CAAC,cAAc,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,EACvE,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAClC,oBAAoB,CAAC,EAAE,OAAO,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAsD5B;AAiRD,MAAM,WAAW,kCAAkC;IAC/C,YAAY,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC;KAAE,CAAC;CAC7C;AAiDD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,QAK5D;AAWD;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAClC,eAAe,EAAE,gBAAgB,EACjC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,gBAAgB,EACxB,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,uBAAuB,CAAC,EAAE,yBAAyB,EACnD,UAAU,CAAC,EAAE,eAAe,EAC5B,YAAY,CAAC,EAAE,YAAY,EAC3B,YAAY,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,kCAAkC,CAAC,CAwC7C"}
1
+ {"version":3,"file":"fetchSnapshot.d.ts","sourceRoot":"","sources":["../src/fetchSnapshot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAItE,OAAO,EACH,gBAAgB,EAChB,gBAAgB,EAEhB,+BAA+B,EAClC,MAAM,yCAAyC,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAwB,wBAAwB,EAA8B,MAAM,aAAa,CAAC;AAGxH,OAAO,EAKH,aAAa,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C;;GAEG;AACH,oBAAY,yBAAyB;IACjC,IAAI,IAAI;IACR,MAAM,IAAI;IACV,aAAa,IAAI;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAC/B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,SAAS,EAAE,MAAM,EACjB,sCAAsC,EAAE,OAAO,EAC/C,MAAM,EAAE,gBAAgB,EACxB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE;IAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC;CAAE,KAAK,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAC9G,OAAO,CAAC,iBAAiB,CAAC,CAiB5B;AAED,wBAAsB,uBAAuB,CACzC,eAAe,EAAE,gBAAgB,EACjC,mBAAmB,EAAE,+BAA+B,EACpD,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,sCAAsC,EAAE,OAAO,EAC/C,MAAM,EAAE,gBAAgB,EACxB,kBAAkB,EAAE,CAChB,oBAAoB,EAAE,gBAAgB,EACtC,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,UAAU,CAAC,EAAE,eAAe,KAC3B,OAAO,CAAC,kCAAkC,CAAC,EAChD,UAAU,EAAE,CAAC,cAAc,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,EACvE,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAClC,oBAAoB,CAAC,EAAE,OAAO,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAsD5B;AA+RD,MAAM,WAAW,kCAAkC;IAC/C,YAAY,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC;KAAE,CAAC;CAC7C;AAiDD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,QAK5D;AAWD;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAClC,eAAe,EAAE,gBAAgB,EACjC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,gBAAgB,EACxB,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,uBAAuB,CAAC,EAAE,yBAAyB,EACnD,UAAU,CAAC,EAAE,eAAe,EAC5B,YAAY,CAAC,EAAE,YAAY,EAC3B,YAAY,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,kCAAkC,CAAC,CAwC7C"}
@@ -21,7 +21,6 @@ const getUrlAndHeadersWithAuth_1 = require("./getUrlAndHeadersWithAuth");
21
21
  const odspUtils_1 = require("./odspUtils");
22
22
  const odspSnapshotParser_1 = require("./odspSnapshotParser");
23
23
  const compactSnapshotParser_1 = require("./compactSnapshotParser");
24
- const ReadBufferUtils_1 = require("./ReadBufferUtils");
25
24
  const packageVersion_1 = require("./packageVersion");
26
25
  /**
27
26
  * Enum to support different types of snapshot formats.
@@ -38,21 +37,14 @@ var SnapshotFormatSupportType;
38
37
  * @param token - token used for authorization in the request
39
38
  * @param storageFetchWrapper - Implementation of the get/post methods used to fetch the snapshot
40
39
  * @param versionId - id of specific snapshot to be fetched
41
- * @param fetchFullSnapshot - whether we want to fetch full snapshot(with blobs)
42
40
  * @param forceAccessTokenViaAuthorizationHeader - whether to force passing given token via authorization header
43
41
  * @returns A promise of the snapshot and the status code of the response
44
42
  */
45
- async function fetchSnapshot(snapshotUrl, token, versionId, fetchFullSnapshot, forceAccessTokenViaAuthorizationHeader, logger, snapshotDownloader) {
43
+ async function fetchSnapshot(snapshotUrl, token, versionId, forceAccessTokenViaAuthorizationHeader, logger, snapshotDownloader) {
46
44
  const path = `/trees/${versionId}`;
47
- let queryParams = {};
48
- if (fetchFullSnapshot) {
49
- if (versionId !== "latest") {
50
- queryParams = { channels: 1, blobs: 2 };
51
- }
52
- else {
53
- queryParams = { deltas: 1, channels: 1, blobs: 2 };
54
- }
55
- }
45
+ // We just want to fetch tree here. So explicitly set to not fetch blobs and deltas
46
+ // as by default server will send that.
47
+ const queryParams = { deltas: 0, blobs: 0 };
56
48
  const queryString = (0, getQueryString_1.getQueryString)(queryParams);
57
49
  const { url, headers } = (0, getUrlAndHeadersWithAuth_1.getUrlAndHeadersWithAuth)(`${snapshotUrl}${path}${queryString}`, token, forceAccessTokenViaAuthorizationHeader);
58
50
  const response = await telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, {
@@ -138,20 +130,22 @@ async function fetchLatestSnapshotCore(odspResolvedUrl, storageTokenFetcher, sna
138
130
  const response = await snapshotDownloader(odspResolvedUrl, storageToken, snapshotOptions, controller);
139
131
  const odspResponse = response.odspResponse;
140
132
  const contentType = odspResponse.headers.get("content-type");
141
- odspResponse.propsToLog = Object.assign(Object.assign({}, odspResponse.propsToLog), { contentType, accept: response.requestHeaders.accept });
133
+ const propsToLog = Object.assign(Object.assign({}, odspResponse.propsToLog), { contentType, accept: response.requestHeaders.accept, driverVersion: packageVersion_1.pkgVersion });
134
+ // Measure how much time we spend processing payload
135
+ const snapshotParseEvent = telemetry_utils_1.PerformanceEvent.start(logger, Object.assign({ eventName: "SnapshotParse" }, propsToLog));
142
136
  let parsedSnapshotContents;
143
137
  let contentTypeToRead;
144
- if ((contentType === null || contentType === void 0 ? void 0 : contentType.indexOf("application/ms-fluid")) !== -1) {
138
+ if (contentType === null || contentType === void 0 ? void 0 : contentType.includes("application/ms-fluid")) {
145
139
  contentTypeToRead = "application/ms-fluid";
146
140
  }
147
- else if ((contentType === null || contentType === void 0 ? void 0 : contentType.indexOf("application/json")) !== -1) {
141
+ else if (contentType === null || contentType === void 0 ? void 0 : contentType.includes("application/json")) {
148
142
  contentTypeToRead = "application/json";
149
143
  }
150
144
  try {
151
145
  switch (contentTypeToRead) {
152
146
  case "application/json": {
153
147
  const text = await odspResponse.content.text();
154
- odspResponse.propsToLog.bodySize = text.length;
148
+ propsToLog.bodySize = text.length;
155
149
  const content = JSON.parse(text);
156
150
  validateBlobsAndTrees(content);
157
151
  const snapshotContents = (0, odspSnapshotParser_1.convertOdspSnapshotToSnapshotTreeAndBlobs)(content);
@@ -160,29 +154,30 @@ async function fetchLatestSnapshotCore(odspResolvedUrl, storageTokenFetcher, sna
160
154
  }
161
155
  case "application/ms-fluid": {
162
156
  const content = await odspResponse.content.arrayBuffer();
163
- odspResponse.propsToLog.bodySize = content.byteLength;
164
- const snapshotContents = (0, compactSnapshotParser_1.parseCompactSnapshotResponse)(new ReadBufferUtils_1.ReadBuffer(new Uint8Array(content)));
157
+ propsToLog.bodySize = content.byteLength;
158
+ const snapshotContents = (0, compactSnapshotParser_1.parseCompactSnapshotResponse)(new Uint8Array(content), logger);
165
159
  if (snapshotContents.snapshotTree.trees === undefined ||
166
160
  snapshotContents.snapshotTree.blobs === undefined) {
167
- throw new driver_utils_1.NonRetryableError("Returned odsp snapshot is malformed. No trees or blobs!", driver_definitions_1.DriverErrorType.incorrectServerResponse, Object.assign({ driverVersion: packageVersion_1.pkgVersion }, odspResponse.propsToLog));
161
+ throw new driver_utils_1.NonRetryableError("Returned odsp snapshot is malformed. No trees or blobs!", driver_definitions_1.DriverErrorType.incorrectServerResponse, propsToLog);
168
162
  }
169
163
  parsedSnapshotContents = Object.assign(Object.assign({}, odspResponse), { content: snapshotContents });
170
164
  break;
171
165
  }
172
166
  default:
173
- throw new driver_utils_1.NonRetryableError("Unknown snapshot content type", driver_definitions_1.DriverErrorType.incorrectServerResponse, Object.assign({ driverVersion: packageVersion_1.pkgVersion }, odspResponse.propsToLog));
167
+ throw new driver_utils_1.NonRetryableError("Unknown snapshot content type", driver_definitions_1.DriverErrorType.incorrectServerResponse, propsToLog);
174
168
  }
175
169
  }
176
170
  catch (error) {
177
171
  if ((0, telemetry_utils_1.isFluidError)(error)) {
178
- error.addTelemetryProperties(Object.assign({ driverVersion: packageVersion_1.pkgVersion }, odspResponse.propsToLog));
172
+ error.addTelemetryProperties(propsToLog);
179
173
  throw error;
180
174
  }
181
- const enhancedError = (0, telemetry_utils_1.wrapError)(error, (errorMessage) => new driver_utils_1.NonRetryableError(`Error parsing snapshot response: ${errorMessage}`, driver_definitions_1.DriverErrorType.genericError, Object.assign({ driverVersion: packageVersion_1.pkgVersion }, odspResponse.propsToLog)));
175
+ const enhancedError = (0, telemetry_utils_1.wrapError)(error, (errorMessage) => new driver_utils_1.NonRetryableError(`Error parsing snapshot response: ${errorMessage}`, driver_definitions_1.DriverErrorType.genericError, propsToLog));
182
176
  throw enhancedError;
183
177
  }
184
178
  (0, common_utils_1.assert)(parsedSnapshotContents !== undefined, 0x312 /* snapshot should be parsed */);
185
179
  const snapshot = parsedSnapshotContents.content;
180
+ const { trees, numBlobs, encodedBlobsSize } = evalBlobsAndTrees(snapshot);
186
181
  // From: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming
187
182
  // fetchStart: immediately before the browser starts to fetch the resource.
188
183
  // requestStart: immediately before the browser starts requesting the resource from the server
@@ -233,7 +228,6 @@ async function fetchLatestSnapshotCore(odspResolvedUrl, storageTokenFetcher, sna
233
228
  break;
234
229
  }
235
230
  }
236
- const { numTrees, numBlobs, encodedBlobsSize } = evalBlobsAndTrees(parsedSnapshotContents.content);
237
231
  // There are some scenarios in ODSP where we cannot cache, trees/latest will explicitly tell us when we
238
232
  // cannot cache using an HTTP response header.
239
233
  const canCache = odspResponse.headers.get("disablebrowsercachingofusercontent") !== "true";
@@ -258,7 +252,8 @@ async function fetchLatestSnapshotCore(odspResolvedUrl, storageTokenFetcher, sna
258
252
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
259
253
  putInCache(valueWithEpoch);
260
254
  }
261
- event.end(Object.assign({ trees: numTrees, blobs: (_e = (_d = snapshot.blobs) === null || _d === void 0 ? void 0 : _d.size) !== null && _e !== void 0 ? _e : 0, leafNodes: numBlobs, encodedBlobsSize,
255
+ snapshotParseEvent.end();
256
+ event.end(Object.assign({ trees, blobs: (_e = (_d = snapshot.blobs) === null || _d === void 0 ? void 0 : _d.size) !== null && _e !== void 0 ? _e : 0, leafNodes: numBlobs, encodedBlobsSize,
262
257
  sequenceNumber, ops: (_g = (_f = snapshot.ops) === null || _f === void 0 ? void 0 : _f.length) !== null && _g !== void 0 ? _g : 0, userOps: (_j = (_h = snapshot.ops) === null || _h === void 0 ? void 0 : _h.filter((op) => (0, driver_utils_1.isRuntimeMessage)(op)).length) !== null && _j !== void 0 ? _j : 0, headers: Object.keys(response.requestHeaders).length !== 0 ? true : undefined,
263
258
  // Interval between the first fetch until the last byte of the last redirect.
264
259
  redirectTime,
@@ -281,7 +276,7 @@ async function fetchLatestSnapshotCore(odspResolvedUrl, storageTokenFetcher, sna
281
276
  // Azure Fluid Relay service; desc=S, FRP; desc=False. Here, FRL is the duration taken for redeem,
282
277
  // Azure Fluid Relay service is the redeem status (S means success), and FRP is a flag to indicate
283
278
  // if the permission has changed.
284
- sltelemetry: odspResponse.headers.get("x-fluid-sltelemetry") }, odspResponse.propsToLog));
279
+ sltelemetry: odspResponse.headers.get("x-fluid-sltelemetry") }, propsToLog));
285
280
  return snapshot;
286
281
  }).catch((error) => {
287
282
  // We hit these errors in stress tests, under load
@@ -327,13 +322,13 @@ function getFormBodyAndHeaders(odspResolvedUrl, storageToken, snapshotOptions, h
327
322
  return { body: postBody, headers: header };
328
323
  }
329
324
  function evalBlobsAndTrees(snapshot) {
330
- const numTrees = countTreesInSnapshotTree(snapshot.snapshotTree);
325
+ const trees = countTreesInSnapshotTree(snapshot.snapshotTree);
331
326
  const numBlobs = snapshot.blobs.size;
332
327
  let encodedBlobsSize = 0;
333
328
  for (const [_, blobContent] of snapshot.blobs) {
334
329
  encodedBlobsSize += blobContent.byteLength;
335
330
  }
336
- return { numTrees, numBlobs, encodedBlobsSize };
331
+ return { trees, numBlobs, encodedBlobsSize };
337
332
  }
338
333
  function validateBlobsAndTrees(snapshot) {
339
334
  (0, common_utils_1.assert)(snapshot.trees !== undefined, 0x200 /* "Returned odsp snapshot is malformed. No trees!" */);