@fluidframework/odsp-driver 2.110.0 → 2.112.0

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 (137) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/api-report/odsp-driver.legacy.beta.api.md +2 -2
  3. package/dist/WriteBufferUtils.d.ts.map +1 -1
  4. package/dist/WriteBufferUtils.js +1 -1
  5. package/dist/WriteBufferUtils.js.map +1 -1
  6. package/dist/fetchSnapshot.d.ts +2 -3
  7. package/dist/fetchSnapshot.d.ts.map +1 -1
  8. package/dist/fetchSnapshot.js +4 -5
  9. package/dist/fetchSnapshot.js.map +1 -1
  10. package/dist/getFileLink.js +1 -1
  11. package/dist/getFileLink.js.map +1 -1
  12. package/dist/localOdspDriver/localOdspDocumentService.d.ts +1 -1
  13. package/dist/localOdspDriver/localOdspDocumentService.d.ts.map +1 -1
  14. package/dist/localOdspDriver/localOdspDocumentService.js +1 -1
  15. package/dist/localOdspDriver/localOdspDocumentService.js.map +1 -1
  16. package/dist/localOdspDriver/localOdspDocumentServiceFactory.d.ts +1 -3
  17. package/dist/localOdspDriver/localOdspDocumentServiceFactory.d.ts.map +1 -1
  18. package/dist/localOdspDriver/localOdspDocumentServiceFactory.js +1 -1
  19. package/dist/localOdspDriver/localOdspDocumentServiceFactory.js.map +1 -1
  20. package/dist/localOdspDriver/localOdspDocumentStorageManager.d.ts +2 -2
  21. package/dist/localOdspDriver/localOdspDocumentStorageManager.d.ts.map +1 -1
  22. package/dist/localOdspDriver/localOdspDocumentStorageManager.js +1 -1
  23. package/dist/localOdspDriver/localOdspDocumentStorageManager.js.map +1 -1
  24. package/dist/odspDelayLoadedDeltaStream.d.ts +1 -1
  25. package/dist/odspDelayLoadedDeltaStream.d.ts.map +1 -1
  26. package/dist/odspDelayLoadedDeltaStream.js +2 -2
  27. package/dist/odspDelayLoadedDeltaStream.js.map +1 -1
  28. package/dist/odspDocumentDeltaConnection.d.ts.map +1 -1
  29. package/dist/odspDocumentDeltaConnection.js +4 -4
  30. package/dist/odspDocumentDeltaConnection.js.map +1 -1
  31. package/dist/odspDocumentStorageManager.d.ts.map +1 -1
  32. package/dist/odspDocumentStorageManager.js +3 -3
  33. package/dist/odspDocumentStorageManager.js.map +1 -1
  34. package/dist/odspDocumentStorageServiceBase.d.ts +2 -2
  35. package/dist/odspDocumentStorageServiceBase.d.ts.map +1 -1
  36. package/dist/odspDocumentStorageServiceBase.js +1 -1
  37. package/dist/odspDocumentStorageServiceBase.js.map +1 -1
  38. package/dist/odspVersionManager/index.d.ts +6 -0
  39. package/dist/odspVersionManager/index.d.ts.map +1 -0
  40. package/dist/odspVersionManager/index.js +10 -0
  41. package/dist/odspVersionManager/index.js.map +1 -0
  42. package/dist/odspVersionManager/odspFileVersionFetcher.d.ts +22 -0
  43. package/dist/odspVersionManager/odspFileVersionFetcher.d.ts.map +1 -0
  44. package/dist/odspVersionManager/odspFileVersionFetcher.js +81 -0
  45. package/dist/odspVersionManager/odspFileVersionFetcher.js.map +1 -0
  46. package/dist/odspVersionManager/odspVersionManager.d.ts +98 -0
  47. package/dist/odspVersionManager/odspVersionManager.d.ts.map +1 -0
  48. package/dist/odspVersionManager/odspVersionManager.js +87 -0
  49. package/dist/odspVersionManager/odspVersionManager.js.map +1 -0
  50. package/dist/packageVersion.d.ts +1 -1
  51. package/dist/packageVersion.js +1 -1
  52. package/dist/packageVersion.js.map +1 -1
  53. package/dist/prefetchLatestSnapshot.d.ts +5 -5
  54. package/dist/prefetchLatestSnapshot.d.ts.map +1 -1
  55. package/dist/prefetchLatestSnapshot.js +6 -6
  56. package/dist/prefetchLatestSnapshot.js.map +1 -1
  57. package/dist/zipItDataRepresentationUtils.d.ts +1 -1
  58. package/dist/zipItDataRepresentationUtils.d.ts.map +1 -1
  59. package/dist/zipItDataRepresentationUtils.js +2 -2
  60. package/dist/zipItDataRepresentationUtils.js.map +1 -1
  61. package/lib/WriteBufferUtils.d.ts.map +1 -1
  62. package/lib/WriteBufferUtils.js +1 -1
  63. package/lib/WriteBufferUtils.js.map +1 -1
  64. package/lib/fetchSnapshot.d.ts +2 -3
  65. package/lib/fetchSnapshot.d.ts.map +1 -1
  66. package/lib/fetchSnapshot.js +4 -5
  67. package/lib/fetchSnapshot.js.map +1 -1
  68. package/lib/getFileLink.js +1 -1
  69. package/lib/getFileLink.js.map +1 -1
  70. package/lib/localOdspDriver/localOdspDocumentService.d.ts +1 -1
  71. package/lib/localOdspDriver/localOdspDocumentService.d.ts.map +1 -1
  72. package/lib/localOdspDriver/localOdspDocumentService.js +1 -1
  73. package/lib/localOdspDriver/localOdspDocumentService.js.map +1 -1
  74. package/lib/localOdspDriver/localOdspDocumentServiceFactory.d.ts +1 -3
  75. package/lib/localOdspDriver/localOdspDocumentServiceFactory.d.ts.map +1 -1
  76. package/lib/localOdspDriver/localOdspDocumentServiceFactory.js +1 -1
  77. package/lib/localOdspDriver/localOdspDocumentServiceFactory.js.map +1 -1
  78. package/lib/localOdspDriver/localOdspDocumentStorageManager.d.ts +2 -2
  79. package/lib/localOdspDriver/localOdspDocumentStorageManager.d.ts.map +1 -1
  80. package/lib/localOdspDriver/localOdspDocumentStorageManager.js +1 -1
  81. package/lib/localOdspDriver/localOdspDocumentStorageManager.js.map +1 -1
  82. package/lib/odspDelayLoadedDeltaStream.d.ts +1 -1
  83. package/lib/odspDelayLoadedDeltaStream.d.ts.map +1 -1
  84. package/lib/odspDelayLoadedDeltaStream.js +2 -2
  85. package/lib/odspDelayLoadedDeltaStream.js.map +1 -1
  86. package/lib/odspDocumentDeltaConnection.d.ts.map +1 -1
  87. package/lib/odspDocumentDeltaConnection.js +4 -4
  88. package/lib/odspDocumentDeltaConnection.js.map +1 -1
  89. package/lib/odspDocumentStorageManager.d.ts.map +1 -1
  90. package/lib/odspDocumentStorageManager.js +3 -3
  91. package/lib/odspDocumentStorageManager.js.map +1 -1
  92. package/lib/odspDocumentStorageServiceBase.d.ts +2 -2
  93. package/lib/odspDocumentStorageServiceBase.d.ts.map +1 -1
  94. package/lib/odspDocumentStorageServiceBase.js +1 -1
  95. package/lib/odspDocumentStorageServiceBase.js.map +1 -1
  96. package/lib/odspVersionManager/index.d.ts +6 -0
  97. package/lib/odspVersionManager/index.d.ts.map +1 -0
  98. package/lib/odspVersionManager/index.js +6 -0
  99. package/lib/odspVersionManager/index.js.map +1 -0
  100. package/lib/odspVersionManager/odspFileVersionFetcher.d.ts +22 -0
  101. package/lib/odspVersionManager/odspFileVersionFetcher.d.ts.map +1 -0
  102. package/lib/odspVersionManager/odspFileVersionFetcher.js +77 -0
  103. package/lib/odspVersionManager/odspFileVersionFetcher.js.map +1 -0
  104. package/lib/odspVersionManager/odspVersionManager.d.ts +98 -0
  105. package/lib/odspVersionManager/odspVersionManager.d.ts.map +1 -0
  106. package/lib/odspVersionManager/odspVersionManager.js +82 -0
  107. package/lib/odspVersionManager/odspVersionManager.js.map +1 -0
  108. package/lib/packageVersion.d.ts +1 -1
  109. package/lib/packageVersion.js +1 -1
  110. package/lib/packageVersion.js.map +1 -1
  111. package/lib/prefetchLatestSnapshot.d.ts +5 -5
  112. package/lib/prefetchLatestSnapshot.d.ts.map +1 -1
  113. package/lib/prefetchLatestSnapshot.js +6 -6
  114. package/lib/prefetchLatestSnapshot.js.map +1 -1
  115. package/lib/zipItDataRepresentationUtils.d.ts +1 -1
  116. package/lib/zipItDataRepresentationUtils.d.ts.map +1 -1
  117. package/lib/zipItDataRepresentationUtils.js +2 -2
  118. package/lib/zipItDataRepresentationUtils.js.map +1 -1
  119. package/package.json +14 -18
  120. package/src/WriteBufferUtils.ts +1 -5
  121. package/src/fetchSnapshot.ts +2 -5
  122. package/src/getFileLink.ts +1 -1
  123. package/src/localOdspDriver/localOdspDocumentService.ts +1 -1
  124. package/src/localOdspDriver/localOdspDocumentServiceFactory.ts +1 -8
  125. package/src/localOdspDriver/localOdspDocumentStorageManager.ts +1 -2
  126. package/src/odspDelayLoadedDeltaStream.ts +2 -2
  127. package/src/odspDocumentDeltaConnection.ts +2 -4
  128. package/src/odspDocumentStorageManager.ts +0 -3
  129. package/src/odspDocumentStorageServiceBase.ts +2 -2
  130. package/src/odspVersionManager/DEV.md +277 -0
  131. package/src/odspVersionManager/index.ts +12 -0
  132. package/src/odspVersionManager/odspFileVersionFetcher.ts +138 -0
  133. package/src/odspVersionManager/odspVersionManager.ts +170 -0
  134. package/src/packageVersion.ts +1 -1
  135. package/src/prefetchLatestSnapshot.ts +7 -8
  136. package/src/zipItDataRepresentationUtils.ts +2 -7
  137. package/tsconfig.json +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"odspDocumentStorageServiceBase.d.ts","sourceRoot":"","sources":["../src/odspDocumentStorageServiceBase.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"odspDocumentStorageServiceBase.d.ts","sourceRoot":"","sources":["../src/odspDocumentStorageServiceBase.ts"],"names":[],"mappings":"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"}
@@ -154,7 +154,7 @@ class OdspDocumentStorageServiceBase {
154
154
  }
155
155
  return this.combineProtocolAndAppSnapshotTree(snapshotTree);
156
156
  }
157
- async downloadSummary(commit) {
157
+ async downloadSummary() {
158
158
  throw new Error("Not implemented yet");
159
159
  }
160
160
  setRootTree(id, tree) {
@@ -1 +1 @@
1
- {"version":3,"file":"odspDocumentStorageServiceBase.js","sourceRoot":"","sources":["../src/odspDocumentStorageServiceBase.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,kEAA6D;AAE7D,0EAaqD;AACrD,oEAA+E;AAG/E,MAAM,SAAS;IAAf;QAGC,kGAAkG;QAClG,gHAAgH;QAChH,6CAA6C;QACrC,wBAAmB,GAAY,KAAK,CAAC;QAE5B,eAAU,GAA6B,IAAI,GAAG,EAAE,CAAC;QAElE,yCAAyC;QACxB,iBAAY,GAAgB,IAAI,GAAG,EAAE,CAAC;QAEvD,4CAA4C;QAC5C,uGAAuG;QACvG,0FAA0F;QAClF,6BAAwB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QAEjD,oFAAoF;QACpF,wGAAwG;QACxG,sEAAsE;QACtE,mCAAmC;QAClB,iBAAY,GAAG,KAAK,CAAC;IA6EvC,CAAC;IA3EA,IAAW,KAAK;QACf,OAAO,IAAI,CAAC,UAAU,CAAC;IACxB,CAAC;IAEM,QAAQ,CAAC,KAA+B;QAC9C,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;QACD,+BAA+B;QAC/B,IAAI,CAAC,uBAAuB,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACK,uBAAuB;QAC9B,IAAI,IAAI,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACzC,sFAAsF;YACtF,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;QACjC,CAAC;aAAM,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YAC9B,qDAAqD;YACrD,mGAAmG;YACnG,MAAM,iBAAiB,GAAG,GAAS,EAAE;gBACpC,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;gBAClC,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;oBAC9B,IAAI,CAAC,mBAAmB,GAAG,KAAK,CAAC;oBACjC,IAAI,CAAC,uBAAuB,EAAE,CAAC;gBAChC,CAAC;qBAAM,CAAC;oBACP,gFAAgF;oBAChF,8FAA8F;oBAC9F,kGAAkG;oBAClG,wFAAwF;oBACxF,iGAAiG;oBACjG,mCAAmC;oBACnC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;wBAC7C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;oBAC/B,CAAC;oBACD,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;gBACzB,CAAC;YACF,CAAC,CAAC;YACF,IAAI,CAAC,gBAAgB,GAAG,UAAU,CAAC,iBAAiB,EAAE,IAAI,CAAC,wBAAwB,CAAC,CAAC;YACrF,iGAAiG;YACjG,iDAAiD;YACjD,IAAI,CAAC,wBAAwB,GAAG,EAAE,GAAG,IAAI,CAAC;QAC3C,CAAC;IACF,CAAC;IAEM,OAAO,CAAC,MAAc;QAI5B,0CAA0C;QAC1C,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC9C,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;IACjC,CAAC;IAEM,OAAO,CAAC,MAAc,EAAE,IAAiB;QAC/C,4EAA4E;QAC5E,uCAAuC;QACvC,wFAAwF;QACxF,2HAA2H;QAC3H,wHAAwH;QACxH,sBAAsB;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;QAC7B,IAAI,IAAI,GAAG,GAAG,GAAG,IAAI,EAAE,CAAC;YACvB,+BAA+B;YAC/B,IAAI,CAAC,uBAAuB,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACP,qCAAqC;YACrC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC;IACF,CAAC;CACD;AAED,MAAsB,8BAA8B;IAGnD,YAAY,MAAuB;QAiBhB,gBAAW,GAA+B,IAAI,GAAG,EAAE,CAAC;QAMpD,cAAS,GAAG,IAAI,SAAS,EAAE,CAAC;QAtB9C,0FAA0F;QAC1F,8EAA8E;QAC9E,sFAAsF;QACtF,wFAAwF;QACxF,MAAM,8BAA8B,GAAG,CACtC,MAAM,CAAC,UAAU,CAAC,qDAAqD,CAAC;YACvE,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,iCAAsB,CACX,CAAC;QAEhB,IAAI,CAAC,QAAQ,GAAG;YACf,8DAA8D;YAC9D,OAAO,EAAE,8BAAmB,CAAC,SAAS;YACtC,sBAAsB,EAAE,8BAA8B;SACtD,CAAC;IACH,CAAC;IASD,IAAW,GAAG,CAAC,GAA4C;QAC1D,IAAA,iBAAM,EACL,IAAI,CAAC,IAAI,KAAK,SAAS,EACvB,KAAK,CAAC,oDAAoD,CAC1D,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;IACjB,CAAC;IAED,IAAW,GAAG;QACb,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,IAAW,sBAAsB;QAChC,OAAO,IAAI,CAAC,uBAAuB,CAAC;IACrC,CAAC;IAIO,KAAK,CAAC,YAAY,CAAC,MAAc;QACxC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAChE,OAAO,WAAW,IAAI,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClE,CAAC;IAOM,KAAK,CAAC,QAAQ,CAAC,MAAc;QACnC,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAEM,KAAK,CAAC,eAAe,CAC3B,OAAkB,EAClB,YAAqB;QAGrB,IAAI,EAAU,CAAC;QACf,IAAI,OAAO,EAAE,EAAE,EAAE,CAAC;YACjB,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;QACjB,CAAC;aAAM,CAAC;YACP,2CAA2C;YAC3C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;YAC/D,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxC,2CAA2C;gBAC3C,OAAO,IAAI,CAAC;YACb,CAAC;YACD,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;QAC3D,IAAI,CAAC,YAAY,EAAE,CAAC;YACnB,2CAA2C;YAC3C,OAAO,IAAI,CAAC;QACb,CAAC;QAED,OAAO,IAAI,CAAC,iCAAiC,CAAC,YAAY,CAAC,CAAC;IAC7D,CAAC;IAmBM,KAAK,CAAC,eAAe,CAAC,MAAsB;QAClD,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACxC,CAAC;IAES,WAAW,CAAC,EAAU,EAAE,IAAmB;QACpD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC;IAES,cAAc,CAAC,KAA+B;QACvD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,EAAU,EAAE,YAAqB;QACvD,IAAI,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpC,6HAA6H;QAC7H,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,IAAI,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;QAC3D,CAAC;QAED,2CAA2C;QAC3C,OAAO,IAAI,IAAI,IAAI,CAAC;IACrB,CAAC;IAOS,iCAAiC,CAAC,YAA2B;QACtE,sGAAsG;QACtG,0GAA0G;QAC1G,MAAM,mBAAmB,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,wBAAwB,GAAG,YAAY,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACjE,MAAM,mBAAmB,GAAkB;YAC1C,KAAK,EAAE;gBACN,GAAG,mBAAmB,CAAC,KAAK;aAC5B;YACD,KAAK,EAAE;gBACN,GAAG,mBAAmB,CAAC,KAAK;aAC5B;YACD,EAAE,EAAE,YAAY,CAAC,EAAE;SACnB,CAAC;QAEF,8FAA8F;QAC9F,2EAA2E;QAC3E,IAAI,wBAAwB,KAAK,SAAS,EAAE,CAAC;YAC5C,mBAAmB,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,wBAAwB,CAAC;QACnE,CAAC;QAED,OAAO,mBAAmB,CAAC;IAC5B,CAAC;IAES,sBAAsB,CAC/B,sBAAiC,EACjC,WAAoB,IAAI,EACxB,gBAAyB,IAAI;QAE7B,IAAI,CAAC,uBAAuB,GAAG,sBAAsB,CAAC,cAAc,CAAC;QACrE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,sBAAsB,CAAC;QAEnE,0DAA0D;QAC1D,IAAI,EAAsB,CAAC;QAC3B,IAAI,YAAY,EAAE,CAAC;YAClB,EAAE,GAAG,YAAY,CAAC,EAAE,CAAC;YACrB,IAAA,iBAAM,EAAC,EAAE,KAAK,SAAS,EAAE,KAAK,CAAC,uCAAuC,CAAC,CAAC;YACxE,IAAI,aAAa,EAAE,CAAC;gBACnB,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;YACpC,CAAC;QACF,CAAC;QAED,yEAAyE;QACzE,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QACnC,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACd,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QAChB,CAAC;QACD,OAAO,EAAE,CAAC;IACX,CAAC;CACD;AAxLD,wEAwLC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ISummaryHandle, ISummaryTree } from \"@fluidframework/driver-definitions\";\nimport {\n\ttype FetchSource,\n\ttype FiveDaysMs,\n\ttype IDocumentStorageService,\n\ttype IDocumentStorageServicePolicies,\n\ttype ISnapshot,\n\ttype ISnapshotFetchOptions,\n\ttype ISummaryContext,\n\tLoaderCachingPolicy,\n\ttype ISnapshotTree,\n\ttype ICreateBlobResponse,\n\ttype IVersion,\n\ttype ISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { maximumCacheDurationMs } from \"@fluidframework/driver-utils/internal\";\nimport type { IConfigProvider } from \"@fluidframework/telemetry-utils/internal\";\n\nclass BlobCache {\n\t// Save the timeout so we can cancel and reschedule it as needed\n\tprivate blobCacheTimeout: ReturnType<typeof setTimeout> | undefined;\n\t// If the defer flag is set when the timeout fires, we'll reschedule rather than clear immediately\n\t// This deferral approach is used (rather than clearing/resetting the timer) as current calling patterns trigger\n\t// too many calls to setTimeout/clearTimeout.\n\tprivate deferBlobCacheClear: boolean = false;\n\n\tprivate readonly _blobCache: Map<string, ArrayBuffer> = new Map();\n\n\t// Tracks all blob IDs evicted from cache\n\tprivate readonly blobsEvicted: Set<string> = new Set();\n\n\t// Initial time-out to purge data from cache\n\t// If this time out is very small, then we purge blobs from cache too soon and that results in a lot of\n\t// requests to storage, which brings down perf and may trip protection limits causing 429s\n\tprivate blobCacheTimeoutDuration = 2 * 60 * 1000;\n\n\t// SPO does not keep old snapshots around for long, so we are running chances of not\n\t// being able to rehydrate data store / DDS in the future if we purge anything (and with blob de-duping,\n\t// even if blob read by runtime, it could be read again in the future)\n\t// So for now, purging is disabled.\n\tprivate readonly purgeEnabled = false;\n\n\tpublic get value(): Map<string, ArrayBuffer> {\n\t\treturn this._blobCache;\n\t}\n\n\tpublic addBlobs(blobs: Map<string, ArrayBuffer>): void {\n\t\tfor (const [blobId, value] of blobs.entries()) {\n\t\t\tthis._blobCache.set(blobId, value);\n\t\t}\n\t\t// Reset the timer on cache set\n\t\tthis.scheduleClearBlobsCache();\n\t}\n\n\t/**\n\t * Schedule a timer for clearing the blob cache or defer the current one.\n\t */\n\tprivate scheduleClearBlobsCache(): void {\n\t\tif (this.blobCacheTimeout !== undefined) {\n\t\t\t// If we already have an outstanding timer, just signal that we should defer the clear\n\t\t\tthis.deferBlobCacheClear = true;\n\t\t} else if (this.purgeEnabled) {\n\t\t\t// If we don't have an outstanding timer, set a timer\n\t\t\t// When the timer runs out, we'll decide whether to proceed with the cache clear or reset the timer\n\t\t\tconst clearCacheOrDefer = (): void => {\n\t\t\t\tthis.blobCacheTimeout = undefined;\n\t\t\t\tif (this.deferBlobCacheClear) {\n\t\t\t\t\tthis.deferBlobCacheClear = false;\n\t\t\t\t\tthis.scheduleClearBlobsCache();\n\t\t\t\t} else {\n\t\t\t\t\t// NOTE: Slightly better algorithm here would be to purge either only big blobs,\n\t\t\t\t\t// or sort them by size and purge enough big blobs to leave only 256Kb of small blobs in cache\n\t\t\t\t\t// Purging is optimizing memory footprint. But count controls potential number of storage requests\n\t\t\t\t\t// We want to optimize both - memory footprint and number of future requests to storage.\n\t\t\t\t\t// Note that Container can realize data store or DDS on-demand at any point in time, so we do not\n\t\t\t\t\t// control when blobs will be used.\n\t\t\t\t\tfor (const blobId of this._blobCache.keys()) {\n\t\t\t\t\t\tthis.blobsEvicted.add(blobId);\n\t\t\t\t\t}\n\t\t\t\t\tthis._blobCache.clear();\n\t\t\t\t}\n\t\t\t};\n\t\t\tthis.blobCacheTimeout = setTimeout(clearCacheOrDefer, this.blobCacheTimeoutDuration);\n\t\t\t// any future storage reads that get into the cache should be cleared from cache rather quickly -\n\t\t\t// there is not much value in keeping them longer\n\t\t\tthis.blobCacheTimeoutDuration = 10 * 1000;\n\t\t}\n\t}\n\n\tpublic getBlob(blobId: string): {\n\t\tblobContent: ArrayBuffer | undefined;\n\t\tevicted: boolean;\n\t} {\n\t\t// Reset the timer on attempted cache read\n\t\tthis.scheduleClearBlobsCache();\n\t\tconst blobContent = this._blobCache.get(blobId);\n\t\tconst evicted = this.blobsEvicted.has(blobId);\n\t\treturn { blobContent, evicted };\n\t}\n\n\tpublic setBlob(blobId: string, blob: ArrayBuffer): Map<string, ArrayBuffer> | undefined {\n\t\t// This API is called as result of cache miss and reading blob from storage.\n\t\t// Runtime never reads same blob twice.\n\t\t// The only reason we may get read request for same blob is blob de-duping in summaries.\n\t\t// Note that the bigger the size, the less likely blobs are the same, so there is very little benefit of caching big blobs.\n\t\t// Images are the only exception - user may insert same image twice. But we currently do not de-dup them - only snapshot\n\t\t// blobs are de-duped.\n\t\tconst size = blob.byteLength;\n\t\tif (size < 256 * 1024) {\n\t\t\t// Reset the timer on cache set\n\t\t\tthis.scheduleClearBlobsCache();\n\t\t\treturn this._blobCache.set(blobId, blob);\n\t\t} else {\n\t\t\t// we evicted it here by not caching.\n\t\t\tthis.blobsEvicted.add(blobId);\n\t\t}\n\t}\n}\n\nexport abstract class OdspDocumentStorageServiceBase implements IDocumentStorageService {\n\treadonly policies: IDocumentStorageServicePolicies;\n\n\tconstructor(config: IConfigProvider) {\n\t\t// We circumvent the restrictions on the policy only when using this TestOverride setting,\n\t\t// which also applies to the code that reads from the cache in epochTracker.ts\n\t\t// This may result in files created for testing being unusable in production sessions,\n\t\t// due to the GC code guarding against this policy changing over the lifetime of a file.\n\t\tconst maximumCacheDurationMsInEffect = (\n\t\t\tconfig.getBoolean(\"Fluid.Driver.Odsp.TestOverride.DisableSnapshotCache\")\n\t\t\t\t? 0\n\t\t\t\t: maximumCacheDurationMs\n\t\t) as FiveDaysMs;\n\n\t\tthis.policies = {\n\t\t\t// By default, ODSP tells the container not to prefetch/cache.\n\t\t\tcaching: LoaderCachingPolicy.NoCaching,\n\t\t\tmaximumCacheDurationMs: maximumCacheDurationMsInEffect,\n\t\t};\n\t}\n\tprotected readonly commitCache: Map<string, ISnapshotTree> = new Map();\n\n\tprivate _ops: ISequencedDocumentMessage[] | undefined;\n\n\tprivate _snapshotSequenceNumber: number | undefined;\n\n\tprotected readonly blobCache = new BlobCache();\n\n\tpublic set ops(ops: ISequencedDocumentMessage[] | undefined) {\n\t\tassert(\n\t\t\tthis._ops === undefined,\n\t\t\t0x0a5 /* \"Trying to set ops when they are already set!\" */,\n\t\t);\n\t\tthis._ops = ops;\n\t}\n\n\tpublic get ops(): ISequencedDocumentMessage[] | undefined {\n\t\treturn this._ops;\n\t}\n\n\tpublic get snapshotSequenceNumber(): number | undefined {\n\t\treturn this._snapshotSequenceNumber;\n\t}\n\n\tpublic abstract createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse>;\n\n\tprivate async readBlobCore(blobId: string): Promise<ArrayBuffer> {\n\t\tconst { blobContent, evicted } = this.blobCache.getBlob(blobId);\n\t\treturn blobContent ?? this.fetchBlobFromStorage(blobId, evicted);\n\t}\n\n\tprotected abstract fetchBlobFromStorage(\n\t\tblobId: string,\n\t\tevicted: boolean,\n\t): Promise<ArrayBuffer>;\n\n\tpublic async readBlob(blobId: string): Promise<ArrayBufferLike> {\n\t\treturn this.readBlobCore(blobId);\n\t}\n\n\tpublic async getSnapshotTree(\n\t\tversion?: IVersion,\n\t\tscenarioName?: string,\n\t\t// eslint-disable-next-line @rushstack/no-new-null\n\t): Promise<ISnapshotTree | null> {\n\t\tlet id: string;\n\t\tif (version?.id) {\n\t\t\tid = version.id;\n\t\t} else {\n\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\tconst versions = await this.getVersions(null, 1, scenarioName);\n\t\t\tif (!versions || versions.length === 0) {\n\t\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tid = versions[0].id;\n\t\t}\n\n\t\tconst snapshotTree = await this.readTree(id, scenarioName);\n\t\tif (!snapshotTree) {\n\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.combineProtocolAndAppSnapshotTree(snapshotTree);\n\t}\n\n\tpublic abstract getSnapshot(\n\t\tsnapshotFetchOptions?: ISnapshotFetchOptions,\n\t): Promise<ISnapshot>;\n\n\tpublic abstract getVersions(\n\t\t// eslint-disable-next-line @rushstack/no-new-null\n\t\tblobid: string | null,\n\t\tcount: number,\n\t\tscenarioName?: string,\n\t\tfetchSource?: FetchSource,\n\t): Promise<IVersion[]>;\n\n\tpublic abstract uploadSummaryWithContext(\n\t\tsummary: ISummaryTree,\n\t\tcontext: ISummaryContext,\n\t): Promise<string>;\n\n\tpublic async downloadSummary(commit: ISummaryHandle): Promise<ISummaryTree> {\n\t\tthrow new Error(\"Not implemented yet\");\n\t}\n\n\tprotected setRootTree(id: string, tree: ISnapshotTree): void {\n\t\tthis.commitCache.set(id, tree);\n\t}\n\n\tprotected initBlobsCache(blobs: Map<string, ArrayBuffer>): void {\n\t\tthis.blobCache.addBlobs(blobs);\n\t}\n\n\tprivate async readTree(id: string, scenarioName?: string): Promise<ISnapshotTree | null> {\n\t\tlet tree = this.commitCache.get(id);\n\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\tif (!tree) {\n\t\t\ttree = await this.fetchTreeFromSnapshot(id, scenarioName);\n\t\t}\n\n\t\t// eslint-disable-next-line unicorn/no-null\n\t\treturn tree ?? null;\n\t}\n\n\tprotected abstract fetchTreeFromSnapshot(\n\t\tid: string,\n\t\tscenarioName?: string,\n\t): Promise<ISnapshotTree | undefined>;\n\n\tprotected combineProtocolAndAppSnapshotTree(snapshotTree: ISnapshotTree): ISnapshotTree {\n\t\t// When we upload the container snapshot, we upload appTree in \".app\" and protocol tree in \".protocol\"\n\t\t// So when we request the snapshot we get \".app\" as tree and not as commit node as in the case just above.\n\t\tconst hierarchicalAppTree = snapshotTree.trees[\".app\"];\n\t\tconst hierarchicalProtocolTree = snapshotTree.trees[\".protocol\"];\n\t\tconst summarySnapshotTree: ISnapshotTree = {\n\t\t\tblobs: {\n\t\t\t\t...hierarchicalAppTree.blobs,\n\t\t\t},\n\t\t\ttrees: {\n\t\t\t\t...hierarchicalAppTree.trees,\n\t\t\t},\n\t\t\tid: snapshotTree.id,\n\t\t};\n\n\t\t// The app tree could have a .protocol in that case we want to server protocol to override it.\n\t\t// Snapshot which are for a loading GroupId, will not have a protocol tree.\n\t\tif (hierarchicalProtocolTree !== undefined) {\n\t\t\tsummarySnapshotTree.trees[\".protocol\"] = hierarchicalProtocolTree;\n\t\t}\n\n\t\treturn summarySnapshotTree;\n\t}\n\n\tprotected initializeFromSnapshot(\n\t\todspSnapshotCacheValue: ISnapshot,\n\t\tcacheOps: boolean = true,\n\t\tcacheSnapshot: boolean = true,\n\t): string | undefined {\n\t\tthis._snapshotSequenceNumber = odspSnapshotCacheValue.sequenceNumber;\n\t\tconst { snapshotTree, blobContents, ops } = odspSnapshotCacheValue;\n\n\t\t// id should be undefined in case of just ops in snapshot.\n\t\tlet id: string | undefined;\n\t\tif (snapshotTree) {\n\t\t\tid = snapshotTree.id;\n\t\t\tassert(id !== undefined, 0x221 /* \"Root tree should contain the id\" */);\n\t\t\tif (cacheSnapshot) {\n\t\t\t\tthis.setRootTree(id, snapshotTree);\n\t\t\t}\n\t\t}\n\n\t\t// Currently always cache blobs as container runtime is not caching them.\n\t\tif (blobContents !== undefined) {\n\t\t\tthis.initBlobsCache(blobContents);\n\t\t}\n\n\t\tif (cacheOps) {\n\t\t\tthis.ops = ops;\n\t\t}\n\t\treturn id;\n\t}\n}\n"]}
1
+ {"version":3,"file":"odspDocumentStorageServiceBase.js","sourceRoot":"","sources":["../src/odspDocumentStorageServiceBase.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 { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ISummaryTree } from \"@fluidframework/driver-definitions\";\nimport {\n\ttype FetchSource,\n\ttype FiveDaysMs,\n\ttype IDocumentStorageService,\n\ttype IDocumentStorageServicePolicies,\n\ttype ISnapshot,\n\ttype ISnapshotFetchOptions,\n\ttype ISummaryContext,\n\tLoaderCachingPolicy,\n\ttype ISnapshotTree,\n\ttype ICreateBlobResponse,\n\ttype IVersion,\n\ttype ISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { maximumCacheDurationMs } from \"@fluidframework/driver-utils/internal\";\nimport type { IConfigProvider } from \"@fluidframework/telemetry-utils/internal\";\n\nclass BlobCache {\n\t// Save the timeout so we can cancel and reschedule it as needed\n\tprivate blobCacheTimeout: ReturnType<typeof setTimeout> | undefined;\n\t// If the defer flag is set when the timeout fires, we'll reschedule rather than clear immediately\n\t// This deferral approach is used (rather than clearing/resetting the timer) as current calling patterns trigger\n\t// too many calls to setTimeout/clearTimeout.\n\tprivate deferBlobCacheClear: boolean = false;\n\n\tprivate readonly _blobCache: Map<string, ArrayBuffer> = new Map();\n\n\t// Tracks all blob IDs evicted from cache\n\tprivate readonly blobsEvicted: Set<string> = new Set();\n\n\t// Initial time-out to purge data from cache\n\t// If this time out is very small, then we purge blobs from cache too soon and that results in a lot of\n\t// requests to storage, which brings down perf and may trip protection limits causing 429s\n\tprivate blobCacheTimeoutDuration = 2 * 60 * 1000;\n\n\t// SPO does not keep old snapshots around for long, so we are running chances of not\n\t// being able to rehydrate data store / DDS in the future if we purge anything (and with blob de-duping,\n\t// even if blob read by runtime, it could be read again in the future)\n\t// So for now, purging is disabled.\n\tprivate readonly purgeEnabled = false;\n\n\tpublic get value(): Map<string, ArrayBuffer> {\n\t\treturn this._blobCache;\n\t}\n\n\tpublic addBlobs(blobs: Map<string, ArrayBuffer>): void {\n\t\tfor (const [blobId, value] of blobs.entries()) {\n\t\t\tthis._blobCache.set(blobId, value);\n\t\t}\n\t\t// Reset the timer on cache set\n\t\tthis.scheduleClearBlobsCache();\n\t}\n\n\t/**\n\t * Schedule a timer for clearing the blob cache or defer the current one.\n\t */\n\tprivate scheduleClearBlobsCache(): void {\n\t\tif (this.blobCacheTimeout !== undefined) {\n\t\t\t// If we already have an outstanding timer, just signal that we should defer the clear\n\t\t\tthis.deferBlobCacheClear = true;\n\t\t} else if (this.purgeEnabled) {\n\t\t\t// If we don't have an outstanding timer, set a timer\n\t\t\t// When the timer runs out, we'll decide whether to proceed with the cache clear or reset the timer\n\t\t\tconst clearCacheOrDefer = (): void => {\n\t\t\t\tthis.blobCacheTimeout = undefined;\n\t\t\t\tif (this.deferBlobCacheClear) {\n\t\t\t\t\tthis.deferBlobCacheClear = false;\n\t\t\t\t\tthis.scheduleClearBlobsCache();\n\t\t\t\t} else {\n\t\t\t\t\t// NOTE: Slightly better algorithm here would be to purge either only big blobs,\n\t\t\t\t\t// or sort them by size and purge enough big blobs to leave only 256Kb of small blobs in cache\n\t\t\t\t\t// Purging is optimizing memory footprint. But count controls potential number of storage requests\n\t\t\t\t\t// We want to optimize both - memory footprint and number of future requests to storage.\n\t\t\t\t\t// Note that Container can realize data store or DDS on-demand at any point in time, so we do not\n\t\t\t\t\t// control when blobs will be used.\n\t\t\t\t\tfor (const blobId of this._blobCache.keys()) {\n\t\t\t\t\t\tthis.blobsEvicted.add(blobId);\n\t\t\t\t\t}\n\t\t\t\t\tthis._blobCache.clear();\n\t\t\t\t}\n\t\t\t};\n\t\t\tthis.blobCacheTimeout = setTimeout(clearCacheOrDefer, this.blobCacheTimeoutDuration);\n\t\t\t// any future storage reads that get into the cache should be cleared from cache rather quickly -\n\t\t\t// there is not much value in keeping them longer\n\t\t\tthis.blobCacheTimeoutDuration = 10 * 1000;\n\t\t}\n\t}\n\n\tpublic getBlob(blobId: string): {\n\t\tblobContent: ArrayBuffer | undefined;\n\t\tevicted: boolean;\n\t} {\n\t\t// Reset the timer on attempted cache read\n\t\tthis.scheduleClearBlobsCache();\n\t\tconst blobContent = this._blobCache.get(blobId);\n\t\tconst evicted = this.blobsEvicted.has(blobId);\n\t\treturn { blobContent, evicted };\n\t}\n\n\tpublic setBlob(blobId: string, blob: ArrayBuffer): Map<string, ArrayBuffer> | undefined {\n\t\t// This API is called as result of cache miss and reading blob from storage.\n\t\t// Runtime never reads same blob twice.\n\t\t// The only reason we may get read request for same blob is blob de-duping in summaries.\n\t\t// Note that the bigger the size, the less likely blobs are the same, so there is very little benefit of caching big blobs.\n\t\t// Images are the only exception - user may insert same image twice. But we currently do not de-dup them - only snapshot\n\t\t// blobs are de-duped.\n\t\tconst size = blob.byteLength;\n\t\tif (size < 256 * 1024) {\n\t\t\t// Reset the timer on cache set\n\t\t\tthis.scheduleClearBlobsCache();\n\t\t\treturn this._blobCache.set(blobId, blob);\n\t\t} else {\n\t\t\t// we evicted it here by not caching.\n\t\t\tthis.blobsEvicted.add(blobId);\n\t\t}\n\t}\n}\n\nexport abstract class OdspDocumentStorageServiceBase implements IDocumentStorageService {\n\treadonly policies: IDocumentStorageServicePolicies;\n\n\tconstructor(config: IConfigProvider) {\n\t\t// We circumvent the restrictions on the policy only when using this TestOverride setting,\n\t\t// which also applies to the code that reads from the cache in epochTracker.ts\n\t\t// This may result in files created for testing being unusable in production sessions,\n\t\t// due to the GC code guarding against this policy changing over the lifetime of a file.\n\t\tconst maximumCacheDurationMsInEffect = (\n\t\t\tconfig.getBoolean(\"Fluid.Driver.Odsp.TestOverride.DisableSnapshotCache\")\n\t\t\t\t? 0\n\t\t\t\t: maximumCacheDurationMs\n\t\t) as FiveDaysMs;\n\n\t\tthis.policies = {\n\t\t\t// By default, ODSP tells the container not to prefetch/cache.\n\t\t\tcaching: LoaderCachingPolicy.NoCaching,\n\t\t\tmaximumCacheDurationMs: maximumCacheDurationMsInEffect,\n\t\t};\n\t}\n\tprotected readonly commitCache: Map<string, ISnapshotTree> = new Map();\n\n\tprivate _ops: ISequencedDocumentMessage[] | undefined;\n\n\tprivate _snapshotSequenceNumber: number | undefined;\n\n\tprotected readonly blobCache = new BlobCache();\n\n\tpublic set ops(ops: ISequencedDocumentMessage[] | undefined) {\n\t\tassert(\n\t\t\tthis._ops === undefined,\n\t\t\t0x0a5 /* \"Trying to set ops when they are already set!\" */,\n\t\t);\n\t\tthis._ops = ops;\n\t}\n\n\tpublic get ops(): ISequencedDocumentMessage[] | undefined {\n\t\treturn this._ops;\n\t}\n\n\tpublic get snapshotSequenceNumber(): number | undefined {\n\t\treturn this._snapshotSequenceNumber;\n\t}\n\n\tpublic abstract createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse>;\n\n\tprivate async readBlobCore(blobId: string): Promise<ArrayBuffer> {\n\t\tconst { blobContent, evicted } = this.blobCache.getBlob(blobId);\n\t\treturn blobContent ?? this.fetchBlobFromStorage(blobId, evicted);\n\t}\n\n\tprotected abstract fetchBlobFromStorage(\n\t\tblobId: string,\n\t\tevicted: boolean,\n\t): Promise<ArrayBuffer>;\n\n\tpublic async readBlob(blobId: string): Promise<ArrayBufferLike> {\n\t\treturn this.readBlobCore(blobId);\n\t}\n\n\tpublic async getSnapshotTree(\n\t\tversion?: IVersion,\n\t\tscenarioName?: string,\n\t\t// eslint-disable-next-line @rushstack/no-new-null\n\t): Promise<ISnapshotTree | null> {\n\t\tlet id: string;\n\t\tif (version?.id) {\n\t\t\tid = version.id;\n\t\t} else {\n\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\tconst versions = await this.getVersions(null, 1, scenarioName);\n\t\t\tif (!versions || versions.length === 0) {\n\t\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tid = versions[0].id;\n\t\t}\n\n\t\tconst snapshotTree = await this.readTree(id, scenarioName);\n\t\tif (!snapshotTree) {\n\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.combineProtocolAndAppSnapshotTree(snapshotTree);\n\t}\n\n\tpublic abstract getSnapshot(\n\t\tsnapshotFetchOptions?: ISnapshotFetchOptions,\n\t): Promise<ISnapshot>;\n\n\tpublic abstract getVersions(\n\t\t// eslint-disable-next-line @rushstack/no-new-null\n\t\tblobid: string | null,\n\t\tcount: number,\n\t\tscenarioName?: string,\n\t\tfetchSource?: FetchSource,\n\t): Promise<IVersion[]>;\n\n\tpublic abstract uploadSummaryWithContext(\n\t\tsummary: ISummaryTree,\n\t\tcontext: ISummaryContext,\n\t): Promise<string>;\n\n\tpublic async downloadSummary(): Promise<ISummaryTree> {\n\t\tthrow new Error(\"Not implemented yet\");\n\t}\n\n\tprotected setRootTree(id: string, tree: ISnapshotTree): void {\n\t\tthis.commitCache.set(id, tree);\n\t}\n\n\tprotected initBlobsCache(blobs: Map<string, ArrayBuffer>): void {\n\t\tthis.blobCache.addBlobs(blobs);\n\t}\n\n\tprivate async readTree(id: string, scenarioName?: string): Promise<ISnapshotTree | null> {\n\t\tlet tree = this.commitCache.get(id);\n\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\tif (!tree) {\n\t\t\ttree = await this.fetchTreeFromSnapshot(id, scenarioName);\n\t\t}\n\n\t\t// eslint-disable-next-line unicorn/no-null\n\t\treturn tree ?? null;\n\t}\n\n\tprotected abstract fetchTreeFromSnapshot(\n\t\tid: string,\n\t\tscenarioName?: string,\n\t): Promise<ISnapshotTree | undefined>;\n\n\tprotected combineProtocolAndAppSnapshotTree(snapshotTree: ISnapshotTree): ISnapshotTree {\n\t\t// When we upload the container snapshot, we upload appTree in \".app\" and protocol tree in \".protocol\"\n\t\t// So when we request the snapshot we get \".app\" as tree and not as commit node as in the case just above.\n\t\tconst hierarchicalAppTree = snapshotTree.trees[\".app\"];\n\t\tconst hierarchicalProtocolTree = snapshotTree.trees[\".protocol\"];\n\t\tconst summarySnapshotTree: ISnapshotTree = {\n\t\t\tblobs: {\n\t\t\t\t...hierarchicalAppTree.blobs,\n\t\t\t},\n\t\t\ttrees: {\n\t\t\t\t...hierarchicalAppTree.trees,\n\t\t\t},\n\t\t\tid: snapshotTree.id,\n\t\t};\n\n\t\t// The app tree could have a .protocol in that case we want to server protocol to override it.\n\t\t// Snapshot which are for a loading GroupId, will not have a protocol tree.\n\t\tif (hierarchicalProtocolTree !== undefined) {\n\t\t\tsummarySnapshotTree.trees[\".protocol\"] = hierarchicalProtocolTree;\n\t\t}\n\n\t\treturn summarySnapshotTree;\n\t}\n\n\tprotected initializeFromSnapshot(\n\t\todspSnapshotCacheValue: ISnapshot,\n\t\tcacheOps: boolean = true,\n\t\tcacheSnapshot: boolean = true,\n\t): string | undefined {\n\t\tthis._snapshotSequenceNumber = odspSnapshotCacheValue.sequenceNumber;\n\t\tconst { snapshotTree, blobContents, ops } = odspSnapshotCacheValue;\n\n\t\t// id should be undefined in case of just ops in snapshot.\n\t\tlet id: string | undefined;\n\t\tif (snapshotTree) {\n\t\t\tid = snapshotTree.id;\n\t\t\tassert(id !== undefined, 0x221 /* \"Root tree should contain the id\" */);\n\t\t\tif (cacheSnapshot) {\n\t\t\t\tthis.setRootTree(id, snapshotTree);\n\t\t\t}\n\t\t}\n\n\t\t// Currently always cache blobs as container runtime is not caching them.\n\t\tif (blobContents !== undefined) {\n\t\t\tthis.initBlobsCache(blobContents);\n\t\t}\n\n\t\tif (cacheOps) {\n\t\t\tthis.ops = ops;\n\t\t}\n\t\treturn id;\n\t}\n}\n"]}
@@ -0,0 +1,6 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ export { createOdspVersionManager, type BaseForSeq, type IOdspVersionManager, type OdspFileVersionRef, type ResolvedVersion, } from "./odspVersionManager.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/odspVersionManager/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,wBAAwB,EACxB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,GACpB,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createOdspVersionManager = void 0;
8
+ var odspVersionManager_js_1 = require("./odspVersionManager.js");
9
+ Object.defineProperty(exports, "createOdspVersionManager", { enumerable: true, get: function () { return odspVersionManager_js_1.createOdspVersionManager; } });
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/odspVersionManager/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,iEAMiC;AALhC,iIAAA,wBAAwB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\tcreateOdspVersionManager,\n\ttype BaseForSeq,\n\ttype IOdspVersionManager,\n\ttype OdspFileVersionRef,\n\ttype ResolvedVersion,\n} from \"./odspVersionManager.js\";\n"]}
@@ -0,0 +1,22 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import type { IOdspUrlParts, InstrumentedStorageTokenFetcher } from "@fluidframework/odsp-driver-definitions/internal";
6
+ import type { TelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
7
+ import type { EpochTracker } from "../epochTracker.js";
8
+ import type { IOdspFileVersionFetcher } from "./odspVersionManager.js";
9
+ /**
10
+ * Inputs needed to make authenticated requests against a specific ODSP file.
11
+ */
12
+ export interface OdspFileVersionFetcherProps {
13
+ readonly urlParts: IOdspUrlParts;
14
+ readonly getAuthHeader: InstrumentedStorageTokenFetcher;
15
+ readonly epochTracker: EpochTracker;
16
+ readonly logger: TelemetryLoggerExt;
17
+ }
18
+ /**
19
+ * Create an {@link IOdspFileVersionFetcher} that talks to a specific ODSP file.
20
+ */
21
+ export declare function createOdspFileVersionFetcher(props: OdspFileVersionFetcherProps): IOdspFileVersionFetcher;
22
+ //# sourceMappingURL=odspFileVersionFetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"odspFileVersionFetcher.d.ts","sourceRoot":"","sources":["../../src/odspVersionManager/odspFileVersionFetcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,KAAK,EACX,aAAa,EACb,+BAA+B,EAC/B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAInF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMvD,OAAO,KAAK,EAAsB,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAmB3F;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,+BAA+B,CAAC;IACxD,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACpC;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC3C,KAAK,EAAE,2BAA2B,GAChC,uBAAuB,CA6EzB"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createOdspFileVersionFetcher = void 0;
8
+ const compactSnapshotParser_js_1 = require("../compactSnapshotParser.js");
9
+ const getUrlAndHeadersWithAuth_js_1 = require("../getUrlAndHeadersWithAuth.js");
10
+ const odspSnapshotParser_js_1 = require("../odspSnapshotParser.js");
11
+ const odspUrlHelper_js_1 = require("../odspUrlHelper.js");
12
+ const odspUtils_js_1 = require("../odspUtils.js");
13
+ /**
14
+ * Create an {@link IOdspFileVersionFetcher} that talks to a specific ODSP file.
15
+ */
16
+ function createOdspFileVersionFetcher(props) {
17
+ const { urlParts, getAuthHeader, epochTracker, logger } = props;
18
+ const { siteUrl, driveId, itemId } = urlParts;
19
+ const listFileVersions = async () => (0, odspUtils_js_1.getWithRetryForTokenRefresh)(async (options) => {
20
+ const method = "GET";
21
+ const versions = [];
22
+ // The file's version history (distinct from the driver's snapshot list), from the same API
23
+ // root as the snapshot call so consumer (ODC) and enterprise (SPO) hosts are handled alike.
24
+ // A long history is paged, so follow `@odata.nextLink` until it is absent; otherwise a base
25
+ // version beyond the first page would be missed and wrongly reported as "no base version".
26
+ let url = `${(0, odspUrlHelper_js_1.getApiRoot)(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions`;
27
+ do {
28
+ const token = await getAuthHeader({ ...options, request: { url, method } }, "FileVersions");
29
+ const headers = (0, getUrlAndHeadersWithAuth_js_1.getHeadersWithAuth)(token);
30
+ const response = await epochTracker.fetchAndParseAsJSON(url, { method, headers }, "versions");
31
+ const page = response.content;
32
+ // The API returns versions newest-first.
33
+ for (const version of page.value ?? []) {
34
+ versions.push({
35
+ versionId: version.id,
36
+ lastModifiedDateTime: version.lastModifiedDateTime,
37
+ });
38
+ }
39
+ url = page["@odata.nextLink"] ?? "";
40
+ } while (url);
41
+ return versions;
42
+ });
43
+ const resolveSequenceNumber = async (versionId) => (0, odspUtils_js_1.getWithRetryForTokenRefresh)(async (options) => {
44
+ // A file version's sequence number lives inside that version's snapshot, so fetch the snapshot
45
+ // from the version-scoped endpoint. `blobs=2` inlines blob contents so the `.protocol/attributes`
46
+ // blob (which carries the sequence number) is included; `deltas=1` is intentionally omitted, as
47
+ // it would bundle the op stream and its op-level sequence numbers.
48
+ const url = `${(0, odspUrlHelper_js_1.getApiRoot)(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions/${encodeURIComponent(versionId)}/opStream/snapshots/trees/latest?blobs=2`;
49
+ const method = "GET";
50
+ const token = await getAuthHeader({ ...options, request: { url, method } }, "FileVersionSnapshot");
51
+ const headers = (0, getUrlAndHeadersWithAuth_js_1.getHeadersWithAuth)(token);
52
+ // The server can return the snapshot in one of two equivalent framings: verbose JSON, or
53
+ // "ms-fluid" — ODSP's compact binary encoding of the same snapshot. Advertise both, and pin the
54
+ // binary format version (as the driver's own snapshot fetch does) so the server cannot hand back
55
+ // a binary version this code's parser does not understand.
56
+ headers.accept = `application/json, application/ms-fluid; v=${compactSnapshotParser_js_1.currentReadVersion}`;
57
+ const response = await epochTracker.fetch(url, { method, headers }, "treesLatest");
58
+ const contentType = response.headers.get("content-type") ?? "";
59
+ let sequenceNumber;
60
+ if (contentType.includes("application/json")) {
61
+ // JSON framing: read it with the driver's JSON snapshot parser.
62
+ const snapshotJson = (await response.content.json());
63
+ sequenceNumber =
64
+ (0, odspSnapshotParser_js_1.convertOdspSnapshotToSnapshotTreeAndBlobs)(snapshotJson).sequenceNumber;
65
+ }
66
+ else {
67
+ // ms-fluid framing: the compact binary form; read it with the driver's compact-snapshot parser.
68
+ const bytes = new Uint8Array(await response.content.arrayBuffer());
69
+ sequenceNumber = (0, compactSnapshotParser_js_1.parseCompactSnapshotResponse)(bytes, logger).sequenceNumber;
70
+ }
71
+ // A version's snapshot must carry a sequence number; a missing one is surfaced as an error
72
+ // naming the version, rather than returning a wrong value.
73
+ if (sequenceNumber === undefined) {
74
+ throw new Error(`ODSP file version ${versionId} snapshot is missing a sequenceNumber`);
75
+ }
76
+ return sequenceNumber;
77
+ });
78
+ return { listFileVersions, resolveSequenceNumber };
79
+ }
80
+ exports.createOdspFileVersionFetcher = createOdspFileVersionFetcher;
81
+ //# sourceMappingURL=odspFileVersionFetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"odspFileVersionFetcher.js","sourceRoot":"","sources":["../../src/odspVersionManager/odspFileVersionFetcher.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\n/*\n * An {@link IOdspFileVersionFetcher} backed by the ODSP REST APIs:\n * - GET /_api/v2.1/.../versions -- enumerate the file's versions.\n * - GET /_api/v2.1/.../versions/{label}/opStream/snapshots/trees/latest?blobs=2 -- fetch a version's\n * snapshot and read its sequence number, parsed with the driver's snapshot parser.\n */\n\nimport type {\n\tIOdspUrlParts,\n\tInstrumentedStorageTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport type { TelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport { currentReadVersion, parseCompactSnapshotResponse } from \"../compactSnapshotParser.js\";\nimport type { IOdspSnapshot } from \"../contracts.js\";\nimport type { EpochTracker } from \"../epochTracker.js\";\nimport { getHeadersWithAuth } from \"../getUrlAndHeadersWithAuth.js\";\nimport { convertOdspSnapshotToSnapshotTreeAndBlobs } from \"../odspSnapshotParser.js\";\nimport { getApiRoot } from \"../odspUrlHelper.js\";\nimport { getWithRetryForTokenRefresh } from \"../odspUtils.js\";\n\nimport type { OdspFileVersionRef, IOdspFileVersionFetcher } from \"./odspVersionManager.js\";\n\n/**\n * Raw shape of a OneDrive/SharePoint driveItem version (an entry in the `/versions` response).\n * @see https://learn.microsoft.com/en-us/onedrive/developer/rest-api/resources/driveitemversion\n */\ninterface IDriveItemVersion {\n\t/** The version's label, e.g. \"42.0\". */\n\treadonly id: string;\n\treadonly lastModifiedDateTime: string;\n}\n\n/** A single page of the driveItem `/versions` response. */\ninterface IDriveItemVersionsPage {\n\treadonly value?: IDriveItemVersion[];\n\t/** Absolute URL of the next page, present only while more versions remain. */\n\treadonly \"@odata.nextLink\"?: string;\n}\n\n/**\n * Inputs needed to make authenticated requests against a specific ODSP file.\n */\nexport interface OdspFileVersionFetcherProps {\n\treadonly urlParts: IOdspUrlParts;\n\treadonly getAuthHeader: InstrumentedStorageTokenFetcher;\n\treadonly epochTracker: EpochTracker;\n\treadonly logger: TelemetryLoggerExt;\n}\n\n/**\n * Create an {@link IOdspFileVersionFetcher} that talks to a specific ODSP file.\n */\nexport function createOdspFileVersionFetcher(\n\tprops: OdspFileVersionFetcherProps,\n): IOdspFileVersionFetcher {\n\tconst { urlParts, getAuthHeader, epochTracker, logger } = props;\n\tconst { siteUrl, driveId, itemId } = urlParts;\n\n\tconst listFileVersions = async (): Promise<OdspFileVersionRef[]> =>\n\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\tconst method = \"GET\";\n\t\t\tconst versions: OdspFileVersionRef[] = [];\n\t\t\t// The file's version history (distinct from the driver's snapshot list), from the same API\n\t\t\t// root as the snapshot call so consumer (ODC) and enterprise (SPO) hosts are handled alike.\n\t\t\t// A long history is paged, so follow `@odata.nextLink` until it is absent; otherwise a base\n\t\t\t// version beyond the first page would be missed and wrongly reported as \"no base version\".\n\t\t\tlet url = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions`;\n\t\t\tdo {\n\t\t\t\tconst token = await getAuthHeader(\n\t\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\t\"FileVersions\",\n\t\t\t\t);\n\t\t\t\tconst headers = getHeadersWithAuth(token);\n\t\t\t\tconst response = await epochTracker.fetchAndParseAsJSON<{\n\t\t\t\t\tvalue?: IDriveItemVersion[];\n\t\t\t\t}>(url, { method, headers }, \"versions\");\n\t\t\t\tconst page = response.content as IDriveItemVersionsPage;\n\t\t\t\t// The API returns versions newest-first.\n\t\t\t\tfor (const version of page.value ?? []) {\n\t\t\t\t\tversions.push({\n\t\t\t\t\t\tversionId: version.id,\n\t\t\t\t\t\tlastModifiedDateTime: version.lastModifiedDateTime,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\turl = page[\"@odata.nextLink\"] ?? \"\";\n\t\t\t} while (url);\n\t\t\treturn versions;\n\t\t});\n\n\tconst resolveSequenceNumber = async (versionId: string): Promise<number> =>\n\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\t// A file version's sequence number lives inside that version's snapshot, so fetch the snapshot\n\t\t\t// from the version-scoped endpoint. `blobs=2` inlines blob contents so the `.protocol/attributes`\n\t\t\t// blob (which carries the sequence number) is included; `deltas=1` is intentionally omitted, as\n\t\t\t// it would bundle the op stream and its op-level sequence numbers.\n\t\t\tconst url = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions/${encodeURIComponent(\n\t\t\t\tversionId,\n\t\t\t)}/opStream/snapshots/trees/latest?blobs=2`;\n\t\t\tconst method = \"GET\";\n\t\t\tconst token = await getAuthHeader(\n\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\"FileVersionSnapshot\",\n\t\t\t);\n\t\t\tconst headers = getHeadersWithAuth(token);\n\t\t\t// The server can return the snapshot in one of two equivalent framings: verbose JSON, or\n\t\t\t// \"ms-fluid\" — ODSP's compact binary encoding of the same snapshot. Advertise both, and pin the\n\t\t\t// binary format version (as the driver's own snapshot fetch does) so the server cannot hand back\n\t\t\t// a binary version this code's parser does not understand.\n\t\t\theaders.accept = `application/json, application/ms-fluid; v=${currentReadVersion}`;\n\t\t\tconst response = await epochTracker.fetch(url, { method, headers }, \"treesLatest\");\n\t\t\tconst contentType = response.headers.get(\"content-type\") ?? \"\";\n\t\t\tlet sequenceNumber: number | undefined;\n\t\t\tif (contentType.includes(\"application/json\")) {\n\t\t\t\t// JSON framing: read it with the driver's JSON snapshot parser.\n\t\t\t\tconst snapshotJson = (await response.content.json()) as IOdspSnapshot;\n\t\t\t\tsequenceNumber =\n\t\t\t\t\tconvertOdspSnapshotToSnapshotTreeAndBlobs(snapshotJson).sequenceNumber;\n\t\t\t} else {\n\t\t\t\t// ms-fluid framing: the compact binary form; read it with the driver's compact-snapshot parser.\n\t\t\t\tconst bytes = new Uint8Array(await response.content.arrayBuffer());\n\t\t\t\tsequenceNumber = parseCompactSnapshotResponse(bytes, logger).sequenceNumber;\n\t\t\t}\n\t\t\t// A version's snapshot must carry a sequence number; a missing one is surfaced as an error\n\t\t\t// naming the version, rather than returning a wrong value.\n\t\t\tif (sequenceNumber === undefined) {\n\t\t\t\tthrow new Error(`ODSP file version ${versionId} snapshot is missing a sequenceNumber`);\n\t\t\t}\n\t\t\treturn sequenceNumber;\n\t\t});\n\n\treturn { listFileVersions, resolveSequenceNumber };\n}\n"]}
@@ -0,0 +1,98 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ /**
6
+ * Selects the ODSP file version whose snapshot sits at or before a target Fluid sequence number —
7
+ * the base to load or replay from when materializing a document at a point in time.
8
+ *
9
+ * The selection logic depends on an injected {@link IOdspFileVersionFetcher}, so it is independent of
10
+ * how versions are enumerated and resolved (real ODSP, a test double, or an alternative backend).
11
+ */
12
+ import { type OdspFileVersionFetcherProps } from "./odspFileVersionFetcher.js";
13
+ /**
14
+ * A single ODSP file version, as listed by the file's version history.
15
+ */
16
+ export interface OdspFileVersionRef {
17
+ /**
18
+ * The version's label (e.g. `"42.0"`), used to address the version when fetching it.
19
+ */
20
+ readonly versionId: string;
21
+ /**
22
+ * Last-modified timestamp of this version, ISO-8601.
23
+ */
24
+ readonly lastModifiedDateTime: string;
25
+ }
26
+ /**
27
+ * An ODSP file version together with its resolved Fluid sequence number.
28
+ */
29
+ export interface ResolvedVersion extends OdspFileVersionRef {
30
+ /**
31
+ * The Fluid sequence number the version's snapshot represents.
32
+ */
33
+ readonly sequenceNumber: number;
34
+ }
35
+ /**
36
+ * Result of resolving the base version for a target sequence number.
37
+ *
38
+ * @remarks
39
+ * There is intentionally no `targetIsLive` case: when the target is at/after the newest recoverable
40
+ * version, the greatest version with `seq <= target` IS that newest version, so it is a normal
41
+ * `found`. A consumer may separately choose to load the live file when the target is near the head.
42
+ */
43
+ export type BaseForSeq = {
44
+ /** A recoverable version with `sequenceNumber <= target` was found. */
45
+ readonly kind: "found";
46
+ readonly base: ResolvedVersion;
47
+ } | {
48
+ /** No recoverable version has `sequenceNumber <= target` (target predates retained history). */
49
+ readonly kind: "noBaseVersion";
50
+ /** The oldest sequence number that was resolved while searching, if any. */
51
+ readonly oldestResolvedSeq?: number;
52
+ };
53
+ /**
54
+ * Provides a file's versions and resolves each version's Fluid sequence number. Injected into
55
+ * the version manager so the selection logic does not depend on how versions are fetched.
56
+ */
57
+ export interface IOdspFileVersionFetcher {
58
+ /**
59
+ * Enumerate the file's versions, newest-first.
60
+ */
61
+ listFileVersions(): Promise<OdspFileVersionRef[]>;
62
+ /**
63
+ * Resolve a single version's Fluid sequence number. Throws on failure rather than returning a
64
+ * wrong value.
65
+ */
66
+ resolveSequenceNumber(versionId: string): Promise<number>;
67
+ }
68
+ /**
69
+ * Selects the file version to use as the base for loading or replaying to a target sequence number.
70
+ */
71
+ export interface IOdspVersionManager {
72
+ /**
73
+ * Given a target sequence number, return the closest version at or before it (`found`), or
74
+ * `noBaseVersion` if the target predates the oldest retained version.
75
+ */
76
+ findBaseForSeq(target: number): Promise<BaseForSeq>;
77
+ }
78
+ /**
79
+ * Default {@link IOdspVersionManager}. Caches the version list and resolved sequence numbers. The
80
+ * resolution strategy (eager, newest-to-oldest, stopping at the first usable base) is hidden behind
81
+ * {@link findBaseForSeq} and can change without affecting callers.
82
+ */
83
+ export declare class OdspVersionManager implements IOdspVersionManager {
84
+ private readonly fetcher;
85
+ private versionsCache;
86
+ private readonly seqByVersion;
87
+ constructor(fetcher: IOdspFileVersionFetcher);
88
+ refresh(): void;
89
+ findBaseForSeq(target: number): Promise<BaseForSeq>;
90
+ listVersions(): Promise<ResolvedVersion[]>;
91
+ private getVersions;
92
+ private resolveSeq;
93
+ }
94
+ /**
95
+ * Create an {@link IOdspVersionManager} for a specific ODSP file, wired to the real ODSP REST APIs.
96
+ */
97
+ export declare function createOdspVersionManager(props: OdspFileVersionFetcherProps): IOdspVersionManager;
98
+ //# sourceMappingURL=odspVersionManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"odspVersionManager.d.ts","sourceRoot":"","sources":["../../src/odspVersionManager/odspVersionManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AAEH,OAAO,EAEN,KAAK,2BAA2B,EAChC,MAAM,6BAA6B,CAAC;AAErC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IAC1D;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GACnB;IACA,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;CAC9B,GACD;IACA,gGAAgG;IAChG,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,4EAA4E;IAC5E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC;AAEL;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACvC;;OAEG;IACH,gBAAgB,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAClD;;;OAGG;IACH,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1D;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;OAGG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACpD;AAED;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB;IAI1C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAH3C,OAAO,CAAC,aAAa,CAA4C;IACjE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsC;gBAE/B,OAAO,EAAE,uBAAuB;IAE7D,OAAO,IAAI,IAAI;IAKT,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAyBnD,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;YAYzC,WAAW;YAOX,UAAU;CAUxB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACvC,KAAK,EAAE,2BAA2B,GAChC,mBAAmB,CAErB"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createOdspVersionManager = exports.OdspVersionManager = void 0;
8
+ /**
9
+ * Selects the ODSP file version whose snapshot sits at or before a target Fluid sequence number —
10
+ * the base to load or replay from when materializing a document at a point in time.
11
+ *
12
+ * The selection logic depends on an injected {@link IOdspFileVersionFetcher}, so it is independent of
13
+ * how versions are enumerated and resolved (real ODSP, a test double, or an alternative backend).
14
+ */
15
+ const odspFileVersionFetcher_js_1 = require("./odspFileVersionFetcher.js");
16
+ /**
17
+ * Default {@link IOdspVersionManager}. Caches the version list and resolved sequence numbers. The
18
+ * resolution strategy (eager, newest-to-oldest, stopping at the first usable base) is hidden behind
19
+ * {@link findBaseForSeq} and can change without affecting callers.
20
+ */
21
+ class OdspVersionManager {
22
+ constructor(fetcher) {
23
+ this.fetcher = fetcher;
24
+ this.seqByVersion = new Map();
25
+ }
26
+ refresh() {
27
+ this.versionsCache = undefined;
28
+ this.seqByVersion.clear();
29
+ }
30
+ async findBaseForSeq(target) {
31
+ // Recoverable base candidates = every version except the tip (index 0 ≈ the live document).
32
+ const versions = await this.getVersions();
33
+ const candidates = versions.slice(1);
34
+ // Versions are listed newest-first, and version order is expected to track sequence number, so
35
+ // the first candidate whose seq is at or before the target is taken as the closest base. Because
36
+ // any base at or before the target replays forward to the same state, this early stop is an
37
+ // optimization, not a correctness requirement: if version order and sequence order ever diverge,
38
+ // a base that is valid but not strictly the closest may be chosen.
39
+ // Scanning newest-first also yields the newest of versions sharing a sequence number (dedup).
40
+ let oldestResolvedSeq;
41
+ for (const version of candidates) {
42
+ const sequenceNumber = await this.resolveSeq(version.versionId);
43
+ oldestResolvedSeq =
44
+ oldestResolvedSeq === undefined
45
+ ? sequenceNumber
46
+ : Math.min(oldestResolvedSeq, sequenceNumber);
47
+ if (sequenceNumber <= target) {
48
+ return { kind: "found", base: { ...version, sequenceNumber } };
49
+ }
50
+ }
51
+ return { kind: "noBaseVersion", oldestResolvedSeq };
52
+ }
53
+ async listVersions() {
54
+ const versions = await this.getVersions();
55
+ // Resolution order does not matter here, so resolve concurrently; the newest-first array order is
56
+ // preserved by Promise.all regardless of completion order.
57
+ return Promise.all(versions.map(async (version) => ({
58
+ ...version,
59
+ sequenceNumber: await this.resolveSeq(version.versionId),
60
+ })));
61
+ }
62
+ async getVersions() {
63
+ // Cache the pending promise, not the awaited value, so concurrent callers share one fetch and a
64
+ // refresh() that runs while the fetch is in flight is not overwritten when the fetch settles.
65
+ this.versionsCache ??= this.fetcher.listFileVersions();
66
+ return this.versionsCache;
67
+ }
68
+ async resolveSeq(versionId) {
69
+ // Cache the pending promise (a version's sequence number never changes) so concurrent callers
70
+ // coalesce and a refresh() is not clobbered by a fetch that was already in flight.
71
+ let pending = this.seqByVersion.get(versionId);
72
+ if (pending === undefined) {
73
+ pending = this.fetcher.resolveSequenceNumber(versionId);
74
+ this.seqByVersion.set(versionId, pending);
75
+ }
76
+ return pending;
77
+ }
78
+ }
79
+ exports.OdspVersionManager = OdspVersionManager;
80
+ /**
81
+ * Create an {@link IOdspVersionManager} for a specific ODSP file, wired to the real ODSP REST APIs.
82
+ */
83
+ function createOdspVersionManager(props) {
84
+ return new OdspVersionManager((0, odspFileVersionFetcher_js_1.createOdspFileVersionFetcher)(props));
85
+ }
86
+ exports.createOdspVersionManager = createOdspVersionManager;
87
+ //# sourceMappingURL=odspVersionManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"odspVersionManager.js","sourceRoot":"","sources":["../../src/odspVersionManager/odspVersionManager.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;;;;;GAMG;AAEH,2EAGqC;AA0ErC;;;;GAIG;AACH,MAAa,kBAAkB;IAI9B,YAAoC,OAAgC;QAAhC,YAAO,GAAP,OAAO,CAAyB;QAFnD,iBAAY,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEI,CAAC;IAEjE,OAAO;QACb,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAEM,KAAK,CAAC,cAAc,CAAC,MAAc;QACzC,4FAA4F;QAC5F,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAErC,+FAA+F;QAC/F,iGAAiG;QACjG,4FAA4F;QAC5F,iGAAiG;QACjG,mEAAmE;QACnE,8FAA8F;QAC9F,IAAI,iBAAqC,CAAC;QAC1C,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;YAClC,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAChE,iBAAiB;gBAChB,iBAAiB,KAAK,SAAS;oBAC9B,CAAC,CAAC,cAAc;oBAChB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;YAChD,IAAI,cAAc,IAAI,MAAM,EAAE,CAAC;gBAC9B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,EAAE,CAAC;YAChE,CAAC;QACF,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;IACrD,CAAC;IAEM,KAAK,CAAC,YAAY;QACxB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,kGAAkG;QAClG,2DAA2D;QAC3D,OAAO,OAAO,CAAC,GAAG,CACjB,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;YAChC,GAAG,OAAO;YACV,cAAc,EAAE,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC;SACxD,CAAC,CAAC,CACH,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW;QACxB,gGAAgG;QAChG,8FAA8F;QAC9F,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC,aAAa,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,SAAiB;QACzC,8FAA8F;QAC9F,mFAAmF;QACnF,IAAI,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;YACxD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;CACD;AAjED,gDAiEC;AAED;;GAEG;AACH,SAAgB,wBAAwB,CACvC,KAAkC;IAElC,OAAO,IAAI,kBAAkB,CAAC,IAAA,wDAA4B,EAAC,KAAK,CAAC,CAAC,CAAC;AACpE,CAAC;AAJD,4DAIC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Selects the ODSP file version whose snapshot sits at or before a target Fluid sequence number —\n * the base to load or replay from when materializing a document at a point in time.\n *\n * The selection logic depends on an injected {@link IOdspFileVersionFetcher}, so it is independent of\n * how versions are enumerated and resolved (real ODSP, a test double, or an alternative backend).\n */\n\nimport {\n\tcreateOdspFileVersionFetcher,\n\ttype OdspFileVersionFetcherProps,\n} from \"./odspFileVersionFetcher.js\";\n\n/**\n * A single ODSP file version, as listed by the file's version history.\n */\nexport interface OdspFileVersionRef {\n\t/**\n\t * The version's label (e.g. `\"42.0\"`), used to address the version when fetching it.\n\t */\n\treadonly versionId: string;\n\t/**\n\t * Last-modified timestamp of this version, ISO-8601.\n\t */\n\treadonly lastModifiedDateTime: string;\n}\n\n/**\n * An ODSP file version together with its resolved Fluid sequence number.\n */\nexport interface ResolvedVersion extends OdspFileVersionRef {\n\t/**\n\t * The Fluid sequence number the version's snapshot represents.\n\t */\n\treadonly sequenceNumber: number;\n}\n\n/**\n * Result of resolving the base version for a target sequence number.\n *\n * @remarks\n * There is intentionally no `targetIsLive` case: when the target is at/after the newest recoverable\n * version, the greatest version with `seq <= target` IS that newest version, so it is a normal\n * `found`. A consumer may separately choose to load the live file when the target is near the head.\n */\nexport type BaseForSeq =\n\t| {\n\t\t\t/** A recoverable version with `sequenceNumber <= target` was found. */\n\t\t\treadonly kind: \"found\";\n\t\t\treadonly base: ResolvedVersion;\n\t }\n\t| {\n\t\t\t/** No recoverable version has `sequenceNumber <= target` (target predates retained history). */\n\t\t\treadonly kind: \"noBaseVersion\";\n\t\t\t/** The oldest sequence number that was resolved while searching, if any. */\n\t\t\treadonly oldestResolvedSeq?: number;\n\t };\n\n/**\n * Provides a file's versions and resolves each version's Fluid sequence number. Injected into\n * the version manager so the selection logic does not depend on how versions are fetched.\n */\nexport interface IOdspFileVersionFetcher {\n\t/**\n\t * Enumerate the file's versions, newest-first.\n\t */\n\tlistFileVersions(): Promise<OdspFileVersionRef[]>;\n\t/**\n\t * Resolve a single version's Fluid sequence number. Throws on failure rather than returning a\n\t * wrong value.\n\t */\n\tresolveSequenceNumber(versionId: string): Promise<number>;\n}\n\n/**\n * Selects the file version to use as the base for loading or replaying to a target sequence number.\n */\nexport interface IOdspVersionManager {\n\t/**\n\t * Given a target sequence number, return the closest version at or before it (`found`), or\n\t * `noBaseVersion` if the target predates the oldest retained version.\n\t */\n\tfindBaseForSeq(target: number): Promise<BaseForSeq>;\n}\n\n/**\n * Default {@link IOdspVersionManager}. Caches the version list and resolved sequence numbers. The\n * resolution strategy (eager, newest-to-oldest, stopping at the first usable base) is hidden behind\n * {@link findBaseForSeq} and can change without affecting callers.\n */\nexport class OdspVersionManager implements IOdspVersionManager {\n\tprivate versionsCache: Promise<OdspFileVersionRef[]> | undefined;\n\tprivate readonly seqByVersion = new Map<string, Promise<number>>();\n\n\tpublic constructor(private readonly fetcher: IOdspFileVersionFetcher) {}\n\n\tpublic refresh(): void {\n\t\tthis.versionsCache = undefined;\n\t\tthis.seqByVersion.clear();\n\t}\n\n\tpublic async findBaseForSeq(target: number): Promise<BaseForSeq> {\n\t\t// Recoverable base candidates = every version except the tip (index 0 ≈ the live document).\n\t\tconst versions = await this.getVersions();\n\t\tconst candidates = versions.slice(1);\n\n\t\t// Versions are listed newest-first, and version order is expected to track sequence number, so\n\t\t// the first candidate whose seq is at or before the target is taken as the closest base. Because\n\t\t// any base at or before the target replays forward to the same state, this early stop is an\n\t\t// optimization, not a correctness requirement: if version order and sequence order ever diverge,\n\t\t// a base that is valid but not strictly the closest may be chosen.\n\t\t// Scanning newest-first also yields the newest of versions sharing a sequence number (dedup).\n\t\tlet oldestResolvedSeq: number | undefined;\n\t\tfor (const version of candidates) {\n\t\t\tconst sequenceNumber = await this.resolveSeq(version.versionId);\n\t\t\toldestResolvedSeq =\n\t\t\t\toldestResolvedSeq === undefined\n\t\t\t\t\t? sequenceNumber\n\t\t\t\t\t: Math.min(oldestResolvedSeq, sequenceNumber);\n\t\t\tif (sequenceNumber <= target) {\n\t\t\t\treturn { kind: \"found\", base: { ...version, sequenceNumber } };\n\t\t\t}\n\t\t}\n\t\treturn { kind: \"noBaseVersion\", oldestResolvedSeq };\n\t}\n\n\tpublic async listVersions(): Promise<ResolvedVersion[]> {\n\t\tconst versions = await this.getVersions();\n\t\t// Resolution order does not matter here, so resolve concurrently; the newest-first array order is\n\t\t// preserved by Promise.all regardless of completion order.\n\t\treturn Promise.all(\n\t\t\tversions.map(async (version) => ({\n\t\t\t\t...version,\n\t\t\t\tsequenceNumber: await this.resolveSeq(version.versionId),\n\t\t\t})),\n\t\t);\n\t}\n\n\tprivate async getVersions(): Promise<OdspFileVersionRef[]> {\n\t\t// Cache the pending promise, not the awaited value, so concurrent callers share one fetch and a\n\t\t// refresh() that runs while the fetch is in flight is not overwritten when the fetch settles.\n\t\tthis.versionsCache ??= this.fetcher.listFileVersions();\n\t\treturn this.versionsCache;\n\t}\n\n\tprivate async resolveSeq(versionId: string): Promise<number> {\n\t\t// Cache the pending promise (a version's sequence number never changes) so concurrent callers\n\t\t// coalesce and a refresh() is not clobbered by a fetch that was already in flight.\n\t\tlet pending = this.seqByVersion.get(versionId);\n\t\tif (pending === undefined) {\n\t\t\tpending = this.fetcher.resolveSequenceNumber(versionId);\n\t\t\tthis.seqByVersion.set(versionId, pending);\n\t\t}\n\t\treturn pending;\n\t}\n}\n\n/**\n * Create an {@link IOdspVersionManager} for a specific ODSP file, wired to the real ODSP REST APIs.\n */\nexport function createOdspVersionManager(\n\tprops: OdspFileVersionFetcherProps,\n): IOdspVersionManager {\n\treturn new OdspVersionManager(createOdspFileVersionFetcher(props));\n}\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/odsp-driver";
8
- export declare const pkgVersion = "2.110.0";
8
+ export declare const pkgVersion = "2.112.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -8,5 +8,5 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.pkgVersion = exports.pkgName = void 0;
10
10
  exports.pkgName = "@fluidframework/odsp-driver";
11
- exports.pkgVersion = "2.110.0";
11
+ exports.pkgVersion = "2.112.0";
12
12
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,6BAA6B,CAAC;AACxC,QAAA,UAAU,GAAG,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/odsp-driver\";\nexport const pkgVersion = \"2.110.0\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,6BAA6B,CAAC;AACxC,QAAA,UAAU,GAAG,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/odsp-driver\";\nexport const pkgVersion = \"2.112.0\";\n"]}
@@ -8,27 +8,27 @@ import type { ISnapshotOptions, OdspResourceTokenFetchOptions, TokenFetcher } fr
8
8
  import { type SnapshotFormatSupportType } from "./fetchSnapshot.js";
9
9
  import type { OdspDocumentServiceFactory } from "./odspDocumentServiceFactory.js";
10
10
  /**
11
- * Function to prefetch the snapshot and cached it in the persistant cache, so that when the container is loaded
11
+ * Function to prefetch the snapshot and cached it in the persistent cache, so that when the container is loaded
12
12
  * the cached latest snapshot could be used and removes the network call from the critical path.
13
13
  *
14
14
  * @param resolvedUrl - Resolved url to fetch the snapshot.
15
15
  * @param getStorageToken - function that can provide the storage token for a given site. This is
16
16
  * is also referred to as the "VROOM" token in SPO.
17
17
  * @param persistedCache - Cache to store the fetched snapshot.
18
- * @param forceAccessTokenViaAuthorizationHeader - @deprecated Not used, true value always used instead. Whether to force passing given token via authorization header.
18
+ * @param _forceAccessTokenViaAuthorizationHeader - Deprecated and not used.
19
19
  * @param logger - Logger to have telemetry events.
20
20
  * @param hostSnapshotFetchOptions - Options to fetch the snapshot if any. Otherwise default will be used.
21
21
  * @param enableRedeemFallback - True to have the sharing link redeem fallback in case the Trees Latest/Redeem
22
22
  * 1RT call fails with redeem error. During fallback it will first redeem the sharing link and then make
23
23
  * the Trees latest call.
24
24
  * Note: this can be considered deprecated - it will be replaced with `snapshotFormatFetchType`.
25
- * @param fetchBinarySnapshotFormat - Control if we want to fetch binary format snapshot.
26
- * @param snapshotFormatFetchType - Snapshot format to fetch.
25
+ * @param _fetchBinarySnapshotFormat - Deprecated and not used.
26
+ * @param _snapshotFormatFetchType - Deprecated and not used.
27
27
  * @param odspDocumentServiceFactory - factory to access the non persistent cache and store the prefetch promise.
28
28
  *
29
29
  * @returns `true` if the snapshot is cached, `false` otherwise.
30
30
  * @legacy
31
31
  * @beta
32
32
  */
33
- export declare function prefetchLatestSnapshot(resolvedUrl: IResolvedUrl, getStorageToken: TokenFetcher<OdspResourceTokenFetchOptions>, persistedCache: IPersistedCache, forceAccessTokenViaAuthorizationHeader: boolean, logger: ITelemetryBaseLogger, hostSnapshotFetchOptions: ISnapshotOptions | undefined, enableRedeemFallback?: boolean, fetchBinarySnapshotFormat?: boolean, snapshotFormatFetchType?: SnapshotFormatSupportType, odspDocumentServiceFactory?: OdspDocumentServiceFactory): Promise<boolean>;
33
+ export declare function prefetchLatestSnapshot(resolvedUrl: IResolvedUrl, getStorageToken: TokenFetcher<OdspResourceTokenFetchOptions>, persistedCache: IPersistedCache, _forceAccessTokenViaAuthorizationHeader: boolean, logger: ITelemetryBaseLogger, hostSnapshotFetchOptions: ISnapshotOptions | undefined, enableRedeemFallback?: boolean, _fetchBinarySnapshotFormat?: boolean, _snapshotFormatFetchType?: SnapshotFormatSupportType, odspDocumentServiceFactory?: OdspDocumentServiceFactory): Promise<boolean>;
34
34
  //# sourceMappingURL=prefetchLatestSnapshot.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prefetchLatestSnapshot.d.ts","sourceRoot":"","sources":["../src/prefetchLatestSnapshot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,OAAO,KAAK,EACX,eAAe,EACf,YAAY,EACZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAGX,gBAAgB,EAChB,6BAA6B,EAC7B,YAAY,EAEZ,MAAM,kDAAkD,CAAC;AAO1D,OAAO,EAEN,KAAK,yBAAyB,EAG9B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAUlF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,sBAAsB,CAC3C,WAAW,EAAE,YAAY,EACzB,eAAe,EAAE,YAAY,CAAC,6BAA6B,CAAC,EAC5D,cAAc,EAAE,eAAe,EAC/B,sCAAsC,EAAE,OAAO,EAC/C,MAAM,EAAE,oBAAoB,EAC5B,wBAAwB,EAAE,gBAAgB,GAAG,SAAS,EACtD,oBAAoB,GAAE,OAAc,EACpC,yBAAyB,CAAC,EAAE,OAAO,EACnC,uBAAuB,CAAC,EAAE,yBAAyB,EACnD,0BAA0B,CAAC,EAAE,0BAA0B,GACrD,OAAO,CAAC,OAAO,CAAC,CA8GlB"}
1
+ {"version":3,"file":"prefetchLatestSnapshot.d.ts","sourceRoot":"","sources":["../src/prefetchLatestSnapshot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,OAAO,KAAK,EACX,eAAe,EACf,YAAY,EACZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAGX,gBAAgB,EAChB,6BAA6B,EAC7B,YAAY,EAEZ,MAAM,kDAAkD,CAAC;AAO1D,OAAO,EAEN,KAAK,yBAAyB,EAG9B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAUlF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,sBAAsB,CAC3C,WAAW,EAAE,YAAY,EACzB,eAAe,EAAE,YAAY,CAAC,6BAA6B,CAAC,EAC5D,cAAc,EAAE,eAAe,EAC/B,uCAAuC,EAAE,OAAO,EAChD,MAAM,EAAE,oBAAoB,EAC5B,wBAAwB,EAAE,gBAAgB,GAAG,SAAS,EACtD,oBAAoB,GAAE,OAAc,EACpC,0BAA0B,CAAC,EAAE,OAAO,EACpC,wBAAwB,CAAC,EAAE,yBAAyB,EACpD,0BAA0B,CAAC,EAAE,0BAA0B,GACrD,OAAO,CAAC,OAAO,CAAC,CA6GlB"}
@@ -12,29 +12,29 @@ const internal_3 = require("@fluidframework/telemetry-utils/internal");
12
12
  const fetchSnapshot_js_1 = require("./fetchSnapshot.js");
13
13
  const odspUtils_js_1 = require("./odspUtils.js");
14
14
  /**
15
- * Function to prefetch the snapshot and cached it in the persistant cache, so that when the container is loaded
15
+ * Function to prefetch the snapshot and cached it in the persistent cache, so that when the container is loaded
16
16
  * the cached latest snapshot could be used and removes the network call from the critical path.
17
17
  *
18
18
  * @param resolvedUrl - Resolved url to fetch the snapshot.
19
19
  * @param getStorageToken - function that can provide the storage token for a given site. This is
20
20
  * is also referred to as the "VROOM" token in SPO.
21
21
  * @param persistedCache - Cache to store the fetched snapshot.
22
- * @param forceAccessTokenViaAuthorizationHeader - @deprecated Not used, true value always used instead. Whether to force passing given token via authorization header.
22
+ * @param _forceAccessTokenViaAuthorizationHeader - Deprecated and not used.
23
23
  * @param logger - Logger to have telemetry events.
24
24
  * @param hostSnapshotFetchOptions - Options to fetch the snapshot if any. Otherwise default will be used.
25
25
  * @param enableRedeemFallback - True to have the sharing link redeem fallback in case the Trees Latest/Redeem
26
26
  * 1RT call fails with redeem error. During fallback it will first redeem the sharing link and then make
27
27
  * the Trees latest call.
28
28
  * Note: this can be considered deprecated - it will be replaced with `snapshotFormatFetchType`.
29
- * @param fetchBinarySnapshotFormat - Control if we want to fetch binary format snapshot.
30
- * @param snapshotFormatFetchType - Snapshot format to fetch.
29
+ * @param _fetchBinarySnapshotFormat - Deprecated and not used.
30
+ * @param _snapshotFormatFetchType - Deprecated and not used.
31
31
  * @param odspDocumentServiceFactory - factory to access the non persistent cache and store the prefetch promise.
32
32
  *
33
33
  * @returns `true` if the snapshot is cached, `false` otherwise.
34
34
  * @legacy
35
35
  * @beta
36
36
  */
37
- async function prefetchLatestSnapshot(resolvedUrl, getStorageToken, persistedCache, forceAccessTokenViaAuthorizationHeader, logger, hostSnapshotFetchOptions, enableRedeemFallback = true, fetchBinarySnapshotFormat, snapshotFormatFetchType, odspDocumentServiceFactory) {
37
+ async function prefetchLatestSnapshot(resolvedUrl, getStorageToken, persistedCache, _forceAccessTokenViaAuthorizationHeader, logger, hostSnapshotFetchOptions, enableRedeemFallback = true, _fetchBinarySnapshotFormat, _snapshotFormatFetchType, odspDocumentServiceFactory) {
38
38
  const mc = (0, internal_3.createChildMonitoringContext)({ logger, namespace: "PrefetchSnapshot" });
39
39
  const odspLogger = (0, odspUtils_js_1.createOdspLogger)(mc.logger);
40
40
  const useGroupIdsForSnapshotFetch = (0, odspUtils_js_1.snapshotWithLoadingGroupIdSupported)(mc.config);
@@ -67,7 +67,7 @@ async function prefetchLatestSnapshot(resolvedUrl, getStorageToken, persistedCac
67
67
  const nonPersistentCacheKey = (0, internal_2.getKeyForCacheEntry)(snapshotKey);
68
68
  const snapshotNonPersistentCache = odspDocumentServiceFactory?.snapshotPrefetchResultCache;
69
69
  snapshotNonPersistentCache?.add(nonPersistentCacheKey, async () => snapshotContentsWithEpochP.promise);
70
- await (0, fetchSnapshot_js_1.fetchSnapshotWithRedeem)(odspResolvedUrl, getAuthHeader, hostSnapshotFetchOptions, forceAccessTokenViaAuthorizationHeader, odspLogger, snapshotDownloader, putInCache, removeEntries, loadingGroupIds, enableRedeemFallback)
70
+ await (0, fetchSnapshot_js_1.fetchSnapshotWithRedeem)(odspResolvedUrl, getAuthHeader, hostSnapshotFetchOptions, odspLogger, snapshotDownloader, putInCache, removeEntries, loadingGroupIds, enableRedeemFallback)
71
71
  .then(async (value) => {
72
72
  (0, internal_1.assert)(!!snapshotEpoch, 0x585 /* prefetched snapshot should have a valid epoch */);
73
73
  snapshotContentsWithEpochP.resolve({